Learn-skills.dev animation
Implement animations using the Motion library. Use when adding motion, transitions, gestures, scroll effects, or interactive animations to components. Triggered by implementation requests, not conceptual discussions.
install
source · Clone the upstream repo
git clone https://github.com/NeverSight/learn-skills.dev
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/NeverSight/learn-skills.dev "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/skills-md/adrsource/adr-source-v2/animation" ~/.claude/skills/neversight-learn-skills-dev-animation && rm -rf "$T"
manifest:
data/skills-md/adrsource/adr-source-v2/animation/SKILL.mdsource content
Animation Implementation with Motion
Use the Motion library (https://motion.dev) for all animation work.
Quick Start
React (Primary):
import { motion } from "motion/react" // Basic animation <motion.div animate={{ opacity: 1, y: 0 }} /> // With transition config <motion.div animate={{ x: 100 }} transition={{ type: "spring", stiffness: 100 }} />
Core Patterns
1. Spring Physics (Preferred)
<motion.div animate={{ scale: 1 }} transition={{ type: 'spring', stiffness: 260, damping: 20, }} />
Spring presets:
- Gentle:
stiffness: 120, damping: 14 - Wobbly:
stiffness: 180, damping: 12 - Stiff:
stiffness: 300, damping: 20
2. Gesture Interactions
<motion.div whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} drag="x" dragConstraints={{ left: -100, right: 100 }} />
3. Layout Animations
<motion.div layout>{/* Content that changes position/size */}</motion.div>
4. Scroll-Linked Effects
import { useScroll, useTransform } from "motion/react" const { scrollYProgress } = useScroll() const opacity = useTransform(scrollYProgress, [0, 1], [1, 0]) <motion.div style={{ opacity }} />
5. Stagger Children
<motion.ul variants={{ visible: { transition: { staggerChildren: 0.07 } }, }} > {items.map((item) => ( <motion.li key={item} variants={{ hidden: { opacity: 0, y: 20 }, visible: { opacity: 1, y: 0 }, }} /> ))} </motion.ul>
6. Enter/Exit Animations
import { AnimatePresence } from 'motion/react'; <AnimatePresence> {show && <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} />} </AnimatePresence>;
Animation Properties
Transform (GPU-accelerated, performant):
- Translatex, y, z
- Scalescale, scaleX, scaleY
- Rotationrotate, rotateX, rotateY, rotateZ
- Skewskew, skewX, skewY
Visual (use sparingly, can affect performance):
opacitybackground, backgroundColorcolorborderRadius
SVG-specific:
- For path drawing animationspathLength
- Offset the pathpathOffset
- Spacing between dashespathSpacing
Accessibility
Always respect user preferences:
<motion.div animate={{ x: 100 }} transition={{ type: 'spring', // Disables animation if user prefers reduced motion duration: 0, }} />
Motion automatically handles
prefers-reduced-motion. Springs become instant transitions.
Performance Tips
- Animate transforms/opacity only when possible (GPU-accelerated)
- Use
prop instead of animating width/height manuallylayout - Avoid animating during scroll when possible
- Use
for complex animations (Motion handles this)will-change: transform - Limit simultaneous animations - stagger instead of all-at-once
Design Principles (Brief)
When to Animate
- State transitions (loading → success)
- Spatial changes (entering/exiting view)
- Drawing attention (sparingly)
- Confirming user action
When NOT to Animate
- Repeated actions after first occurrence
- Performance-critical paths
- User-controlled scrolling
- Every single interaction (restraint matters)
Timing Guidelines
- Micro-interactions: 150-250ms
- Panel/modal transitions: 200-300ms
- Page transitions: 300-500ms
- Springs: Let physics determine duration
Spring vs Duration
- Use springs for: Interactive elements, gestures, layout changes
- Use duration for: Intentional sequences, choreography, loaders
See
principles.md for detailed animation philosophy.
Common Patterns
Loading state:
<motion.div animate={{ rotate: 360 }} transition={{ repeat: Infinity, duration: 1, ease: 'linear', }} />
Toast notification:
<motion.div initial={{ x: 400, opacity: 0 }} animate={{ x: 0, opacity: 1 }} exit={{ x: 400, opacity: 0 }} transition={{ type: 'spring', stiffness: 300, damping: 30 }} />
Drawer:
<motion.div initial={{ x: '-100%' }} animate={{ x: 0 }} exit={{ x: '-100%' }} transition={{ type: 'spring', damping: 25 }} />
Accordion:
<motion.div animate={{ height: isOpen ? 'auto' : 0 }} transition={{ type: 'spring', bounce: 0 }} style={{ overflow: 'hidden' }} />
Resources
- Motion Docs: https://motion.dev/docs/react
- Motion Examples: https://motion.dev/examples (100+ free examples)
- GitHub Repository: https://github.com/motiondivision/motion
- Extended resources: See
for curated animation.dev lessons and vaultresources.md
Quick Troubleshooting
Animation not running?
- Check if element is conditionally rendered (use AnimatePresence)
- Verify target values are different from initial values
- Check for CSS that might override (e.g.,
)!important
Performance issues?
- Stick to transforms and opacity
- Use
prop instead of animating dimensionslayout - Check browser DevTools Performance tab
Layout animations flickering?
- Ensure parent has
position: relative - Add
to both parent and child if neededlayout - Check for conflicting CSS transitions
Notes
- Motion is MIT licensed, production-ready
- Hybrid engine: 120fps, GPU-accelerated
- TypeScript support built-in
- Tree-shakable for optimal bundle size
- Works with React 18+ (including Suspense)