Sowrasree Banerjee
Get in touch
← Back to portfolio
Claude Code Skill

web-animation-design

A comprehensive guide for creating web animations that feel natural and purposeful, based on Emil Kowalski's "Animations on the Web" course.

AnimationsFramer MotionReact SpringGSAPPerformance

Overview

This skill provides comprehensive guidance for designing and implementing web animations that feel right. It covers easing functions, spring physics, timing, duration, and accessibility considerations for motion.

Based on Emil Kowalski's animations.dev course, this skill helps you make informed decisions about when and how to animate, which easing curves to use, and how to ensure your animations are performant and accessible.

Quick Start: Four Questions

Is this element entering or exiting?

Use ease-out

Is an on-screen element moving?

Use ease-in-out

Is this a hover/color transition?

Use ease

Will users see this 100+ times daily?

Don't animate it

The Easing Blueprint

ease-out (Most Common)

Use for user-initiated interactions: dropdowns, modals, tooltips, any element entering or exiting the screen.

Why it works: Acceleration at the start creates an instant, responsive feeling. The element "jumps" toward its destination then settles in.

/* Sorted weak to strong */
--ease-out-quad:  cubic-bezier(0.25, 0.46, 0.45, 0.94);
--ease-out-cubic: cubic-bezier(0.215, 0.61, 0.355, 1);
--ease-out-quart: cubic-bezier(0.165, 0.84, 0.44, 1);
--ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);
--ease-out-expo:  cubic-bezier(0.19, 1, 0.22, 1);
--ease-out-circ:  cubic-bezier(0.075, 0.82, 0.165, 1);

ease-in-out (For Movement)

Use when elements already on screen need to move or morph. Mimics natural motion like a car accelerating then braking.

/* Sorted weak to strong */
--ease-in-out-quad:  cubic-bezier(0.455, 0.03, 0.515, 0.955);
--ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1);
--ease-in-out-quart: cubic-bezier(0.77, 0, 0.175, 1);
--ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1);
--ease-in-out-expo:  cubic-bezier(1, 0, 0, 1);
--ease-in-out-circ:  cubic-bezier(0.785, 0.135, 0.15, 0.86);

ease (For Hover Effects)

Use for hover states and color transitions. The asymmetrical curve (faster start, slower end) feels elegant for gentle animations.

transition: background-color 150ms ease;

Duration Guidelines

100-150ms
Micro-interactions
150-250ms
Standard UI (tooltips, dropdowns)
200-300ms
Modals, drawers

Rules:

  • • UI animations should stay under 300ms
  • • Larger elements animate slower than smaller ones
  • • Exit animations can be ~20% faster than entrance
  • • Match duration to distance - longer travel = longer duration

When to Animate

✓ Do Animate

  • • Enter/exit transitions for spatial consistency
  • • State changes benefiting from visual continuity
  • • Responses to user actions (feedback)
  • • Rarely-used interactions where delight adds value

✗ Don't Animate

  • • Keyboard-initiated actions
  • • Hover effects on frequently-used elements
  • • Anything users interact with 100+ times daily
  • • When speed matters more than smoothness

Spring Animations

Springs feel more natural because they don't have fixed durations—they simulate real physics.

When to Use Springs

  • • Drag interactions with momentum
  • • Elements that should feel "alive"
  • • Gestures that can be interrupted mid-animation
  • • Organic, playful interfaces

Bounce Guidelines

  • • Avoid bounce in most UI contexts
  • • Use bounce for drag-to-dismiss, playful interactions
  • • Keep bounce subtle (0.1-0.3) when used

Performance: The Golden Rule

Only animate transform and opacity

These properties skip layout and paint stages, running entirely on the GPU.

Avoid animating:

  • padding, margin, height, width (trigger layout)
  • blur filters above 20px (expensive, especially Safari)
  • • CSS variables in deep component trees

Accessibility: prefers-reduced-motion

Animations can cause motion sickness or distraction for some users. Whenever you add an animation, also add a media query to disable it:

.modal {
  animation: fadeIn 200ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .modal {
    animation: none;
  }
}

Guidelines:

  • • Every animated element needs its own prefers-reduced-motion media query
  • • Set animation: none or transition: none
  • • No exceptions for opacity or color - disable all animations
  • • Show play buttons instead of autoplay videos

Practical Tips

ScenarioSolution
Make buttons feel responsiveAdd transform: scale(0.97) on :active
Element appears from nowhereStart from scale(0.95), not scale(0)
Shaky/jittery animationsAdd will-change: transform
Hover causes flickerAnimate child element, not parent
Popover scales from wrong pointSet transform-origin to trigger location
Sequential tooltips feel slowSkip delay/animation after first tooltip