AI Skill Library

Motion Design Principles

Easing curves, duration guidelines, choreography, spring physics, 12 principles.

animationdesignuxmotion
# Motion Design Principles

## Disney's 12 principles (UI application)
- **Squash & Stretch**: scale buttons on press `scale(0.95)`, bounce on release.
- **Anticipation**: slight wind-up before action (button dip before launch).
- **Staging**: direct attention -- animate the important thing, keep rest still.
- **Follow-through**: elements overshoot then settle (spring easing).
- **Ease in / Ease out**: never use `linear` for physical objects.
- **Arc**: curved paths feel natural. Use `motionPath` for element travel.
- **Secondary action**: supporting animations reinforce the main one.
- **Timing**: short = energetic, long = heavy. Match object weight.
- **Exaggeration**: slightly over-animate for emphasis, but stay tasteful in UI.

## Easing reference
```ts
// Standard eases (Material Design / Apple HIG)
const EASES = {
  standard:      'cubic-bezier(0.2, 0, 0, 1)',     // most UI transitions
  decelerate:    'cubic-bezier(0, 0, 0, 1)',        // enter screen
  accelerate:    'cubic-bezier(0.3, 0, 1, 1)',      // exit screen
  emphasized:    'cubic-bezier(0.2, 0, 0, 1)',      // hero transitions
  spring:        'cubic-bezier(0.34, 1.56, 0.64, 1)', // overshoot
  bounce:        'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
}
// GSAP equivalents
// power2.out = decelerate, power2.in = accelerate, elastic.out = spring
```

## Duration guidelines
| Element size | Duration |
|---|---|
| Micro (icon, badge) | 100-150ms |
| Small (tooltip, chip) | 150-200ms |
| Medium (card, modal) | 250-350ms |
| Large (drawer, page) | 350-500ms |
| Complex choreography | 500-700ms |
- Fast in, slow out: elements entering take slightly longer than leaving.
- Mobile: 20-30% shorter than desktop.

## Spring physics (Framer Motion)
```tsx
// Spring feels physical, responds to interruption
<motion.div
  animate={{ x: 100 }}
  transition={{ type: 'spring', stiffness: 300, damping: 30, mass: 1 }}
/>
// Stiffness: higher = faster/snappier
// Damping: lower = more bouncy
// Mass: higher = heavier, slower

// Common presets
// Snappy: stiffness:400, damping:40
// Gentle: stiffness:150, damping:20
// Bouncy: stiffness:300, damping:10
```

## Choreography (stagger)
```ts
// Items should enter like a wave, not all at once
// Stagger = 20-60ms between each item
const variants = {
  hidden: {},
  show: { transition: { staggerChildren: 0.05, delayChildren: 0.1 } },
}
// Rule: stagger * num_items < 300ms total
// For 10 items: 30ms stagger = 300ms total ✓
// For 10 items: 100ms stagger = 1s total ✗ (too slow)
```

## Reduced motion
```ts
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches

// Framer Motion
const transition = prefersReduced
  ? { duration: 0.01 }
  : { type: 'spring', stiffness: 300 }

// GSAP
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
  gsap.globalTimeline.timeScale(100)  // instant
}
```

## Page transitions (Next.js App Router)
```tsx
// layout.tsx -- wrap page content
<AnimatePresence mode="wait">
  <motion.div
    key={pathname}
    initial={{ opacity: 0, y: 8 }}
    animate={{ opacity: 1, y: 0 }}
    exit={{ opacity: 0, y: -8 }}
    transition={{ duration: 0.25, ease: [0.2, 0, 0, 1] }}
  >
    {children}
  </motion.div>
</AnimatePresence>
```

## Don'ts
- Never animate `width`/`height` (use `transform: scaleX/scaleY` instead)
- Don't animate more than 3 properties simultaneously
- Avoid `all` in CSS transitions (animates hidden properties too)
- Never block user input during animation
- Don't use the same duration for all elements

API: /api/skills/motion-design-principles