Skip to content
cccskills
FreePublished on GitHub

framer-motion

Framer Motion / Motion sub-skill - AnimatePresence, layout animations, gestures, motion values.

The English summary is being prepared. Showing the original description.

See how to install

Files included (2)

  • SKILL.md7.3 KB
  • references/api.md9.7 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Version-sensitive. Every API name, SDK gate and browser-support claim below was verified on 2026-09-08 against primary sources. What against, and when, is in _jutsu/VERSIONS.md. If that date is old, re-verify before acting on a version number.

Framer Motion - Sub-skill

Two package names, one library. Framer Motion was renamed to Motion. motion and framer-motion both publish the same version (13.2.0 as of 2026-09-08): motion declares "framer-motion": "^13.2.0" as a dependency and motion/react re-exports it. Neither is broken, and framer-motion is still the one most installed projects have.

Read package.json and follow what is there. Do not migrate a project from one to the other unless the user asks - that is Iron Rule 8 in cast / 10 in paint.

In package.jsonImport fromInstall line
motion"motion/react"npm install motion
framer-motion"framer-motion"npm install framer-motion
bothwhichever the file you are editing already imports; say the project is mid-migration-

Every API in this skill is identical across the two names at v13. Where a symbol is newer than v11, it is flagged inline. Peers: react / react-dom ^18 || ^19.

When to use Framer Motion vs alternatives

CriteriaFramer MotionGSAPNative CSS
Layout animationsExcellent (layoutId)ManualImpossible
Exit animationsAnimatePresenceTimeline reverseLimited (display)
Gestures (drag, hover)Native, declarativeDraggable pluginBasic
Scroll-drivenuseScroll + useTransformScrollTrigger (more powerful)scroll-timeline
Complex orchestrationVariants + propagationTimeline (more flexible)@keyframes
Bundle size~50kb tree-shaken~30kb core0kb
React integrationNative, component-firstRefs + useGSAPclassName toggle

Rule: Framer Motion for React UI interactions (modals, toasts, reorder, shared layout). GSAP for complex timelines, cinematic scroll-driven, SVG morphing.

AnimatePresence - Exit animations

<AnimatePresence mode="wait">
  {isVisible && (
    <motion.div
      key="unique-key"        // REQUIRED - identifies the component
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    />
  )}
</AnimatePresence>
  • mode="wait" - waits for exit to finish before enter (page transitions)
  • mode="sync" - exit and enter simultaneously
  • mode="popLayout" - removes from flow immediately (good for lists)
  • onExitComplete - callback when all exit animations are finished

Layout animations

// Shared layout - the element "slides" between two positions
<motion.div layoutId="highlight" className={activeTab === id ? "active" : ""} />

// Auto layout - animates position/size when layout changes
<motion.div layout>
  {isExpanded && <motion.p layout>Additional content</motion.p>}
</motion.div>

// layout="position" - animates position only (not size)
// layout="size" - animates size only
// layout="preserve-aspect" - preserves the ratio during the transition

Variants - Propagation and orchestration

import { stagger } from "motion/react";

const container = {
  hidden: { opacity: 0 },
  show: {
    opacity: 1,
    transition: {
      // staggerChildren + staggerDirection are DEPRECATED (Motion 12.22, Jul 2025).
      // Pass a stagger() function to delayChildren instead.
      delayChildren: stagger(0.08, { startDelay: 0.2 }),
      // reverse order: stagger(0.08, { from: "last" })
      // also available: from: "first" | "center" | "last" | index, and ease
    },
  },
};

const item = {
  hidden: { opacity: 0, y: 20 },
  show: { opacity: 1, y: 0 },
};

<motion.ul variants={container} initial="hidden" animate="show">
  {items.map((i) => (
    <motion.li key={i.id} variants={item} />
  ))}
</motion.ul>

Variants automatically propagate to motion children - no need for initial/animate on children.

Gestures

<motion.div
  whileHover={{ scale: 1.05 }}
  whileTap={{ scale: 0.95 }}
  whileFocus={{ borderColor: "#3b82f6" }}
  // Drag
  drag               // true = x+y, "x" = horizontal only, "y" = vertical only
  dragConstraints={{ left: -100, right: 100, top: -50, bottom: 50 }}
  dragElastic={0.2}  // 0 = rigid, 1 = free (default 0.35)
  dragSnapToOrigin   // returns to initial position
  onDragEnd={(e, info) => {
    if (info.offset.x > 100) handleSwipe("right");
  }}
/>

Motion values - Reactive without re-render

const x = useMotionValue(0);
const opacity = useTransform(x, [-200, 0, 200], [0, 1, 0]);
const background = useTransform(x, [-200, 200], ["#ff0000", "#00ff00"]);

// Spring-based smoothing
const smoothX = useSpring(x, { stiffness: 300, damping: 30 });

// Scroll tracking
const { scrollY, scrollYProgress } = useScroll();
const parallaxY = useTransform(scrollYProgress, [0, 1], [0, -300]);

// Element-scoped scroll
const ref = useRef(null);
const { scrollYProgress } = useScroll({
  target: ref,
  offset: ["start end", "end start"],
});

Motion values do NOT trigger React re-renders - they update the DOM directly via style.

Do Not

Do not use motion with styled-components / Emotion without isValidProp (v13+)

Motion 13.0 removed @emotion/is-prop-valid as an optional dependency. Without explicit injection, motion-only props leak onto the DOM.

import isPropValid from "@emotion/is-prop-valid";
import { MotionConfig } from "motion/react";

<MotionConfig isValidProp={isPropValid}>
  <App />
</MotionConfig>

Or reverse the composition so the styling library owns prop forwarding: const MotionDiv = motion.create(StyledDiv).

Do not setState in callbacks without a guard

// BAD - infinite re-render if animate depends on state
onUpdate={(latest) => setPosition(latest.x)}

// GOOD - guard or useMotionValueEvent
const x = useMotionValue(0);
useMotionValueEvent(x, "change", (latest) => {
  if (latest > threshold) onThresholdReached();
});

Do not use layout animation without a stable key

// BAD - key changes every render, breaks layout tracking
<motion.div layout key={Math.random()} />

// GOOD - stable key derived from data
<motion.div layout key={item.id} />

Do not forget the unique key on AnimatePresence

// BAD - no key, exit animation does not trigger
<AnimatePresence>
  {isOpen && <motion.div exit={{ opacity: 0 }} />}
</AnimatePresence>

// GOOD - unique key for each conditional child
<AnimatePresence>
  {isOpen && <motion.div key="modal" exit={{ opacity: 0 }} />}
</AnimatePresence>

Do not wrap an already animated component with motion.div

// BAD - double animation, transform conflicts
<motion.div animate={{ x: 100 }}>
  <motion.div animate={{ x: -50 }}>Content</motion.div>
</motion.div>

// GOOD - single animation level per transform axis
<motion.div animate={{ x: 100 }}>
  <motion.div animate={{ opacity: 0.5 }}>Content</motion.div>
</motion.div>

// GOOD - use variants to coordinate parent/child
<motion.div variants={parent} animate="active">
  <motion.div variants={child} />
</motion.div>

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Summon shadow clones: genjutsu's full-scale pipeline for a whole website or web app, from scratch or as a full redesign. Harvests the client's real material, researches in parallel, lets Impeccable lead the direction and genjutsu the motion, builds the pages with parallel agents, then loops fixes, verdicts and a cold-eyes art director until only minor issues remain, the round cap of the chosen tier is reached, or a round fixes nothing. Announces its cost first and asks twice. Web. Needs a host that can spawn subagents.

The English summary is being prepared. Showing the original description.

AThevon/genjutsu555Updated Oct 6, 2026

Algorithmic and generative art with Canvas 2D - particles, flow fields, noise, fractals, L-systems.

The English summary is being prepared. Showing the original description.

AThevon/genjutsu555Updated Oct 6, 2026

cast

Free

Cast genjutsu on a UI - creative coding for motion, micro-interactions, and wow-factor. Scans the stack, proposes an interaction thesis, loads the right sub-skills, implements the illusion. Adapts to Web, Android (Compose), Apple (SwiftUI).

The English summary is being prepared. Showing the original description.

AThevon/genjutsu555Updated Oct 6, 2026

Advanced Compose visuals - Material 3 Expressive motion physics, AGSL shaders (Android 13+), Canvas/DrawScope generative, graphicsLayer effects.

The English summary is being prepared. Showing the original description.

AThevon/genjutsu555Updated Oct 6, 2026

Jetpack Compose animation foundations - animate*AsState, AnimatedVisibility, Crossfade, updateTransition, SharedTransitionLayout, gestures.

The English summary is being prepared. Showing the original description.

AThevon/genjutsu555Updated Oct 6, 2026

Compose Multiplatform / KMP patterns - expect/actual composables, platform-specific code, density and font handling cross-target, iOS/Android/Desktop interop.

The English summary is being prepared. Showing the original description.

AThevon/genjutsu555Updated Oct 6, 2026

See all skills by AThevon

Report a problem with this skill