# UI Animation

> Designs and builds website and web-app animations that feel deliberate and stay smooth: durations, curves and springs by element, staggers, enter and exit, layout and shared-element transitions, gestures, scroll-linked motion, collections, reduced motion. React with Motion, and CSS. Use when adding, tuning or reviewing animations or transitions in a web interface; React Native and Expo motion routes to the global React skill.

- Skill: `quegenx/ui-animation` (Agent Skill, multi-file: 23 files)
- Install (CLI): `npx get-skill add quegenx/ui-animation`
- Raw SKILL.md: https://api.skillmd.com/api/skills/quegenx/ui-animation/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: Quegenx (https://skillmd.com/u/quegenx)
- Updated: 2026-11-12
- Page: https://skillmd.com/skills/quegenx/ui-animation

---


# UI animation

The model knows what a card entrance is. It doesn't know this card should take 280 ms, the one behind it should start 60 ms later, and both must be interruptible mid-flight. Pick from the numbers; deviate on purpose, never by accident. Every animation answers one question: what changed, and where did it go?

The optional [Animista catalog](ANIMISTA.md) adds exact preset names and recorded preview settings from Ana Travas's `animista.json` and the supplied play catalog; its defaults remain separate from the product rules below. [Animista, animista.json and animista-play-catalog.md]

Apply only the routes and checks for the selected job. Read a linked skill's named file from its installed folder when available, or from the linked source. Report an unavailable required reference instead of inventing it. [skill-authoring, DISTRIBUTION.md#composing-skills]

| The job | Read |
|---|---|
| How long, which curve, which spring; staggers, overlaps, distance, direction | [TIMING.md](TIMING.md) |
| Enter and exit, layout and shared-element transitions, lists, modals, trays, a button that grows into a panel, feedback at the tap, icon choices, numbers, gestures, scroll and delight | [PATTERNS.md](PATTERNS.md) |
| Live values and charts: Liveline, shared easing, loading and pause states, momentum and hostile data | [LIVE-CHARTS.md](LIVE-CHARTS.md) |
| Galleries, carousels and rings: pose interpolation, endless wrapping, velocity tilt and detail opening | [COLLECTIONS.md](COLLECTIONS.md) |
| A card grid that morphs into a full-screen detail while the URL follows, so Back closes it | [CARD-TO-MODAL.md](CARD-TO-MODAL.md) |
| Presses and drags in detail: grab and hold on, flick to dismiss, handing release velocity to a spring, pointer-following, tilt, a draggable switch thumb | [GESTURES.md](GESTURES.md) |
| Toasts and tooltips: stacking, swipe and timers, tooltip delay groups | [TOASTS-AND-TOOLTIPS.md](TOASTS-AND-TOOLTIPS.md) |
| Hold to confirm, clip-path and blur reveals, the generation reveal | [REVEALS.md](REVEALS.md) |
| One hover highlight per list, labels whose weight changes without reflow, merged selection blocks | [HIGHLIGHTS-AND-SELECTION.md](HIGHLIGHTS-AND-SELECTION.md) |
| No library: top-layer enter and exit with `@starting-style`, `<details>` to `height: auto`, waiting for CSS transitions, a CSS FLIP (AIM), view transitions and their limits, scroll-driven ranges, Web Animations offsets, focus by demotion | [NATIVE-CSS.md](NATIVE-CSS.md) |
| React's `<ViewTransition>` (stable in React 19.3): triggers, `default="none"`, `addTransitionType`, Suspense reveals, shared elements, isolating chrome and popovers, Next.js `transitionTypes`, a symptom table, the audit and navigation map | [REACT-VIEW-TRANSITIONS.md](REACT-VIEW-TRANSITIONS.md) |
| The CSS those view transitions name: fades, directional slides and their right-to-left flip, morphs, isolation, the tab indicator, and their durations and reduced motion against this skill's | [VIEW-TRANSITION-RECIPES.md](VIEW-TRANSITION-RECIPES.md) |
| A sheet swiped away on native scroll: snap points, swipe-synced animation, stacking, the software keyboard | [SHEETS.md](SHEETS.md) |
| Per-frame math in your own loop: lerp and exponential approach, a spring by hand, physics, facing the direction of travel, sine waves, sawtooth loops, controlled randomness, piecewise segments | [MATH.md](MATH.md) |
| Drawn characters and scenes: face layers, moving holds, delayed follow-through, limbs, weight, prop contact and camera-dependent proportions | [ILLUSTRATION-ACTING.md](ILLUSTRATION-ACTING.md) |
| Authored product illustrations: a readable poster, retained UI tracks, cause and payoff, loop resets and rehearsal in the real host | [PRODUCT-ILLUSTRATIONS.md](PRODUCT-ILLUSTRATIONS.md) |
| Smooth on a slow phone: which properties, GPU vs main thread, React re-renders, reduced motion, measuring | [PERFORMANCE.md](PERFORMANCE.md) |
| Motion from a physical model: words to spring numbers, bodies, fields and walls, the hand that drags, projection on release, baking physics into keyframes | [PHYSICS.md](PHYSICS.md) |
| React Native and Expo motion policy and setup: Reanimated runtimes, tool choices, springs, haptics and reduced motion | [React native motion policy](https://github.com/Quegenx/agent-skills/blob/main/skills/web-ui/react/REACT-NATIVE-MOTION.md) |
| React Native worked recipes: press, sheet, swipe, header, list, keyboard, tab, navigation, toast and threshold | [React native motion recipes](https://github.com/Quegenx/agent-skills/blob/main/skills/web-ui/react/REACT-NATIVE-MOTION-RECIPES.md) |
| React Native SVG illustration clocks and live faces, with source API and lifecycle limits | [React native illustration](https://github.com/Quegenx/agent-skills/blob/main/skills/web-ui/react/REACT-NATIVE-ILLUSTRATION.md) |
| Measure a recorded illustration: full-rate cropped sheets, edges, proportions, colors and matched-time comparison | [Reference motion](https://github.com/Quegenx/agent-skills/blob/main/skills/web-ui/pixel-reverse-engineer/REFERENCE-MOTION.md) |
| Name an effect or a feeling: the term to ask for, and close terms told apart | [VOCABULARY.md](VOCABULARY.md) |
| Look up Animista's 75 groups and 662 variations, recorded preview settings and generated-CSS limits | [ANIMISTA.md](ANIMISTA.md) |
| Review existing motion: scan, rank, write one fix plan per pick | [AUDIT.md](AUDIT.md) |
| Find where motion belongs, and reject the rest | [OPPORTUNITIES.md](OPPORTUNITIES.md) |

Images and video loading, long lists and bundle splitting are in [web-performance BROWSER.md](https://github.com/Quegenx/agent-skills/blob/main/skills/web-ui/web-performance/BROWSER.md); how much motion a page should have at all is the MOTION dial in `anti-slop-ui`; how each app component (menus, dialogs, confirms, tables, boards) moves and behaves is in `app-ui`; a marketing site's hero, reveals and page transitions are in `landing-page-ui`; an agent chat's status line, streaming and cards are in `agent-chat-ui`; SVG technique (goo filters, displacement maps, line-based icon geometry) is in [the `svg` skill](https://github.com/Quegenx/agent-skills/blob/main/skills/web-ui/svg/SKILL.md); GSAP tweens, timelines and ScrollTrigger are in [the `gsap` skill](https://github.com/Quegenx/agent-skills/blob/main/skills/web-ui/gsap/SKILL.md); building several motion directions behind a picker is anti-slop-ui's [anti-slop-ui VARIANTS.md](https://github.com/Quegenx/agent-skills/blob/main/skills/anti-ai-slop/anti-slop-ui/VARIANTS.md), and every state of one component on one page its [anti-slop-ui STATE-PAGE.md](https://github.com/Quegenx/agent-skills/blob/main/skills/anti-ai-slop/anti-slop-ui/STATE-PAGE.md).

**Code or a tool:** "The strength of animation written in code lies in real-time interaction", motion that responds to input and changes with state. A character walking and running, a hand-drawn morph, or an intro where dozens of layers interlock "just isn't realistic" in code alone: use After Effects exported with Lottie, Rive for interactive animation, or a pre-rendered video (kciter).

**A different source choice:** Rossark builds small illustrated scenes directly from pose channels, idle waves and delayed follow-through, with React Native SVG templates and SwiftUI Canvas demos. Keep kciter's tool preference above; use the bounded [illustration method](ILLUSTRATION-ACTING.md) where that is the selected job, without treating its demos as proof that every animated production scene should be hand-coded. [rossark-motion-skill, SKILL.md sections 2 to 6; templates/react-native/liveFace.tsx; demo/RevealScene.swift; kciter, How to Design an Animation]

## Before you build

**Choose the platform first.** For React Native or Expo, read [React native motion policy](https://github.com/Quegenx/agent-skills/blob/main/skills/web-ui/react/REACT-NATIVE-MOTION.md) before implementing its [recipes](https://github.com/Quegenx/agent-skills/blob/main/skills/web-ui/react/REACT-NATIVE-MOTION-RECIPES.md); use that file's tool ladder, properties, timing alternatives and device-verification contract. The CSS, WAAPI, Motion and browser-tool checks below are the web branch. Shared motion principles remain, with the existing source differences kept explicit. [Emil Kowalski, animate; Emil Kowalski, animate-expo; REACT-NATIVE.md]

[Emil Kowalski, animate] "Two failure modes, and the first is worse: 1. **Animating something that shouldn't animate.** The gate below exists to produce zero lines of code sometimes. That's a success, not a dodge. 2. **Animating the right thing with the wrong ingredients**." Ask in order and stop at the first no:

1. **How often?** The frequency gate in [TIMING.md](TIMING.md#should-it-animate-at-all): keyboard-initiated and 100+-a-day actions get no animation. Failing it, "say so plainly and don't write the animation. Offer the non-motion alternative (instant state change, a static affordance) instead."
2. **What for, in one word?** Feedback, Spatial consistency, State indication, Preventing a jarring change, Explanation (marketing or onboarding only), Delight ("allowed *only* at the rare/first-time tier"). "Can't name it? Don't build it."
3. **Is it data someone is reading?** "data the user is reading or acting on should not move for style. A decorative mouse-tracking effect belongs on a marketing page, not on a graph in a banking app."
4. **For web motion, which tool, cheapest first?** "Walk down; stop at the first that fits": a CSS transition (hover, press, colour, a class or attribute toggle), `@starting-style` (entry on mount, no JS state), a CSS animation (predetermined motion), WAAPI (`element.animate()`), then Motion (springs, layout, exit, gestures). "Use CSS for predetermined motion, JS for dynamic and interruptible motion." CSS runs off the main thread only "as long as the properties we want to animate do not trigger reflow/repaint" ([MDN](https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/CSS_JavaScript_animation_performance)). A toast, drawer, command menu or dropdown is a component, not an animation: "Hand-rolling those is how you end up with a `<div>` dropdown and no focus management."

- [Emil Kowalski, animate] "Reduced motion and hover gating ship with the animation, not as a follow-up": hover motion sits under `@media (hover: hover) and (pointer: fine)` because "touch fires false hovers on tap". app-ui's checker accepts `(hover: hover)` alone ([app-ui CHECKS.md](https://github.com/Quegenx/agent-skills/blob/main/skills/web-ui/app-ui/CHECKS.md)).
- [Emil Kowalski, animate] "Never present motion options as a menu. Make the call, state the reasoning in one line, write the code." Then report in a few lines: the gate result, the ingredients (tool, properties, curve, duration or spring), and what to feel-check.
- [feel] Size the job first and say which size it is: one interaction (a toggle, a press, a slider thumb) is "20-45 minutes. Build it without asking"; a gesture system (a sheet with stops, a momentum carousel) is "1-3 hours. Say so, then build it"; a product's whole motion system: "Don't start it. Propose the 3 interactions that matter most, and list what the full system would add."

## The rules

1. **Motion explains a change.** Something appeared, left, moved, grew into a detail view, was confirmed or rejected. Motion with no change to explain (floating cards, everything fading up on scroll, idle bouncing) is decoration; cut it or keep it subliminal. Treat the app as having "unbreakable physical rules": know how and why a transition makes sense before adding it (Family). Family and Honk add motion past this line on purpose, for delight and play; that case, both ways, is in [PATTERNS.md](PATTERNS.md#delight-where-flourish-goes).
2. **Small and frequent is fast; big and rare is slower.** A toggle is 120-180 ms, a modal 300-400 ms, a page transition 400-600 ms. Anything a user triggers dozens of times a day stays near the bottom of its range, and nothing blocks input while it plays. Applied thoughtfully, motion can "enhance clarity and feel just as fast" as a static cut: "We fly instead of teleport" (Family). Stricter sources cut frequent actions to no animation at all; both views are in [TIMING.md](TIMING.md#should-it-animate-at-all).
3. **One motion language per product:** one curve for arrivals, one for exits, one spring family for things that feel physical, one stagger rhythm, one base duration that the others are multiples of. A screen that invents its own is a defect, not a style. One fluid transition doesn't make a fluid product; that takes "hundreds of small, deliberate decisions", and "Every interaction feeds into the next" (Family).
4. **Exits are faster than entrances** (about half to two thirds of the entrance), and leave through the nearest edge or back where they came from. The named exceptions (symmetric pairs, hover-out, deliberate holds) are in [TIMING.md](TIMING.md#staggers-and-sequencing).
5. **Interruptible always.** A new target starts from the current position and velocity; never wait for an animation to finish before responding, never snap back to the start first. In Motion only a physics spring (`stiffness`, `damping`, `mass`) carries the velocity: duration-based springs "don't incorporate velocity" ([motion.dev](https://motion.dev/docs/animate); [TIMING.md](TIMING.md#springs)). [Craft] "Never lock the door": "An `isAnimating` flag drops clicks, or `pointer-events: none` stays on until the motion is done", and "people tap again, which drops another tap, which makes it worse."
6. **Things that move together move as one:** a group shifts in one direction, never crossing paths; one element is the focus of each change, everything else yields.
7. **The web performance default is that only transform and opacity move,** so it stays smooth while the page is busy; keep the documented alternatives in [PERFORMANCE.md](PERFORMANCE.md). React Native has its own [property policy and absolute-childless-element exception](https://github.com/Quegenx/agent-skills/blob/main/skills/web-ui/react/REACT-NATIVE-MOTION.md#properties); retain both source views rather than erasing that exception. [Emil Kowalski, animation-performance; Emil Kowalski, animate-expo]
8. **Reduce, don't remove:** with reduced motion, movement becomes short fades; feedback and state changes stay. [Jakub Krehel, better-ui] Motion is never the only feedback channel: every animated state change also leaves a static cue (a colour, an icon or a label).

## Prove it

For React Native and Expo, use [the native device checks](https://github.com/Quegenx/agent-skills/blob/main/skills/web-ui/react/REACT-NATIVE-MOTION.md#prove-it). The browser checks below apply to web interactions. [Emil Kowalski, animate-expo; REACT-NATIVE.md]

Record the web interaction at 4x CPU slowdown: no dropped frames, no layout in the animation frames. Click twice fast and mid-animation: it retargets smoothly. Toggle reduced motion: no slides or zooms remain, every state change is still visible. Check every duration and curve against [TIMING.md](TIMING.md).

- **Remove the motion and compare side by side,** as Family did: without it, "the action's intent and outcome become much less clear", and the static version "feels like digital whiplash". Smoothness matters most where money is on the line: a glitchy animation in a banking app makes users question whether it "can execute my actions accurately".
- **Play every A-to-B pair** of states that morph into each other, with a dev tool that cycles chosen sequences; jank in specific pairs (arrow-right to arrow-down) is "the sort of thing you only notice by playing with it" (Benji Taylor).
- **Name the part:** break a "feels sluggish" note into the delay before it starts, the duration and the easing, and pause mid-transition to point at the in-between frame (Benji Taylor, "Annotating for agents").
- **Slow it down, then come back tomorrow:** [Emil Kowalski, animate] "play it at 2-5× duration or in the DevTools animation inspector, step it frame by frame, test gestures on a real device, and look again the next day with fresh eyes." Look for colours overlapping as two states, easing that starts or stops abruptly, a wrong transform-origin and properties out of sync [Emil Kowalski, emil-design-eng]. [Jakub Krehel, make-interfaces-feel-better] replays at 10% and walks every state: hover, focus, active, loading, empty. Chrome's Animations panel documents speed buttons and scrubbing, not frame-by-frame stepping or a 10% value ([Chrome DevTools](https://developer.chrome.com/docs/devtools/css/animations)).
- **Real hardware for gestures:** open the dev server on the phone by IP address with Safari's remote devtools; the Xcode Simulator works, "but real hardware is better for gesture testing" [Emil Kowalski, emil-design-eng]. Desktop CPU throttling "models a slow CPU, not a weak GPU or a small memory budget" [Emil Kowalski, animation-performance].
- **Live data:** run it on hostile data, sharp reversals and irregular arrival included ([LIVE-CHARTS.md](LIVE-CHARTS.md#live-values-and-charts)).
- **Agents build for working, not feeling right:** a human watches the transitions and describes what feels off ("Play with the result, notice what's wrong, describe it, repeat"), and gives the agent the structural constraint, not the goal: "smooth transitions" produced a crossfade; "exactly three SVG lines" per icon produced the morph.

