agents/skills/web-animation-design/SKILL.md
Design and implement web animations that feel natural and purposeful. Use whenever the user asks about motion, easing, timing, springs, transitions, or animation performance — how to animate a UI element, which easing to pick, best practices, or reduced-motion accessibility. Triggers on easing/cubic-bezier, keyframes, transform/opacity, spring physics, Framer Motion, React Spring, GSAP, CSS transitions, page/entrance/exit transitions, stagger, modal/dropdown/tooltip animations, gesture and drag interactions, 'feels janky', or 'make it smooth'.
npx skillsauth add carterdea/dots web-animation-designInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A comprehensive guide for creating animations that feel right, based on Emil Kowalski's "Animations on the Web" course.
When this skill is first invoked without a specific question, respond only with:
I'm ready to help you with animations based on Emil Kowalski's animations.dev course.
Do not provide any other information until the user asks a question.
When reviewing animations, you MUST use a markdown table. Do NOT use a list with "Before:" and "After:" on separate lines. Always output an actual markdown table like this:
| Before | After |
| --------------------------------- | ----------------------------------------------- |
| transform: scale(0) | transform: scale(0.95) |
| animation: fadeIn 400ms ease-in | animation: fadeIn 200ms ease-out |
| No reduced motion support | @media (prefers-reduced-motion: reduce) {...} |
Wrong format (never do this):
Before: transform: scale(0)
After: transform: scale(0.95)
────────────────────────────
Before: 400ms duration
After: 200ms
Correct format: A single markdown table with | Before | After | columns, one row per issue.
Every animation decision starts with these questions:
ease-outease-in-outeaseUse for user-initiated interactions: dropdowns, modals, tooltips, any element entering or exiting the screen.
/* 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.
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);
Use for hover states and color transitions. The asymmetrical curve (faster start, slower end) feels elegant for gentle animations.
transition: background-color 150ms ease;
Only use for:
Linear feels robotic and unnatural for interactive elements.
Avoid for UI animations. Makes interfaces feel sluggish because the slow start delays visual feedback.
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.
/* Both use the same timing */
.modal {
transition: transform 200ms ease-out;
}
.overlay {
transition: opacity 200ms ease-out;
}
| Element Type | Duration | | --------------------------------- | --------- | | Micro-interactions | 100-150ms | | Standard UI (tooltips, dropdowns) | 150-250ms | | Modals, drawers | 200-300ms |
Rules:
Determine how often users will see the animation:
Example: Raycast never animates because users open it hundreds of times a day.
Do animate:
Don't animate:
Marketing vs. Product:
Springs feel more natural because they don't have fixed durations—they simulate real physics.
Apple's approach (recommended):
// Duration + bounce (easier to understand)
{ type: "spring", duration: 0.5, bounce: 0.2 }
Traditional physics:
// Mass, stiffness, damping (more complex)
{ type: "spring", mass: 1, stiffness: 100, damping: 10 }
Springs maintain velocity when interrupted—CSS animations restart from zero. This makes springs ideal for gestures users might change mid-motion.
Only animate transform and opacity. These 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)/* Force GPU acceleration */
.animated-element {
will-change: transform;
}
React-specific:
Framer Motion:
// Hardware accelerated (transform as string)
<motion.div animate={{ transform: "translateX(100px)" }} />
// NOT hardware accelerated (more readable)
<motion.div animate={{ x: 100 }} />
requestAnimationFrameAnimations 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;
}
}
prefers-reduced-motion media queryanimation: none or transition: none (no !important)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 }}
/>
);
}
/* Disable hover animations on touch devices */
@media (hover: hover) and (pointer: fine) {
.element:hover {
transform: scale(1.05);
}
}
Touch devices trigger hover on tap, causing false positives.
Quick reference for common scenarios. See PRACTICAL-TIPS.md for detailed implementations.
| Scenario | Solution |
| ------------------------------- | ----------------------------------------------- |
| Make buttons feel responsive | Add 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 child element, not parent |
| Popover scales from wrong point | Set transform-origin to trigger location |
| Sequential tooltips feel slow | Skip delay/animation after first tooltip |
| Small buttons hard to tap | Use 44px minimum hit area (pseudo-element) |
| Something still feels off | Add subtle blur (under 20px) to mask it |
| Hover triggers on mobile | Use @media (hover: hover) and (pointer: fine) |
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
development
Add net-new product, workflow, platform, or developer-experience features as small vertical slices. Use this skill whenever the user asks to build a new feature, add a new page/route/API/workflow/job/eval/operator path, enrich an existing feature with a new user-visible capability, or plan feature architecture before coding. This skill maps the files to change or create, defines the authoritative contract, specifies tests, and gives a QA plan before treating the feature as done.
development
Verify a developer's finished Trello ticket on a non-Shopify web app and render a verdict. Dogfood the posted preview (desktop + mobile) against the card's acceptance criteria, then PASS it (approve the PR, move to Ready for Release) or FAIL it (request changes, attach repro, reassign the dev, move to Development). Read-only: never implements, commits, or opens a PR. Use when asked to 'QA this card', 'test before release', or 'sign off on this ticket'. Shopify themes use shopify-trello-qa; building a ticket uses trello-delivery.
development
Verify a developer's finished Shopify theme ticket and render a verdict. Dogfood the posted preview theme and Customizer (desktop + mobile) against the card's acceptance criteria and Figma, then PASS it (approve the PR, move to Ready for Release) or FAIL it (request changes, attach repro, reassign the dev, move to Development). Read-only: never implements, commits, deploys, or opens a PR. Use when asked to 'QA this Shopify card', 'verify the Ready for Testing card', or 'sign off on this theme ticket'. Non-Shopify apps use trello-qa; building a ticket uses shopify-trello-delivery.
development
Survey any codebase as a senior advisor and produce prioritized, self-contained implementation plans for OTHER models/agents to execute. Strictly read-only on source code — never implements, fixes, or refactors anything itself. Use when asked to audit a codebase, find improvement opportunities (bugs, security, performance, test coverage, tech debt, migrations, DX), suggest features or where to take the project next (roadmap, product direction), or generate handoff plans for another agent to implement.