Foundations

Motion

Four durations, three curves, and one rule: if an animation doesn’t explain something, it doesn’t ship.

Principles #

  • Enter slow, leave fast. Arrivals get just enough time to be understood; departures get out of the way.
  • Travel short distances. Things move 2–12px, from where they came from. Nothing flies across the screen.
  • Animate only transform and opacity. They’re composited by the GPU and never trigger layout.
  • Colour changes are fast. Hover and focus respond within 120ms so the interface feels immediate.

Durations #

TokenValueUse
--juxt-duration-instant80msLeaving, pressing
--juxt-duration-fast120msHover, colour, focus
--juxt-duration-normal180msEntering, toggles
--juxt-duration-slow240msTravel: indicators, sheets

Easing #

Press play to compare the three curves over the same distance.

--juxt-ease-standard
--juxt-ease-out
--juxt-ease-in

Component choreography #

ButtonPress: scale 0.97 in 80ms. Release eases back in 120ms.
Input, SelectFocus: border takes the accent and a 3px halo fades in over 180ms.
CheckboxThe box fills in 120ms; the tick draws itself 40ms later.
SwitchThe thumb travels in 180ms with ease-out, stretching 3px while pressed.
Menus, SelectEnter: fade in 120ms while rising 4px and scaling from 0.97 toward the trigger. Leave: 80ms.
TooltipEnter: 120ms, 2px toward its trigger. Leave: 80ms fade. Instant when moving between tooltips.
DialogBackdrop fades in 180ms. Panel fades and settles from 8px below at 0.97 scale over 240ms. Leave: 120ms.
Command paletteFaster than a dialog: 120ms fade, 180ms settle, 80ms leave.
ToastRises 12px from the edge over 240ms; others glide to make room. Leaves in 120ms.
TabsOne indicator slides in 240ms. Panels only fade — content never slides.

Reduced motion #

When the operating system asks for reduced motion, juxt.ui sets --juxt-motion-shift to 0 and --juxt-motion-scale to 1. Things still fade — a fade conveys a change of state without motion — but nothing travels, scales, stretches or slides. Spinners slow down, and the tab indicator jumps instead of gliding.

Use the same two tokens in your own transitions and you get the same behaviour for free.