agentsclimarketplace

Framer motion

Skill AThevon/genjutsu/skills/_jutsu/framer-motion

Framer Motion / Motion sub-skill - AnimatePresence, layout animations, gestures, motion values.From its SKILL.md

Install
npx -y skills add AThevon/genjutsu --skill framer-motion

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

SKILL.md

5.4 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it

Framer Motion — Sub-skill

Package: motion (v11+, formerly framer-motion). Import: import { motion, AnimatePresence } from "motion/react"

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

const container = {
  hidden: { opacity: 0 },
  show: {
    opacity: 1,
    transition: {
      staggerChildren: 0.08,
      delayChildren: 0.2,
      staggerDirection: 1,    // 1 = normal, -1 = reverse
    },
  },
};

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 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>

What ships with it: 1 file

9.6 KB alongside SKILL.md

references/

Gives 0 of the 12 instructions most css styling skills give in ~1.4k tokens

Counted across 512 of the 512 authors here whose files we hold, read 2026-09-06

  • Animate only transform and opacityin 32 of 512, across 30 files
  • Respect prefers-reduced-motionin 21 of 512
  • Support reduced motion preferencesin 16 of 512, across 6 files
  • Use Tailwind CSS for stylingin 14 of 512, across 13 files
  • Specify AnimatePresence mode explicitlyin 12 of 512, across 2 files
  • Set initial states explicitlyin 12 of 512, across 2 files
  • Use semantic HTML elementsin 11 of 512, across 10 files
  • Use oklch for color valuesin 11 of 512, across 10 files
  • Honor prefers-reduced-motion in animationsin 10 of 512
  • Provide a reduced-motion fallback for animationsin 10 of 512, across 9 files
  • Use property names in camelCasein 9 of 512, across 4 files
  • Ensure UI animations stay under 300msin 9 of 512, across 6 files

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.