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.
| Token | Value | Role |
|---|---|---|
--duration-fast | 0.2s | Overlays, hovers, most transitions. |
--duration-normal | 0.3s | Larger movements. |
--duration-slow | 0.5s | Rare, deliberate reveals. |
--ease-standard | cubic-bezier(0.4, 0, 0.2, 1) | The general-purpose curve. |
--ease-overlay | cubic-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.