Motion
Duration and easing tokens, MotionProvider modes, and the transform-and-opacity contract.
Hewn treats motion as a global contract, not a per-component prop.
Tokens set timing, MotionProvider sets the mode, and sources may only animate
transform, opacity, and filter.
Live mode
Preference full · Effective full
Full mode: springs, press scale, and chart draws run.
Tokens
CSS custom properties live in @hewnui/themes/motion.css (imported by
tokens.css). Theme packs still tune --kp-motion-duration for character;
the scale below is shared.
| Token | Role | Default |
|---|---|---|
--kp-motion-duration-instant | Immediate / disabled | 0ms |
--kp-motion-duration-fast | Micro feedback | 120ms |
--kp-motion-duration | Pack base (theme character) | pack-specific |
--kp-motion-duration-slow | Presence / draws | 360ms |
--kp-motion-ease-standard | Default CSS easing | cubic-bezier(0.2, 0, 0, 1) |
--kp-motion-ease-emphasized | Emphasized settle | cubic-bezier(0.16, 1, 0.3, 1) |
--kp-motion-ease-exit | Exit curves | cubic-bezier(0.4, 0, 1, 1) |
--kp-motion-ease-linear | Progress / meters | linear |
TypeScript mirrors for Motion transitions ship from @hewnui/motion:
Use CSS vars in class strings (duration-[var(--kp-motion-duration-fast)],
ease-[var(--kp-motion-ease-standard)]) and the TS constants in
transition={{ … }} props. Do not hard-code millisecond or bezier values in
components.
Modes
MotionProvider exposes three modes:
| Mode | Behavior |
|---|---|
full | Springs, press scale, chart draws, layout presence |
reduced | MotionConfig reducedMotion="always"; CSS durations collapse to 0 |
off | Same hard stop as reduced for Motion + CSS; static fallbacks only |
Resolution rules:
- Default preference is
full. prefers-reduced-motion: reducecaps effective mode atreduced— a user preference offullcannot win.- Users may only reduce motion further (
full→reduced→off). - The effective mode is written to
document.documentElement.dataset.motionso CSS-only surfaces can key off[data-motion="reduced"]/"off".
| Field | Meaning |
|---|---|
motion | Stored user preference |
effectiveMode | Preference after OS clamp |
motionEnabled | effectiveMode === "full" |
reducedMotion | OS preference is active |
setMotion | Update preference |
MotionConfig receives reducedMotion="never" in full mode and "always"
otherwise.
Rules
- Animate transform, opacity, and filter only. Never animate layout
properties (
width,height,top,left,margin, …). - Never use
transition: allor Tailwindtransition-all. - Press feedback uses
scale(0.96). - Reduced motion always wins over product defaults and user “more motion” choices.
- Infinite motion must be isolated, memoized, and disabled when
motionEnabledis false. pnpm check:motionfails the build ifpackages/uisources violate the transition contract.
Appearance controls
Docs and Theme Lab appearance docks include the motion mode control next to
theme, mode, material, and radius. Choices persist in localStorage
(kp-motion). Legacy on values migrate to full.