motion

SKILL.md

Motion Animation Library

Motion (package: motion, formerly framer-motion) is the industry-standard animation library for JavaScript, React, and Vue.

Installation

npm install motion      # React/JS
npm install motion-v    # Vue

Platform Quick Reference

JavaScript

import { animate, scroll, inView, stagger, hover, press } from "motion"

// Basic animation
animate("#box", { x: 100, opacity: 1 })

// With spring physics
animate(element, { scale: 1.2 }, { type: "spring", stiffness: 300, damping: 30 })

// Staggered list
animate("li", { opacity: 1 }, { delay: stagger(0.1) })

// Scroll-linked
scroll(animate("#progress", { scaleX: [0, 1] }))

// Viewport detection
inView(".card", ({ target }) => {
  animate(target, { opacity: 1, y: 0 })
})

// Gestures
hover(".btn", el => {
  animate(el, { scale: 1.1 })
  return () => animate(el, { scale: 1 })
})

press(".btn", el => {
  animate(el, { scale: 0.95 })
  return () => animate(el, { scale: 1 })
})

React

import { motion, AnimatePresence, useScroll, useTransform } from "motion/react"

// Basic motion component
<motion.div
  initial={{ opacity: 0, y: 20 }}
  animate={{ opacity: 1, y: 0 }}
  exit={{ opacity: 0 }}
  transition={{ type: "spring" }}
/>

// Gestures
<motion.button
  whileHover={{ scale: 1.1 }}
  whileTap={{ scale: 0.95 }}
  drag="x"
  dragConstraints={{ left: 0, right: 100 }}
/>

// Layout animations
<motion.div layout layoutId="shared-element" />

// Scroll animations
const { scrollYProgress } = useScroll()
const y = useTransform(scrollYProgress, [0, 1], [0, -300])
<motion.div style={{ y }} />

Vue

<script setup>
import { motion, AnimatePresence } from "motion-v"
</script>

<template>
  <motion.div
    :initial="{ opacity: 0 }"
    :animate="{ opacity: 1 }"
    :exit="{ opacity: 0 }"
    :whileHover="{ scale: 1.1 }"
  />
</template>

Core APIs

API Platform Description
animate() All Animate elements with spring/tween
scroll() JS Scroll-linked animations
inView() JS Viewport detection
hover() JS Hover gesture
press() JS Press/tap gesture
stagger() All Stagger delays

React-Specific

API Description
motion.div Motion-enhanced elements
AnimatePresence Exit animations
LayoutGroup Coordinate layout animations
LazyMotion Bundle optimization (~4.6kb)
useMotionValue() Reactive animation values
useTransform() Derived motion values
useSpring() Spring-animated values
useScroll() Scroll progress
useAnimate() Imperative control

Transition Options

Spring (Physics-based)

{
  type: "spring",
  stiffness: 300,    // Higher = snappier
  damping: 30,       // Higher = less bounce
  mass: 1,           // Higher = more momentum
  bounce: 0.25,      // 0-1, alternative to stiffness/damping
  visualDuration: 0.5
}

Tween (Duration-based)

{
  duration: 0.5,
  ease: "easeInOut", // or cubic bezier [0.4, 0, 0.2, 1]
  delay: 0.2,
  repeat: Infinity,
  repeatType: "reverse" // "loop" | "mirror"
}

Easing Functions

"linear", "easeIn", "easeOut", "easeInOut", "circIn", "circOut", "backIn", "backOut", "anticipate"

Common Patterns

AnimatePresence (Exit Animations)

// CRITICAL: AnimatePresence must stay mounted, children need unique keys
<AnimatePresence>
  {isVisible && (
    <motion.div
      key="modal"
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    />
  )}
</AnimatePresence>

Layout Animations

<motion.div layout>
  {isExpanded ? <FullContent /> : <Summary />}
</motion.div>

// Shared element transitions
<motion.div layoutId="card-123" />

Scroll Animations

// Viewport-triggered
<motion.div
  initial={{ opacity: 0, y: 50 }}
  whileInView={{ opacity: 1, y: 0 }}
  viewport={{ once: true, margin: "-100px" }}
/>

// Scroll-linked
const { scrollYProgress } = useScroll()
const y = useTransform(scrollYProgress, [0, 1], [0, -300])
<motion.div style={{ y }} />

Drag Gestures

<motion.div
  drag="x"
  dragConstraints={{ left: 0, right: 300 }}
  dragElastic={0.2}
  dragMomentum={true}
  dragSnapToOrigin
/>

SVG Line Drawing

<motion.path
  initial={{ pathLength: 0 }}
  animate={{ pathLength: 1 }}
  transition={{ duration: 2, ease: "easeInOut" }}
/>

Variants (Orchestration)

const container = {
  hidden: { opacity: 0 },
  show: {
    opacity: 1,
    transition: { staggerChildren: 0.1 }
  }
}

const item = {
  hidden: { opacity: 0, y: 20 },
  show: { opacity: 1, y: 0 }
}

<motion.ul variants={container} initial="hidden" animate="show">
  <motion.li variants={item} />
  <motion.li variants={item} />
</motion.ul>

Performance

Bundle Size Optimization

// Full bundle: ~34 KB
import { motion } from "motion/react"

// Optimized: ~4.6 KB
import { LazyMotion, domAnimation, m } from "motion/react"

<LazyMotion features={domAnimation}>
  <m.div animate={{ x: 100 }} />
</LazyMotion>

// Minimal: 2.3 KB
import { useAnimate } from "motion/react"

Avoid Tailwind Conflicts

// WRONG - causes stuttering
<motion.div className="transition-all" animate={{ x: 100 }} />

// CORRECT
<motion.div animate={{ x: 100 }} />

Next.js Integration

App Router (RSC)

// components/motion-client.tsx
"use client"
import * as motion from "motion/react-client"
export { motion }

// app/page.tsx
import { motion } from "@/components/motion-client"

Direct Client Component

"use client"
import { motion } from "motion/react"

Accessibility

import { MotionConfig } from "motion/react"

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

Troubleshooting

AnimatePresence Exit Not Working

Problem: Exit animations don't play Causes:

  1. AnimatePresence unmounts with child
  2. Missing unique key prop
  3. Child not direct descendant

Solution:

// WRONG
{isVisible && <AnimatePresence><motion.div /></AnimatePresence>}

// CORRECT
<AnimatePresence>
  {isVisible && <motion.div key="unique" exit={{ opacity: 0 }} />}
</AnimatePresence>

Scrollable Container Layout Issues

<motion.div layoutScroll style={{ overflow: "auto" }}>
  <motion.div layout />
</motion.div>

Fixed Position Layout Issues

<motion.div layoutRoot style={{ position: "fixed" }}>
  <motion.div layout />
</motion.div>

Layout Scale Distortion

// Set borderRadius/boxShadow via style for scale correction
<motion.div layout style={{ borderRadius: 20, boxShadow: "..." }} />

Large List Performance

Use virtualization libraries: react-window, react-virtuoso, @tanstack/react-virtual

Reference Documentation

See reference/ folder for detailed platform-specific docs:

  • reference/react.md - React components and hooks
  • reference/javascript.md - Vanilla JS APIs
  • reference/vue.md - Vue directives and components
  • reference/examples.md - Example index by category

Resources

Weekly Installs
20
First Seen
Feb 3, 2026
Installed on
opencode20
amp20
codex20
gemini-cli17
github-copilot17
kimi-cli17