# motion-ui

> A Claude Code skill from Affaan M's everything-claude-code repo for the React / Next.js UI motion system layer — buttons, modals, menus, state transitions, navigation continuity — built on motion/react with mandatory reduced-motion support and device adaptation. Consumes motion-foundations tokens and springs.

**Use case**: Build interactive component motion (buttons, modals, menus, state transitions) on top of the motion-foundations layer

**Canonical URL**: https://agentcookbooks.com/skills/motion-ui/

**Topics**: claude-code, skills, animation, design

**Trigger phrases**: "animate this modal open", "framer-motion button feedback", "shared element transition for navigation"

**Source**: [Affaan M](https://github.com/affaan-m/everything-claude-code/tree/main/skills/motion-ui)

**License**: MIT

---

## What it does

`motion-ui` is the component-layer motion skill in [Affaan M's everything-claude-code](https://github.com/affaan-m/everything-claude-code) — see [skills/motion-ui](https://github.com/affaan-m/everything-claude-code/tree/main/skills/motion-ui). It builds on `motion-foundations` (tokens + springs + `shouldAnimate()` gate + reduced-motion handling) and focuses on production component motion: buttons, modals, menus, state transitions (loading → loaded, open → closed), and navigation continuity (shared elements, crossfade).

Three principles repeated from foundations because they apply at the component layer too: motion must guide attention OR communicate state OR preserve spatial continuity, accessibility (reduced motion) is mandatory not optional, device adaptation (low-end fallback) is part of the contract. The skill is explicit about the package boundary — `motion/react` is the default for current Motion-for-React projects; `framer-motion` is the legacy import path for projects that still depend on it. Mixing the two causes conflicting internal schedulers and broken `AnimatePresence` contexts so components from one package won't coordinate exit animations with the other.

The token bridge is concrete: components import `motionTokens` from `@/lib/motionTokens` and use `motionTokens.duration.normal` + `motionTokens.easing.smooth` + `motionTokens.distance.md` directly in `transition` and `initial` / `animate` props. Inline numeric durations or hardcoded easing tuples are banned by the foundations layer — `motion-ui` enforces consumption from the shared object. The "avoid using motion when" list is the negative space: purely decorative, reduces usability, impacts performance — remove instead of optimizing.

## When to use it

- Interactive components (buttons with press feedback, modals opening / closing, menus expanding)
- State transitions (loading → loaded, open → closed, success / error states)
- Navigation continuity — shared elements between routes, crossfade page transitions
- Layout-change animations where preserving spatial continuity matters
- Form interaction motion (focus rings, error shake, submit success)

When *not* to reach for it:

- Setting up the base layer (tokens / springs / reduced-motion) — that's `motion-foundations`
- Native iOS / macOS animations — that's `swiftui-patterns` / `liquid-glass-design`
- Video animation primitives — that's `manim-video` or `remotion-video-creation`
- Decorative motion with no UX purpose — remove instead of building

## Install

From [affaan-m/everything-claude-code](https://github.com/affaan-m/everything-claude-code) at `skills/motion-ui/`. Drop the folder into `~/.claude/skills/motion-ui/`. Runtime needs `motion` (the package; imports from `motion/react`) — `npm install motion` per the upstream. Optional `framer-motion` for legacy projects, but the skill is explicit that mixing the two in the same project is a bug. Depends on `motion-foundations` being in the project first (the `motionTokens` / `springs` / `shouldAnimate()` references all assume the foundations layer landed).

## What a session looks like

1. **Pick the motion purpose.** Modal open = communicate state. Button press = communicate state + guide attention. Tab switch = preserve spatial continuity. If none, the skill says remove the motion.
2. **Pick a duration token.** `fast` for button feedback, `normal` for modal / card, `slow` for hero entrance. Imported from `motionTokens`, no inline values.
3. **Pick a spring or easing.** `snappy` for default UI, `gentle` for cards / modals, `instant` for popovers. Springs go in the `transition` object's `type: "spring"`; for non-spring transitions, `motionTokens.easing.smooth` for natural motion, `motionTokens.easing.sharp` for snappy / mechanical feel.
4. **Wire `initial` + `animate` + `exit`.** Use only `transform` and `opacity` — layout properties are banned by foundations. `AnimatePresence` wraps the conditionally-rendered component for exit animations.
5. **Reduced-motion fallback.** If `useReducedMotion()` is true, transforms get disabled; only opacity fades ≤ 0.2s are allowed.
6. **Test across devices.** Low-end-device gate from foundations covers the perf fallback. The skill's stance: responsiveness > smoothness.

The discipline that makes it work: tokens-as-source-of-truth. Once a component imports `motionTokens.duration.normal`, fixing the duration for the whole design system is one edit to the foundations object. Without that, "make the modals snappier" becomes a global find-replace across every motion file.

## Receipts

_TODO — to be filled in from a real session. Once the motion system has been wired into a real production app, this section will capture: which spring preset (snappy / gentle / bouncy / instant / release) got the most use vs. which were defined and never picked, how often the layout-property ban (no `width` / `height` / `top` / `margin` / `padding`) surfaced as a fight with a designer's spec, whether `motion/react` vs. `framer-motion` package coexistence actually broke `AnimatePresence` as the skill warns or stayed stable, and the actual frame-rate impact of reduced motion on the worst case animation in the app._

## Source and attribution

From [Affaan M's everything-claude-code](https://github.com/affaan-m/everything-claude-code/tree/main/skills/motion-ui) — an MIT-licensed skill collection covering harness construction, agent ops, video, payments, and platform-specific patterns.

License: MIT.

Quoting the package-mixing warning verbatim: *"Do not mix. Mixing causes conflicting internal schedulers and broken AnimatePresence contexts."* That's the wedge — most "framer motion is broken" reports trace back to two packages in the same dependency graph; the skill enforces single-source imports as the first thing to check.