Motion Brief
A motion designer settles every movement, its timing, and its relationship to every other movement before a single frame gets made. Do that for the interface: interview the user down the decision tree of one animation until a motion brief has no blanks, then stop.
Animations get rebuilt three times not because the code was wrong but because nobody decided what the motion was for. This skill front-loads that decision. It does not write the animation. The brief is the deliverable for interview-only requests. If implementation is already explicitly authorized, use the agreed decisions and continue without asking for the same approval again.
Follow the canonical motion policy. Values below are starting points, not universal requirements.
The three rules
- One question at a time. Ask, then wait for the answer before forming the next question — later questions genuinely depend on earlier ones. A batch of questions gets a batch of shrugs.
- Facts you look up. Decisions you ask. Anything discoverable in the filesystem — the component, its trigger, the animation stack, the existing easing tokens — you find yourself. Asking the user something you could have read wastes the interview's credibility and their patience.
- Never ask for a number the user can't feel. "What duration?" and "which cubic-bezier?" are unanswerable. Ask for the sensation or a reference product, then propose the number yourself and let them react to it. People can't author 240ms; they can tell you 240ms feels slow.
Every question ships with your recommended answer, so the user can agree in one word and the interview stays cheap.
Step 1 — Recon
Before the first question, read the code. Establish:
- The component and the two states the motion moves between.
- What triggers the change — click, hover, keyboard, route change, data arriving, drag.
- The stack available:
motion/react in package.json, Tailwind, plain CSS, WAAPI.
- Existing motion tokens — custom
cubic-bezier values, duration variables, --ease-* in the theme, and what sibling components already do.
- Whether
prefers-reduced-motion is handled anywhere globally.
Done when you can state all five, or state plainly that one doesn't exist in this codebase. Report the recon in three or four lines, then go straight to the first question — no preamble, no plan announcement.
From here on, every question is grounded in what you found: "The drawer currently uses @keyframes — what should happen if the user swipes it back down mid-open?" beats "should it be interruptible?" every time.
Step 2 — The two questions that can end the interview
Ask these first. Both can end in a cut, and a cut is a successful outcome — it's the answer an agent never volunteers on its own.
- Frequency. "How many times a day does one user see this?" For a rapidly repeated action, recommend immediate feedback and cut any motion that delays or disconnects input. Keyboard input or a count alone is not an automatic ban; test the actual flow.
- Purpose. "What does the motion tell the user that the static change doesn't?" Valid answers: feedback, spatial consistency, state indication, explanation, preventing a jarring change, or — for something seen rarely — delight. "It looks cool" on a frequently-seen element is not one.
If either lands on a cut, write the brief as a cut with the reasoning and stop. Do not soften it into "a very subtle version."
Step 3 — Choreograph the movement
- Which properties actually differ between state A and state B. Force the user to name both states out loud; this is where
transition: all dies and where an animation of four properties turns out to need two.
- Where it comes from and where it goes. Is it anchored to a trigger, or centered? Does the exit mirror the entry? Which direction is "forward"? Motion that enters one way and leaves another breaks the sense of a single coherent space.
- What happens mid-flight. "If they trigger it again — or reverse it — halfway through, what should it do?" This is the one question that decides
@keyframes vs transitions vs springs, and skipping it is how toasts end up jumping.
Step 4 — Set the feel
- Personality, by reference. "Name a product whose version of this feels right to you." A reference is worth ten adjectives, and you can go study it frame by frame. Fall back to a two-way choice — crisp and serious, or playful with some bounce — rather than an open question.
- Easing and duration together. These are one decision, not two: a steep curve can afford a longer duration, a weak one can't. Propose both as a pair, in that order — curve first, duration tuned to it.
Step 5 — The edges
- Reduced motion. "With movement removed, what should survive?" An instant change is valid; retain restrained opacity/color feedback only if it aids comprehension, and drop unnecessary travel. Purely decorative motion goes away entirely.
- Scale and load. What this does with 200 items instead of 3, on a mid-range phone, while data is still loading. Ask only where the recon showed a list, a drag, a filter, or a blur — otherwise it's a question about nothing.
Step 6 — The brief
The interview ends when the brief has no blanks — not when the user seems satisfied, and not when you feel ready to code. If a field is still empty, there's another question to ask.
## Motion brief — <component>
**Verdict:** animate | cut
**Trigger:** <what starts it>
**Frequency:** <seen how often> → <why that permits motion>
**Purpose:** <one sentence — what the motion communicates>
**Enter:** <properties, from → to>
**Exit:** <properties, from → to, or "mirrors enter">
**Origin:** <transform-origin / direction>
**Easing:** <curve> · **Duration:** <ms>
**Interrupt:** <what happens when re-triggered or reversed>
**Reduced motion:** <what survives>
**Stack:** <CSS transition / @starting-style / spring / layout animation>
**Open risk:** <what we're least sure of, and how we'd check it>
For interview-only requests, present the brief and wait for the user's implementation choice. When the user already authorized implementation, continue with the settled brief; ask only about unresolved decisions that materially change the result.
Defaults you bring to each question
Recommend these unless the interview gives you a reason to depart. Never present a question without one.
| Decision |
Recommend |
| Should it animate |
Prefer immediate feedback for repeated actions; reduce motion that delays input; standard for occasional (modals, drawers, toasts); delight only for rare or first-run |
| Which properties |
Prefer transform and opacity when geometry remains correct; verify rendering cost |
| Entrance |
scale(0.95) + opacity: 0 for ordinary surface entrances; stronger scaling needs an intentional visual purpose and a reduced-motion alternative |
| Press / hover |
scale(0.97) on press (felt, not seen); 1–2% on hover, gated behind (hover: hover) and (pointer: fine) |
| Origin |
Trigger-anchored for popovers, dropdowns, menus (var(--radix-popover-content-transform-origin)); centered for modals |
| Easing |
Start with ease-out for responsive entrances, ease-in-out for movement, ease for hover/color, and linear for constant speed. Tune named or custom curves to the interaction; an accelerating exit can be appropriate |
| Curve to start from |
cubic-bezier(0.19, 1, 0.22, 1) reveals · cubic-bezier(0.32, 0.72, 0, 1) sheets · cubic-bezier(0.645, 0.045, 0.355, 1) on-screen moves |
| Duration |
Under 300ms unless the element is large or travels far: press ~150ms, tooltip 125–200ms, dropdown 150–250ms, modal or drawer 200–500ms. Exits shorter than entries |
| Interrupt |
CSS transitions or springs, which retarget from the current state — keyframe timelines need explicit retargeting/playback control |
| Spring |
{ type: "spring", duration: 0.3, bounce: 0 }. Bounce stays at 0 unless the user asked for personality; smaller elements need more bounce to read the same |
| Reduced motion |
Instant or restrained opacity/color feedback; reduce spatial and disable decorative motion |
| Stagger |
30–80ms, varied by importance — uniform stagger kills hierarchy. One entrance per container |
When the user stalls
"Just make it nice" is not an answer — it's a decision handed back to you. Convert it into a concrete choice: two named options with your recommendation first, and what each would feel like in one clause. "Snap in at 180ms like a Linear menu, or ease in over 300ms with a slight settle like a Notion panel? I'd take the first — you said this opens on every row hover."
If they still can't say, take the default, record it in the brief as assumed, and move on. An assumption written down is worth more than a question left open.
Companion skills
If installed: animate implements the brief, review-animations audits what came out, animation-vocabulary names an effect the user is describing loosely.
1---2name: motion-brief3description: Interview the user relentlessly about an animation before any of it gets built — one decision at a time, each with a recommended answer — until a motion brief has no blanks. Use when motion needs to be decided or stress-tested before it's implemented, when the user says "grill me" / "write a motion brief" / "help me decide how this should animate", when an animation has been rebuilt several times and still feels wrong, or when another skill needs the motion specified before it writes code. Produces a brief, not an implementation.4---56# Motion Brief78A motion designer settles every movement, its timing, and its relationship to every other movement before a single frame gets made. Do that for the interface: interview the user down the decision tree of one animation until a **motion brief** has no blanks, then stop.910Animations get rebuilt three times not because the code was wrong but because nobody decided what the motion was for. This skill front-loads that decision. **It does not write the animation.** The brief is the deliverable for interview-only requests. If implementation is already explicitly authorized, use the agreed decisions and continue without asking for the same approval again.1112Follow the [canonical motion policy](../animate/references/canonical-policy.md). Values below are starting points, not universal requirements.1314## The three rules15161. **One question at a time.** Ask, then wait for the answer before forming the next question — later questions genuinely depend on earlier ones. A batch of questions gets a batch of shrugs.172. **Facts you look up. Decisions you ask.** Anything discoverable in the filesystem — the component, its trigger, the animation stack, the existing easing tokens — you find yourself. Asking the user something you could have read wastes the interview's credibility and their patience.183. **Never ask for a number the user can't feel.** "What duration?" and "which cubic-bezier?" are unanswerable. Ask for the _sensation_ or a _reference product_, then propose the number yourself and let them react to it. People can't author 240ms; they can tell you 240ms feels slow.1920Every question ships with **your recommended answer**, so the user can agree in one word and the interview stays cheap.2122## Step 1 — Recon2324Before the first question, read the code. Establish:2526- The component and the **two states** the motion moves between.27- What **triggers** the change — click, hover, keyboard, route change, data arriving, drag.28- The **stack** available: `motion/react` in `package.json`, Tailwind, plain CSS, WAAPI.29- Existing **motion tokens** — custom `cubic-bezier` values, duration variables, `--ease-*` in the theme, and what sibling components already do.30- Whether **`prefers-reduced-motion`** is handled anywhere globally.3132Done when you can state all five, or state plainly that one doesn't exist in this codebase. Report the recon in three or four lines, then go straight to the first question — no preamble, no plan announcement.3334From here on, every question is grounded in what you found: _"The drawer currently uses `@keyframes` — what should happen if the user swipes it back down mid-open?"_ beats _"should it be interruptible?"_ every time.3536## Step 2 — The two questions that can end the interview3738Ask these first. Both can end in a **cut**, and a cut is a successful outcome — it's the answer an agent never volunteers on its own.39401. **Frequency.** "How many times a day does one user see this?" For a rapidly repeated action, recommend immediate feedback and cut any motion that delays or disconnects input. Keyboard input or a count alone is not an automatic ban; test the actual flow.412. **Purpose.** "What does the motion tell the user that the static change doesn't?" Valid answers: feedback, spatial consistency, state indication, explanation, preventing a jarring change, or — for something seen rarely — delight. "It looks cool" on a frequently-seen element is not one.4243If either lands on a cut, write the brief as a cut with the reasoning and stop. Do not soften it into "a very subtle version."4445## Step 3 — Choreograph the movement46473. **Which properties actually differ** between state A and state B. Force the user to name both states out loud; this is where `transition: all` dies and where an animation of four properties turns out to need two.484. **Where it comes from and where it goes.** Is it anchored to a trigger, or centered? Does the exit mirror the entry? Which direction is "forward"? Motion that enters one way and leaves another breaks the sense of a single coherent space.495. **What happens mid-flight.** "If they trigger it again — or reverse it — halfway through, what should it do?" This is the one question that decides `@keyframes` vs transitions vs springs, and skipping it is how toasts end up jumping.5051## Step 4 — Set the feel52536. **Personality, by reference.** "Name a product whose version of this feels right to you." A reference is worth ten adjectives, and you can go study it frame by frame. Fall back to a two-way choice — crisp and serious, or playful with some bounce — rather than an open question.547. **Easing and duration together.** These are one decision, not two: a steep curve can afford a longer duration, a weak one can't. Propose both as a pair, in that order — curve first, duration tuned to it.5556## Step 5 — The edges57588. **Reduced motion.** "With movement removed, what should survive?" An instant change is valid; retain restrained opacity/color feedback only if it aids comprehension, and drop unnecessary travel. Purely decorative motion goes away entirely.599. **Scale and load.** What this does with 200 items instead of 3, on a mid-range phone, while data is still loading. Ask only where the recon showed a list, a drag, a filter, or a blur — otherwise it's a question about nothing.6061## Step 6 — The brief6263The interview ends when the brief has **no blanks** — not when the user seems satisfied, and not when you feel ready to code. If a field is still empty, there's another question to ask.6465```markdown66## Motion brief — <component>6768**Verdict:** animate | cut69**Trigger:** <what starts it>70**Frequency:** <seen how often> → <why that permits motion>71**Purpose:** <one sentence — what the motion communicates>7273**Enter:** <properties, from → to>74**Exit:** <properties, from → to, or "mirrors enter">75**Origin:** <transform-origin / direction>76**Easing:** <curve> · **Duration:** <ms>77**Interrupt:** <what happens when re-triggered or reversed>78**Reduced motion:** <what survives>79**Stack:** <CSS transition / @starting-style / spring / layout animation>8081**Open risk:** <what we're least sure of, and how we'd check it>82```8384For interview-only requests, present the brief and wait for the user's implementation choice. When the user already authorized implementation, continue with the settled brief; ask only about unresolved decisions that materially change the result.8586## Defaults you bring to each question8788Recommend these unless the interview gives you a reason to depart. Never present a question without one.8990| Decision | Recommend |91| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |92| Should it animate | Prefer immediate feedback for repeated actions; reduce motion that delays input; standard for occasional (modals, drawers, toasts); delight only for rare or first-run |93| Which properties | Prefer `transform` and `opacity` when geometry remains correct; verify rendering cost |94| Entrance | `scale(0.95)` + `opacity: 0` for ordinary surface entrances; stronger scaling needs an intentional visual purpose and a reduced-motion alternative |95| Press / hover | `scale(0.97)` on press (felt, not seen); 1–2% on hover, gated behind `(hover: hover) and (pointer: fine)` |96| Origin | Trigger-anchored for popovers, dropdowns, menus (`var(--radix-popover-content-transform-origin)`); centered for modals |97| Easing | Start with `ease-out` for responsive entrances, `ease-in-out` for movement, `ease` for hover/color, and `linear` for constant speed. Tune named or custom curves to the interaction; an accelerating exit can be appropriate |98| Curve to start from | `cubic-bezier(0.19, 1, 0.22, 1)` reveals · `cubic-bezier(0.32, 0.72, 0, 1)` sheets · `cubic-bezier(0.645, 0.045, 0.355, 1)` on-screen moves |99| Duration | Under 300ms unless the element is large or travels far: press ~150ms, tooltip 125–200ms, dropdown 150–250ms, modal or drawer 200–500ms. Exits shorter than entries |100| Interrupt | CSS transitions or springs, which retarget from the current state — keyframe timelines need explicit retargeting/playback control |101| Spring | `{ type: "spring", duration: 0.3, bounce: 0 }`. Bounce stays at 0 unless the user asked for personality; smaller elements need more bounce to read the same |102| Reduced motion | Instant or restrained opacity/color feedback; reduce spatial and disable decorative motion |103| Stagger | 30–80ms, varied by importance — uniform stagger kills hierarchy. One entrance per container |104105## When the user stalls106107"Just make it nice" is not an answer — it's a decision handed back to you. Convert it into a concrete choice: two named options with your recommendation first, and what each would feel like in one clause. _"Snap in at 180ms like a Linear menu, or ease in over 300ms with a slight settle like a Notion panel? I'd take the first — you said this opens on every row hover."_108109If they still can't say, take the default, record it in the brief as **assumed**, and move on. An assumption written down is worth more than a question left open.110111## Companion skills112113If installed: `animate` implements the brief, `review-animations` audits what came out, `animation-vocabulary` names an effect the user is describing loosely.