| name | animate |
| description | Improve or implement purposeful motion systems, micro-interactions, gestures, and transition behavior for production-grade UI. Use when the user mentions animation, motion, transitions, micro-interactions, hover states, drawers, toasts, gestures, or making the UI feel more alive. |
| metadata | {"argument-hint":"[component, state, or interaction]"} |
Analyze a feature and add motion that improves clarity, feedback, perceived performance, and polish without making the interface feel slow, noisy, or theatrical.
MANDATORY PREPARATION
Users start this workflow with /animate. Once this skill is active, load $frontend-design — it contains design principles, anti-patterns, and the Context Gathering Protocol. Follow that protocol before proceeding — if no design context exists yet, you MUST load $setup first. Additionally gather: performance constraints.
Consult the motion reference for timing, easing, choreography, and reduced-motion handling.
Consult the animate reference index when you need to browse the deeper motion library by use case instead of guessing filenames.
Consult the elevation system when motion should reinforce raised, pressed, inset, dragged, or layered depth.
Consult the interaction reference when animation decisions overlap with focus, loading, transitions, or feedback states.
Consult the component anatomy reference when motion affects custom primitives such as buttons, tabs, tooltips, toasts, toggles, drawers, or submit actions.
Consult the responsive design reference when motion needs to adapt across compact viewports, coarse-pointer contexts, or reduced viewport space.
Consult the framework official docs reference before making framework-specific animation decisions.
Consult the React shadcn accelerators reference when the request overlaps with React toasts, drawers, text motion, or other UI patterns that already have strong accelerators.
Consult the Tailwind and WAAPI motion reference to decide when Tailwind utilities, Tailwind-compatible keyframes, or WAAPI can solve the motion cleanly without reaching for a framework animation library.
Consult the linear easing patterns reference when defining CSS linear() easing tokens, Tailwind motion tokens, React component motion examples, or View Transition easing.
Consult the motion choreography reference when orchestrating multi-element motion, staggered reveals, list insert/remove/reorder, modal stacks, drawer sequences, route choreography, or dense interaction flows.
Consult the scroll-driven animations reference when motion should progress with scroll position rather than time.
Consult the view transitions reference when animating between page states or DOM changes with shared-element continuity.
Consult attribution and sources for the source lineage behind this skill's Emil-inspired motion guidance.
Consult entrance animations, exit animations, gesture interactions, and micro-interactions for consolidated thematic guidance by motion type.
Consult ease-out defaults, easing by context, and custom easing curves when choosing motion curves.
Consult UI under 300ms, asymmetric press and release timing, 500ms drawer timing, faster perceived performance, and tooltip timing escalation when the main question is duration rather than easing.
Consult on-screen movement easing, sheet and drawer easing, and spring motion when the motion pattern needs more specific guidance.
Consult damped drag boundaries, upward drag friction, interruptible animations, momentum dismissal, pointer capture, scroll and drag conflicts, and velocity-aware snap points when implementing gesture-heavy surfaces.
Consult blur-bridged transitions, clip-path tabs, respect reduced motion, opacity fallback, reduced motion alternatives, Motion's useReducedMotion, hover gap fill, scroll reveal thresholds, child orchestration, and toast stack depth for polish and accessibility refinement.
Consult transform and opacity only, avoid inherited token mutation in drag loops, clip-path reveals, hardware-accelerated motion under load, and surgical will-change for performance-sensitive property choices.
Consult immediate action feedback, interaction frequency, no keyboard animation, marketing exceptions, and animation purpose for strategy-heavy motion decisions.
Consult preserve-3d effects, never scale from zero, origin-aware animations, and percentage translateY when the question is really about transform technique and spatial feel.
Consult button press scale 0.97, scale affecting children, and SVG path morph disclosure icons for finer transform polish details.
If the interface already feels laggy under frequent use, also load optimize.
If the interface needs stronger resilience around reduced motion, errors, overflow, edge cases, or mixed input modes, also load harden.
Attribution and Inspiration
This skill's motion guidance is informed in part by Emil Kowalski's animations.dev course, especially the emphasis on easing choice, timing, tasteful restraint, springs, and motion that "feels right" in production UI.
It is also informed by Emil's animation-heavy open-source work on Sonner and Vaul, which are already relevant elsewhere in this library for React toast and drawer guidance.
This repository rewrites those lessons into original, repository-specific guidance rather than reproducing the course materials directly.
Motion Operating Model
Use this decision order before adding any animation:
- Fix structure first — motion should reinforce hierarchy and state, not rescue a confusing layout.
- Animate only with a job to do — every animation should improve feedback, orientation, relationship, or delight.
- Bias toward speed — product UI should feel responsive first and impressive second.
- Keep motion interruptible — new user intent beats finishing the old animation.
- Match the input method — precise pointer, coarse pointer, and keyboard interactions do not all deserve the same motion treatment.
- Plan reduced motion up front — accessibility is part of the system, not a cleanup pass.
- Prefer the lightest implementation that fits — Tailwind utilities and Tailwind-compatible keyframes first, WAAPI when imperative timing matters, Motion when the interaction genuinely needs it.
Use motion for one or more of these jobs:
- Feedback — acknowledge that an action happened
- Orientation — help users understand where something came from or where it went
- Relationship — show how surfaces, layers, and controls relate spatially
- Delight — add warmth or personality after the fundamentals already work
- Hierarchy: clarify what changed most and why
- Focus guidance: move attention to the right target without stealing control
If the animation cannot justify itself with one of those jobs, cut it.
Assess Motion Opportunities
Analyze where motion would improve the experience:
-
Identify static areas:
- Missing feedback: Actions without visual acknowledgment (button clicks, form submission, etc.)
- Jarring transitions: Instant state changes that feel abrupt (show/hide, page loads, route changes)
- Unclear relationships: Spatial or hierarchical relationships that aren't obvious
- Lack of delight: Functional but joyless interactions
- Missed guidance: Opportunities to direct attention or explain behavior
-
Understand the context:
- What's the personality? (Playful vs serious, energetic vs calm)
- What's the performance budget? (Compact-layout-first? Complex page?)
- Who's the audience? (Motion-sensitive users? Power users who want speed?)
- What matters most? (One hero animation vs many micro-interactions?)
- Which inputs matter? (precise pointer, coarse pointer, keyboard, stylus)
- Which interactions are high-frequency and should stay especially snappy?
If any of these are unclear from the codebase, ask the user directly to clarify what you cannot infer.
CRITICAL: Respect prefers-reduced-motion. Always provide non-animated alternatives for users who need them.
Motion should reinforce hierarchy, not compensate for weak hierarchy. If the layout only becomes understandable once it moves, fix the layout first.
Plan Animation Strategy
Create a purposeful animation plan:
- Hero moment: What's the ONE signature animation? (Page load? Hero section? Key interaction?)
- Feedback layer: Which interactions need acknowledgment?
- Transition layer: Which state changes need smoothing?
- Gesture layer: Which drag, swipe, snap, or dismiss interactions need physical logic?
- Delight layer: Where can we surprise and delight?
- Depth logic: Which elements should feel raised, pressed, dragged, inset, or layered?
- Reduced-motion plan: What simplifies to fade, blur, or instant state change?
- Performance budget: Which motions must stay lightweight because they happen often?
IMPORTANT: One well-orchestrated experience beats scattered animations everywhere. Focus on high-impact moments.
Default Motion Rules
Use these as the default guidelines for animation work unless the product context gives a strong reason to deviate.
1. Strategy and Purpose
- Every animation must earn its place through feedback, orientation, relationship, or delight.
- Product interfaces should usually feel fast, calm, and precise. Save slower or more dramatic motion for onboarding, hero moments, storytelling, or marketing surfaces.
- Favor one signature moment plus disciplined micro-interactions over adding motion everywhere.
- Do not animate keyboard-initiated actions just because pointer interactions animate. Keyboard users usually want predictable state change with minimal delay.
- The more often an interaction happens, the less motion it usually needs. High-frequency controls should feel nearly instant.
- Acknowledge user input immediately. Aim for visible feedback within roughly 80ms for micro-interactions whenever possible.
- If real work may exceed roughly 400ms, respond immediately with optimistic UI, skeletons, progress, or clear loading feedback instead of leaving a dead pause.
- Never use motion to disguise slow loading, weak hierarchy, or missing state design.
2. Easing Defaults
- Use ease-out as the default for entrances, reveals, and most feedback transitions.
- Use custom cubic-bezier curves through Tailwind arbitrary easing values or theme tokens instead of the generic
ease default.
- Use ease-in-out for reversible, on-screen state changes that travel there and back.
- Use spring motion when the movement should feel physically connected to gesture input or object behavior.
- For drawers, sheets, and similar surfaces, a good starting point is the sheet-style curve
cubic-bezier(0.32, 0.72, 0, 1).
- Prefer exponential-style deceleration such as
ease-out-quart, ease-out-quint, or ease-out-expo for refined UI motion.
- Avoid bounce and elastic curves unless the product intentionally embraces a toy-like or playful physical metaphor. They usually feel dated, noisy, or self-conscious.
- Match easing to context:
- entering surfaces → ease-out
- exiting surfaces → shorter duration, often ease-in or a snappier exit curve
- state toggles / reversible movement → ease-in-out
- gesture-linked movement → spring or velocity-aware interpolation
- constant autonomous motion → linear, unless the loop needs a deliberate mechanical feel
3. Timing and Duration
- Keep most recurring UI motion under 300ms.
- Use 100-150ms for micro-interactions such as press states, toggles, color changes, and immediate acknowledgment.
- Use 150-250ms for standard UI such as tooltips, dropdowns, menus, hover states, and small reveals.
- Use 200-300ms for modals, drawers, and medium surface transitions when they do not need sheet-like weight.
- Use 300-500ms for larger layout transitions such as accordions, sheets, drawers, and major surface changes.
- Treat 500ms as a special-case upper bound for bigger surface motion like sheets or staged entrances, not as the default for ordinary controls.
- Exit animations should be faster than entrances. A good default is roughly 75% of enter duration.
- Press should be faster than release. Downward feedback should feel immediate; reset can be slightly softer.
- Delay the first tooltip or hover-revealed helper when needed, but make subsequent related reveals much faster or instant so the interface does not feel sticky.
- For small grouped entrances, start with 30-80ms stagger steps. Long stagger chains are a smell. Cap total stagger time so the last item does not arrive embarrassingly late.
- Match duration to travel distance and visual mass. Larger elements and longer travel usually need slightly more time than small local changes.
4. Property Selection and Performance
- Prefer animating transform and opacity.
- Avoid
transition-all in production UI. Specify the properties that should move, such as transition-[transform,opacity], transition-transform, transition-opacity, or transition-colors.
- Avoid animating width, height, top, left, padding, margin, border-width, or other layout-heavy properties unless there is a strong reason and the surface is small.
- For accordion-like height transitions, prefer grid-template-rows or equivalent layout-friendly patterns over raw
height animation when possible.
- Use clip-path, masks, or composited reveals when you need a layout-free reveal effect.
- Use hardware-friendly full transforms such as
translateX(...), translateY(...), or translate3d(...) when the main thread is busy or the component animates frequently. Avoid framework props that mutate layout-position values under load when a real transform would do the job.
- Use
will-change sparingly and only when animation is imminent or proven to need it.
- During drag loops, avoid animation setups that route every frame through expensive inherited-token or layout recalculation paths if they introduce lag.
- Prefer Intersection Observer for scroll-triggered motion and stop observing once the motion has completed if it only needs to happen once.
5. Transform and Scale Techniques
- For button or chip press feedback,
scale(0.97) is a strong default starting point.
- Never animate entry from
scale(0). Start closer to scale(0.95) or higher so the element keeps believable mass.
- Use percentage-based translate values when movement should scale with the element or viewport size.
- Make motion origin-aware:
- menus and tooltips should emerge from the trigger edge
- drawers and sheets should move from their anchored side
- lifted cards should feel like they rise from their current plane
- Remember that scaling affects children. Text and icons can feel blurry or distorted if the scale range is too aggressive.
- Use 3D transforms only when they improve spatial understanding or delight meaningfully. Do not reach for
preserve-3d just because it looks flashy in isolation.
6. Gesture and Interaction Patterns
- Make interactive animations interruptible. Users should not have to wait for motion to finish before expressing new intent.
- Prefer CSS transitions over keyframes for rapidly triggered hover, press, menu, and popover state because transitions can reverse cleanly when user intent changes.
- For native dialogs and popovers, consider
@starting-style plus transition-behavior: allow-discrete for display/top-layer entry and exit, but keep it progressive and never replace focus or lifecycle correctness with animation tricks.
- For swipe-to-dismiss, sheet snapping, and similar gestures, use distance plus velocity, not distance alone.
- Add friction or damping near boundaries so drags resist instead of hard-stopping.
- Handle scroll-vs-drag conflicts intentionally. Nested surfaces should not feel like they are fighting over input.
- Use robust pointer handling such as pointer capture or equivalent gesture ownership when implementing drag interactions.
- Visually lift dragged items with depth cues such as shadow, slight scale, or elevated layering.
- When a surface can be dragged past its resting point, allow controlled resistance instead of making the gesture feel abruptly blocked.
- Snap points should feel velocity-aware and purposefully chosen, not like arbitrary invisible walls.
7. Accessibility and Polish
- Always respect
prefers-reduced-motion.
- Reduced motion should usually mean simplified motion, not zero feedback. Replace large spatial movement with opacity, blur, highlight, or shorter transitions where possible.
- Preserve functional cues such as focus states, progress, loading feedback, and success or error acknowledgment.
- Use blur carefully to bridge between visual states when a straight cut feels harsh.
- Use stagger intentionally for orchestration, not as decoration. Small lists can benefit; huge lists usually cannot.
- Gate hover-only motion behind hover and pointer capability. In Tailwind, prefer
motion-safe: plus custom @media (hover: hover) and (pointer: fine) variants or CSS when hover motion would misfire on touch.
- Scroll reveals should trigger before the user has fully passed the element, but not so early that the effect feels detached from scroll context.
- Fill hover gaps between triggers and floating surfaces so tooltips, menus, and popovers do not flicker closed during pointer travel.
- Toast stacks can use offset, scale, and opacity to imply depth without becoming chaotic.
- Respect motion sensitivity in compact and coarse-pointer contexts as much as in wide layouts. Gesture-led movement can be especially uncomfortable if overdone.
Implement Animations
Add motion systematically across these categories:
Entrance Animations
- Page load choreography: Stagger only where it improves comprehension; keep total orchestration tight
- Hero section: Give the primary story moment a distinct entrance if the product tone supports it
- Content reveals: Scroll-triggered animations using intersection observer
- Modal/drawer entry: Smooth slide + fade, backdrop fade, focus management
Micro-interactions
- Button feedback:
- Hover: Subtle scale, color shift, or shadow change only if it improves affordance
- Click / press: Quick scale down then up, pressed-in feel, or depth shift
- Loading: Spinner or pulse state
- Form interactions:
- Input focus: Border, background, or elevation transition that clarifies focus without being distracting
- Validation: Prefer clear color, icon, or text-state change before ornamental motion
- Toggle switches: Smooth slide + color transition
- Checkboxes/radio: Clear state change with tight timing
- Like/favorite: Small scale or icon motion only if it fits the product tone
State Transitions
- Show/hide: Fade + slide (not instant), appropriate timing (200-300ms)
- Expand/collapse: Layout-friendly open/close transitions with overflow handling, icon rotation if helpful
- Loading states: Skeleton screen fades, spinner animations, progress bars
- Success/error: Color transitions, icon animations, gentle scale pulse
- Enable/disable: Opacity transitions, cursor changes
Navigation & Flow
- Page transitions: Crossfade between routes, shared element transitions when they truly clarify continuity
- Tab switching: Slide indicator, content fade, clip-path, or other fast directional cues
- Carousel/slider: Smooth transforms, snap points, momentum, and interruptible input
- Scroll effects: Parallax layers, sticky headers with state changes, scroll progress indicators
Feedback & Guidance
- Hover hints: Tooltip fade-ins, cursor changes, element highlights
- Drag & drop: Lift effect (shadow + scale), drop zone highlights, smooth repositioning — dragging should feel like the item pops forward on the z-axis
- Copy/paste: Brief highlight flash on paste, "copied" confirmation
- Focus flow: Highlight path through form or workflow
Depth & Elevation Motion
- Raised elements should feel like they move toward the user
- Pressed elements should feel like they move inward or downward
- Use shadow and movement together to communicate state, not just style
- Match motion emphasis to the same hierarchy logic used for color and typography
Delight Moments
- Empty states: Subtle floating animations on illustrations
- Completed actions: Confetti, check mark flourish, success celebrations
- Easter eggs: Hidden interactions for discovery
- Contextual animation: Weather effects, time-of-day themes, seasonal touches
Technical Implementation
Use appropriate techniques for each animation:
Mechanism Selection
Choose the lightest mechanism that satisfies the interaction:
- Tailwind transition utilities for reversible single-element state changes such as hover, selected, pressed, open, or closed
- Tailwind-compatible keyframes for repeated or multi-stage timelines such as loaders, attention pulses, staged reveals, or choreography
- WAAPI for imperative sequencing, playback control, cancel/reverse behavior, or animation sync with logic
- View Transitions API for continuity across DOM swaps, route transitions, list/detail transitions, or layout-mode changes
Do not escalate to a framework animation library unless utility classes, Tailwind keyframes, WAAPI, or View Transitions cannot honestly handle the job.
Timing & Easing
Durations by purpose:
- 100-150ms: Instant feedback (button press, toggle)
- 200-300ms: State changes (hover, menu open)
- 300-500ms: Layout changes (accordion, modal, drawer)
- 500ms max by default: Large surface transitions that truly need it
Easing curves (use these through Tailwind arbitrary values or theme tokens):
--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
--ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
--ease-in-out-standard: cubic-bezier(0.65, 0, 0.35, 1);
--ease-sheet-standard: cubic-bezier(0.32, 0.72, 0, 1);
Exit animations are faster than entrances. Use ~75% of enter duration.
Tailwind-Compatible Animations
- transitions for state changes
- @keyframes for complex sequences
- transform + opacity first (GPU-friendly)
- Tailwind utilities when the project already uses Tailwind
Tailwind examples:
<button className="transition-transform duration-150 ease-[cubic-bezier(0.16,1,0.3,1)] active:scale-[0.97] motion-reduce:transition-none motion-reduce:transform-none">
Save
</button>
<div className="transition-[transform,opacity] duration-200 ease-[cubic-bezier(0.16,1,0.3,1)] data-[state=open]:scale-100 data-[state=open]:opacity-100 data-[state=closed]:scale-95 data-[state=closed]:opacity-0 origin-[var(--radix-popover-content-transform-origin)]">
...
</div>
Use individual Tailwind transform utilities when separate states own separate transform channels:
<div className="translate-y-2 scale-95 opacity-0 transition-[translate,scale,opacity] duration-200 ease-[cubic-bezier(0.16,1,0.3,1)] data-[state=open]:translate-y-0 data-[state=open]:scale-100 data-[state=open]:opacity-100 motion-reduce:translate-y-0 motion-reduce:scale-100">
...
</div>
Use arbitrary transform shorthand only when order is intentionally coupled. Do not use translate3d() as a blanket performance hack; profile first or reserve it for real 3D/perspective work.
Tailwind-compatible linear() easing tokens are useful for piecewise velocity control, soft enters, crisp exits, and controlled settle. Prefer named theme tokens over one-off arbitrary values:
@theme {
--ease-enter-soft: linear(0, 0.08 12%, 0.34 36%, 0.74 66%, 0.93 84%, 1);
--ease-exit-crisp: linear(0, 0.3 18%, 0.72 58%, 0.9 78%, 1);
--ease-settle-gentle: linear(0, 0.06 10%, 0.31 32%, 0.72 62%, 0.92 82%, 1);
--ease-emphasis-pop: linear(0, 0.38 20%, 0.88 62%, 1);
}
JavaScript Animation
- Web Animations API for programmatic control
- Framer Motion / Motion for React
- GSAP for complex sequences
Default rule: if a hover, press, reveal, or reduced-motion fallback can be expressed cleanly with Tailwind utilities or Tailwind-compatible keyframes, prefer that path before escalating to Motion.
Performance
- GPU acceleration: Use
transform and opacity, avoid layout properties
- will-change: Add sparingly for known expensive animations
- Reduce paint: Minimize repaints, use
contain where appropriate
- Monitor FPS: Ensure 60fps on target devices
- Interaction-first: Frequent product interactions should feel responsive even on weaker devices
Accessibility
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
Prefer replacing large movement with short fades, highlights, blur transitions, or instant state changes instead of deleting every form of feedback.
Useful Default Values
Use these as starting points, then tune for context:
| Value | Good default use |
|---|
scale(0.97) | Button and chip press feedback |
scale(0.95) | Minimum believable enter scale |
200ms | Standard UI transition |
300ms | Soft cap for common UI motion |
500ms | Large sheet / drawer transition upper bound |
cubic-bezier(0.32, 0.72, 0, 1) | Drawer / bottom-sheet easing |
10-16px | Toast-stack offset starting range |
~100px from viewport edge | Scroll-reveal trigger starting point |
NEVER:
- Use bounce or elastic easing curves by default—they draw attention to the animation itself
- Animate layout properties such as width, height, top, or left when transform or opacity would do the job
- Use long durations for routine feedback—it feels laggy fast
- Animate without purpose—every animation needs a reason
- Ignore
prefers-reduced-motion—this is an accessibility violation
- Animate everything—animation fatigue makes interfaces feel exhausting
- Force users to wait for motion to finish before they can continue
- Use motion to paper over weak structure, unclear hierarchy, or slow data fetching
- Ship gesture logic that ignores momentum, damping, or scroll conflicts
Verify Quality
Test animations thoroughly:
- Smooth at 60fps: No jank on target devices
- Feels natural: Easing curves feel organic, not robotic
- Appropriate timing: Not too fast (jarring) or too slow (laggy)
- Immediate acknowledgment: Inputs get visible response quickly
- Interruptible where needed: New intent can override old motion
- Gesture quality: Drag, swipe, snap, and dismiss interactions feel physically coherent
- Reduced motion works: Animations disabled or simplified appropriately
- Doesn't block: Users can interact during/after animations
- Adds value: Makes interface clearer or more delightful
During review, flag these problems immediately:
transition-all where exact properties are known
- entry animation from
scale(0) instead of roughly scale(0.95) plus opacity
- routine UI motion over
300ms
- hover animation without hover-capability gating
- keyboard-triggered action using pointer-style animation
- popover, tooltip, or menu scaling from the wrong origin
- keyframes on rapidly triggered controls where reversible transitions would behave better
- parent hover animation that flickers or distorts children when a child-layer animation would be cleaner
- Motion
x or y style updates used under load where a composited transform string would be safer
- identical enter and exit timing when exit should feel faster
- list children appearing all at once when a small, capped stagger would clarify order
- immediate React unmounts that prevent item, dialog, toast, or popover exit animation
transition: all on dialogs, popovers, or removable list items
Remember: the best UI animation usually feels inevitable, not attention-seeking. Animate with purpose, tune for responsiveness, respect accessibility, and let motion support the product instead of starring in it.
Output Contract
When the user asks for a motion plan, motion system, or significant animation implementation, respond with:
- Intent: user perception or behavior the motion should drive
- Motion Spec: duration, easing token, distance, trigger, and affected elements
- Implementation: concrete Tailwind, Tailwind keyframe, WAAPI, or View Transition code
- Accessibility Fallback: reduced-motion and unsupported-API behavior
- QA Checklist: performance, usability, focus, keyboard, and cross-device checks
When the work is choreography-heavy, use the stricter storyboard format from motion choreography: storyboard, timeline spec, implementation plan, a11y/fallback, and validation plan.