hamedmp/matrix-os/animate

Claude Code and agent skill by hamedmp/matrix-os

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

Design and build web animations that feel right, grounded in the complete "Animations on the Web" course (animations.dev). Use proactively whenever building or improving motion — deciding whether to animate, choosing easing/duration/springs, implementing entrances, exits, hovers, gestures, drawers, popovers, morphs, layout and shared-element transitions, SVG animation, or fixing motion that feels janky, sluggish, or off. Triggers on — animate, animation, motion, easing, ease-out, ease-in-out, c…

Install

npx vskill@latest install hamedmp/matrix-os/animate

SKILL.md

Building Animations

The complete builder's guide to motion that feels right, distilled from Emil Kowalski's Animations on the Web course (animations.dev). Use it to make decisions first, then implement.

Core Philosophy

An animation feels right when it satisfies three things at once:

  1. It feels natural. It mirrors the physics of the real world. Nothing around us moves at a constant speed or appears out of nowhere — so linear easing feels lifeless and scale(0) entrances feel wrong.
  2. It has a purpose. You can answer "why does this animate?" in one sentence, and neither you nor the user is surprised or annoyed by it.
  3. It's made with taste. Taste is trained, not innate — the ability to tell good motion from bad and justify why. In a world where everyone's software works, taste is the differentiator.

Two consequences run through everything below:

  • Unseen details compound. Most motion details users never consciously notice — that's the point. The aggregate of invisible correctness is what makes an interface feel expensive.
  • If everything animates, nothing stands out. Motion is a spice, not the meal. Pace it through the experience; the more you add, the less each one is worth.

Load These When Implementing

This file is the decision layer. When you move to code, load the companion reference for the exact recipe:

  • [css-techniques.md](css-techniques.md) — transitions vs keyframes, transforms, clip-path, @starting-style, stagger, hover patterns, 3D.
  • [framer-motion.md](framer-motion.md) — motion/react: initial/animate/exit, spring configs, AnimatePresence modes, layout/layoutId, motion values & hooks, animating height, and the component recipes (drawer, crossfade, morph, shared-element, trash).
  • [svg-animation.md](svg-animation.md) — viewBox, line-drawing (stroke-dashoffset), transform-box/origin, path morphing, shakes, ambient "life."

Err on the side of loading a reference rather than approximating a value.

The Animation Decision Framework

Answer these in order before writing animation code.

1. Should this animate at all?

Match motion to how often the user sees it:

FrequencyDecision
100+/day (keyboard shortcuts, command-palette toggle, arrow-key list nav)No animation. Ever.
Tens/day (hover effects, list navigation)Remove or drastically reduce
Occasional (modals, drawers, toasts)Standard animation
Rare / first-time (onboarding, feedback, celebrations)Can add delight

Never animate keyboard-initiated actions — they repeat hundreds of times a day; animation makes them feel slow and disconnected. Raycast has no open/close animation — that's correct for something opened hundreds of times a day. A high-frequency selection highlight should be instant (track the cursor exactly), not a smooth fade that trails one step behind.

2. What's the purpose?

Every animation needs one of: explanation (marketing/onboarding), feedback/responsiveness (a button that reacts to a press), spatial consistency (an element enters and exits the same way), state indication, preventing a jarring change (a toast that eases in instead of popping), or — rarely — delight (reserved for interactions seen seldom, so it stays a pleasant surprise). "It looks cool" on a frequently-seen element is not a purpose.

3. Then pick the ingredients

Easing → duration → physicality → (spring?) → interruptibility → performance → accessibility. The rest of this file is those ingredients.

Easing

Easing is the single most important part of an animation — it can make a bad animation look great or a great one feel wrong.

SituationCurve
Entering or exiting the screen`ease-out` (fast start, gentle settle — feels responsive)
Moving / morphing while already on screen`ease-in-out` (car accelerating then braking)
Hover / color / background / opacity`ease` (asymmetric, elegant for small changes; CSS default)
Constant motion (marquee, spinner, timer, hold-to-delete)`linear`
Default`ease-out`

Never use `ease-in` on UI. It starts slow — delaying the exact moment the user is watching — then accelerates into the stop, the opposite of how things settle.

Built-in named curves are almost never strong enough. Their acceleration is too weak, so animations feel flat. Every course example uses a custom curve. Prefer asymmetric curves (steep start, slow settle) — they feel alive and mimic a spring without one. When an animation feels flat, the curve is probably too weak, not the duration.

Curves worth reaching for:

css
--ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1); /* strong ease-out: hovers, reveals */
--ease-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94); /* button press */
--ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1); /* on-screen back-and-forth */
--ease-vaul: cubic-bezier(0.32, 0.72, 0, 1); /* iOS sheet — extremely steep start */
--ease-drawer-height: cubic-bezier(0.25, 1, 0.5, 1); /* snappy height change */

Pair entering and exiting elements to the same direction and curve family so the interaction reads as one coherent space.

Duration

Keep UI animations under ~300ms unless justified. A 180ms dropdown feels more responsive than a 400ms one. Faster spinners make loads feel faster.

ElementDuration
Button press~150ms
Tooltips, small popovers125–200ms
Dropdowns, selects150–250ms
Modals, drawers200–500ms
Small floating drawer~270ms
Wide menu resize~250ms
Big element crossing the screenup to ~1s

Duration and easing are inseparable. A steep curve can afford a longer duration (Vaul's 500ms doesn't feel slow because the curve front-loads the movement); a weak curve must be shorter. Choose the easing first, then tune duration to it. Duration scales with element size and travel distance (a bigger element is heavier). Exits are shorter and simpler than entries — the user already decided; get out of the way. Too fast is as bad as too slow. Marketing pages can run longer; product must feel fast.

For transitions whose size varies (an auto-height drawer), make duration proportional to how much changed so small changes don't over-animate — see the adaptive-duration recipe in framer-motion.md.

Physicality

  • Never animate from `scale(0)`. Start entrances from scale(0.9–0.95) + opacity: 0. Nothing appears from nothing; a near-full start reads as "it was always almost there." Bigger floating elements start closer to 1 (a nav menu uses scale(0.98)).
  • Button press: transform: scale(0.97) on :active, transition: transform ~150ms. Press feedback is felt, not seen — scale(0.9) visibly collapses. Buttons feel best with both hover and press feedback; hover with nothing on click feels dead.
  • Hover scale: 1–2% is plenty (scale(1.02)). hover:scale-105 inflates like a balloon. Hover duration 100–150ms.
  • Origin-aware popovers. Scale from the trigger, not the center (the CSS default transform-origin: center is wrong for almost every triggered element). Use the library's variable:

``css .popover { transform-origin: var(--radix-popover-content-transform-origin); } /* Radix */ .popover { transform-origin: var(--transform-origin); } /* Base UI */ .menu { transform-origin: top center; } /* trigger above */ ` **Modals are exempt** — they appear centered, keep transform-origin: center`.

  • Never put a hover lift on the hover target itself. Animating translateY on the hovered element moves it out from under the cursor → hover ends → it drops → flicker loop. Move the lift to an inner child; the parent stays under the cursor.

Springs

Springs simulate physics (mass, stiffness/tension, damping) with no fixed duration, so they feel organic and alive. Reach for them for: drag with momentum, "alive" elements (Dynamic Island), interruptible gestures, and cursor-following. Simple color/opacity changes don't need a spring. Real springs are impossible in pure CSS (only approximable with linear()).

js
// Apple / Motion style (easier to reason about) — great for UI text/state swaps
{ type: "spring", duration: 0.3, bounce: 0 }
{ type: "spring", duration: 0.5, bounce: 0.2 }
// Physics form (more control)
{ type: "spring", stiffness: 100, damping: 10, mass: 0.75 }
  • Default bounce to 0. No overshoot keeps UI natural and elegant. Add bounce only intentionally — a slight bounce at the end of a drag (a drag applies force); a press-to-close gets none. Bounce is personality: more = playful, zero = serious.
  • Bounce scales inversely with element size — smaller elements need more bounce to read the same amount.
  • Springs are interruptible — redirected mid-motion, they carry velocity, so gestures the user reverses stay smooth. This is why the Sonner toast bug (new toast jumping) was a keyframe/interruptibility problem.
  • "Weird" spring motion is usually fixed by increasing `damping`.

Interruptibility

Anything triggered rapidly (toasts, toggles, drawers, accordions, drags) must animate from its current state, not restart. CSS transitions and springs are interruptible; @keyframes restart from zero and make new items jump. Prefer transitions/springs for dynamic UI, and @keyframes only for autonomous, looping, or one-shot motion. Use @starting-style to animate an enter without JS — see css-techniques.md.

Performance

The golden rule: only animate `transform` and `opacity`. They run on the GPU (Composite step only). width/height/margin/padding/top/left trigger Layout + Paint + Composite and drop frames. Prefer transform: translate (percentages — relative to the element's own size) over margin/top, and scale over animating dimensions. Target 60fps (≤16.7ms/frame).

  • Framer Motion `x`/`y`/`scale` shorthands are not hardware-accelerated — they run on the main thread via rAF. When motion must stay smooth under load, animate the full transform string.
  • Don't drive child transforms through a CSS variable on a shared parent — inherited vars recalc styles for all descendants (the Vaul lag past ~20 items). Set transform directly on the element.
  • CSS/WAAPI beat JS under load — they run off the main thread. Use CSS for predetermined motion, JS for dynamic/interruptible.
  • `will-change: transform` fixes 1px GPU/CPU shift and promotes heavy/filtered elements to their own layer — but add it (and contain: layout style paint, translateZ(0)) only once you see dropped frames; too many layers cost memory.
  • Keep animated `blur()` ≤ ~20px — blur gets laggy fast, especially in Safari.

For the full frame-budget model (the Layout/Paint/Composite pipeline, main-thread vs GPU, React re-renders, and a diagnosis checklist for dropped frames), use the animation-performance skill.

Stagger, hierarchy & orchestration

Stagger group entrances 30–80ms apart — longer feels slow, and stagger is decorative so it must never block interaction. Vary the delay and distance by visual importance: the most important element appears first with the most screen time; the least important can just fade in without sliding. Uniform stagger (identical delay/distance/easing per item) kills hierarchy and feels artificial.

One entrance per container. Don't slide a panel in and trickle its children in — slide it in with content already there. Sometimes the best animation is no animation.

Cohesion & spatial consistency

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 96 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
85
Repository forks
25
7-day trend score
0

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/hamedmp/matrix-os/animate/badge)](https://verified-skill.com/skills/hamedmp/matrix-os/animate)

Something wrong with this skill or its page? Tell us.