ZICUA
0123456789
0123456789
100

How to Document a Motion Spec Before Development

A motion spec is a written, shared description of an animation — trigger, duration, easing, delay, animated properties, reduced-motion behavior, and performance budget — produced before development starts, so designers and developers implement the same motion instead of negotiating it from memory. Verbal motion briefs fail because animation has too many degrees of freedom: “fade the section in as you scroll” leaves start/end opacity, distance, easing curve, duration, trigger point, and reduced-motion fallback entirely unspecified, and each gap becomes a different guess in code. A usable motion spec fits on one screen per moment (or one table row), uses units and named easings rather than adjectives, and is referenced in the ticket’s acceptance criteria. Teams that document motion this way ship animations that match the design on the first review pass, avoid accessibility regressions, and keep performance budgets intact — the same discipline that makes white-label Figma to WordPress processes predictable.

This guide covers why informal motion briefs break, the exact fields every motion spec needs, Figma annotations versus dedicated spec docs, a handoff meeting agenda, a fully worked example of one scroll-reveal spec, and a copy-paste template table you can drop into your process. For how motion work fits into a time-boxed engagement, see motion sprint explained.

Why verbal motion briefs fail

Motion is ephemeral by nature — it exists only at runtime, so a conversation leaves no artifact QA can check against. Typical failure modes:

  • Adjective drift. “Smooth” means cubic-bezier(0.22, 1, 0.36, 1) to one person and a linear 600ms fade to another.
  • Trigger ambiguity. Does the reveal fire at 80% viewport, when the element enters the bottom 100px, or on image load?
  • Property ambiguity. Fade only? Fade + rise 24px? Scale from 0.96? Each choice changes CLS risk and perceived style.
  • Reduced-motion silence. Nobody decides what happens when the user asks for less motion — so developers either ship nothing or ship too much.
  • No performance ceiling. The “just one more tween” pattern quietly breaks the page’s motion budget.

Written specs convert taste into testable statements. If the spec says 500ms, ease-out, opacity + translateY(24px), trigger at 75% viewport, reduced-motion = instant visible — QA can verify every clause without opening a Figma prototype.

The fields of a motion spec

Every animated moment needs these fields. Missing any one of them invites a guess:

FieldExampleWhy it matters
Name / IDreveal--features-gridStable reference for design, code, QA, analytics
TriggerIntersectionObserver, 75% viewport, onceWhen it starts; scroll vs hover vs load vs route
Duration500ms (±50ms tolerance)Perceived pacing; total main-thread exposure
EasingNamed token, e.g. ease-out-quart → cubic-bezier(0.25, 1, 0.5, 1)Personality; avoids “make it feel premium” loops
Delay0ms (or 80ms stagger × index)Choreography; prevents timeline pile-ups
Propertiesopacity: 0→1, transform: translateY(24px)→0CLS safety; only transform/opacity for in-flow reveals
Initial state (pre-JS)Visible by default; hidden only after JS marks html.js-motionNo-JS and SEO: content never trapped invisible
Reduced-motionSet final state immediately; duration 0; no transformAccessibility; often a merge gate
Performance budgetTransform/opacity only; no layout props; ≤1 ScrollTrigger groupKeeps CLS <0.1 and INP healthy
Interrupt / reverse behaviorOnce: true (no reverse on scroll up)Prevents flicker and extra work
Owner / statusDesign: Ana · Dev: Luis · Status: ApprovedSingle source of truth for questions

Figma annotations vs a dedicated motion spec

Both work; they solve different problems.

Figma annotations

Good for: pinning duration/easing callouts next to frames, recording prototype interactions, keeping visual context attached to layout. Use sticky annotations or a dedicated annotation layer with the same field names as your spec table. Limitations: prototypes simulate motion, they don’t encode exact tokens, and comments get resolved/lost. Figma is also the wrong place for reduced-motion and performance clauses.

Dedicated spec (table in Notion/Docs/ticket, or code-adjacent config)

Good for: full field coverage, versioning, QA checklists, and review in PR templates. A single “Motion Spec” table per page (one row per moment) scales better than dozens of sticky notes. The strongest setups keep the table as the contract and, during implementation, mirror names into a central config (e.g., a GSAP registry) so the spec stays greppable — patterns like those in GSAP motion systems in production make the spec and the code use identical moment IDs.

Recommended hybrid: annotate the Figma frame with the moment ID and headline values; keep the full row (trigger, reduced-motion, budget, QA notes) in the shared spec table linked from the ticket.

Handoff meeting agenda (30 minutes)

  1. 5 min — Page motion budget recap. How many moments this template allows; what was cut.
  2. 10 min — Moment-by-moment walkthrough. For each spec row: play prototype, confirm trigger/properties/reduced-motion; resolve adjectives into tokens.
  3. 5 min — Initial states & no-JS. Confirm content is visible without JS; decide the class/flag strategy for hiding pre-animation.
  4. 5 min — Reduced-motion & a11y. Agree the fallback per moment (usually: jump to end state). Reference your reduced-motion guide if the team needs shared rules.
  5. 5 min — Open questions, owners, ship criteria. Who approves deviations; what QA checks; link spec from acceptance criteria.

Rule: the meeting ends only when every adjective has a number and every moment has a reduced-motion clause.

Worked example: scroll reveal on a features grid

Moment ID: reveal--features-grid

  • Trigger: element enters viewport at 75% (IntersectionObserver or ScrollTrigger start: "top 75%"), fires once, no reverse.
  • Duration: 500ms.
  • Easing: token ease-out-quart = cubic-bezier(0.25, 1, 0.5, 1).
  • Delay / stagger: 80ms per card, max 4 cards staggered (320ms tail); remaining cards reveal together.
  • Properties: cards opacity 0→1, transform translateY(24px)→0. No width/height/margin animation.
  • Initial state: cards fully visible in HTML/CSS. JS adds data-motion="pending" only when animation will run and reduced-motion is not set; CSS hides only pending nodes.
  • Reduced-motion: remove pending state; final values applied immediately; duration 0.
  • Performance budget: transform/opacity only; single observer; passive scroll; no per-frame layout reads.
  • Acceptance: matches prototype within ±50ms duration; Lighthouse CLS unchanged; axe no violations; with prefers-reduced-motion: reduce, cards appear instantly.

That paragraph is enough for a developer to implement without Slack archaeology — and enough for QA to test without watching a prototype ten times.

Copy-paste motion spec template

Moment IDTriggerDurationEasingDelay / staggerProperties (from → to)Pre-JS stateReduced-motionPerf notesQA
hero--headlineDOMContentLoaded, once600msease-out-expo0 / 60ms linesopacity 0→1; y 16→0VisibleInstant final stateMust not delay LCP paintLCP <2.5s
reveal--features-gridtop 75% viewport, once500msease-out-quart0 / 80ms × 4opacity 0→1; y 24→0Visible (hide via JS flag)Duration 0, end stateTransform/opacity onlyCLS <0.1
nav--mega-openhover / focus / click200msease-out0opacity 0→1; y −8→0Visible if no JS? → hidden via CSS :focus-within fallbackInstant toggleNo layout animationINP <200ms on open
route--page-enterview transition / route change250msease-in-out0opacity onlyn/aDisable transitionNever block first paintSee INP/CWV notes

Keeping the spec alive after handoff

  • Link the spec table from every motion-related ticket’s acceptance criteria.
  • Add PR checklist lines: matches spec IDs? reduced-motion present? no layout-animating properties?
  • If implementation needs a deviation (duration 420ms instead of 500ms), update the spec row in the same PR — the table stays the contract.
  • Retire moments explicitly: when a moment is cut for budget, mark the row “removed” rather than deleting history, so nobody re-adds it from an old prototype.

Documentation is the cheapest performance and accessibility tool you will ever adopt: a 15-minute spec write prevents multi-day rebuild loops, keeps white-label handoffs calm (as in structured Figma handoff checklists for developers), and makes motion reviewable instead of vibes-based.

Frequently asked questions

What is the minimum viable motion spec?

Moment ID, trigger, duration, easing, animated properties, initial/pre-JS state, reduced-motion behavior, and one performance constraint (usually transform/opacity only, plus budget impact). If a field would force a developer to guess, it belongs in the spec.

Where should the motion spec live — Figma or a document?

Use both lightly: annotate Figma with the moment ID and key values for context; keep the full field table in a shared doc or ticket that QA and engineering reference. Figma prototypes cannot reliably encode reduced-motion or performance rules.

How do I handle reduced-motion in the spec?

Give every moment an explicit clause — almost always “apply final state immediately, duration 0, no transform/opacity interpolation.” Never leave it implicit; silence defaults to whatever the developer implements, which is often the animated path.

Should designers specify easing curves numerically?

Yes, via named tokens mapped to cubic-bezier values or GSAP ease names (e.g., power2.out). Tokens keep brand personality consistent across pages and make “it feels different” conversations resolvable against the spec.

How does a motion spec connect to performance budgets?

Each spec row states its perf notes (allowed properties, observer strategy, whether it delays LCP). Summing rows against the page’s moment cap keeps the design inside the motion budget — the same allocation discipline described for page-level budgets in motion budget planning for marketing sites.

Read next: white-label web development for agencies · pixel-perfect Figma to WordPress development · GSAP motion and page transitions

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *