60fps-animation
This skill should be used when the user asks to "fix janky CSS animation", "make animation 60fps", "stop layout thrashing",…
This skill should be used when the user asks to "add a hover/press effect", "animate a toggle or switch", "build an animated like button", "make a toast/snackbar slide in", "animate a drawer or modal", "animate list reordering or add/remove", "do a shared-element layout
$ npx -y skills add iart-ai/web-animation-skills --skill micro-interaction --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/micro-interactionContext preview
The summary Claude sees to decide when to auto-load this skill.
This skill should be used when the user asks to "add a hover/press effect", "animate a toggle or switch", "build an animated like button", "make a toast/snackbar slide in", "animate a drawer or modal", "animate list reordering or add/remove", "do a shared-element layout
name: micro-interaction description: This skill should be used when the user asks to "add a hover/press effect", "animate a toggle or switch", "build an animated like button", "make a toast/snackbar slide in", "animate a drawer or modal", "animate list reordering or add/remove", "do a shared-element layout transition", or "polish UI feedback". Covers UI motion with Framer Motion (motion/react) and modern CSS. version: 0.1.0
Small, functional motion that makes an interface feel responsive and alive: hover/press/focus feedback, toggles, toasts, drawers, and list/layout animation. The goal is feedback and continuity, not decoration.
As of v11+, the package is imported as `motion/react` (the `framer-motion` name still works).
import { motion } from "motion/react";
<motion.button
whileHover={{ scale: 1.03 }}
whileTap={{ scale: 0.96 }}
whileFocus={{ boxShadow: "0 0 0 3px rgba(59,130,246,.5)" }}
transition={{ type: "spring", stiffness: 400, damping: 30 }}
/>Spring intuition: higher `stiffness` = faster; higher `damping` = less bounce. `stiffness: 400, damping: 30` is a snappy UI default. For visible bounce, lower damping (e.g. `damping: 12`).
Exit animations require `AnimatePresence` wrapping conditionally-rendered children, each with a stable `key`.
import { AnimatePresence, motion } from "motion/react";
<AnimatePresence>
{open && (
<motion.div
key="panel"
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 8 }}
transition={{ duration: 0.2, ease: [0.16, 1, 0.3, 1] }}
/>
)}
</AnimatePresence>For toasts/lists, use `mode="popLayout"` so removed items don't hold space while exiting.
`layout` automatically animates any layout change (position/size) using transforms — perfect for reordering, expanding cards, and grid<->list.
<motion.li layout transition={{ type: "spring", stiffness: 500, damping: 40 }} />Shared-element transition across components: give two elements the same `layoutId` and Framer Motion animates between them as one mounts and the other unmounts.
{!open && <motion.div layoutId="card" onClick={() => setOpen(true)} />}
<AnimatePresence>
{open && <motion.div layoutId="card" />} {/* "magic moves" from the source */}
</AnimatePresence>Gotcha: a plain `layout` element distorts `border-radius` and text during scale. Add `layout` to direct children that should counter-scale, and prefer `borderRadius`/`boxShadow` as motion values, or use `layout="position"` to animate position only.
Modern CSS can animate enter/exit and even `display` toggles without a library.
.toast {
transition: opacity 0.2s ease, transform 0.2s ease;
/* allow animating to/from display:none and from initial render */
transition-behavior: allow-discrete;
}
.toast[hidden] { display: none; }
/* animate FROM these values on first render / when entering */
@starting-style {
.toast { opacity: 0; transform: translateY(8px); }
}`@starting-style` defines the "before-open" values so an element animates in on first appearance; `transition-behavior: allow-discrete` lets `display` (and `overlay` for popovers/dialogs) participate so exit animations run before the element is removed. Baseline in Chrome/Edge/Safari; provide a no-animation fallback for older browsers.
Always include a reduced-motion guard:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}Loading → success → error should be one continuous motion (e.g. a button morphs spinner → checkmark), not a jump cut. Keep the element mounted and animate between states so the eye tracks the same object.
> **Packaged helper** (`scripts/`): `scripts/seek-shot.sh anim.html 0 1.5 3` freezes the `?t=N` harness and screenshots each moment; `scripts/contact-sheet.sh sheet.png frame-*.png` tiles them for one-glance review. See `scripts/README.md`.
For a self-contained interaction demo (toggle, like button, toast, drawer) the deliverable is **one HTML file that opens directly in a browser**. Pure-CSS interactions ship as-is; for a Framer Motion demo, load React + `motion` from CDN (`esm.sh`) into one inline module — no build step. One file is the right tier; don't reach for a bundler.
**Output contract:**
Web animation skills for AI coding agents — GSAP, SVG, Lottie, micro-interactions, page transitions, and 60fps performance, installed straight into your agent.
This skill should be used when the user asks to "fix janky CSS animation", "make animation 60fps", "stop layout thrashing",…
This skill should be used when the user asks to "respect prefers-reduced-motion", "honor reduced motion", "make my animations…
This skill should be used when the user asks to "make an ASCII animation", "build a terminal/CLI intro or loader", "convert an…
This skill should be used when the user asks to "add a glassmorphism effect", "frosted glass UI", "Apple liquid glass style",…
This skill should be used when the user asks to "build a scroll animation", "add ScrollTrigger", "pin a section while scrolling",…
This skill should be used when the user asks to "add a Lottie animation", "play a .lottie or .json animation", "integrate a…