framer-motion-expert
A guide for implementing declarative animations, layout transitions, and complex UI gestures using Framer Motion.
Install
mkdir -p .claude/skills/framer-motion-expert && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/15548" && unzip -o skill.zip -d .claude/skills/framer-motion-expert && rm skill.zipInstalls to .claude/skills/framer-motion-expert
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Framer Motion 12+ for React. Declarative animations, layout transitions, gestures, scroll-linked motion, AnimatePresence, useAnimate, LazyMotion. Use when building component animations, page transitions, shared layout animations, or gesture-driven UI.Key capabilities
- →Implement declarative animations using `motion.div` and other `motion.X` components
- →Orchestrate animations with variants for stagger effects
- →Define various transition types including tween and spring physics
- →Add gesture-driven animations for hover, tap, focus, and drag events
- →Create scroll-triggered animations with `whileInView` and `viewport` options
- →Perform shared layout transitions using the `layout` prop and `layoutId`
How it works
This skill provides patterns for Framer Motion 12+ by detailing core primitives, gestures, layout animations, and hooks for React.
Inputs & outputs
When to use framer-motion-expert
- →Building component animations
- →Creating page transitions
- →Implementing gesture-driven UI
- →Shared layout animations
About this skill
Framer Motion 12+ — Dense Reference
Hallucination Traps (Read First)
- ❌
<Motion>(capital M) → ✅motion.div(lowercase dot notation) - ❌
motion()wrapper function → ✅motion.div,motion.span, etc. - ❌
exitBeforeEnterprop → ✅mode="wait"on<AnimatePresence>(removed in FM7+) - ❌
exitworks without<AnimatePresence>→ ✅ REQUIRES AnimatePresence wrapper - ❌
<AnimatePresence>children without uniquekey→ ✅ ALWAYS setkey - ❌
stiffness + dampingANDduration + bouncetogether → ✅ pick ONE pair - ❌
m.divwithout<LazyMotion>wrapper → ✅ REQUIRES LazyMotion parent - ❌
layoutanimations withdomAnimationfeature set → ✅ requiresdomMax - ❌ Force-animating
width/height/top/left→ ✅ usex,y,scale,opacity(GPU) - ❌
viewport.oncedefaults to true → ✅ defaults to false — addonce: truefor entrance anims
Core Primitives
motion.X / Declarative Animation
import { motion } from "framer-motion";
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3, ease: "easeOut" }}
/>
Variants (Stagger / Orchestration)
const container = {
hidden: {},
visible: { transition: { staggerChildren: 0.08, delayChildren: 0.1 } },
};
const item = {
hidden: { opacity: 0, y: 20, filter: "blur(4px)" },
visible: { opacity: 1, y: 0, filter: "blur(0px)", transition: { duration: 0.4 } },
};
<motion.ul variants={container} initial="hidden" animate="visible">
{list.map(e => <motion.li key={e.id} variants={item}>{e.name}</motion.li>)}
</motion.ul>
// Variant names propagate to children automatically — no need to set initial/animate on each child
Transitions
// Tween (default)
transition={{ duration: 0.5, ease: "easeInOut", delay: 0.2, repeat: Infinity, repeatType: "reverse" }}
// Spring (physics)
transition={{ type: "spring", stiffness: 300, damping: 20 }} // OR use duration+bounce, not both
transition={{ type: "spring", duration: 0.8, bounce: 0.25 }}
// Per-property
transition={{ x: { type: "spring", stiffness: 300 }, opacity: { duration: 0.2 } }}
Gestures
// Hover/Tap/Focus
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
whileFocus={{ boxShadow: "0 0 0 3px rgba(66,153,225,0.6)" }}
transition={{ type: "spring", stiffness: 400, damping: 15 }}
/>
// Drag
<motion.div
drag="x" // "x" | "y" | true
dragConstraints={{ left: -100, right: 100 }}
dragElastic={0.2} // 0=hard stop, 1=free
dragMomentum={true}
dragSnapToOrigin
/>
// Scroll-triggered
<motion.div
initial={{ opacity: 0, y: 50 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.3 }} // ← once: true is almost always what you want
/>
Layout Animations
// layout prop — auto-animates position/size changes
<motion.div layout transition={{ type: "spring", stiffness: 200 }}>
{/* layout="position" = only position, layout="size" = only size */}
</motion.div>
// layoutId — shared element transition (morph between renders)
// List thumbnail → expanded modal:
<motion.div key={item.id} layoutId={`card-${item.id}`} /> // in list
<motion.div layoutId={`card-${selectedId}`} className="modal" /> // in modal
// ❌ TRAP: Cross-tree layoutId requires <LayoutGroup> wrapper
import { LayoutGroup } from "framer-motion";
<LayoutGroup><Sidebar /><MainContent /></LayoutGroup>
AnimatePresence
<AnimatePresence mode="sync"> {/* "sync"|"wait"|"popLayout" */}
{items.map(item => (
<motion.div key={item.id} /* ← REQUIRED */
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: "auto" }}
exit={{ opacity: 0, height: 0 }}
/>
))}
</AnimatePresence>
// mode="wait" — waits for exit before entering
// initial={false} on AnimatePresence — skip first-render animation
Scroll Animations
import { useScroll, useTransform } from "framer-motion";
// Page scroll progress (0–1)
const { scrollYProgress } = useScroll();
const y = useTransform(scrollYProgress, [0, 1], [0, -200]);
const opacity = useTransform(scrollYProgress, [0, 0.5], [1, 0]);
<motion.div style={{ y, opacity }} />
// Element-scoped scroll
const ref = useRef(null);
const { scrollYProgress } = useScroll({ target: ref, offset: ["start end", "end start"] });
Hooks
useAnimate — Imperative sequences
import { useAnimate, stagger } from "framer-motion";
const [scope, animate] = useAnimate(); // ← returns [scope, animate] NOT [ref, controls]
await animate(".item", { opacity: 1 }, { delay: stagger(0.1) });
<div ref={scope}>...</div>
useMotionValue + useTransform — No re-renders
const x = useMotionValue(0);
const rotateY = useTransform(x, [-200, 200], [-45, 45]);
// ✅ useMotionValue does NOT trigger React re-renders — key perf advantage over useState
<motion.div style={{ x, rotateY }} drag="x" />
useSpring / useVelocity
const springX = useSpring(x, { stiffness: 300, damping: 30 });
const xVel = useVelocity(x);
const skewX = useTransform(xVel, [-1000, 0, 1000], [-15, 0, 15]);
Performance & Bundle
// LazyMotion — ~5KB vs ~30KB full bundle
import { LazyMotion, domAnimation, m } from "framer-motion";
// domAnimation ≈ 5KB | domMax ≈ 20KB (needed for layout/drag)
<LazyMotion features={domAnimation}><m.div animate={{ opacity: 1 }} /></LazyMotion>
Accessibility
import { useReducedMotion } from "framer-motion";
const reduce = useReducedMotion();
// opacity/color: always safe | position/scale/rotation: must be disabled when reduce=true
<motion.div animate={{ x: reduce ? 0 : 100, opacity: 1 }} transition={{ duration: reduce ? 0 : 0.5 }} />
Rules
- ✅ Animate:
x,y,scale,rotation,opacity(GPU composited) - ❌ Never animate:
width,height,top,left,padding,margin(causes layout thrashing) - ✅
useMotionValuefor animation-driven values — neveruseState - ❌ Nest
AnimatePresenceonly when necessary — each adds reconciler overhead "use client"required in Next.js —motion.divcannot run in Server Components
When not to use it
- →When using `<Motion>` (capital M) instead of `motion.div`
- →When expecting `exit` animations to work without `<AnimatePresence>`
- →When animating `width`, `height`, `top`, `left`, `padding`, `margin` directly
Limitations
- →This skill does not support `<Motion>` (capital M).
- →This skill requires `<AnimatePresence>` for `exit` animations.
- →This skill does not recommend animating `width`, `height`, `top`, `left`, `padding`, `margin`.
How it compares
This approach focuses on declarative animation patterns and specific Framer Motion features like `AnimatePresence` and `layoutId`, which is more structured than manual CSS animations.
Compared to similar skills
framer-motion-expert side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| framer-motion-expert (this skill) | 0 | 4mo | No flags | Intermediate |
| scroll-experience | 101 | 6mo | No flags | Intermediate |
| rendering-animate-svg | 13 | 7mo | No flags | Beginner |
| frontend-ui-dark-ts | 4 | 3mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
scroll-experience
davila7
Expert in building immersive scroll-driven experiences - parallax storytelling, scroll animations, interactive narratives, and cinematic web experiences. Like NY Times interactives, Apple product pages, and award-winning web experiences. Makes websites feel like experiences, not just pages. Use when: scroll animation, parallax, scroll storytelling, interactive story, cinematic website.
rendering-animate-svg
TheOrcDev
Wrap animated SVG elements in a div to enable hardware acceleration. Apply when animating SVG icons or elements, especially in 8-bit retro components with pixel art animations.
frontend-ui-dark-ts
microsoft
Build dark-themed React applications using Tailwind CSS with custom theming, glassmorphism effects, and Framer Motion animations. Use when creating dashboards, admin panels, or data-rich interfaces with a refined dark aesthetic.
react-native-r3f
TheMystic07
Expert guidance for React Three Fiber development with React, Vite, Tailwind CSS, and three.js
anthropic-frontend-design
chaibuilder
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.
infographic-structure-creator
antvis
Generate or update infographic Structure components for this repo (TypeScript/TSX in src/designs/structures). Use when asked to design, implement, or modify structure layouts (list/compare/sequence/hierarchy/relation/geo/chart), including layout logic, component composition, and registration.