Speed
Slow motion multiplier
1×
Reduced motion
Show

Motion Lab

core@0.5.0
A bench for the H2 2026 motion proposals. Every proposal is here as a working before-and-after with its values exposed as controls, so the decisions get made by looking rather than by arguing about numbers in a document.Decide here: Whether the audit in the brief matches the code, and which decisions are actually blocking.

Measured against the installed package

Generated by scripts/generate-motion-audit.mjs from packages/core/src and packages/lab/src at core@0.5.0, so these move when the packages do. Every finding carries the package it is in.
121Component directories55 animate, 65 do not
1Easing tokens--ease-standard, for every job
9Duration tokensnamed by size, not by job
59Hardcoded duration / easing35 durations, 24 curves
40Animated files with no reduced-motion branchof 88 animated files
13Durations with no declared curvesilently getting the CSS default
34Transitions on transformacross 23 components
36getComputedStyle readsthe JS mirror's caseload
How the counting works, and where it misleads
The audit attributes motion to the component directory the file sits in. Astryx composes heavily, so a surface can animate without a single transition in its own folder — Tooltip, HoverCard, Popover, Typeahead and the rest inherit theirs from Layer/, AlertDialog from Dialog/, IconButton and ToggleButton from Button/, FieldStatus from hooks/containerReveal.stylex.ts. Read the per-component numbers as “where the motion is authored”, not “which components move”. The same trap is waiting for the rubric: a per-component score has to follow composition, or it will fail a component for a curve it does not own.

Where the brief and the code disagree

Only the rows that differ. Everything else in the audit checked out.
MeasureBriefMeasuredReading
Component directories107 (90 core, 17 lab)121 (104 core, 17 lab)Lab matches exactly. Core is higher than the brief’s 90 — the split it quotes is close but not current.
Animate something6355Counted as component directories with at least one transition, animation or keyframe. The brief counted across core and lab together.
Hardcoded duration / easing2859Higher, not lower. The brief undercounts: the sweep is bigger than budgeted, and about a quarter of it is a reduced-motion idiom rather than carelessness.
Files animating with no reduced-motion branch3940Close. The gap is counting method, not a disagreement worth chasing.
Dead no-op transitions3, in Selector / ComplexSelector / MultiSelector1, in LightboxThe brief’s three do not exist as described. The one real instance is a deliberate transitionProperty: none. Worth re-checking before it becomes a milestone line item.
CSS transition on transform20+ components34 sites, 23 componentsThe brief is right, and this row is a caution about the tool rather than the doc: two earlier versions of the audit script reported 13 across 9, because a wrapped value and a nested StyleX rule each hid matches. Trust a generated number only as far as its generator has been tested.

How to use the bench

The rail applies everywhereSlow-mo stretches every duration without moving the token, so you can judge a 175ms curve at 8× and still export 175ms. Reduced motion drives the real policy switch. Show hides one half of every comparison.
Every slider writes a real tokenTune a value anywhere and every demo in the section updates, because they all read the same custom property. When it feels right, the export page emits the token block and the JS mirror.
Numbers are generated, prose is notCounts and file:line citations come from the audit script. Judgements about what they mean are written, and are the part worth arguing with.
Published guidance: astryx.atmeta.com/docs/motion