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.

What a prototype video conveys versus what code needsThe spec fills the right-hand column.What a prototype video conveys versus what code needsVisible in a video?Needed in code?Rough durationand feelYesAs tokensExact from andto valuesNoYesStagger stepand capApproximatelyYesInterruptionbehaviourNoYesReduced-motionvariantNoYesRendering tierNoYes
The spec fills the right-hand column.

Step-by-step resolution

Writing the specOne table per transition, plus three short answers.Writing the spec1Write the trigger and the two states, for example closed to open on button press.Scope is explicit2Add one row per element and property with from, to, token timing and delay.Values are exact3Mark the lead element and the stagger step and cap for followers.Relationships are exact4Answer: what happens if the trigger reverses mid-motion?Interruption is designed5Answer: what is shown under reduced motion?Accessibility is designed6Mark each property's rendering tier and flag any layout or paint on large areas.
One table per transition, plus three short answers.

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 opacity instead 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.

Where the spec sits between design and codeThe prototype conveys feel; the spec makes it implementable and reviewable.Where the spec sits between design and codePrototypefeelSpec tablevalues + tokensReviewtier, a11yImplementationVisual checkagainst prototype
The prototype conveys feel; the spec makes it implementable and reviewable.

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.