All pages

Foundations

Motion

Motion in Curation is the legacy app's overlay choreography, ported keyframe for keyframe. Every overlay animation is a paired -in and -out of the same length, because Radix keeps a closing panel mounted until its animation ends — an out that outlives its in leaves a scrim hanging on a dismissed dialog.

Durations and easing

Overlays run on the fast step, not the normal one — 0.3s of scale reads as the app thinking about it. --ease-overlay is the curve the legacy BaseModal hands every overlay, so the two clients' modals arrive with the same weight.

TokenValueRole
--duration-fast0.2sOverlays, hovers, most transitions.
--duration-normal0.3sLarger movements.
--duration-slow0.5sRare, deliberate reveals.
--ease-standardcubic-bezier(0.4, 0, 0.2, 1)The general-purpose curve.
--ease-overlaycubic-bezier(0.25, 0.46, 0.45, 0.94)Every overlay's arrival and exit.

The overlay set

Four pairs, spent as animate-*-in / animate-*-out. The scrim crossfades on its own while the panel moves — splitting the two stops a scaling panel from dragging the scrim's opacity along its own curve. The dialog scales from 0.8; the popover from 0.96, out of the corner Radix placed it against, so it grows from its trigger; the sheet travels with no fade — a sheet that is also translucent on the way up reads as two effects rather than one movement. Click a plate to replay it.

"data-[state=open]:animate-dialog-in data-[state=closed]:animate-dialog-out"
"data-[state=open]:animate-scrim-in  data-[state=closed]:animate-scrim-out"

Radix waits for animationend before unmounting, which is what makes the closed half play at all. Overlays that are not Radix — the mount-to-open ones — lean on hooks/use-dialog-exit.ts instead, whose DIALOG_EXIT_MS is --duration-fast in milliseconds; moving one means moving both.

Working marks

Three marks say the app is working: animate-chat-dot (the thinking dots, a staggered 1.4s pulse), animate-skeleton (the placeholder sweep), and the agent's face pondering — tweened in script rather than a keyframe loop, so it can ease home when the turn ends. They live on the Loading and Skeleton pages.

Reduced motion

Under prefers-reduced-motion, the working marks stop — the placeholder still reads as a placeholder at rest. Dialogs and sheets are swapped down to a crossfade rather than switched off: the preference is against travel, not against the surface arriving, and the timing has to survive either way — animation: none would leave Radix nothing to wait on, unmounting a dismissed dialog on the spot while the timed overlays sat through their hold showing nothing.