11 · Tempo · Motion

Brief. Honest. Out of the way.

11 / 22

Every animation earns its place by telling the user something a static frame can't — state changed, something entered, something's still working. No bounces, no elastic, no decorative drift. prefers-reduced-motion silences everything.

Hover / press
150ms

ease-out. Border shift, bg shift, or translate-y 1px. One effect, not three.

Panel reveal
350ms

cubic-bezier(.25,1,.5,1). Fade + 8px rise. Staggered 30ms per sibling up to 12 items.

Theme swap
300ms

Background + foreground cross-fade. Accents switch instantly — they're meaning, not decoration.

Scan line
14s

Slow sweep across hero. Ambient, low-opacity. A heartbeat, not a siren.

Tokens

Bind the rhythm to variables.

Every transition and keyframe pulls from this set. Two easing curves — one for most things (quart), one for decisive arrivals (expo) — and four durations from instant to stage. No bespoke cubic-beziers sprinkled across components.

--ease-out-quart cubic-bezier(0.25, 1, 0.5, 1)

Hover states, small transitions, most UI work. Natural deceleration.

--ease-out-expo cubic-bezier(0.16, 1, 0.3, 1)

Menu reveals, sidebar swaps. Starts fast, settles decisively.

--dur-instant 90ms

Pressure feedback: border, color, tiny translate on hover.

--dur-quick 160ms

Panel swaps, dropdown reveals, collapse/restore.

--dur-base 220ms

Larger state changes: stagger intervals, layered entrances.

--dur-stage 320ms

Full-stage transitions. Page-sized cross-fades, theme swaps.

prefers-reduced-motion short-circuits every transition-duration and animation-duration globally to 0.001ms. No per-component opt-in needed.