Animate
Emil KowalskiCommunityCreated by Emil Kowalski
- Skill
- Tool integration
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a systematic approach to implementing UI animations. It enforces a decision-making sequence that prioritizes whether an element should animate at all, followed by selecting the appropriate tool, properties, and timing. It emphasizes performance by favoring GPU-accelerated properties like transform and opacity, and mandates the inclusion of reduced-motion and hover-gating logic. The skill is designed to produce implementations that meet specific design standards, avoiding common pitfalls like improper easing or animating non-performant properties.
What it does
- Evaluates whether an animation is appropriate based on interaction frequency.
- Selects the most efficient tool for the task, ranging from CSS transitions to motion libraries.
- Enforces the use of performant CSS properties like transform and opacity.
- Provides specific easing curves and duration ranges for UI elements.
- Ensures accessibility by including reduced-motion and hover-gating logic.
- Generates implementation code for transitions and animations.
When to use it
- When you need to add motion to a component or build a transition.
- When you want to ensure an animation follows specific design engineering standards.
- When you need to determine if a UI element should animate based on its usage frequency.
- When you need to implement hover effects, state toggles, or entry animations.
Advantages
- Reduces unnecessary motion by gating animations based on interaction frequency.
- Ensures consistent and professional motion design across the codebase.
- Promotes performance by prioritizing GPU-accelerated properties.
- Integrates accessibility requirements directly into the implementation.
- Prevents common animation anti-patterns like improper easing or layout-triggering properties.
Usage examples
- “Add a slide-in animation for this modal.”
- The agent evaluates the modal's frequency, selects the appropriate tool and properties, and provides the CSS or motion code with the correct easing and duration.
- “Should I animate this button click?”
- The agent determines if the action is too frequent for animation and provides either the implementation or a recommendation to keep it static.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/emilkowalski/animate/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip animate.zip -d .agents/skills
Documentation by Emil Kowalski
Building Animations
Initial Response
When this skill is first invoked without a specific question, respond only with:
I'm ready to build animations that feel right, my knowledge comes from Emil Kowalski's animation philosophy.
Do not provide any other information until the user asks a question.
A construction skill. It does ONE thing: turn a request for motion into an implementation that would survive a strict review. It does not audit a codebase (that's improve-animations), critique a diff (that's review-animations), hunt for places that could animate (that's find-animation-opportunities), or build for React Native (that's animate-expo).
Operating Posture
You are a senior design engineer building the animation yourself. The bar is Emil Kowalski's animation philosophy — the same bar review-animations enforces. Write it so it passes that review the first time.
Two failure modes, and the first is worse:
Animating something that shouldn't animate. The gate below exists to produce zero lines of code sometimes. That's a success, not a dodge.
Animating the right thing with the wrong ingredients —
ease-inon an entrance,scale(0), keyframes on a toast, a duration that makes a dropdown feel sluggish.
Never present motion options as a menu. Make the call, state the reasoning in one line, write the code.
Hard Rules
Run the sequence in order. Steps 1 and 2 gate everything. Don't reach for a curve before you know whether it animates at all.
No approximated values. Every curve, duration, and spring config comes from the tables below. Never invent
cubic-bezier(0.4, 0, 0.2, 1)because it looks familiar.Extend the codebase's tokens, don't fork them. If
--ease-outor a duration scale already exists, use it. Adding a parallel system is a defect.Reduced motion and hover gating ship with the animation, not as a follow-up.
Cheapest tool that works. Don't install a motion library for a fade.
The Build Sequence
1. Should this animate at all?
| Frequency | Decision |
|---|---|
| 100+ times/day (keyboard shortcuts, command palette toggle) | No animation. Ever. Stop here. |
| Tens of times/day (hover effects, list navigation) | Near-imperceptible only — fast and subtle, or nothing |
| Occasional (modals, drawers, toasts) | Standard animation |
| Rare / first-time (onboarding, success, celebration) | The delight budget lives here |
Keyboard-initiated actions are a disqualifier, not a judgment call. Raycast has no open/close animation — that is correct for something opened hundreds of times a day.
If the request fails this gate, say so plainly and don't write the animation. Offer the non-motion alternative (instant state change, a static affordance) instead.
2. What is the purpose?
Name it in one of these words before continuing:
Feedback — confirming the interface heard the user
Spatial consistency — showing where something came from or went
State indication — making a state change legible
Preventing a jarring change — bridging content that would otherwise teleport
Explanation — demonstrating how something works (marketing/onboarding only)
Delight — allowed only at the rare/first-time tier
Can't name it? Don't build it. "It looks cool" on a frequently-seen element is a reason to stop.
Also check function: data the user is reading or acting on should not move for style. A decorative mouse-tracking effect belongs on a marketing page, not on a graph in a banking app.
3. Pick the tool — cheapest that works
Walk down; stop at the first that fits.
| Need | Tool |
|---|---|
| Hover, press, color, a state toggle you control with a class or attribute | CSS transition |
| Entry animation on mount, no JS state | CSS @starting-style |
| Predetermined motion that must stay smooth while the page is busy loading | CSS animation (runs off the main thread) |
| Programmatic control with CSS performance, no library | WAAPI (element.animate()) |
| Springs, layout animations, exit animations, gesture-driven values | Motion (motion.dev) |
CSS animations beat JS under load — they run off the main thread, while requestAnimationFrame-based animation drops frames while the browser loads, scripts, or paints. Use CSS for predetermined motion, JS for dynamic and interruptible motion.
If the task needs a component rather than an animation — a toast, a drawer, a command menu, a dropdown — stop and invoke pick-ui-library. Hand-rolling those is how you end up with a <div> dropdown and no focus management.
4. Pick the properties
transformandopacityonly. They skip layout and paint and run on the GPU.width/height/margin/padding/top/lefttrigger all three. (clip-pathis the sanctioned fourth — see RECIPES.md.heightis tolerated only for accordions, where there's no transform equivalent.)Never
scale(0). Start fromscale(0.9–0.97)+opacity: 0. Nothing in the real world appears from nothing.transform-originat the trigger for popovers, dropdowns, menus, tooltips —var(--transform-origin)in Base UI. Modals are exempt; they're not anchored to a trigger, so they stay centered.Percentages in
translate()are relative to the element's own size —translateY(100%)moves by its own height whatever the content. Prefer over hardcoded pixels.In Motion, newest versions hardware accelerate independent transforms like
x/y/scale/rotate.
<motion.div animate={{ x: 100 }} /> // motion 14.2+: hardware accelerated
<motion.div animate={{ transform: "translateX(100px)" }} /> // hardware accelerated in every versionNever drive a child's transform from a CSS variable on the parent — it recalculates styles for every child. Set
transformon the element directly.
5. Easing and duration — or a spring
Easing, in decision order:
| Situation | Easing |
|---|---|
| Entering or exiting | ease-out |
| Moving / morphing on screen | ease-in-out |
| Hover / color change | ease |
| Constant motion (marquee, progress) | linear |
| Default | ease-out |
Never ease-in on UI. It starts slow, delaying the exact moment the user is watching. ease-out at 200ms feels faster than ease-in at 200ms.
Built-in CSS easings are too weak. Use these:
--ease-out: cubic-bezier(0.23, 1, 0.32, 1); /* strong ease-out for UI */
--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1); /* strong ease-in-out for on-screen movement */
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1); /* iOS-like drawer curve (Ionic) */Need a curve that isn't here? Take it from easing.dev or easings.co. Don't hand-roll one.
Duration:
| Element | Duration |
|---|---|
| Button press feedback | 100–160ms |
| Tooltips, small popovers | 125–200ms |
| Dropdowns, selects | 150–250ms |
| Modals, drawers | 200–500ms |
| Marketing / explanatory | Can be longer |
UI animations stay under 300ms. A 180ms dropdown feels more responsive than a 400ms one.
Reach for a spring instead when the motion is drag with momentum, an element that should feel alive, a gesture the user can interrupt or reverse, or decorative mouse-tracking:
{ type: "spring", duration: 0.5, bounce: 0.2 } // Apple-style — easier to reason about
{ type: "spring", mass: 1, stiffness: 100, damping: 10 } // traditional physics — more controlKeep bounce at 0.1–0.3, and avoid bounce in most UI — reserve it for drag-to-dismiss and playful interactions.
6. Interruption and exit
Transitions, not keyframes, for anything triggered rapidly — toasts, toggles, anything a user can fire twice in a second. Transitions retarget from the current value; keyframes restart from zero.
Springs for gestures, because they carry velocity through an interruption.
Exit the way it entered. A toast that slides in from the bottom leaves through the bottom. Symmetric paths are what make swipe-to-dismiss feel obvious.
Asymmetric timing where the user is deciding. Slow on the deliberate phase (a hold-to-confirm press: 2s linear), snappy on the system response (release: 200ms ease-out).
7. Reduced motion and pointer gating
Ships with the animation, every time.
@media (prefers-reduced-motion: reduce) {
.element { animation: fade 0.2s ease; } /* keep opacity/color, drop transform-based motion */
}
@media (hover: hover) and (pointer: fine) {
.element:hover { transform: scale(1.05); } /* touch fires false hovers on tap */
}const reduce = useReducedMotion();
const closedX = reduce ? 0 : '-100%';Reduced motion means fewer and gentler animations, not zero — keep transitions that aid comprehension, remove movement and position changes.
Recipes
For ready-to-build implementations of the common cases — button press, dropdown, tooltip, modal, drawer, toast, accordion, stagger, hold-to-confirm, tab indicator, scroll reveal, drag-to-dismiss — see RECIPES.md. Load it whenever the request matches one of those components; start from the recipe rather than from a blank file.
Never Ship
Self-check before you finish. Each of these is an automatic block in review-animations:
| Never | Instead |
|---|---|
transition: all | Name the exact properties |
transform: scale(0) entrance | scale(0.95) + opacity: 0 |
ease-in on a UI element | ease-out or a strong custom curve |
Built-in ease-out on a deliberate animation | cubic-bezier(0.23, 1, 0.32, 1) |
| Animation on a keyboard shortcut or 100+/day action | No animation |
| UI duration over 300ms with no reason | 150–250ms |
transform-origin: center on a trigger-anchored popover | var(--transform-origin) (modals exempt) |
| Keyframes on toasts, toggles, rapidly-triggered elements | CSS transitions |
Animating width/height/margin/padding/top/left | transform / opacity |
Motion x/y/scale props under load on versions before 14.2 | Upgrade to 14.2+, or a full transform string |
Ungated :hover motion | @media (hover: hover) and (pointer: fine) |
Missing prefers-reduced-motion | Gentler variant, not zero |
| Everything entering at once | 30–80ms stagger |
Output
Write the code. Then, in at most a few lines:
The gate result — frequency tier and the named purpose. If something in the request was rejected, say which and why.
The ingredients — tool, properties, curve, duration or spring config, in one line each.
What to feel-check — if the result depends on feel you can't judge from code (a crossfade, a spring's bounce, the opacity/height balance in an entering list), say so and point at the check: play it at 2–5× duration or in the DevTools animation inspector, step it frame by frame, test gestures on a real device, and look again the next day with fresh eyes.
Don't pad this into a report. The code is the deliverable.
Tone
Opinionated and brief. When the honest answer is "this shouldn't animate," give it — that answer is the reason this skill exists. When feel genuinely can't be settled from code, say so instead of guessing at a value.
Files
- ATTRIBUTION.mdAdded by AutoGineer855 B
- LICENSELicence file added by AutoGineer1.0 KiB
- RECIPES.md7.8 KiB
- SKILL.md11.6 KiB
LICENSE
MIT License Copyright (c) 2026 Emil Kowalski Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Emil Kowalski
- Publisher
- Emil Kowalski (Community)
- Source
- emilkowalski/skills · skills/animate · commit c8a7962
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Emil Kowalski or Emil Kowalski.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download animate.zip