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 small screens, touch 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 CSS, Tailwind, and WAAPI motion reference to decide when modern CSS, Tailwind, or WAAPI can solve the motion cleanly without reaching for a framework animation library.
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 CSS variables 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 — mouse, touch, 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 — modern CSS and Tailwind 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
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? (mouse, touch, 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 instead of the generic CSS
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
3. Timing and Duration
- Keep most recurring UI motion under 300ms.
- Use 100-150ms for press states, toggles, color changes, and immediate acknowledgment.
- Use 200-300ms for standard UI state changes such as hover, menus, tooltips, and small reveals.
- Use 300-500ms for larger layout transitions such as drawers, modals, accordions, 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.
- Long stagger chains are a smell. Cap total stagger time so the last item does not arrive embarrassingly late.
4. Property Selection and Performance
- Prefer animating transform and opacity.
- 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 transforms when the main thread is busy or the component animates frequently.
- 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 CSS-variable 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.
- 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.
- 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 touch-capable 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:
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, not CSS defaults):
/* Recommended - natural deceleration */
--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1); /* Smooth, refined */
--ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1); /* Slightly snappier */
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); /* Confident, decisive */
--ease-in-out-standard: cubic-bezier(0.65, 0, 0.35, 1); /* Reversible movement */
--ease-sheet-standard: cubic-bezier(0.32, 0.72, 0, 1); /* Sheets / drawers */
/* AVOID - feel dated and tacky */
/* bounce: cubic-bezier(0.34, 1.56, 0.64, 1); */
/* elastic: cubic-bezier(0.68, -0.6, 0.32, 1.6); */
Exit animations are faster than entrances. Use ~75% of enter duration.
CSS Animations
/* Prefer for simple, declarative animations */
- transitions for state changes
- @keyframes for complex sequences
- transform + opacity first (GPU-friendly)
- Tailwind utilities when the project already uses Tailwind
JavaScript Animation
/* Use for complex, interactive animations */
- 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 modern CSS or Tailwind utilities, 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
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.
1---
2name: animate
3description: 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.
4metadata:
5 argument-hint: "[target]"
6---
7
8Analyze a feature and add motion that improves clarity, feedback, perceived performance, and polish without making the interface feel slow, noisy, or theatrical.
9
10## MANDATORY PREPARATION
11
12Users 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.
13
14Consult the [motion reference](../frontend-design/reference/motion-design.md) for timing, easing, choreography, and reduced-motion handling.
15Consult the [animate reference index](reference/README.md) when you need to browse the deeper motion library by use case instead of guessing filenames.
16Consult the [elevation system](../frontend-design/reference/elevation-system.md) when motion should reinforce raised, pressed, inset, dragged, or layered depth.
17Consult the [interaction reference](../frontend-design/reference/interaction-design.md) when animation decisions overlap with focus, loading, transitions, or feedback states.
18Consult the [component anatomy reference](../frontend-design/reference/component-anatomy.md) when motion affects custom primitives such as buttons, tabs, tooltips, toasts, toggles, drawers, or submit actions.
19Consult the [responsive design reference](../frontend-design/reference/responsive-design.md) when motion needs to adapt across small screens, touch contexts, or reduced viewport space.
20Consult the [framework official docs reference](../frontend-design/reference/framework-official-docs.md) before making framework-specific animation decisions.
21Consult the [React shadcn accelerators reference](../frontend-design/reference/react-shadcn-accelerators.md) when the request overlaps with React toasts, drawers, text motion, or other UI patterns that already have strong accelerators.
22Consult the [CSS, Tailwind, and WAAPI motion reference](../frontend-design/reference/css-tailwind-and-waapi-motion.md) to decide when modern CSS, Tailwind, or WAAPI can solve the motion cleanly without reaching for a framework animation library.
23Consult the [scroll-driven animations reference](../frontend-design/reference/scroll-driven-animations.md) when motion should progress with scroll position rather than time.
24Consult the [view transitions reference](../frontend-design/reference/view-transitions.md) when animating between page states or DOM changes with shared-element continuity.
25Consult [attribution and sources](reference/attribution-and-sources.md) for the source lineage behind this skill's Emil-inspired motion guidance.
26Consult [entrance animations](reference/entrance-animations.md), [exit animations](reference/exit-animations.md), [gesture interactions](reference/gesture-interactions.md), and [micro-interactions](reference/micro-interactions.md) for consolidated thematic guidance by motion type.
27Consult [ease-out defaults](reference/ease-out-default.md), [easing by context](reference/easing-context.md), and [custom easing curves](reference/custom-easing-curves.md) when choosing motion curves.
28Consult [UI under 300ms](reference/ui-under-300ms.md), [asymmetric press and release timing](reference/asymmetric-press-release.md), [500ms drawer timing](reference/drawer-500ms-duration.md), [faster perceived performance](reference/faster-improves-performance.md), and [tooltip timing escalation](reference/tooltip-delay-instant-followups.md) when the main question is duration rather than easing.
29Consult [on-screen movement easing](reference/ease-in-out-on-screen-movement.md), [sheet and drawer easing](reference/sheet-drawer-easing.md), and [spring motion](reference/spring-motion.md) when the motion pattern needs more specific guidance.
30Consult [damped drag boundaries](reference/damp-drag-boundaries.md), [upward drag friction](reference/upward-drag-friction.md), [interruptible animations](reference/interruptible-animations.md), [momentum dismissal](reference/momentum-dismissal.md), [pointer capture](reference/pointer-capture.md), [scroll and drag conflicts](reference/scroll-drag-conflicts.md), and [velocity-aware snap points](reference/velocity-aware-snap-points.md) when implementing gesture-heavy surfaces.
31Consult [blur-bridged transitions](reference/blur-bridge-states.md), [clip-path tabs](reference/clip-path-tab-transitions.md), [respect reduced motion](reference/respect-reduced-motion.md), [opacity fallback](reference/opacity-reduced-motion-fallback.md), [reduced motion alternatives](reference/reduced-motion-not-zero.md), [Motion's `useReducedMotion`](reference/use-reduced-motion-hook.md), [hover gap fill](reference/hover-gap-fill.md), [scroll reveal thresholds](reference/scroll-animation-threshold.md), [child orchestration](reference/stagger-children-orchestration.md), and [toast stack depth](reference/toast-stack-depth.md) for polish and accessibility refinement.
32Consult [transform and opacity only](reference/transform-opacity-only.md), [avoid CSS variables in drag loops](reference/avoid-css-variables-drag.md), [clip-path reveals](reference/clip-path-layout-free-reveals.md), [hardware-accelerated motion under load](reference/hardware-accelerated-busy-main-thread.md), and [surgical `will-change`](reference/will-change-subpixel-shift.md) for performance-sensitive property choices.
33Consult [immediate action feedback](reference/immediate-feedback-actions.md), [interaction frequency](reference/interaction-frequency.md), [no keyboard animation](reference/no-animation-for-keyboard.md), [marketing exceptions](reference/marketing-exception.md), and [animation purpose](reference/animation-purpose.md) for strategy-heavy motion decisions.
34Consult [preserve-3d effects](reference/preserve-3d-effects.md), [never scale from zero](reference/never-scale-zero.md), [origin-aware animations](reference/origin-aware-animations.md), and [percentage translateY](reference/percentage-translate-y.md) when the question is really about transform technique and spatial feel.
35Consult [button press scale 0.97](reference/button-press-scale-097.md), [scale affecting children](reference/scale-affects-children.md), and [SVG path morph disclosure icons](reference/svg-path-morph-disclosure.md) for finer transform polish details.
36
37If the interface already feels laggy under frequent use, also load `optimize`.
38If the interface needs stronger resilience around reduced motion, errors, overflow, edge cases, or mixed input modes, also load `harden`.
39
40---
41
42## Attribution and Inspiration
43
44This skill's motion guidance is informed in part by [Emil Kowalski's animations.dev course](https://animations.dev/), especially the emphasis on easing choice, timing, tasteful restraint, springs, and motion that "feels right" in production UI.
45
46It is also informed by Emil's animation-heavy open-source work on [Sonner](https://github.com/emilkowalski/sonner) and [Vaul](https://github.com/emilkowalski/vaul), which are already relevant elsewhere in this library for React toast and drawer guidance.
47
48This repository rewrites those lessons into original, repository-specific guidance rather than reproducing the course materials directly.
49
50---
51
52## Motion Operating Model
53
54Use this decision order before adding any animation:
55
561. **Fix structure first** — motion should reinforce hierarchy and state, not rescue a confusing layout.
572. **Animate only with a job to do** — every animation should improve feedback, orientation, relationship, or delight.
583. **Bias toward speed** — product UI should feel responsive first and impressive second.
594. **Keep motion interruptible** — new user intent beats finishing the old animation.
605. **Match the input method** — mouse, touch, and keyboard interactions do not all deserve the same motion treatment.
616. **Plan reduced motion up front** — accessibility is part of the system, not a cleanup pass.
627. **Prefer the lightest implementation that fits** — modern CSS and Tailwind first, WAAPI when imperative timing matters, Motion when the interaction genuinely needs it.
63
64Use motion for one or more of these jobs:
65
66- **Feedback** — acknowledge that an action happened
67- **Orientation** — help users understand where something came from or where it went
68- **Relationship** — show how surfaces, layers, and controls relate spatially
69- **Delight** — add warmth or personality after the fundamentals already work
70
71If the animation cannot justify itself with one of those jobs, cut it.
72
73## Assess Motion Opportunities
74
75Analyze where motion would improve the experience:
76
771. **Identify static areas**:
78 - **Missing feedback**: Actions without visual acknowledgment (button clicks, form submission, etc.)
79 - **Jarring transitions**: Instant state changes that feel abrupt (show/hide, page loads, route changes)
80 - **Unclear relationships**: Spatial or hierarchical relationships that aren't obvious
81 - **Lack of delight**: Functional but joyless interactions
82 - **Missed guidance**: Opportunities to direct attention or explain behavior
83
842. **Understand the context**:
85 - What's the personality? (Playful vs serious, energetic vs calm)
86 - What's the performance budget? (Compact-layout-first? Complex page?)
87 - Who's the audience? (Motion-sensitive users? Power users who want speed?)
88 - What matters most? (One hero animation vs many micro-interactions?)
89 - Which inputs matter? (mouse, touch, keyboard, stylus)
90 - Which interactions are high-frequency and should stay especially snappy?
91
92If any of these are unclear from the codebase, ask the user directly to clarify what you cannot infer.
93
94**CRITICAL**: Respect `prefers-reduced-motion`. Always provide non-animated alternatives for users who need them.
95
96Motion should reinforce hierarchy, not compensate for weak hierarchy. If the layout only becomes understandable once it moves, fix the layout first.
97
98## Plan Animation Strategy
99
100Create a purposeful animation plan:
101
102- **Hero moment**: What's the ONE signature animation? (Page load? Hero section? Key interaction?)
103- **Feedback layer**: Which interactions need acknowledgment?
104- **Transition layer**: Which state changes need smoothing?
105- **Gesture layer**: Which drag, swipe, snap, or dismiss interactions need physical logic?
106- **Delight layer**: Where can we surprise and delight?
107- **Depth logic**: Which elements should feel raised, pressed, dragged, inset, or layered?
108- **Reduced-motion plan**: What simplifies to fade, blur, or instant state change?
109- **Performance budget**: Which motions must stay lightweight because they happen often?
110
111**IMPORTANT**: One well-orchestrated experience beats scattered animations everywhere. Focus on high-impact moments.
112
113## Default Motion Rules
114
115Use these as the default guidelines for animation work unless the product context gives a strong reason to deviate.
116
117### 1. Strategy and Purpose
118
119- Every animation must earn its place through **feedback, orientation, relationship, or delight**.
120- Product interfaces should usually feel **fast, calm, and precise**. Save slower or more dramatic motion for onboarding, hero moments, storytelling, or marketing surfaces.
121- Favor **one signature moment plus disciplined micro-interactions** over adding motion everywhere.
122- Do **not** animate keyboard-initiated actions just because pointer interactions animate. Keyboard users usually want predictable state change with minimal delay.
123- The more often an interaction happens, the less motion it usually needs. High-frequency controls should feel nearly instant.
124- Acknowledge user input immediately. Aim for visible feedback within roughly **80ms** for micro-interactions whenever possible.
125- If real work may exceed roughly **400ms**, respond immediately with optimistic UI, skeletons, progress, or clear loading feedback instead of leaving a dead pause.
126- Never use motion to disguise slow loading, weak hierarchy, or missing state design.
127
128### 2. Easing Defaults
129
130- Use **ease-out** as the default for entrances, reveals, and most feedback transitions.
131- Use **custom cubic-bezier curves** instead of the generic CSS `ease` default.
132- Use **ease-in-out** for reversible, on-screen state changes that travel there and back.
133- Use **spring motion** when the movement should feel physically connected to gesture input or object behavior.
134- For drawers, sheets, and similar surfaces, a good starting point is the sheet-style curve `cubic-bezier(0.32, 0.72, 0, 1)`.
135- Prefer exponential-style deceleration such as `ease-out-quart`, `ease-out-quint`, or `ease-out-expo` for refined UI motion.
136- 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.
137- Match easing to context:
138 - **entering surfaces** → ease-out
139 - **exiting surfaces** → shorter duration, often ease-in or a snappier exit curve
140 - **state toggles / reversible movement** → ease-in-out
141 - **gesture-linked movement** → spring or velocity-aware interpolation
142
143### 3. Timing and Duration
144
145- Keep most recurring UI motion under **300ms**.
146- Use **100-150ms** for press states, toggles, color changes, and immediate acknowledgment.
147- Use **200-300ms** for standard UI state changes such as hover, menus, tooltips, and small reveals.
148- Use **300-500ms** for larger layout transitions such as drawers, modals, accordions, and major surface changes.
149- Treat **500ms** as a special-case upper bound for bigger surface motion like sheets or staged entrances, not as the default for ordinary controls.
150- Exit animations should be faster than entrances. A good default is roughly **75%** of enter duration.
151- Press should be faster than release. Downward feedback should feel immediate; reset can be slightly softer.
152- 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.
153- Long stagger chains are a smell. Cap total stagger time so the last item does not arrive embarrassingly late.
154
155### 4. Property Selection and Performance
156
157- Prefer animating **transform** and **opacity**.
158- 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.
159- For accordion-like height transitions, prefer **grid-template-rows** or equivalent layout-friendly patterns over raw `height` animation when possible.
160- Use **clip-path**, masks, or composited reveals when you need a layout-free reveal effect.
161- Use hardware-friendly transforms when the main thread is busy or the component animates frequently.
162- Use `will-change` sparingly and only when animation is imminent or proven to need it.
163- During drag loops, avoid animation setups that route every frame through expensive CSS-variable or layout recalculation paths if they introduce lag.
164- Prefer Intersection Observer for scroll-triggered motion and stop observing once the motion has completed if it only needs to happen once.
165
166### 5. Transform and Scale Techniques
167
168- For button or chip press feedback, `scale(0.97)` is a strong default starting point.
169- Never animate entry from `scale(0)`. Start closer to `scale(0.95)` or higher so the element keeps believable mass.
170- Use percentage-based translate values when movement should scale with the element or viewport size.
171- Make motion **origin-aware**:
172 - menus and tooltips should emerge from the trigger edge
173 - drawers and sheets should move from their anchored side
174 - lifted cards should feel like they rise from their current plane
175- Remember that scaling affects children. Text and icons can feel blurry or distorted if the scale range is too aggressive.
176- 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.
177
178### 6. Gesture and Interaction Patterns
179
180- Make interactive animations **interruptible**. Users should not have to wait for motion to finish before expressing new intent.
181- For swipe-to-dismiss, sheet snapping, and similar gestures, use **distance plus velocity**, not distance alone.
182- Add **friction or damping** near boundaries so drags resist instead of hard-stopping.
183- Handle **scroll-vs-drag conflicts** intentionally. Nested surfaces should not feel like they are fighting over input.
184- Use robust pointer handling such as pointer capture or equivalent gesture ownership when implementing drag interactions.
185- Visually lift dragged items with depth cues such as shadow, slight scale, or elevated layering.
186- When a surface can be dragged past its resting point, allow controlled resistance instead of making the gesture feel abruptly blocked.
187- Snap points should feel velocity-aware and purposefully chosen, not like arbitrary invisible walls.
188
189### 7. Accessibility and Polish
190
191- Always respect `prefers-reduced-motion`.
192- Reduced motion should usually mean **simplified motion**, not zero feedback. Replace large spatial movement with opacity, blur, highlight, or shorter transitions where possible.
193- Preserve functional cues such as focus states, progress, loading feedback, and success or error acknowledgment.
194- Use blur carefully to bridge between visual states when a straight cut feels harsh.
195- Use stagger intentionally for orchestration, not as decoration. Small lists can benefit; huge lists usually cannot.
196- Scroll reveals should trigger before the user has fully passed the element, but not so early that the effect feels detached from scroll context.
197- Fill hover gaps between triggers and floating surfaces so tooltips, menus, and popovers do not flicker closed during pointer travel.
198- Toast stacks can use offset, scale, and opacity to imply depth without becoming chaotic.
199- Respect motion sensitivity in compact and touch-capable contexts as much as in wide layouts. Gesture-led movement can be especially uncomfortable if overdone.
200
201## Implement Animations
202
203Add motion systematically across these categories:
204
205### Entrance Animations
206- **Page load choreography**: Stagger only where it improves comprehension; keep total orchestration tight
207- **Hero section**: Give the primary story moment a distinct entrance if the product tone supports it
208- **Content reveals**: Scroll-triggered animations using intersection observer
209- **Modal/drawer entry**: Smooth slide + fade, backdrop fade, focus management
210
211### Micro-interactions
212- **Button feedback**:
213 - Hover: Subtle scale, color shift, or shadow change only if it improves affordance
214 - Click / press: Quick scale down then up, pressed-in feel, or depth shift
215 - Loading: Spinner or pulse state
216- **Form interactions**:
217 - Input focus: Border, background, or elevation transition that clarifies focus without being distracting
218 - Validation: Prefer clear color, icon, or text-state change before ornamental motion
219- **Toggle switches**: Smooth slide + color transition
220- **Checkboxes/radio**: Clear state change with tight timing
221- **Like/favorite**: Small scale or icon motion only if it fits the product tone
222
223### State Transitions
224- **Show/hide**: Fade + slide (not instant), appropriate timing (200-300ms)
225- **Expand/collapse**: Layout-friendly open/close transitions with overflow handling, icon rotation if helpful
226- **Loading states**: Skeleton screen fades, spinner animations, progress bars
227- **Success/error**: Color transitions, icon animations, gentle scale pulse
228- **Enable/disable**: Opacity transitions, cursor changes
229
230### Navigation & Flow
231- **Page transitions**: Crossfade between routes, shared element transitions when they truly clarify continuity
232- **Tab switching**: Slide indicator, content fade, clip-path, or other fast directional cues
233- **Carousel/slider**: Smooth transforms, snap points, momentum, and interruptible input
234- **Scroll effects**: Parallax layers, sticky headers with state changes, scroll progress indicators
235
236### Feedback & Guidance
237- **Hover hints**: Tooltip fade-ins, cursor changes, element highlights
238- **Drag & drop**: Lift effect (shadow + scale), drop zone highlights, smooth repositioning — dragging should feel like the item pops forward on the z-axis
239- **Copy/paste**: Brief highlight flash on paste, "copied" confirmation
240- **Focus flow**: Highlight path through form or workflow
241
242### Depth & Elevation Motion
243- Raised elements should feel like they move toward the user
244- Pressed elements should feel like they move inward or downward
245- Use shadow and movement together to communicate state, not just style
246- Match motion emphasis to the same hierarchy logic used for color and typography
247
248### Delight Moments
249- **Empty states**: Subtle floating animations on illustrations
250- **Completed actions**: Confetti, check mark flourish, success celebrations
251- **Easter eggs**: Hidden interactions for discovery
252- **Contextual animation**: Weather effects, time-of-day themes, seasonal touches
253
254## Technical Implementation
255
256Use appropriate techniques for each animation:
257
258### Timing & Easing
259
260**Durations by purpose:**
261- **100-150ms**: Instant feedback (button press, toggle)
262- **200-300ms**: State changes (hover, menu open)
263- **300-500ms**: Layout changes (accordion, modal, drawer)
264- **500ms max by default**: Large surface transitions that truly need it
265
266**Easing curves (use these, not CSS defaults):**
267```css
268/* Recommended - natural deceleration */
269--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1); /* Smooth, refined */
270--ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1); /* Slightly snappier */
271--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); /* Confident, decisive */
272--ease-in-out-standard: cubic-bezier(0.65, 0, 0.35, 1); /* Reversible movement */
273--ease-sheet-standard: cubic-bezier(0.32, 0.72, 0, 1); /* Sheets / drawers */
274
275/* AVOID - feel dated and tacky */
276/* bounce: cubic-bezier(0.34, 1.56, 0.64, 1); */
277/* elastic: cubic-bezier(0.68, -0.6, 0.32, 1.6); */
278```
279
280**Exit animations are faster than entrances.** Use ~75% of enter duration.
281
282### CSS Animations
283```css
284/* Prefer for simple, declarative animations */
285- transitions for state changes
286- @keyframes for complex sequences
287- transform + opacity first (GPU-friendly)
288- Tailwind utilities when the project already uses Tailwind
289```
290
291### JavaScript Animation
292```javascript
293/* Use for complex, interactive animations */
294- Web Animations API for programmatic control
295- Framer Motion / Motion for React
296- GSAP for complex sequences
297```
298
299Default rule: if a hover, press, reveal, or reduced-motion fallback can be expressed cleanly with modern CSS or Tailwind utilities, prefer that path before escalating to Motion.
300
301### Performance
302- **GPU acceleration**: Use `transform` and `opacity`, avoid layout properties
303- **will-change**: Add sparingly for known expensive animations
304- **Reduce paint**: Minimize repaints, use `contain` where appropriate
305- **Monitor FPS**: Ensure 60fps on target devices
306- **Interaction-first**: Frequent product interactions should feel responsive even on weaker devices
307
308### Accessibility
309```css
310@media (prefers-reduced-motion: reduce) {
311 * {
312 animation-duration: 0.01ms !important;
313 animation-iteration-count: 1 !important;
314 transition-duration: 0.01ms !important;
315 }
316}
317```
318
319Prefer replacing large movement with short fades, highlights, blur transitions, or instant state changes instead of deleting every form of feedback.
320
321## Useful Default Values
322
323Use these as starting points, then tune for context:
324
325| Value | Good default use |
326| --- | --- |
327| `scale(0.97)` | Button and chip press feedback |
328| `scale(0.95)` | Minimum believable enter scale |
329| `200ms` | Standard UI transition |
330| `300ms` | Soft cap for common UI motion |
331| `500ms` | Large sheet / drawer transition upper bound |
332| `cubic-bezier(0.32, 0.72, 0, 1)` | Drawer / bottom-sheet easing |
333| `10-16px` | Toast-stack offset starting range |
334| `~100px` from viewport edge | Scroll-reveal trigger starting point |
335
336**NEVER**:
337- Use bounce or elastic easing curves by default—they draw attention to the animation itself
338- Animate layout properties such as width, height, top, or left when transform or opacity would do the job
339- Use long durations for routine feedback—it feels laggy fast
340- Animate without purpose—every animation needs a reason
341- Ignore `prefers-reduced-motion`—this is an accessibility violation
342- Animate everything—animation fatigue makes interfaces feel exhausting
343- Force users to wait for motion to finish before they can continue
344- Use motion to paper over weak structure, unclear hierarchy, or slow data fetching
345- Ship gesture logic that ignores momentum, damping, or scroll conflicts
346
347## Verify Quality
348
349Test animations thoroughly:
350
351- **Smooth at 60fps**: No jank on target devices
352- **Feels natural**: Easing curves feel organic, not robotic
353- **Appropriate timing**: Not too fast (jarring) or too slow (laggy)
354- **Immediate acknowledgment**: Inputs get visible response quickly
355- **Interruptible where needed**: New intent can override old motion
356- **Gesture quality**: Drag, swipe, snap, and dismiss interactions feel physically coherent
357- **Reduced motion works**: Animations disabled or simplified appropriately
358- **Doesn't block**: Users can interact during/after animations
359- **Adds value**: Makes interface clearer or more delightful
360
361Remember: 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.