motion-foundations
A Claude Code skill from Affaan M's everything-claude-code repo that ships the base layer of a React / Next.js motion system — shared motionTokens (duration / easing / distance / scale), a five-config springs preset map, a shouldAnimate() gate, useReducedMotion-based accessibility defaults, and SSR-safe initial states. All downstream motion skills depend on this.
Establish tokens, springs, reduced-motion handling, and SSR-safe initial states before any animation work begins
Trigger phrases
Phrases that activate this skill when typed to Claude Code:
set up motion tokens for my Next.js appfix hydration mismatch from animation initial statereduced motion accessibility for framer-motion
What it does
motion-foundations is the base-layer motion skill in Affaan M’s everything-claude-code — see skills/motion-foundations. It defines every value, constraint, and rule that downstream motion skills (motion-ui, plus any motion-patterns / motion-advanced variants) inherit. The skill must load before any animation work begins; otherwise tokens, springs, and the shouldAnimate() gate end up defined ad-hoc per component.
Outputs are five concrete things: a shared motionTokens object (duration values from instant: 0.08s through crawl: 1.0s, easing curves as cubic bezier tuples, distance scale, scale scale), a five-config springs preset map (snappy for default UI, gentle for cards / modals, bouncy for playful moments, instant for tooltips, release for drag-end physics), the shouldAnimate() gate used by all components, accessibility-compliant defaults via useReducedMotion, and SSR-safe initial states with zero hydration warnings.
Eight non-negotiable rules: use motion/react only (never framer-motion in the same tree), initial must match server output (no exceptions), reduced motion overrides everything (opacity-only ≤ 0.2s is the only allowed fallback), never animate layout properties (width, height, top, left, margin, padding are banned from animate — transform and opacity only), all tokens come from motionTokens, all springs come from the springs map, "use client" required on every motion file, never read window or navigator at module level.
When to use it
- Starting any animated component from scratch — load this before writing motion code
- Setting up tokens, spring presets, or easing values for a fresh design system
- Implementing
prefers-reduced-motioncorrectly with the four-tier disable logic (reduced-motion / low-end-device / off-screen / decorative) - Debugging hydration mismatches caused by animation initial states diverging from server output
- Evaluating whether an animation should exist at all (guide attention / communicate state / preserve spatial continuity — otherwise remove)
When not to reach for it:
- Writing the actual animated components — that’s
motion-ui(which depends on this skill) - Native Apple platforms — SwiftUI / UIKit animation is a different stack
- CSS-only animations — the skill is
motion/react-shaped - Server components that don’t render motion — no motion files needed
Install
From affaan-m/everything-claude-code at skills/motion-foundations/. Drop the folder into ~/.claude/skills/motion-foundations/. The skill is markdown + reference TypeScript snippets — the runtime is whatever project imports motion/react (the modern package; framer-motion is the legacy import path the skill is explicit about not mixing with). Token / spring objects get committed into the project’s lib/ directory; the skill doesn’t ship them as a package.
What a session looks like
- Drop in the tokens.
lib/motion-tokens.tsexportsmotionTokenswith the four scales (duration / easing / distance / scale). Hard-coded values in component files are explicitly banned. - Drop in the springs.
lib/motion-springs.tsexports the five named configs. Inlinestiffness/dampingvalues are banned. - Set up
useReducedMotion+shouldAnimate(). The four-tier disable logic: reduced motion preference, low-end device, off-screen, decorative-with-no-purpose. - Pick durations by purpose.
instantfor tooltip / focus ring / badge updates,fastfor button feedback,normalfor modal open / card expand,slowfor hero entrance,crawlfor deliberate storytelling — used sparingly. - Pick springs by feel.
snappyis the default;gentlefor landing softly;bouncyfor empty states / onboarding;instantfor popovers;releasefor drag-end. - Verify SSR safety.
initialmatches server output. Nowindowreads at module level."use client"on every motion file. - Hand off to
motion-ui. Components consume the tokens and springs; the foundations skill stops here.
The discipline that makes it work: shared primitives. Without the tokens / springs / gate, every component invents its own duration values and reduced-motion handling — the design system fragments and hydration bugs become routine. The wedge is committing to one source of truth.
Receipts
TODO — to be filled in from a real session. Once the foundations have been wired into a real Next.js app, this section will capture: which duration token the operator actually defaulted to (the normal 0.35s vs. something faster / slower based on the project’s feel), whether the shouldAnimate() four-tier disable logic caught a low-end-device case that would’ve otherwise dropped frames, how often the initial mismatch rule actually fired and surfaced a hydration warning, and whether the eight non-negotiable rules survived contact with a real designer pushing for a layout-property animation.
Source and attribution
From Affaan M’s everything-claude-code — an MIT-licensed skill collection covering harness construction, agent ops, video, payments, and platform-specific patterns.
License: MIT.
Quoting the existential rule verbatim: “Motion must do at least one of the following or it must be removed: guide attention, communicate state, preserve spatial continuity.” Three purposes. Decorative motion fails the test by definition — that’s the wedge that keeps a motion system useful instead of distracting.