transitions
Flying Instead of Teleporting
When one state replaces another, the default is not a crossfade. Work in this order: find what persists across the boundary and keep it continuous, then let everything that does not persist enter and exit along the axis that matches the spatial relationship. If nothing persists and there is no spatial relationship to express, a hard cut beats a decorative crossfade — a fade is what you ship when you have not worked out what moved. Benji Taylor's framing is the one to hold: "we fly instead of teleport", and each transition "serves a purpose from an architectural perspective, aiding users in understanding their path from A → B." motion owns one element's curve, duration, and enter shape; this skill owns which elements move, in what order, in which direction, and what stays continuous — and if the clock is a finger rather than a timer, it is gestures.
Find the mechanism the project already has before choosing one. Grep for startViewTransition, view-transition-name, ::view-transition, @view-transition, layoutId, AnimatePresence, Motion's layout prop, a FLIP helper, or a framework route hook (template.tsx, useNavigation, a router's transition callback). A codebase that already runs View Transitions gets its next shared element in View Transitions; a codebase on Motion layoutId gets layoutId. Two shared-element systems in one app produce two different physics for the same gesture, which is worse than either alone.
Quick Reference
| When | Open |
|---|---|
| More than one element enters at once, or a tab switch, route change, or list reorder needs an exact delay and a direction | choreography.md |
| The same component exists on both sides of the boundary — the case where a wrong implementation quietly duplicates it | shared-element.md |
Which mechanism?
Walk the ladder and stop at the first match.