Motion
Motion shows what changed, where it came from, and where it went. In Wolf-Rayet it also costs attention, so how much something may move depends on how much it is allowed to ask for.
Principles
Purposeful. Motion explains a change. If removing it would not lose the reader anything, remove it.
Rationed. Movement draws the eye, so it is budgeted like colour. Each attention level has a longest duration it may use, and only a demand may keep moving.
Accessible. When a reader asks for reduced motion, every change shortens to 110ms and repeating motion slows or stops. Nothing flashes, and nothing sweeps across the screen.
Fast. Nothing waits for an animation to finish. Exits are quicker than entrances, so a dismissed thing never stands in the way.
Duration
How long a change takes. Short for things people do often, longer for things that are rarer and larger.
| Token | Value | Use for |
|---|---|---|
| --wr-duration-0 | 80ms | Hover and press feedback that happens many times a minute. |
| --wr-duration-1 | 110ms | Small entrances and exits. The ambient grant. |
| --wr-duration-2 | 155ms | Popups, menus and state changes that should be noticed. |
| --wr-duration-3 | 220ms | Drawers and larger surfaces arriving on screen. |
| --wr-duration-4 | 305ms | The longest a single change may take. Reserved for a demand. |
| --wr-duration-5 | 430ms | Longer than any level is granted. Not used by components. |
Easing
How a change speeds up and slows down. Choose the curve by what the element is doing.
| Token | Curve | Use for |
|---|---|---|
| --wr-easing-enter | cubic-bezier(0, 0, 0.2, 1) | Things arriving. Fast start, soft landing. |
| --wr-easing-exit | cubic-bezier(0.4, 0, 1, 1) | Things leaving. Slow start, then out of the way. |
| --wr-easing-standard | cubic-bezier(0.2, 0, 0, 1) | Things that change in place, like a colour or a size. |
| --wr-easing-emphasized | cubic-bezier(0.05, 0.7, 0.1, 1) | A demand arriving. Used sparingly. |
| --wr-easing-linear | cubic-bezier(0, 0, 1, 1) | Loops, like a spinner, where no moment matters more than another. |
Properties
What changes. Pick one, or two at most.
Motion by attention level
The longest duration each level may use, and what it may do. A component declares its level, and its motion comes from that grant.
| Level | May | Longest |
|---|---|---|
| 0 · Substrate | Nothing. The page itself does not move. | 0ms |
| 1 · Ambient | Enter and exit. | 110ms |
| 2 · Marked | Enter, exit, and change state. | 155ms |
| 3 · Directed | Also arrive, which means travel to draw the eye. | 220ms |
| 4 · Demanded | Also keep moving until it is answered. | 305ms |
A spinner or a loading bar repeats because work is still running, not because it wants attention. Loops use the period tokens, --wr-period-0 to --wr-period-4, and never repeat faster than once every 800ms. Under reduced motion they slow to once every 3 seconds or stop.
Component tokens
Every component with a token record has its own motion tokens. Use these before anything else.
| Token | What it is |
|---|---|
| --wr-<component>-transition-duration | The longest duration the component's level grants it. |
| --wr-<component>-transition-easing | The curve its record gives it. |
| --wr-<component>-sustained-duration | Only on components that may keep moving while they demand attention. |
A build check reads every stylesheet: a component with a record must move by its own tokens, and no stylesheet may write a raw duration or curve.
Best practices
Do
Don't
Do
Don't
Accessibility
Reduced motion is handled by the tokens, not by each component. When the setting is on, every level's grant becomes 110ms and loops slow down, so a component that uses its own tokens is covered without writing anything. Check every screen with the setting on, and make sure it still works with no motion at all.