Building a Duration and Easing Token Scale
Part of Motion Design Systems & Tokens in Core CSS Animation Fundamentals.
The problem
The first attempt at motion tokens produced --duration-fast, --duration-medium, --duration-slow and, within a month, --duration-medium-fast, --duration-slower and --duration-dialog. Easing followed the same path: --ease-in, --ease-out, --ease-bounce, --ease-smooth, --ease-smooth-2. Designers could not tell medium-fast from medium in a prototype, and nobody knew whether changing --duration-dialog would affect anything but dialogs.
A scale fails when its steps are too close to tell apart, when names describe usage instead of position, or when every exception becomes a new token.
Root cause analysis: steps must be perceptible and names must be ordinal
Perception sets the spacing. People do not perceive durations linearly. A difference between 200ms and 220ms is invisible in an interface; between 200ms and 280ms it is noticeable. Steps spaced by a ratio of roughly 1.3 to 1.5 — a geometric progression — keep adjacent tokens meaningfully different at both ends of the scale. Linear spacing (100, 150, 200, 250…) wastes steps at the long end where differences are hard to see.
The range is bounded by attention. Below about 100ms, motion is barely perceived as motion at all. Above about 500ms, interface animation starts to feel like waiting. A primitive scale spanning roughly 100ms to 500ms, with perhaps one longer step for large full-screen transitions, covers nearly everything.
Five to seven steps is enough. Fewer steps force distinct motions into the same value; more invite arbitrary choices between near-identical values. When a new need does not fit, the question should be which semantic role it belongs to, not which new primitive to add.
Primitives need ordinal names. --duration-100 through --duration-500 says where a token sits on the scale and nothing about where it is used. It can be re-valued without renaming, and a new step can be inserted as --duration-250 without breaking alphabetical or numeric order. Usage-based names belong in the semantic layer, described in the parent topic.
Easings are fewer than durations. Almost every interface motion is a deceleration (entering), an acceleration (exiting) or a standard ease-in-out (moving). One expressive curve with overshoot covers playful emphasis. A fifth curve is usually a variant someone preferred by eye.
Step-by-step resolution
Production code pattern
{
"duration": {
"100": { "value": "100ms" },
"200": { "value": "140ms" },
"300": { "value": "190ms" },
"400": { "value": "260ms" },
"500": { "value": "350ms" },
"600": { "value": "480ms" }
},
"easing": {
"standard": { "value": [0.4, 0, 0.2, 1] },
"decelerate": { "value": [0.2, 0.8, 0.2, 1] },
"accelerate": { "value": [0.4, 0, 1, 1] },
"expressive": { "value": [0.34, 1.4, 0.64, 1] }
}
}
/* Generated: tokens/motion.css. Do not edit by hand. */
:root {
--duration-100: 100ms;
--duration-200: 140ms;
--duration-300: 190ms;
--duration-400: 260ms;
--duration-500: 350ms;
--duration-600: 480ms;
--ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
--ease-decelerate: cubic-bezier(0.2, 0.8, 0.2, 1);
--ease-accelerate: cubic-bezier(0.4, 0, 1, 1);
--ease-expressive: cubic-bezier(0.34, 1.4, 0.64, 1);
}
/* Generated reduced-motion variant: long steps collapse, expressive becomes standard. */
@media (prefers-reduced-motion: reduce) {
:root {
--duration-400: 100ms;
--duration-500: 100ms;
--duration-600: 140ms;
--ease-expressive: var(--ease-standard);
}
}
Rendering Impact: none. Primitive tokens are static configuration read at style time; they never change the rendering tier of any animation.
Storing easing as four numbers rather than a CSS string is what makes the source platform-neutral: the same values generate cubic-bezier() for CSS, UICubicTimingParameters control points for iOS and PathInterpolator arguments for Android, as covered in sharing motion tokens across web and native.
Collapsing long primitives under reduced motion is a safety net rather than the main mechanism. The semantic layer should do most of the work, but primitives that are shortened too mean a component that bypassed roles still gets a calmer result.
Documenting the scale
A scale that people cannot see will be ignored. Publish a reference page that animates the same element at every duration step side by side, and every easing curve with its graph and a moving sample, so the difference between duration-300 and duration-400 is something designers and engineers have watched, not read. Include the reduced-motion values on the same page. When a request arrives for a new step, the page is also the argument: show the two nearest existing steps and ask whether the new value is visibly different from both.
Verification checklist
Constraints and trade-offs
- A geometric scale produces non-round values that some teams find odd; round to the nearest 10ms if needed.
- Collapsing primitives under reduced motion affects everything that uses them, including non-motion uses of durations such as tooltip delays.
- Brand-specific signature curves may need a fifth easing; add it as a semantic role mapped to a primitive, not a new primitive per component.
- Changing primitive values affects every role that references them; version the token package.
- Durations appropriate for the web may feel different on native platforms with different frame pacing.
Frequently asked questions
How many duration tokens does a design system need?
Five to seven primitive steps, spaced so each is visibly different from its neighbours, cover almost all interface motion.
Should duration tokens be named fast, medium and slow?
Not at the primitive level. Ordinal names like duration-300 leave room to insert steps and re-value tokens. Descriptive names belong to semantic roles.
How should duration steps be spaced?
Geometrically, with each step about 1.3 to 1.5 times the previous one, because perceived differences shrink as durations grow.
How many easing curves should a system have?
Usually four: standard for moves, decelerate for entrances, accelerate for exits, and one expressive curve for emphasis.
Related
- Motion Design Systems & Tokens — the parent topic
- Choosing Easing for Enter and Exit Motion — why these curves map to these roles
- Scaling Duration by Distance and Size — when a fixed step is not enough