Synthesized from the portfolio's shipped motion (Spectre, the NEMIXO console, this site) and the systems worth studying: Apple's springs, Material's easing pairs, Carbon's two registers, the sonner and vaul playbooks.
| Rule | It means |
|---|---|
| motion shows behavior | Every animation answers "what just happened"; a heading earns nothing |
| enter ≠ exit | Arrivals decelerate (--ease-entrance); permanent departures accelerate (--ease-exit); panels that will return leave on --ease-standard |
| two registers | Task UI is fast and quiet (--dur-1/2); brand moments get --dur-3/4, and one page gets ONE of them |
| interruptible | State motion is a transition flipped by class, never a one-shot keyframe; mid-flight reversals animate from where they are |
| attention is finite | Pulse twice, hold, fade. Only progress may loop forever, at the 1.4s house period |
| compositor first | transform + opacity; the earned exceptions are outline (.attn), fr tracks (.grow-*), and alpha-only masks |
| JS writes numbers | Handlers set --mx/--my or a transform; every visual decision stays in CSS where the theme owns it |
| frequency discounts delight | Never decorate an action performed a hundred times a day; hover may delight, focus never |
Four beats, six curves. Fire them: the difference between the curves IS the doctrine. --ease-exit leaves for good; --ease-back settles direct manipulation.
| Token | Value | Job |
|---|---|---|
| --dur-1 | 120ms | Press, hover, color shifts |
| --dur-2 | 200ms | Toggles, switches, chips |
| --dur-3 | 320ms | Entrances, sheets, disclosure |
| --dur-4 | 480ms | Orchestrated moments, rare |
| --ease-standard | cubic-bezier(.2, 0, 0, 1) | The default; press and state |
| --ease-entrance | cubic-bezier(.16, 1, .3, 1) | Things arriving |
| --ease-emph | cubic-bezier(.3, 0, .1, 1) | Emphasis, attention |
| --ease-exit | cubic-bezier(.3, 0, 1, 1) | Leaving for good |
| --ease-back | cubic-bezier(.34, 1.56, .64, 1) | Snap-back settle after a drag or magnet |
| --ease-spring | cubic-bezier(.22, 1, .36, 1) | Playful settle, sparing |
Acknowledged within 120ms, always. Bar and inline controls sit down 1px; floating and icon controls compress to .94-.97; a disabled control never animates. Amended 2026-08-31.
Fade + 10px rise on --ease-entrance, children 60ms apart, capped at six. Travel scales with the surface: 10px for cards, 24px for drawers and sheets, and the responsive trick is swapping animation-name, not the class.
Each line travels up out of its own mask, 70ms apart, on a transition so it stays interruptible. For display headings only: one per page.
The light follows the pointer; the group tracks on the container so neighbors warm before arrival. One handler writes --mx/--my, the CSS owns every visual decision. Touch gets no dead effect.
Follows at a third of the pointer's offset with no transition, then settles home on --ease-back. Direct manipulation is the only place overshoot is honest.
Digits are columns travelling on transform behind an edge mask; tabular-nums so the width never jitters; every column rolls the SAME direction so the trend stays legible. The live number keeps its meaning in a sr-only twin.
Two strings cross-dissolved read as garbage. The house idiom sequences them by flipping transition-delay: the outgoing string fully leaves, THEN the incoming one lands. Fenced behind hover-capable pointers.
The guide ring: pulse twice, hold five seconds, fade to nothing. Attention that persists is nagging; the reduced-motion cut keeps the ring and the fade, drops the pulse. From the console's error guide.
Skeletons mirror the real layout and sweep at the 1.4s house period, an overlay on transform, never background-position. Content replaces them with one rise beat, and the swap happens once: loading never flickers back.
Intrinsic size animates through fr tracks: 0fr to 1fr, the one sanctioned route. Disclosure chrome still snaps, chevron-only. Width adds opacity so the string never squishes visibly.
The beam and the marquee live on marketing surfaces only, never near data. Ambient loops randomize or pause; a uniform loop reads cheap in a minute. Hover pauses the marquee.
Every page's theme toggle does it: the new theme sweeps out of the control as a circle, one View Transition, 480ms. The one orchestrated moment a page spends. No support, no motion preference: instant flip, same result.
If a surface matches a row, the motion is wrong.