AI Skill Library

Framer Motion

React animation library: variants, gestures, layout animations, scroll, exit.

framer-motionanimationreactfrontend
# Framer Motion

## Install
```bash
npm install framer-motion
```

## Basic motion
```tsx
import { motion } from 'framer-motion'

// Animate on mount
<motion.div
  initial={{ opacity: 0, y: 20 }}
  animate={{ opacity: 1, y: 0 }}
  transition={{ duration: 0.5, ease: 'easeOut' }}
/>

// Hover + tap
<motion.button
  whileHover={{ scale: 1.05 }}
  whileTap={{ scale: 0.95 }}
/>
```

## Variants (stagger children)
```tsx
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">
  {items.map(i => (
    <motion.li key={i} variants={item}>{i}</motion.li>
  ))}
</motion.ul>
```

## AnimatePresence (exit animations)
```tsx
import { AnimatePresence, motion } from 'framer-motion'

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

## Layout animations
```tsx
// Automatically animate layout changes
<motion.div layout />

// Shared layout transition between routes
<motion.div layoutId="hero-image" />
// On next page, same layoutId -> morphs between positions
```

## Scroll animations
```tsx
import { useScroll, useTransform, motion } from 'framer-motion'

function ParallaxHero() {
  const { scrollY } = useScroll()
  const y = useTransform(scrollY, [0, 500], [0, -150])
  return <motion.img style={{ y }} src="/hero.jpg" />
}

// Viewport entrance
<motion.section
  initial={{ opacity: 0 }}
  whileInView={{ opacity: 1 }}
  viewport={{ once: true, margin: '-100px' }}
/>
```

## useAnimate (imperative)
```tsx
import { useAnimate } from 'framer-motion'
const [scope, animate] = useAnimate()
await animate(scope.current, { x: 100 }, { duration: 0.5 })
await animate('.child', { opacity: 0 }, { delay: stagger(0.1) })
```

## Gestures
```tsx
<motion.div
  drag
  dragConstraints={{ left: -100, right: 100, top: -50, bottom: 50 }}
  dragElastic={0.1}
  onDragEnd={(e, info) => console.log(info.offset)}
/>
```

API: /api/skills/framer-motion