Writing Motion Specs for Design Handoff
Part of Motion Design Systems & Tokens in Core CSS Animation Fundamentals.
The problem
A designer hands over a prototype video of a new filter panel: it slides in, the chips cascade, and the results list dims. The engineer implements it by watching the video frame by frame. Durations are guessed from timestamps, the easing is approximated, the cascade delay is eyeballed, and nobody specified what happens when the user closes the panel halfway through opening it. Reduced motion is not mentioned. Two weeks later the designer files a bug that it “feels off”, and neither side can say precisely why.
Prototype tools are good at showing motion and poor at specifying it. A short written spec closes the gap.
Root cause analysis: video shows one path, code needs all of them
A prototype shows the happy path at one screen size with no interruptions. Implementation needs decisions a video cannot encode.
Values, not impressions. “Slides in” does not say from where, how far, or whether opacity changes too. Each animated property needs a from value and a to value.
Tokens, not milliseconds. A spec that says “300ms, cubic-bezier(0.2, 0.8, 0.2, 1)” invites a new one-off value. A spec that says “enter duration, decelerate easing” maps to existing tokens and stays correct when the tokens change, as described in the parent topic.
Relationships. Which element leads, which follow, how long the stagger is and whether it is capped — the choreography rules — are invisible in a single recording.
Interruption. What happens when the trigger reverses mid-motion is a design decision with engineering consequences: a reversal from the current position suggests a transition; a restart suggests an animation, following interrupting and reversing transitions.
Reduced motion. The alternative experience must be designed, not left to a global override that might remove feedback the design depends on.
Cost. A spec that animates height or box-shadow on a large surface is making a performance decision. Flagging the rendering tier lets the team agree on substitutes before implementation.
Step-by-step resolution
Production code pattern
A spec for the filter panel, written in the format above:
| Element | Property | From | To | Timing | Delay | Tier |
|---|---|---|---|---|---|---|
| Panel (lead) | translate |
100% 0 |
0 0 |
enter / decelerate | 0 | composite |
| Panel | opacity |
0 | 1 | duration-200 / standard | 0 | composite |
| Chips (followers) | opacity |
0 | 1 | enter / decelerate | follow-delay + stagger 30ms, cap 120ms | composite |
| Chips | translate |
12px 0 |
0 0 |
enter / decelerate | same as above | composite |
| Results list | opacity |
1 | 0.6 | duration-300 / standard | 0 | composite |
- Interruption: closing during opening reverses from the current position; chips that have not started do not animate.
- Reduced motion: panel and chips fade in together over duration-100 with no travel; results list dims instantly.
- Performance: all composite; the results list is dimmed with
opacity, not a colour change, to avoid repainting the list.
The implementation follows directly:
.filters {
translate: 100% 0;
opacity: 0;
transition:
translate var(--motion-exit-duration) var(--motion-exit-easing),
opacity var(--duration-200) var(--ease-standard);
}
.filters[data-open] {
translate: 0 0;
opacity: 1;
transition:
translate var(--motion-enter-duration) var(--motion-enter-easing),
opacity var(--duration-200) var(--ease-standard);
}
.filters[data-open] .chip {
animation: follow-in var(--motion-enter-duration) var(--motion-enter-easing) backwards;
animation-delay: calc(var(--motion-follow-delay) + min(calc(var(--i) * 30ms), 120ms));
}
.results { transition: opacity var(--duration-300) var(--ease-standard); }
.filters[data-open] ~ .results { opacity: 0.6; }
@keyframes follow-in { from { opacity: 0; translate: 12px 0; } }
@media (prefers-reduced-motion: reduce) {
.filters, .filters[data-open] { translate: 0 0; transition: opacity var(--duration-100) linear; }
.filters[data-open] .chip { animation: none; }
.results { transition: none; }
}
Rendering Impact: composite. The spec’s tier column was the design review: dimming the results with
opacityinstead of a background colour kept a potentially large repaint out of the transition.
Using a transition for the panel and a keyframe animation for the chips is a direct consequence of the interruption answer: the panel must reverse from its current position, while chips simply fade and do not need to reverse.
Reviewing implementations against the spec
With a spec, “feels off” becomes checkable. Open the Animations drawer, slow playback to 25%, and compare each animation group’s duration, delay and easing with its row. Mismatches are usually a wrong token or a missing follow delay. For interruption, trigger the reversal at the midpoint and compare with the written answer. For reduced motion, emulate the preference and compare with the variant description. Keeping specs next to the component in the repository — as a Markdown file or in the component’s documentation page — means they are updated with the code rather than lost in a design file.
Verification checklist
Constraints and trade-offs
- Writing specs takes designer time; limit full specs to new patterns and reuse existing ones by name.
- Tables become unwieldy for complex choreography; split by phase.
- Token names must be shared vocabulary in the design tool, or specs mix names and numbers.
- A spec can be wrong; treat it as the starting point for review, not an unchangeable contract.
- Specs drift if stored away from code; keep them versioned with components.
Frequently asked questions
Is a prototype video enough for handoff?
It shows the feel but not the values, relationships, interruption behaviour, reduced-motion variant or rendering cost. A short spec table covers those.
Should motion specs use milliseconds or tokens?
Tokens. They map to existing values, stay correct when the scale changes and prevent one-off durations from entering the codebase.
What should a motion spec say about reduced motion?
Exactly what the user sees instead, such as a short fade with no travel, so the variant is designed rather than left to a global override.
Why include the rendering tier in a design spec?
It surfaces expensive properties such as height, box-shadow or colour on large areas early, when substitutes are cheap to agree on.
Related
- Motion Design Systems & Tokens — the parent topic
- Building a Duration and Easing Token Scale — the vocabulary specs reference
- Hardware-Accelerated Properties — the tiers in the spec’s last column