Home
cd ../playbooks
Developer ToolsIntermediate

Web Animation Design Principles

Design web animations that feel natural and purposeful — a decision-first easing blueprint (ease-out for entrances, ease-in-out for movement, ease for hover), duration and frequency rules, spring configuration, the GPU-only performance rule, and mandatory prefers-reduced-motion accessibility patterns with working CSS and Framer Motion code.

5 minutes
By Emil Kowalski (animations.dev)Source
#css-animation#framer-motion#web-performance#accessibility#frontend#ui-design

Most 'janky' web animations aren't a performance problem — they're using ease-in-out on a modal that should use ease-out, or animating height and padding instead of transform and opacity, and the fix is a handful of decision rules that take longer to explain than to apply.

Who it's for: frontend developers implementing UI animations who want a decision rule instead of trial and error, designers and engineers debating which easing curve to use for a given interaction, teams auditing an interface for animations that feel janky, sluggish, or overused, anyone who needs a concrete prefers-reduced-motion implementation instead of a vague accessibility reminder

Example

"This modal animation feels off" → A markdown table diagnosis (before/after CSS) identifying the wrong easing curve or duration against the decision rules — ease-in-out swapped for ease-out since the modal is entering the screen, duration trimmed to the 200-300ms modal range, and a prefers-reduced-motion media query added since the original had none

CLAUDE.md Template

New here? 3-minute setup guide → | Already set up? Copy the template below.

# Web Animation Design

Design and implement web animations that feel natural and purposeful, based on the practical principles behind well-regarded animation courses like Emil Kowalski's "Animations on the Web." Use it for easing, timing, duration, springs, transitions, and animation performance — how to animate a specific UI element, which easing to use, and accessibility considerations for motion.

## Quick Start

Every animation decision starts with these questions:

1. **Is this element entering or exiting?** → Use `ease-out`.
2. **Is an on-screen element moving?** → Use `ease-in-out`.
3. **Is this a hover/color transition?** → Use `ease`.
4. **Will users see this 100+ times a day?** → Don't animate it.

## The Easing Blueprint

### ease-out (Most Common)

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

```css
/* 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);
```

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

### 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.

```css
--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.

```css
transition: background-color 150ms ease;
```

### linear (Avoid in UI)

Only use for constant-speed animations (marquees, tickers) or time visualization (hold-to-delete progress indicators). Linear feels robotic and unnatural for interactive elements.

### ease-in (Almost Never)

Avoid for UI animations. Makes interfaces feel sluggish because the slow start delays visual feedback.

### Paired Elements Rule

Elements that animate together must use the same easing and duration. Modal + overlay, tooltip + arrow, drawer + backdrop — if they move as a unit, they should feel like a unit.

```css
.modal { transition: transform 200ms ease-out; }
.overlay { transition: opacity 200ms ease-out; }
```

## Timing and Duration

| Element Type | Duration |
|---|---|
| Micro-interactions | 100–150ms |
| Standard UI (tooltips, dropdowns) | 150–250ms |
| Modals, drawers | 200–300ms |

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 needs longer duration.

### The Frequency Rule

Determine how often users will see the animation: 100+ times a day → no animation (or drastically reduced); occasional use → standard animation; rare/first-time → can be more special. Raycast never animates its core interactions because users open it hundreds of times a day.

## When to Animate

**Do animate:** enter/exit transitions for spatial consistency, state changes that benefit 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 interacted with 100+ times daily, when speed matters more than smoothness.

**Marketing vs. Product:** marketing pages tolerate more elaborate, longer animations; product UI should be fast, purposeful, never frivolous.

## 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.

**Configuration** — prefer Apple's duration+bounce approach (easier to reason about) over raw physics:

```js
// Apple's approach (recommended)
{ type: "spring", duration: 0.5, bounce: 0.2 }

// Traditional physics (more complex)
{ type: "spring", mass: 1, stiffness: 100, damping: 10 }
```

Avoid bounce in most UI contexts; use it for drag-to-dismiss and playful interactions, kept subtle (0.1–0.3).

**Interruptibility:** springs maintain velocity when interrupted — CSS animations restart from zero. This makes springs ideal for gestures users might change mid-motion.

## Performance

### The Golden Rule

Only animate `transform` and `opacity`. They 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.

```css
/* Force GPU acceleration */
.animated-element {
  will-change: transform;
}
```

**React-specific:** animate outside React's render cycle when possible; use refs to update styles directly instead of state — re-renders on every frame drop frames.

**CSS vs. JavaScript:** CSS animations run off the main thread (smoother under load); JS animations (Framer Motion, React Spring) use `requestAnimationFrame`. CSS is better for simple, predetermined animations; JS is better for dynamic, interruptible ones.

## Accessibility

Animations can cause motion sickness or distraction for some users.

### prefers-reduced-motion

Whenever you add an animation, add a media query to disable it:

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

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

Guidelines: every animated element needs its own `prefers-reduced-motion` query; set `animation: none` or `transition: none` without `!important`; no exceptions for opacity or color — disable all animations; show play buttons instead of autoplaying video.

```jsx
import { useReducedMotion } from "framer-motion";

function Component() {
  const shouldReduceMotion = useReducedMotion();
  return (
    <motion.div
      initial={shouldReduceMotion ? false : { opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
    />
  );
}
```

### Touch Device Considerations

```css
@media (hover: hover) and (pointer: fine) {
  .element:hover { transform: scale(1.05); }
}
```

Touch devices trigger hover on tap, causing false positives — gate hover animations behind this media query.

## Practical Tips

| Scenario | Solution |
|---|---|
| Make buttons feel responsive | `transform: scale(0.97)` on `:active` |
| Element appears from nowhere | Start from `scale(0.95)`, not `scale(0)` |
| Shaky/jittery animations | Add `will-change: transform` |
| Hover causes flicker | Animate the child element, not the parent |
| Popover scales from wrong point | Set `transform-origin` to trigger location |
| Sequential tooltips feel slow | Skip the delay/animation after the first tooltip |
| Small buttons hard to tap | Use a 44px minimum hit area (pseudo-element) |
| Something still feels off | Add subtle blur (under 20px) to mask it |
| Hover triggers on mobile | `@media (hover: hover) and (pointer: fine)` |

## Easing Decision Flowchart

```
Is the element entering or exiting the viewport?
├── Yes → ease-out
└── No
    ├── Is it moving/morphing on screen?
    │   └── Yes → ease-in-out
    └── Is it a hover change?
        ├── Yes → ease
        └── Is it constant motion?
            ├── Yes → linear
            └── Default → ease-out
```

Get new playbooks like this one

One email a week with new Claude Code workflows. Free, like everything here.

No spam. Unsubscribe anytime.

README.md

What This Does

A decision-first reference for web animation, distilled from Emil Kowalski's "Animations on the Web" course, that replaces animation guesswork with four questions: is the element entering/exiting (use ease-out), moving on screen (use ease-in-out), a hover/color change (use ease), or something seen 100+ times a day (don't animate it at all). A full easing blueprint gives ready-to-use cubic-bezier values sorted weak-to-strong for each category, a duration table by element type (100–150ms for micro-interactions up to 200–300ms for modals), and the "paired elements" rule — anything that visually moves together (a modal and its overlay, a tooltip and its arrow) must share identical easing and duration or the pairing reads as broken.

It covers spring animations (when they beat fixed-duration easing — drag interactions, interruptible gestures — and Apple's duration+bounce configuration over raw physics parameters), the hard performance rule of animating only transform and opacity since they skip layout and paint entirely, and a non-negotiable accessibility section: every animated element needs its own prefers-reduced-motion media query with real CSS and a Framer Motion useReducedMotion hook example, not a general reminder to "consider accessibility." A practical-tips table closes it out with nine specific fixes for common animation complaints — jittery motion, popovers scaling from the wrong origin, buttons that don't feel responsive on press.


Quick Start

Step 1: Create a Project Folder

mkdir web-animation && cd web-animation

Step 2: Download the Template

Click Download above, then:

mv ~/Downloads/CLAUDE.md ./

Step 3: Design or Review Animations

claude

Ask Claude to add an animation to a component, or to review an existing one that "feels off." It will apply the easing/duration decision rules, check for the accessibility media query, and — when reviewing — present before/after CSS in a markdown table showing exactly what changed and why.


Tips & Best Practices

  • Apply the frequency rule aggressively — an animation on something a power user triggers dozens of times a session (like a command palette) should be minimal to nonexistent, however nice it looks in isolation.
  • Never ship an animation without its matching prefers-reduced-motion query; treat it as part of the animation, not an optional accessibility add-on done later.
  • When something still feels subtly wrong after fixing easing and duration, try the "add subtle blur under 20px" trick before reaching for a bigger rewrite — it masks a surprising number of minor timing mismatches.

Limitations

  • Principles and CSS/Framer Motion examples specifically — a team on GSAP, React Spring, or a native mobile animation system will need to translate the underlying rules (easing choice, duration, GPU-only properties) into that framework's API.
  • The duration and frequency guidance reflects product-UI conventions; a marketing page or brand experience intentionally has looser rules, as the guide itself notes.
  • Spring configuration examples assume Framer Motion's duration+bounce API; a different spring-physics library will need the raw mass/stiffness/damping values translated to its own parameter names.

$Related Playbooks

Developer Tools

Web Technique to Skill Extractor

Turn a one-off web visual or interaction technique into a reusable, well-scoped skill — the one-sentence mechanism test that separates a real technique from mere styling, a mechanism-vs-staging sort for what belongs in the skill versus the demo, rules anchored to named failures instead of adjectives, and a demo craft bar that treats the acceptance reference as a target, not inspiration.

10 minutes
Advanced
Developer Tools

Planning with Files

Persistent, file-based planning for multi-step AI-agent work — task_plan.md, findings.md, and progress.md on disk, a 2-action rule for capturing multimodal findings before they're lost, a 3-strike error protocol, and a 5-question reboot test to verify state survives a compaction.

5 minutes
Intermediate
Developer Tools

Tool Interface Design for Agents

Design agent-facing tools as contracts an agent must infer entirely from the description alone — the consolidation principle over narrow overlapping tools, architectural reduction toward primitives, actionable error-recovery messages, and an 8-point audit checklist.

10 minutes
Advanced
Developer Tools

PR Queue Triage

Clear a backlog of open pull requests before a release by classifying every PR into an evidence-based disposition — never by title — with a real git merge-tree test against the actual release branch, not the platform's often-wrong mergeable flag.

10 minutes
Intermediate
Developer Tools

Reproducible Database Lookup

A methodology for querying public database APIs — scientific, regulatory, financial, or otherwise — so another agent or human can repeat exactly what you did: bounded calls, count reconciliation, identifier-conversion tracking, and untrusted-data handling for every response.

10 minutes
Advanced
Developer Tools

Project Graveyard: Autopsy Your Abandoned Side Projects

Scan local repos for dead side projects, autopsy each one from its git history, surface your personal death patterns, and pick the one corpse most worth resurrecting — then help ship it.

10 minutes
Intermediate
Developer Tools

PR Review Toolkit

Six specialist reviewers — comments, tests, error handling, type design, general quality, and simplification — each triggered by name or automatically based on what changed in the diff.

5 minutes
Intermediate
Developer Tools

Ralph Wiggum Autonomous Loop

Self-referential development loop that keeps Claude iterating on the same task until it hits a completion promise or an iteration cap — a Stop hook that blocks exit and re-feeds the same prompt.

5 minutes
Advanced
Developer Tools

Vercel Analytics & Speed Insights Setup

Wire up Vercel Analytics, Speed Insights, and SPA routing rewrites into a React/Vite project in one pass — including the routing fix most people miss.

5 minutes
Beginner
Developer Tools

Unslop UI: Kill the AI Design Tells

A frontend guardrail built from a 3.2M-post Reddit analysis of what people actually call AI slop, with a build mode that forces design decisions up front and an audit mode that scans existing code for the tells

10 minutes
Intermediate
Developer Tools

Redesign Existing Projects: UI Audit and Upgrade

A design audit checklist that finds generic AI-look patterns in an existing codebase and fixes them without breaking functionality or migrating frameworks

10 minutes
Intermediate
Developer Tools

Prompt Optimizer (EARS)

Transform vague prompts into precise, well-structured specifications using EARS (Easy Approach to Requirements Syntax) — ideal for AI-generated code, products, and docs.

10 minutes
Intermediate

Browse all Developer Tools playbooks →