Motion

Three axes that compose at point of use — how long, along what curve, and how far.

Duration, easing and scale are separate scales rather than a set of named animations, for the same reason --font-size-* and --line-height-* are separate: a preset can only offer the combinations someone thought of, where three axes multiply. The cost is that a transition names three tokens instead of one, and that is the right cost — it is three decisions, and hiding them in a preset does not make them fewer.

These previews have to be run. A duration does not exist while it is not happening, so the tables below animate on demand rather than showing a picture of a number.

Duration

Named by role, not by number. Press Play — all three run together, which is the only way to compare them.

TokenValuePreview
--motion-duration-fast…
--motion-duration-base…
--motion-duration-slow…

A component asks for fast, never for 120. The gaps are wide on purpose: a scale with 150ms and 180ms in it invites a choice nobody can perceive, and the whole point of a token is to remove that choice rather than to offer it more precisely.

fast is for things that answer you — a hover, a press, a colour change — where anything slower reads as lag. base is for something appearing or moving that you are meant to notice. slow is for large travel, and is the one to distrust: if a transition needs 320ms to look right, the usual cause is that it is moving too far, not that it is moving too quickly.

Easing

Four curves, all run at slow, so the curve is the only thing that differs.

TokenValuePreview
--motion-ease-standard…
--motion-ease-in…
--motion-ease-out…
--motion-ease-in-out…

standard is the default and the one to reach for: it leaves immediately and settles gently, which is how something being moved behaves. out is its milder relative, for things entering.

in is the odd one, and the CSS names are genuinely confusing — in means “eases into the motion”, so it starts slowly and accelerates away. That is right for something leaving and wrong for almost everything else: an element that responds sluggishly to a click feels broken even when the total time is identical. Play the band and watch the starts rather than the ends.

Scale

Five steps for interaction feedback — press the press ones, hover the hover ones.

TokenValuePreview
--motion-scale-press…
--motion-scale-press-lg…
--motion-scale-none…
--motion-scale-hover…
--motion-scale-hover-lg…

A transform: scale() set for interaction feedback, paired with --motion-duration-fast and an ease at use. It sits under motion rather than in a category of its own because it is never a static size — a box is not 1.01 large, it grows to 1.01 and comes back.

A percentage is applied to a box, but the eye measures the result in pixels — and that is the whole design of this set. 1% of a 40px control is 0.4px, which is below what anyone can see; 1% of a 200px card is 2px, which reads. So the base pair is for controls and -lg is for large surfaces, and the larger thing takes the smaller percentage so both land in the same perceptual place. Every specimen above is the same size so the column stays readable, which means the -lg pair looks weaker there than it is — see it on something card-sized and the two are the same gesture.

Press is stronger than hover on purpose — it answers a direct action, where a hover is only an offer. none is the identity, there so a rule can be switched off by swapping a variable rather than being rewritten.

Reduced motion

Nothing in this system responds to prefers-reduced-motion. A reader who has asked their operating system for less movement currently gets every transition in full. That is a real gap, and stating it is worth more than a page that looks complete.

It is left open rather than patched because the fix is a design decision, not a line of CSS. Zeroing the duration tokens under the query would reach everything at once and is tempting — but reduced motion does not mean no motion, and an interface where things teleport can be harder to follow, not easier. The likely answer is to keep short functional transitions and drop travel and scale, which is a per-property judgement that wants real components in front of it.

The previews on this page are the deliberate exception either way. They animate on a click, and the motion is the content — suppressing it would show an empty box labelled 320ms.