Claude-skill-registry animation

Expert guidance for creating premium, performant animations in React using Motion (motion.dev). Covers all animation types, best practices, accessibility, and performance optimization.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/animation" ~/.claude/skills/majiayu000-claude-skill-registry-animation && rm -rf "$T"
manifest: skills/data/animation/SKILL.md
source content

Animation Skill

You are an expert in creating world-class, premium animations for React applications using Motion (motion.dev), the modern animation library for React.

Installation

npm install motion

Import from

"motion/react"
:

import { motion } from "motion/react";

Core Concepts

1. The
<motion />
Component

The foundation of all animations in Motion. It's a React component that wraps any HTML or SVG element and supercharges it with animation capabilities.

Basic Usage:

<motion.div animate={{ x: 100 }} />
<motion.button whileHover={{ scale: 1.1 }} />
<motion.svg whileTap={{ rotate: 90 }} />

Key Props:

  • initial
    : Starting visual state (can be an object, variant name, or
    false
    to disable enter animation)
  • animate
    : Target state to animate to
  • exit
    : State to animate to when removed from DOM (requires
    <AnimatePresence>
    )
  • transition
    : Customize animation timing and easing
  • variants
    : Reusable animation states
  • style
    : React style prop with support for MotionValues

Animation Types

2. Enter Animations

Components automatically animate to

animate
values when they mount.

<motion.div initial={{ opacity: 0, y: 50 }} animate={{ opacity: 1, y: 0 }} />

Disable enter animation:

<motion.div initial={false} animate={{ opacity: 1 }} />

3. Gesture Animations

Motion provides declarative gesture handlers that feel better than CSS or plain JavaScript events.

Hover

<motion.button
  whileHover={{ scale: 1.1, backgroundColor: "#ff0000" }}
  transition={{ duration: 0.2 }}
/>

Tap/Press

<motion.button
  whileTap={{ scale: 0.95 }}
  onTap={() => console.log("Tapped!")}
/>

Focus

<motion.input whileFocus={{ borderColor: "#0099ff" }} />

Drag

<motion.div
  drag
  dragConstraints={{ left: -100, right: 100, top: -100, bottom: 100 }}
  whileDrag={{ scale: 1.1 }}
/>

Drag Options:

  • drag={true}
    : Drag in all directions
  • drag="x"
    : Horizontal only
  • drag="y"
    : Vertical only
  • dragConstraints
    : Limits (object or ref to container)
  • dragElastic
    : Elasticity when out of bounds (0-1, default: 0.5)
  • dragMomentum
    : Enable momentum on release (default: true)

4. Scroll Animations

Scroll-Triggered (whileInView)

Animate when element enters viewport:

<motion.div
  initial={{ opacity: 0, y: 100 }}
  whileInView={{ opacity: 1, y: 0 }}
  viewport={{ once: true, amount: 0.5 }}
/>

viewport options:

  • once
    : Only trigger once (default: false)
  • amount
    : How much of element must be visible ("some", "all", or 0-1)
  • margin
    : Offset from viewport edges
  • root
    : Custom scroll container

Scroll-Linked (useScroll)

Link animations directly to scroll position:

const { scrollYProgress } = useScroll();

return <motion.div style={{ scaleX: scrollYProgress }} />;

useScroll returns:

  • scrollX
    ,
    scrollY
    : Scroll offset in pixels
  • scrollXProgress
    ,
    scrollYProgress
    : Scroll progress (0-1)

Advanced scroll tracking:

const { scrollYProgress } = useScroll({
  target: ref, // Element to track
  offset: ["start end", "end start"], // When to start/end
});

5. Layout Animations

Motion uses FLIP (First, Last, Invert, Play) to animate layout changes using performant transforms.

Simple Layout Animation

<motion.div layout />

Shared Element Transitions

{
  isExpanded ? <motion.div layoutId="card" /> : <motion.div layoutId="card" />;
}

Layout Props:

  • layout
    : Animate size and position changes
  • layoutId
    : Shared element transitions between components
  • layoutDependency
    : Force recalculation on value change
  • layoutScroll
    : Animate within scrollable containers

Performance Note: Layout animations run at 60fps by animating transforms, not layout properties.


6. Exit Animations

Wrap components with

<AnimatePresence>
to enable exit animations:

<AnimatePresence mode="wait">
  {isVisible && (
    <motion.div
      key="modal"
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    />
  )}
</AnimatePresence>

AnimatePresence Props:

  • mode
    : "sync" (default), "wait", "popLayout"
  • initial
    : Disable initial animations (default: true)
  • onExitComplete
    : Callback when all exit animations complete

7. SVG Animations

Motion supports SVG-specific animations:

// Line drawing
<motion.path
  initial={{ pathLength: 0 }}
  animate={{ pathLength: 1 }}
/>

// Morphing (same number of points)
<motion.path
  animate={{ d: "M10,10 L20,20 ..." }}
/>

// Attributes
<motion.circle
  animate={{
    cx: 50,
    r: 20,
    fill: "#ff0000"
  }}
/>

Advanced Features

8. Variants

Reusable animation states with propagation and orchestration:

const variants = {
  hidden: { opacity: 0, y: 20 },
  visible: {
    opacity: 1,
    y: 0,
    transition: {
      delay: 0.2,
      when: "beforeChildren",
      staggerChildren: 0.1,
    },
  },
};

<motion.ul variants={variants} initial="hidden" animate="visible">
  <motion.li variants={variants} />
  <motion.li variants={variants} />
</motion.ul>;

Variant Orchestration:

  • when
    : "beforeChildren", "afterChildren"
  • staggerChildren
    : Delay between child animations
  • delayChildren
    : Delay before first child
  • staggerDirection
    : 1 (forward) or -1 (backward)

Dynamic Variants:

const variants = {
  visible: (i) => ({
    opacity: 1,
    transition: { delay: i * 0.1 },
  }),
};

<motion.div custom={index} variants={variants} />;

9. Transitions

Configure animation timing and behavior:

Tween (Time-based)

<motion.div
  animate={{ x: 100 }}
  transition={{
    duration: 0.5,
    ease: "easeInOut", // or [.17,.67,.83,.67] for cubic-bezier
  }}
/>

Easing options: "linear", "easeIn", "easeOut", "easeInOut", "circIn", "circOut", "circInOut", "backIn", "backOut", "backInOut", "anticipate"

Spring (Physics-based)

<motion.div
  animate={{ x: 100 }}
  transition={{
    type: "spring",
    stiffness: 100,
    damping: 10,
    mass: 1,
  }}
/>

Spring Presets:

  • bounce: 0.25
    : Natural feel (default)
  • bounce: 0
    : No bounce
  • bounce: 0.6
    : Very bouncy

Or use

duration
with
bounce
:

transition={{ duration: 0.8, bounce: 0.3 }}

Keyframes

<motion.div
  animate={{
    x: [0, 100, 0],
    backgroundColor: ["#ff0000", "#00ff00", "#0000ff"],
  }}
  transition={{
    duration: 2,
    times: [0, 0.5, 1], // Optional: control keyframe timing
    ease: ["easeIn", "easeOut"], // Different easing per segment
  }}
/>

10. Motion Values

Track and compose values without triggering re-renders:

const x = useMotionValue(0);
const opacity = useTransform(x, [0, 100], [1, 0]);

return <motion.div style={{ x, opacity }} />;

Key Hooks:

useMotionValue

const x = useMotionValue(0);
x.set(100); // Update without re-render
x.get(); // Get current value

useTransform

// Map one range to another
const y = useTransform(scrollY, [0, 300], [0, 100]);

// Custom function
const color = useTransform(x, (latest) =>
  latest > 50 ? "#ff0000" : "#0000ff",
);

useSpring

const x = useMotionValue(0);
const smoothX = useSpring(x, {
  stiffness: 100,
  damping: 20,
});

useScroll

const { scrollYProgress } = useScroll({
  target: containerRef,
  offset: ["start start", "end end"],
});

useInView

const ref = useRef(null);
const isInView = useInView(ref, {
  once: true,
  amount: 0.5,
});

useVelocity

const x = useMotionValue(0);
const xVelocity = useVelocity(x);

Premium Components

11. AnimateNumber

Animate number changes with layout animations:

import { AnimateNumber } from "motion/react";

<AnimateNumber value={count} transition={{ duration: 0.5 }} />;

12. Carousel

Production-ready carousel with infinite scrolling:

import { Carousel } from "motion/react";

<Carousel.Root loop>
  <Carousel.Viewport>
    {items.map((item) => (
      <Carousel.Item key={item.id}>{item.content}</Carousel.Item>
    ))}
  </Carousel.Viewport>
  <Carousel.Controls />
</Carousel.Root>;

13. Cursor

Custom cursor with auto-adaptation to interactive elements:

import { Cursor } from "motion/react";

<Cursor className="custom-cursor" />;

14. Ticker

Infinite scrolling marquee:

import { Ticker } from "motion/react";

<Ticker speed={50}>
  <div>Scrolling content...</div>
</Ticker>;

15. Typewriter

Realistic typing animation:

import { Typewriter } from "motion/react";

<Typewriter text="Hello, world!" speed={50} />;

16. Reorder

Drag-to-reorder lists:

import { Reorder } from "motion/react";

<Reorder.Group values={items} onReorder={setItems}>
  {items.map((item) => (
    <Reorder.Item key={item} value={item}>
      {item}
    </Reorder.Item>
  ))}
</Reorder.Group>;

Performance & Optimization

17. LazyMotion

Reduce bundle size by loading features on demand:

import { LazyMotion, domAnimation } from "motion/react";

<LazyMotion features={domAnimation} strict>
  <App />
</LazyMotion>;

Features:

  • domAnimation
    : ~30kb (gestures, drag, layout)
  • domMax
    : ~60kb (all features)
  • Async loading:
    features={() => import('./features')}

18. MotionConfig

Configure all child motion components:

<MotionConfig
  transition={{ duration: 0.3 }}
  reducedMotion="user" // Respect prefers-reduced-motion
>
  <App />
</MotionConfig>

19. Performance Tips

Hardware Acceleration: Motion automatically uses transforms for layout animations (60fps).

Avoid animating:

width
,
height
,
top
,
left
directly. Use
scale
and
x
/
y
instead.

Good:

<motion.div animate={{ x: 100, scale: 1.2 }} />

Bad:

<motion.div animate={{ left: 100, width: 200 }} /> // Forces layout recalc

Will-change: Motion automatically applies

will-change
when needed.

Reduce render triggers: Use MotionValues to update without re-renders.


Accessibility

20. Reduced Motion

Respect user preferences:

const shouldReduceMotion = useReducedMotion();

<motion.div
  animate={shouldReduceMotion ? { opacity: 1 } : { opacity: 1, y: 0 }}
/>;

Or globally:

<MotionConfig reducedMotion="user">
  <App />
</MotionConfig>

Best Practices

21. Premium Animation Guidelines

  1. Natural Motion: Use spring animations for interactive elements

    transition={{ type: "spring", bounce: 0.25 }}
    
  2. Micro-interactions: Add subtle hover/tap feedback

    whileHover={{ scale: 1.05 }}
    whileTap={{ scale: 0.98 }}
    
  3. Stagger Children: Create elegant cascading effects

    variants={{
      visible: {
        transition: { staggerChildren: 0.1 }
      }
    }}
    
  4. Smooth Scroll Links: Use scroll-linked animations for parallax and progress

    const { scrollYProgress } = useScroll();
    
  5. Exit Animations: Always animate elements out, don't just remove them

    <AnimatePresence mode="wait">{/* content */}</AnimatePresence>
    
  6. Layout Animations: Use

    layout
    prop for seamless size/position transitions

    <motion.div layout />
    
  7. Performant Transforms: Use scale/translate over width/height

    // Good
    animate={{ scale: 1.2, x: 100 }}
    
    // Bad
    animate={{ width: 200, left: 100 }}
    

Common Patterns

22. Page Transitions

<AnimatePresence mode="wait">
  <motion.div
    key={router.pathname}
    initial={{ opacity: 0, x: -20 }}
    animate={{ opacity: 1, x: 0 }}
    exit={{ opacity: 0, x: 20 }}
    transition={{ duration: 0.3 }}
  >
    {children}
  </motion.div>
</AnimatePresence>

23. Modal/Dialog

<AnimatePresence>
  {isOpen && (
    <>
      <motion.div
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
        onClick={onClose}
        className="backdrop"
      />
      <motion.div
        initial={{ opacity: 0, scale: 0.9, y: 20 }}
        animate={{ opacity: 1, scale: 1, y: 0 }}
        exit={{ opacity: 0, scale: 0.9, y: 20 }}
        className="modal"
      >
        {content}
      </motion.div>
    </>
  )}
</AnimatePresence>

24. Accordion

<motion.div layout>
  <motion.button onClick={toggle} layout>
    {title}
  </motion.button>
  <AnimatePresence initial={false}>
    {isOpen && (
      <motion.div
        initial={{ height: 0, opacity: 0 }}
        animate={{ height: "auto", opacity: 1 }}
        exit={{ height: 0, opacity: 0 }}
      >
        {content}
      </motion.div>
    )}
  </AnimatePresence>
</motion.div>

25. Parallax Scroll

const { scrollYProgress } = useScroll();
const y = useTransform(scrollYProgress, [0, 1], [0, -500]);

return <motion.div style={{ y }}>{content}</motion.div>;

26. Hover Cards

<motion.div
  whileHover={{
    scale: 1.05,
    boxShadow: "0px 10px 30px rgba(0,0,0,0.2)",
  }}
  transition={{ type: "spring", stiffness: 300 }}
>
  {content}
</motion.div>

Troubleshooting

Common Issues

Layout animations not working:

  • Ensure element has defined dimensions
  • Check parent isn't
    display: inline
  • Verify no
    transform
    in CSS (conflicts with Motion)

Exit animations not working:

  • Must be direct child of
    <AnimatePresence>
  • Ensure unique
    key
    prop
  • Check component isn't conditional before
    <AnimatePresence>

Performance issues:

  • Avoid animating layout properties directly
  • Use
    will-change
    sparingly (Motion handles this)
  • Consider
    LazyMotion
    for bundle optimization

SVG animations broken:

  • Set
    layout="position"
    instead of
    layout={true}
  • Use
    attrX
    /
    attrY
    for SVG positioning

Resources


Summary

Motion is the most powerful animation library for React, offering:

  • ✅ Declarative API with
    <motion />
    components
  • ✅ Gesture support (hover, tap, drag, focus)
  • ✅ Layout animations using FLIP
  • ✅ Scroll-triggered and scroll-linked animations
  • ✅ Exit animations with
    <AnimatePresence>
  • ✅ SVG animation support
  • ✅ Motion values for performance
  • ✅ Accessibility with reduced motion support
  • ✅ Premium components (Carousel, Ticker, Typewriter, etc.)
  • ✅ Tree-shakeable and optimizable with LazyMotion

Remember: Always prioritize performance by using transforms, respect user preferences with reduced motion, and create premium experiences with natural spring animations and thoughtful micro-interactions.