Communitygithub.com

Motion-Advanced

Fortgeschrittene Animationsmuster für React / Next.js — Drag & Drop, Gesten, Textanimationen, SVG-Pfadzeichnung, benutzerdefinierte Hooks, imperative Sequenzen (useAnimate), Ladeanimationen und der vollständige API-Entscheidungsbaum. Erfordert motion-foundations. Verwenden Sie dies beim Erstellen von Drag-and-Drop, Gesten, Text- oder SVG-Animationen oder imperativen Animationssequenzen in React oder Next.js.

Was ist Motion-Advanced?

Dieses Skill konzentriert sich auf komplexe, interaktive und physikbasierte Animationen in React/Next.js, die über einfache Muster hinausgehen. Es behandelt Drag-Interaktionen (ziehkarten, zum Verwerfen wischen, neu anordenbare Listen), Gesten (Wischen, langes Drücken), Textanimationen (Wort-für-Wort-Enthüllung, Schreibmaschine, Zahlenzähler), SVG-Animationen (Pfadzeichnung, Ikonenmorphing, Fortschrittsringe) und benutzerdefinierte Hooks wie `useScrollReveal` und Cursor-Follower. Es betont den Einsatz von Physik (`useSpring`, `springs.*`) für direkte Manipulation für ein natürlicheres Gefühl, die Verwendung von `useMotionValue` und `useTransform` für reaktive Berechnungen ohne erneutes Rendern, sowie die imperative und unterbrechungssichere `useAnimate`-API für mehrstufige Sequenzen. Wichtige Regeln umfassen das Testen von Drag auf Touch-Geräten, das Anhalten von Endlosschleifen bei ausgeblendetem Tab, die Verwendung expliziter Wischschwellenwerte und die ordnungsgemäße Bereinigung von Event-Listenern. Das Skill bietet eine Entscheidungshilfe zur Auswahl der richtigen API für verschiedene Szenarien und umfasst mehrere Codebeispiele, die die Integration mit `motion-foundations` demonstrieren.

Funktioniert mit~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/motion-advanced

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Motion Advanced

Komplexe, interaktive und physikbasierte Animationsmuster. Benötigt zuerst motion-foundations. Verwenden Sie diese, wenn motion-patterns nicht ausreicht.

Wann zu aktivieren

  • Erstellen von Blättern zum Verwerfen durch Ziehen, Wischgesten oder neu anordenbaren Listen
  • Animieren von Text Wort für Wort, Zeichen für Zeichen oder als Live-Zähler
  • Zeichnen von SVG-Pfaden, Ikonenmorphing oder animieren von kreisförmigen Fortschritten
  • Schreiben eines benutzerdefinierten Animations-Hooks (useScrollReveal, Magnetknopf, Cursor-Folger)
  • Sequenzieren von mehrstufigen Animationen imperativ mit useAnimate
  • Erstellen von Spinnern, Schimmer-Skeletten, Pulsindikatoren oder Ladezuständen von Schaltflächen

Ausgaben

Dieses Skill produziert:

  • Drag-Interaktionen: ziehbare Karten, zum Verwerfen ziehbare Blätter, Reorder.Group-Listen
  • Gesten-Hooks: Wischerkennung, langes Drücken, Pin-Übersicht
  • Textanimationskomponenten: Wortenthüllung, Zeichen-Schreibmaschine, Zahlenzähler
  • SVG-Animation: Pfadzeichnung, Ikonenmorphing, Strich-Fortschrittsring
  • Benutzerdefinierte Hooks: useScrollReveal, useHoverScale, useNavigationDirection, useInViewOnce
  • Imperative Sequenzen via useAnimate mit unterbrechungssicherem async/await
  • Ladekomponenten: Spinner, Schimmer, Puls-Punkt, Fortschrittsbalken, Ladezustand der Schaltfläche

Prinzipien

  • Physikbasierte Bewegung (useSpring, springs.*) fühlt sich für direkte Manipulation immer natürlicher an als zeitbasierte.
  • useMotionValue + useTransform berechnet abgeleitete Werte ohne erneutes Rendern auszulösen.
  • useAnimate-Sequenzen sind imperativ und unterbrechungssicher — ein Aufruf von animate() während der Ausführung bricht die vorherige Animation automatisch ab.
  • Bewegungs-Werte (useMotionValue, useSpring) sind SSR-sicher und verursachen keine Hydratationsfehler.

Regeln

  1. Drag-Interaktionen müssen auf Touch-Geräten getestet werden, nicht nur mit der Maus. Das drag-Attribut funktioniert auf beiden, aber das Gefühl und die Schwellenwerte unterscheiden sich.
  2. Unendliche Animationen müssen pausieren, wenn document.visibilityState === "hidden". Hintergrund-Tabs dürfen keine GPU/CPU verbrauchen.
  3. Der Wisch-Schwellenwert muss explizit sein. Niemals nur aus der Geschwindigkeit auf die Absicht schließen; kombinieren Sie offset- und velocity-Prüfungen.
  4. Der useAnimate-Scope-Ref muss an ein gemountetes DOM-Element angehängt werden. Ein Aufruf von animate() vor dem Mounten führt zu einem stillen Fehler.
  5. Bewegungs-Werte dürfen nicht bei jedem Rendern neu erstellt werden. useMotionValue(0) innerhalb eines Komponentenrumpfs ist korrekt; new MotionValue(0) in einem Render ist nicht.
  6. Alle Token-Werte werden aus motion-foundations importiert. Keine Inline-Zahlen.
  7. Benutzerdefinierte Hooks müssen die Bereinigung übernehmen. Jeder window.addEventListener benötigt einen passenden removeEventListener im useEffect-Rückgabewert.
  8. SVG-Morphing erfordert gleiche Pfadkommando-Anzahlen. Pfade mit unterschiedlichen Kommandostrukturen springen anstatt zu interpolieren.

Entscheidungshilfe

Auswahl der richtigen erweiterten API

SzenarioAPI
Ziehen mit Physik beim Loslassendrag + dragTransition: springs.release
Geordnete Zieh-zum-Neuordnen-ListeReorder.Group + Reorder.Item
Verwerfen bei Zieh-Versatzdrag="y" + onDragEnd-Versatz-Prüfung
Nach links / rechts wischendrag="x" + onDragEnd-Versatz-Prüfung
Langes DrückenuseLongPress-Hook
Wert über Zeit geglättetuseSpring
Wert von einem anderen abgeleitetuseTransform
Mehrstufige SequenzuseAnimate mit async/await
Einmalige imperative Animationanimate() aus motion
Text, der Wort für Wort erscheintStagger (Staffelung) auf inline-block-Spannen
SVG-ZeichnungpathLength 0 → 1
SVG-Morphd-Attribut-Tween (gleiche Kommandos)
Kreisförmiger FortschrittstrokeDashoffset-Tween

Wann useSpring vs. eine Spring-Transition verwendet werden sollte

useSpringtransition: springs.*
Verwenden fürCursor-Folger, zeigergesteuerte WerteDiskrete Zustandsänderungen
AktualisierungenKontinuierlich, bei jedem FrameAusgelöst durch Zustandsänderung
UnterbrechungSanft — Physik übernimmt ab der GeschwindigkeitStartet vom aktuellen Wert neu

Kernkonzepte

useMotionValue + useTransform

Reaktive Berechnung ohne erneutes Rendern:

const x = useMotionValue(0)
const opacity = useTransform(x, [-200, 0, 200], [0, 1, 0])
// opacity wird bei jeder Änderung von x aktualisiert — kein setState, kein erneutes Rendern

useAnimate

Gibt [scope, animate] zurück. Der Scope-Ref muss an ein DOM-Element angehängt werden. animate()-Aufrufe sind unterbrechungssicher — ein Aufruf während der Ausführung bricht den vorherigen Lauf ab.

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 })  // feuern und vergessen
}

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

Codebeispiele

Ziehbare Karte

"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}
/>

Zum Verwerfen ziehbares Blatt

"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) => {
        // Regel 3: offset + velocity kombinieren
        if (info.offset.y > 120 || info.velocity.y > 500) onClose()
      }}
    />
  )
}

Neu anordenbare Liste

"use client"
import { Reorder } from "motion/react"

export function SortableList() {
  const [items, setItems] = useState(initialItems)
  return (
    <Reorder.Group axis="y" values={items} onReorder={setItems}>
      {items.map((item) => (
        <Reorder.Item key={item.id} value={item}>
          {item.label}
        </Reorder.Item>
      ))}
    </Reorder.Group>
  )
}

Wischerkennung

"use client"
import { motion } from "motion/react"

const OFFSET_THRESHOLD  = 50
const VELOCITY_THRESHOLD = 300

<motion.div
  drag="x"
  dragConstraints={{ left: 0, right: 0 }}
  onDragEnd={(_, info) => {
    const swipedRight = info.offset.x > OFFSET_THRESHOLD  || info.velocity.x > VELOCITY_THRESHOLD
    const swipedLeft  = info.offset.x < -OFFSET_THRESHOLD || info.velocity.x < -VELOCITY_THRESHOLD
    if (swipedRight) onSwipeRight()
    if (swipedLeft)  onSwipeLeft()
  }}
/>

Long-Press-Hook

import { useRef } from "react"

export function useLongPress(callback: () => void, ms = 600) {
  const timerRef = useRef<ReturnType<typeof setTimeout>>()
  return {
    onPointerDown:  () => { timerRef.current = setTimeout(callback, ms) },
    onPointerUp:    () => clearTimeout(timerRef.current),
    onPointerLeave: () => clearTimeout(timerRef.current),
  }
}

Wort-für-Wort-Enthüllung

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

export function AnimatedText({ text }: { text: string }) {
  return (
    <motion.p
      variants={{ visible: { transition: { staggerChildren: 0.05 } } }}
      initial="hidden"
      animate="visible"
    >
      {text.split(" ").map((word, i) => (
        <motion.span
          key={i}
          className="inline-block mr-1"
          variants={{
            hidden:  { opacity: 0, y: 12 },
            visible: { opacity: 1, y: 0, transition: springs.gentle },
          }}
        >
          {word}
        </motion.span>
      ))}
    </motion.p>
  )
}

Zahlenzähler

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

export function Counter({ to }: { to: number }) {
  const nodeRef = useRef<HTMLSpanElement>(null)

  useEffect(() => {
    const controls = animate(0, to, {
      duration: motionTokens.duration.crawl,
      ease: motionTokens.easing.smooth,
      onUpdate: (v) => {
        if (nodeRef.current) nodeRef.current.textContent = Math.round(v).toString()
      },
    })
    return controls.stop   // Regel 7: Bereinigung
  }, [to])

  return <span ref={nodeRef} />
}

SVG-Pfadzeichnung

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

<motion.path
  d="M 0 100 Q 50 0 100 100"
  initial={{ pathLength: 0, opacity: 0 }}
  animate={{ pathLength: 1, opacity: 1 }}
  transition={{ duration: motionTokens.duration.slow, ease: motionTokens.easing.smooth }}
/>

Strich-Fortschrittsring

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

const CIRCUMFERENCE = 2 * Math.PI * 40   // r=40

export function ProgressRing({ progress }: { progress: number }) {
  return (
    <svg width="100" height="100" viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="40" fill="none" stroke="#e5e7eb" strokeWidth="8" />
      <motion.circle
        cx="50" cy="50" r="40"
        fill="none" stroke="#6366f1" strokeWidth="8"
        strokeLinecap="round"
        strokeDasharray={CIRCUMFERENCE}
        animate={{ strokeDashoffset: CIRCUMFERENCE - (progress / 100) * CIRCUMFERENCE }}
        transition={{ duration: motionTokens.duration.normal, ease: motionTokens.easing.smooth }}
        style={{ rotate: -90, transformOrigin: "center" }}
      />
    </svg>
  )
}

useScrollReveal Hook

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

export function useScrollReveal() {
  const ref = useRef(null)
  const { scrollYProgress } = useScroll({ target: ref, offset: ["start end", "end start"] })
  const opacity = useTransform(scrollYProgress, [0, 0.3], [0, 1])
  const y       = useTransform(scrollYProgress, [0, 0.3], [motionTokens.distance.lg, 0])
  return { ref, style: { opacity, y } }
}

// Verwendung
const { ref, style } = useScrollReveal()
<motion.section ref={ref} style={style} />

Cursor-Folger

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

export function CursorFollower() {
  const x = useMotionValue(-100)
  const y = useMotionValue(-100)
  const sx = useSpring(x, springs.gentle)
  const sy = useSpring(y, springs.gentle)

  useEffect(() => {
    const move = (e: MouseEvent) => { x.set(e.clientX); y.set(e.clientY) }
    window.addEventListener("mousemove", move)
    return () => window.removeEventListener("mousemove", move)   // Regel 7
  }, [])

  return (
    <motion.div
      className="fixed top-0 left-0 w-6 h-6 rounded-full bg-indigo-500
                 pointer-events-none -translate-x-1/2 -translate-y-1/2 z-50"
      style={{ x: sx, y: sy }}
    />
  )
}

Schimmer-Skelett

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

export function ShimmerSkeleton({ className = "" }: { className?: string }) {
  const controls = useAnimation()

  useEffect(() => {
    const play = () =>
      controls.start({
        x: ["-100%", "100%"],
        transition: {
          repeat: Infinity,
          duration: motionTokens.duration.crawl,
          ease: motionTokens.easing.linear,
        },
      })

    const handleVisibility = () => {
      if (document.visibilityState === "hidden") controls.stop()
      else void play()
    }

    void play()
    document.addEventListener("visibilitychange", handleVisibility)
    return () => {
      controls.stop()
      document.removeEventListener("visibilitychange", handleVisibility)
    }
  }, [controls])

  return (
    <div className={`relative overflow-hidden bg-gray-200 rounded ${className}`}>
      <motion.div
        className="absolute inset-0 bg-gradient-to-r from-transparent via-white/60 to-transparent"
        initial={{ x: "-100%" }}
        animate={controls}
      />
    </div>
  )
}

Ladezustand der Schaltfläche

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

export function LoadingButton({
  loading,
  label,
  onClick,
}: {
  loading: boolean
  label: string
  onClick: () => void
}) {
  return (
    <motion.button
      onClick={onClick}
      animate={{ opacity: loading ? 0.7 : 1 }}
      whileTap={loading ? {} : { scale: motionTokens.scale.press }}
      transition={springs.snappy}
      disabled={loading}
    >
      <AnimatePresence mode="wait">
        {loading ? (
          <motion.span
            key="loading"
            initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
            transition={{ duration: motionTokens.duration.fast }}
          >
            …
          </motion.span>
        ) : (
          <motion.span
            key="label"
            initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
            transition={{ duration: motionTokens.duration.fast }}
          >
            {label}
          </motion.span>
        )}
      </AnimatePresence>
    </motion.button>
  )
}

Unendliche Animation mit Sichtbarkeits-Pause

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

export function PulseDot() {
  const controls = useAnimation()

  useEffect(() => {
    const pulse = () =>
      controls.start({
        scale: [1, 1.4, 1],
        opacity: [1, 0.6, 1],
        transition: { repeat: Infinity, duration: motionTokens.duration.crawl },
      })

    // Regel 2: pausieren, wenn Tab versteckt ist
    const handleVisibility = () => {
      if (document.visibilityState === "hidden") controls.stop()
      else void pulse()
    }

    void pulse()
    document.addEventListener("visibilitychange", handleVisibility)
    return () => {
      controls.stop()
      document.removeEventListener("visibilitychange", handleVisibility)
    }
  }, [controls])

  return <motion.div className="w-3 h-3 bg-indigo-500 rounded-full" />
}

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Verwandte Skills