Speed1×
Slow motion multiplier
Reduced motion
Show
Live previews
Sliding indicators
ADDToday — per-item cross-fade
Core’s TabList. Each tab draws its own indicator and they cross-fade on opacity, so nothing travels and the eye has to re-find the selection after every change.
Proposed — one indicator travels
One indicator for the strip, moved with transform on --ease-move. Compositor-only, and the eye can follow it. Jump between distant tabs to judge the duration — a bar crossing five tabs feels different from one crossing two.
travel
TabList. The right one is a swizzled copy of that same source with three changes — a hasTravellingIndicator prop, one indicator in the strip positioned over the selected tab, and a context flag telling each Tab to suppress the indicator it draws for itself. It lives at proposed/TabList/, so the difference you are watching is the diff. The position is measured from the DOM rather than tracked in state, because the tabs size themselves — that ResizeObserver is the only real cost the proposal adds, and is the part to review if it ships.The proposed pane uses --ease-move rather than the entry curve, because the indicator is already on screen: it needs a legible path, not an arrival accent. This is also the strongest candidate for the layout spring, since a travelling indicator is exactly the interruptible case.Disclosure bake-off
PARTIAL — three techniquesGrid tracks — CodeBlock, ChatNo measurement needed, and it survives content changing mid-transition. Cannot be used on a table row, which is why this may not be the single winner.
Astryx ships nine duration tokens and one easing token.Nine surfaces disclose content, using three different techniques.
Height interpolationNeeds a scrollHeight measurement on every open, so streaming content fights it. Works anywhere, including a table row.
Astryx ships nine duration tokens and one easing token.Nine surfaces disclose content, using three different techniques.
Height + offset fade — CollapsibleHeight plus a delayed content fade. The newest component uses this, and it is the only one that does.
Astryx ships nine duration tokens and one easing token.Nine surfaces disclose content, using three different techniques.
reveal
SideNav rail collapse
ADDToday — only the chevron rotatesOnly the chevron rotates. The rail snaps between widths, so the content beside it jumps. Approximated — see the note in LabDemos.tsx for why this one is not the real SideNav.
HomeProjectsComponentsTokensSettings
Content
Proposed — the rail animatesThe rail’s own width animates on --ease-move. width is a layout property, so this is a deliberate criterion-6 exception — the transform alternative leaves neighbouring content un-reflowed until the animation ends, which reads worse on a rail this narrow.
HomeProjectsComponentsTokensSettings
Content
The transform alternative — translate the rail and clip it — keeps the animation on the compositor but leaves the content beside it un-reflowed until the end, which reads worse than the layout cost. Worth prototyping both before granting the exception.Both panes here are approximated, not the real component. A fork of core’s
SideNav needs SideNavCollapseContext on the public surface — SideNav is a provider and core exports only the reader hook. Importing the context by relative path compiles and is silently wrong: the app resolves to dist while the relative path reaches src, so the fork provides one context object and core’s own children read another. The one-line fix is a public API surface change and wants its own review, so this demo stays weaker than the TabList one below it until that lands.Skeleton → content
ADDToday — content hard-swapsContent hard-swaps the instant it arrives, at a moment the user cannot predict.
Astryx Motion48 of 104 core components animate something.Audited against core@0.5.0.
Proposed — crossfade with overlapSkeleton fades out while content fades in, overlapping just enough that the box is never empty.
Astryx Motion48 of 104 core components animate something.Audited against core@0.5.0.
crossfade
Chip add and remove
ADDToday — instant
designmotiontokens
Chips appear and disappear on a frame. The canonical scale-in case, unanimated.Proposed — scale in, accelerate away
designmotiontokens
Scale-in with opacity; removal accelerates away and the neighbours close the gap.add
remove
List add, remove and reorder
ADDToday — instant
Item 1Item 2Item 3Item 4
Reorder is instant, so the user has to re-read the list to find out what changed.Proposed — FLIP on --ease-move
Item 1Item 2Item 3Item 4
FLIP: measure, move, invert, play. Rows travel on --ease-move, so a change the user did not initiate stays followable.FLIP — measure, move, invert, play — is the technique here because the rows are genuinely re-laid-out and only the visual correction is animated. Try it at 4×: a shuffle that is legible at 4× and illegible at 1× means the duration is too short, not that the technique is wrong.
Checkbox tick
ADDToday — real CheckboxInputReal CheckboxInput — the tick appears instantly
Draw
Draws along its path
Scale
Scales in
Stat value change
ADDToday — replaces itself
1,247The number replaces itself, so a change of 4 and a change of 4,000 look identical.
Proposed — counts
1,247Counts to the new value. Needs a delta threshold so a jump from 12 to 1,300,000 does not spin for a second.