ui-animation
Builds, reviews, and measures UI motion, including springs, gestures, scroll effects, and curve fitting from recordings. Use when asked to "add animation", "match this easing", "reverse engineer this motion", or find animation opportunities. For action semantics use product-design; for visual layout
By mblode · 9,077 installs
npx skills add mblode/agent-skills --skill ui-animation
Source repository · Upstream listing
UI Animation
IS: designing, implementing, reviewing, debugging UI motion (springs, gestures, drag, easing, CSS transitions, keyframes, Motion), sweeping an interface for the moments that would genuinely benefit from motion, measuring motion from a recording (extract frames, track, fit curves) to emit code plus a handoff spec, and naming a described motion effect (reverse lookup vocabulary).
IS NOT: choosing overall visual direction, palettes, or typography (use ui design Direction mode), auditing a whole page's UI quality (use ui design Audit mode), or named text effect specs (use the external animate text skill where installed).
Routing boundary
product design owns action semantics, scope, reversibility, and contested state choices. ui design builds and styles those states. ui animation owns timing, gestures, and measured motion. A routine missing loading or error state stays with the UI build; a gesture replacing a control needs a product decision and an accessible alternative before its physics.
Reference files
File Read when
[references/discovery workflow.md](references/discovery workflow.md) Finding worthwhile opportunities for motion in an existing interface
[references/decision framework.md](references/decision framework.md) Default: deciding whether/why to animate, picking easing character; also the seam list for a Discovery sweep
[references/spring animations.md](references/spring animations.md) Spring physics, Motion useSpring , configuring spring params, Apple damping/response values, asymmetric open/close character, interruption mechanics
[references/component patterns.md](references/component patterns.md) Buttons, popovers, tooltips, drawers, modals, toasts with animation
[references/clip path techniques.md](references/clip path techniques.md) clip path for reveals, tabs, hold to delete, comparison sliders
[references/gesture drag.md](references/gesture drag.md) Drag, swipe to dismiss, momentum, pointer capture, velocity handoff, momentum projection, rotary/knob drag, detents, carousel touch action
[references/scroll animations.md](references/scroll animations.md) Scroll triggered reveals, scrubbed/scroll driven animation ( animation timeline , useScroll ), parallax, sticky scrollytelling, and when a scroll animation shouldn't exist
[references/performance deep dive.md](references/performance deep dive.md) Jank, CSS vs JS, WAAPI, CSS variables trap, Framer Motion caveats
[references/debugging symptoms.md](references/debugging symptoms.md) An animation feels off and the cause isn't named: symptom indexed tables for sluggish, robotic, cheap, jumpy, and misfiring motion
[references/svg animation.md](references/svg animation.md) Animating vector art: line drawing ( stroke dashoffset ), SVG transform origin traps, path morphing, shakes, ambient life
[references/review format.md](references/review format.md) Reviewing animation code: ten standards (each with flag on sight triggers), Before/After/Why table, Block/Approve verdict
[references/contextual animations.md](references/contextual animations.md) Contextual icon swaps, word level stagger entrances, peripheral de emphasis, fixed offset exits
[references/transition recipes.md](references/transition recipes.md) Installing a CSS transition: container morph, card resize, badge, dropdown, modal, panel, page slide, icon swap, number pop in, odometer roll, text swap, success, avatar hover, error shake
[references/measurement guide.md](references/measurement guide.md) Reverse engineer: what to measure, eye vs script, reading metrics.json , choosing an ROI
[references/curve fitting.md](references/curve fitting.md) Reverse engineer: reading fit curves.py output, spring vs bezier, judging fit error, asymmetric open/close
[references/code output.md](references/code output.md) Reverse engineer: emitting code for CSS, Motion/Framer Motion, SwiftUI, React Native, UIKit
[references/choreography.md](references/choreography.md) Reverse engineer: multi element/multi phase motion: staggers, blur before move, per edge settling
[references/vocabulary.md](references/vocabulary.md) Naming a motion effect the user describes vaguely ("what's it called when...")
Core rules
Animate for feedback, orientation, continuity, or deliberate delight. If it's just "it looks cool" and the user sees it often, don't.
Keep keyboard focus and repeated navigation immediate. A state transition may animate if focus and task completion do not wait for it.
Prefer CSS transitions for interruptible UI: keyframes restart from zero on interruption, transitions retarget. Use keyframes only for predetermined sequences.
Implementation priority: CSS transitions WAAPI CSS keyframes JS ( requestAnimationFrame ); under load CSS stays smooth while JS drops frames.
Asymmetric timing: occasional interactions can enter slightly slower, exit fast. High frequency ephemeral UI (hover highlights, popovers, panel toggles) inverts this: enter instantly (0ms), exit with a brief fade (100 150ms) so the action feels immediate.
Tappable controls press on :active at 0ms and set touch action: manipulation .
Use @starting style for DOM entry; fall back to a data mounted attribute where unsupported.
A small filter: blur(2px) hides rough crossfades between swapped content.
Motion design principles
Continuity over teleportation. Elements visible in both states transition in place; expand from where elements sit rather than fading in a new instance. Never duplicate a persistent element or hard cut between views that share components; hard cuts lose spatial context.
Directional motion matches position. Tab and carousel transitions animate in the direction matching spatial layout (left to right forward, right to left back).
Emerge from the trigger. Overlays, trays, and panels animate outward from the element that opened them; generic centre screen entrances break spatial orientation. Better still where the shapes allow: let the trigger become the surface (see the container morph recipe).
Confirm in place, not in a corner. An action's result belongs on the control that caused it: the button becomes "Copied", holds, and reverts. A toast in the far corner makes the user's eye leave the thing they just touched to find out whether it worked. Reserve corner toasts for results with no on screen origin (a background job finishing, an incoming message).
Animate paired states together. If open animates, close animates. If hover has motion, focus and pressed states get equivalent feedback. Do not polish only one half of a repeated interaction.
Delight scales inversely with frequency. Rarer interactions get more personality; high frequency actions must be invisible.
Motion enhances perceived speed. Smooth transitions feel faster than hard cuts, even at identical load times.
What to animate
Movement: transform and opacity only; they skip layout and paint.
State feedback: color , background color , and opacity are acceptable.
Never animate layout properties ( width , height , top , left ); they trigger layout recalc every frame. (Exception: a deliberate container tween, see the card resize and container morph recipes.)
Never use transition: all ; it animates unintended properties and silently adopts future ones. List them explicitly.
Avoid filter animation for core interactions; if unavoidable keep blur ≤ 20px (heavy blur is expensive, especially in Safari).
SVG: apply transforms on a <g wrapper with transform box: fill box; transform origin: center ; without it they rotate/scale around the canvas origin. Line drawing, path morphing, and the Motion SVG origin override live in [references/svg animation.md](references/svg animation.md).
transform: scale() also scales children (icons, text, borders scale proportionally), unlike width / height : a feature for press feedback, but account for it when an inner element must stay fixed size.
Disable transitions during theme switches ( [data theme switching] { transition: none !important } ), or every themed property animates at once.
Easing defaults
Element Duration Easing
Button press feedback 100 160ms cubic bezier(0.22, 1, 0.36, 1)
Tooltips, small popovers 125 200ms ease out or enter curve
Dropdowns, selects 150 250ms cubic bezier(0.22, 1, 0.36, 1)
Modals, drawers 200 350ms cubic bezier(0.22, 1, 0.36, 1)
Move/slide on screen 200 300ms cubic bezier(0.25, 1, 0.5, 1)
Page transitions 250 400ms enter or move curve
Hover (colour/opacity) 200ms ease
Hover (transform/scale) 100 150ms enter curve
Illustrative/marketing Up to 1000ms Spring or custom
Keep routine UI under 300ms; scale duration with distance (a full screen slide can exceed 300ms, a 6px tooltip shift stays under 150ms).
Named curves
Enter: cubic bezier(0.22, 1, 0.36, 1) for entrances and transform based hover
Move: cubic bezier(0.25, 1, 0.5, 1) for slides, drawers, panels
Drawer (iOS like): cubic bezier(0.32, 0.72, 0, 1) (extremely steep start; the reason its 500ms doesn't read as slow)
Expo out: cubic bezier(0.19, 1, 0.22, 1) for dramatic reveals, card hovers, text reveals
Press: cubic bezier(0.25, 0.46, 0.45, 0.94) for button press feedback
On screen move: cubic bezier(0.645, 0.045, 0.355, 1) for back and forth movement that stays on screen
Avoid ease in for UI: it starts slow, so the element lags the user's action and feels sluggish. Prefer custom curves from [easing.dev](https://easing.dev/) over built in ease / ease out , whose gentle acceleration reads soft, not decisive.
Transition decision rules
Match the UI element first, then pick the recipe from [references/transition recipes.md](references/transition recipes.md):
UI pattern Recipe
Trigger + floating dot/count Notification badge
Trigger grows into the surface it opens Container morph
Trigger + anchored surface Menu dropdown
Centred surface on top of page Modal dialog
Panel sliding into existing container Panel reveal
List ↔ detail or wizard steps Page side by side slides
Element dimension changes Card resize
Text updating in place Text state swap
Two icons in same slot Icon swap
Number arriving on its own Number pop in
Number the user is driving Odometer digit roll
Confirmation / success moment Success celebration
Hovering item in horizontal stack Avatar group hover
Form validation error Error state shake
Prefer lower overhead transitions (CSS only) unless the design requires JS orchestration.
Spatial and sequencing
Popover transform origin at the trigger (modals stay center ), dialog/menu entrances from scale(0.85 0.9) not scale(0) , and 30 50ms staggers (total under 300ms, most important element leading). Full rules and code in [references/component patterns.md](references/component patterns.md) and [references/contextual animations.md](references/contextual animations.md).
Paired elements rule: elements that animate together (modal + overlay, tooltip + arrow, FAB + label) must share easing and duration. Mismatched timing is the usual cause of "something feels off".
Accessibility
Gate hover (motion and paint) behind @media (hover: hover) and (pointer: fine) , or touch devices replay hover on tap. Inspect the generated CSS before adding a gate; Tailwind v4 already wraps hover: in @media (hover: hover) .
During direct manipulation, keep the element locked to