KG-03 · FIELD MANUAL

Reduced Motion Is a First-Class State

The degradation policy, and how to test it in one click.

A policy, not a patch

Reduced motion is usually an afterthought — a media query bolted on before launch. In Kinetiq it is a designed state: every category of animation has a documented fallback, decided when the component was designed, not discovered when someone complained.

CategoryFull motionReduced
enters / exitsspring + directional offsetopacity fade, fast
discrete statetravel + overshootinstant position, color tween only
direct manipulation1:1 tracking + inertia + settle1:1 tracking kept — inertia and settle removed
autoplay loopscontinuousstatic, or ≤1Hz opacity pulse
scroll-linkedscrubbed transformsfinal state, opacity only
number rollsrolling digitsinstant value + brief highlight
morphsshared-element rect morphplain centered fade

Two distinctions carry most of the weight. Dragging keeps 1:1 tracking because tracking is input, not decoration — removing it would break the interaction, not calm it. And progress indicators keep filling because progress is information; only the flourish around it goes.

One hook decides

No component reads the media query itself. Everything asks useMotionSafe, which combines the OS preference with an optional app-level override — so the policy has exactly one enforcement point.

hooks/use-motion-safe.ts
const motionSafe = useMotionSafe();

<motion.div
  animate={{ x: open ? 240 : 0 }}
  transition={motionSafe ? springs.snap : { duration: 0 }}
/>

Test it in one click

The header carries an RM · TEST switch. Flip it and this entire site — every demo, every page transition — drops into its reduced pathway with a banner confirming the state. If a fallback ever feels broken rather than calm, that is a bug, and it is visible to anyone in one click. Policies you can't inspect don't survive contact with shipping.