Skip to content
Development
Skill

/motion-advanced

Advanced motion patterns for React / Next.js — drag & drop, gestures, text animations, SVG path drawing, custom hooks, imperative sequences (useAnimate), loaders, and the full API decision tree. Requires motion-foundations.

From plugin
ecc
239k200 skills72 agents109 commands7 hooks
+1
Install
$ npx -y skills add affaan-m/ECC --skill motion-advanced --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/motion-advanced

Context preview

The summary Claude sees to decide when to auto-load this skill.

Advanced motion patterns for React / Next.js — drag & drop, gestures, text animations, SVG path drawing, custom hooks, imperative sequences (useAnimate), loaders, and the full API decision tree. Requires motion-foundations.

SKILL.md

motion-advanced.SKILL.md
name: motion-advanced
description: Advanced motion patterns for React / Next.js — drag & drop, gestures, text animations, SVG path drawing, custom hooks, imperative sequences (useAnimate), loaders, and the full API decision tree. Requires motion-foundations.
version: 1.0
tags: [motion, animation, advanced, gestures, svg]
category: frontend
author: jeff

Motion Advanced

Complex, interactive, and physics-based animation patterns. Requires `motion-foundations` to be set up first. Use these when `motion-patterns` is not enough.

When to Activate

  • Building drag-to-dismiss sheets, swipe gestures, or reorderable lists
  • Animating text word-by-word, character-by-character, or as a live counter
  • Drawing SVG paths, morphing icons, or animating circular progress
  • Writing a custom animation hook (`useScrollReveal`, magnetic button, cursor follower)
  • Sequencing multi-step animations imperatively with `useAnimate`
  • Building spinners, shimmer skeletons, pulse indicators, or loading button states

Outputs

This skill produces:

  • Drag interactions: draggable cards, drag-to-dismiss sheets, `Reorder.Group` lists
  • Gesture hooks: swipe detection, long press, pinch outline
  • Text animation components: word reveal, character typewriter, number counter
  • SVG animation: path draw-on, icon morph, stroke progress ring
  • Custom hooks: `useScrollReveal`, `useHoverScale`, `useNavigationDirection`, `useInViewOnce`
  • Imperative sequences via `useAnimate` with interrupt-safe `async/await`
  • Loader components: spinner, shimmer, pulse dot, progress bar, button loading state

Principles

  • Physics-based motion (`useSpring`, `springs.*`) always feels more natural than duration-based for direct manipulation.
  • `useMotionValue` + `useTransform` computes derived values without triggering re-renders.
  • `useAnimate` sequences are imperative and interrupt-safe — calling `animate()` mid-flight cancels the previous animation automatically.
  • Motion values (`useMotionValue`, `useSpring`) are SSR-safe and do not cause hydration errors.

Rules

1. **Drag interactions must be tested on touch devices**, not just mouse. `drag` prop works on both but feel and threshold differ. 2. **Infinite animations must pause when `document.visibilityState === "hidden"`.** Background tabs must not consume GPU/CPU. 3. **Swipe threshold must be explicit.** Never infer intent from velocity alone; combine `offset` + `velocity` checks. 4. **`useAnimate` scope ref must be attached to a mounted DOM element.** Calling `animate()` before mount throws silently. 5. **Motion values must not be recreated on render.** `useMotionValue(0)` inside a component body is correct; `new MotionValue(0)` in a render is not. 6. **All token values are imported from `motion-foundations`.** No inline numbers. 7. **Custom hooks must handle cleanup.** Every `window.addEventListener` needs a matching `removeEventListener` in the `useEffect` return. 8. **SVG morphing requires equal path command counts.** Paths with different command structures snap instead of interpolating.

Decision Guidance

Choosing the right advanced API

| Scenario | API | | ------------------------------ | -------------------------------- | | Drag with physics on release | `drag` + `dragTransition: springs.release` | | Ordered drag-to-reorder list | `Reorder.Group` + `Reorder.Item` | | Dismiss on drag offset | `drag="y"` + `onDragEnd` offset check | | Swipe left/right | `drag="x"` + `onDragEnd` offset check | | Long press | `useLongPress` hook | | Value smoothed over time | `useSpring` | | Value derived from another | `useTransform` | | Multi-step sequence | `useAnimate` with `async/await` | | One-shot imperative animation | `animate()` from `motion` | | Text entering word by word | Stagger on `inline-block` spans | | SVG drawing on | `pathLength` 0 → 1 | | SVG morph | `d` attribute tween (equal commands) | | Circular progress | `strokeDashoffset` tween |

When to use `useSpring` vs a spring transition

| | `useSpring` | `transition: springs.*` | | -------------- | ---------------------------------------- | ----------------------- | | Use for | Cursor follower, pointer-tracked values | Discrete state changes | | Updates | Continuous, on every frame | Triggered by state change | | Interrupt | Smooth — physics picks up from velocity | Restarts from current value |

Core Concepts

useMotionValue + useTransform

Reactive computation without re-renders:

const x = useMotionValue(0)
const opacity = useTransform(x, [-200, 0, 200], [0, 1, 0])
// opacity updates every frame as x changes — no setState, no re-render

useAnimate

Returns `[scope, animate]`. The scope ref must be attached to a DOM element. `animate()` calls are interrupt-safe — calling mid-flight cancels the previous run.

const [scope, animate] = useAnimate()

async function play() {
  await animate(".step-1", { opacity: 1 }, { duration: 0.3 })
  await animate(".step-2", { x: 0 },       { duration: 0.4 })
        animate(".step-3", { scale: 1 },    { duration: 0.25 })  // fire and forget
}

return <div ref={scope}>...</div>

Code Examples

Draggable card

"use client"
import { motion } from "motion/react"
import { springs, motionTokens } from "@/lib/motion-tokens"

<motion.div
  drag
  dragConstraints={{ left: -100, right: 100, top: -100, bottom: 100 }}
  dragElastic={0.1}
  whileDrag={{
    scale: motionTokens.scale.pop,
    boxShadow: "0 16px 40px rgba(0,0,0,0.2)",
  }}
  dragTransition={springs.release}
/>

Drag-to-dismiss sheet

"use client"
import { motion, useMotionValue, useTransform } from "motion/react"

export function BottomSheet({ onClose }: { onClose: () => void }) {
  const y = useMotionValue(0)
  const opacity = useTransform(y, [0, 200], [1, 0])

  return (
    <motion.div
      drag="y"
      dragConstraints={{ top: 0 }}
      style={{ y, opacity }}
      onDragEnd={(_, info) => {
        // Rule 3: combine offset + velocity
        if (in
Read more
Ships withecc

Your agent can write code, but ECC gives it a coordinated engineering system and toolbox: it plans before it builds, verifies changes with tests, reviews its own work from a fresh context, remembers what matters, and turns repeated wins into reusable skills

Get the whole plugin