Motion as System
A motion system defines duration and easing as named tokens — ensuring every animation in the interface draws from the same vocabulary and feels coherent at scale.
Individual animations can each feel correct while the interface as a whole feels inconsistent. A motion system prevents this by defining the shared vocabulary — durations, easing curves, property constraints — that every animation draws from.
What a motion system contains
A motion system has two primary components: duration tokens and easing tokens. Duration tokens define the allowed animation lengths — typically three to five values covering the range from micro-interactions to complex transitions. Easing tokens define the allowed curves — typically one for entering elements, one for exiting elements, one for elements moving between positions, and optionally a spring value for physical interactions. Every animation in the interface uses a token from each set rather than a one-off value.
Duration tokens
A minimal duration scale:
duration-fast: 100ms — micro-interactions, hover states, small element transitionsduration-base: 200ms — standard element transitions, dropdowns, tooltipsduration-slow: 300ms — larger elements, modals, panels, page sectionsduration-complex: 400ms — full-page transitions, orchestrated sequences
These map to the tiers established in Duration. Fewer tokens are better — the goal is constraint, not coverage. An unlimited number of values produces the same inconsistency as no system at all.
Easing tokens
A minimal easing set:
ease-enter:cubic-bezier(0, 0, 0.2, 1)— decelerates into position; for elements arrivingease-exit:cubic-bezier(0.4, 0, 1, 1)— accelerates out; for elements departingease-move:cubic-bezier(0.4, 0, 0.2, 1)— ease-in-out; for elements moving between positions
These correspond to the semantic easing values established in Easing. Naming them by role rather than by curve value (ease-enter not cubic-bezier-0.2) makes the token system legible to designers and developers who do not need to reason about the underlying mathematics.
Implementing the system
In CSS, define tokens as custom properties:
:root {
--duration-fast: 100ms;
--duration-base: 200ms;
--ease-enter: cubic-bezier(0, 0, 0.2, 1);
--ease-exit: cubic-bezier(0.4, 0, 1, 1);
}
In a design tool, define them as shared styles applied to every component that animates. In a JavaScript animation library, export them as a shared constants file imported wherever animations are defined.
Motion and reduced-motion
The motion system should include a reduced-motion variant. Under prefers-reduced-motion: reduce, duration tokens can be set to 0.01ms (functionally instant) and spring animations disabled. Colour transitions remain — they are safe under reduced motion. This one override applied to all tokens means individual components do not need to handle reduced motion independently.
Decision framework
When choosing a motion mechanism, match the tool to the trigger:
| Situation | Mechanism |
|---|---|
| Hover, focus, or active state | CSS transition |
| Class-toggled state change | CSS transition |
| Multi-step or looping animation | CSS @keyframes |
| Element scrolling into view | IntersectionObserver + CSS transition |
| Page-to-page navigation | View Transitions API |
| Shared element between routes | View Transitions API + view-transition-name |
| Physics-based feel (spring, bounce) | linear() or JavaScript library |
| Gesture-following motion (drag) | JavaScript pointer events + transform |
When in doubt, prefer transition over @keyframes — transitions handle interruption correctly by default. Prefer the View Transitions API over custom JavaScript for page navigation — it is native, performant, and accessible. Every entry in this table should draw its duration and easing from the token system.
The takeaway
Define duration and easing as tokens. Apply them consistently. Audit the interface periodically against the token set — any animation using a value outside the tokens is a candidate for correction. A motion system is not complete when the tokens are defined; it is complete when every animation in the interface uses them.