Motion (Framer Motion) — Skill
SkillMonitoring & opsImplement smooth, accessible animations with motion/react (Framer Motion) in React. Use when adding animations, gestures, or layout transitions with motion, AnimatePresence, useScroll, and related APIs. Requires a 'use client' boundary; not for strictly server-rendered components or when no animation is needed.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Motion (Framer Motion) — Skill skill
What this skill tells your AI
The instructions your AI receives, as published by asymmetric-al/core in .agents/skills/motion/SKILL.md and read by ahel’s review.
Name: motion
Purpose: Implement smooth, accessible animations with motion/react in React.
Use this skill whenever adding animations, gestures, or layout transitions.
Applies when: Using motion/react (motion, AnimatePresence, useScroll, etc.).
Do not use when: No animations are needed or the component is strictly server-rendered.
Rules
- Client-only boundary: Motion requires
'use client'; keep client islands small. - Start simple: Begin with opacity/translate before adding spring physics.
- Use the right tool:
AnimatePresencefor enter/exit,layoutfor layout,whileHover/whileTapfor gestures. - Respect reduced motion: Use
useReducedMotion(). - Bundle discipline: Use
LazyMotionfor larger motion surfaces.
Workflow
- Identify the UX purpose (feedback, transition, focus).
- Add the smallest
'use client'boundary. - Implement enter/exit or layout transitions correctly.
- Respect reduced motion preferences.
- Check performance and bundle size.
Checklists
Implementation checklist
-
'use client'only where needed - Reduced motion behavior defined
-
AnimatePresencewraps conditional UI - Layout transitions use
layout
Review checklist
- Animations don’t re-run on every render
- Motion code doesn’t expand the client tree unnecessarily
Minimal examples
Enter/exit
"use client";
import { AnimatePresence, motion } from "motion/react";
export function Toast({
open,
children,
}: {
open: boolean;
children: React.ReactNode;
}) {
return (
<AnimatePresence>
{open ? (
<motion.div
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 8 }}
transition={{ duration: 0.18 }}
>
{children}
</motion.div>
) : null}
</AnimatePresence>
);
}
Layout animation
"use client";
import { motion } from "motion/react";
export function Expander({ open }: { open: boolean }) {
return (
<motion.div layout className="overflow-hidden rounded-md border p-3">
<div className="font-medium">Title</div>
{open ? <div className="mt-2 text-sm">More content...</div> : null}
</motion.div>
);
}
Reduced motion
"use client";
import { motion, useReducedMotion } from "motion/react";
export function FadeIn({ children }: { children: React.ReactNode }) {
const reduce = useReducedMotion();
return (
<motion.div
initial={reduce ? false : { opacity: 0, y: 6 }}
animate={reduce ? { opacity: 1 } : { opacity: 1, y: 0 }}
transition={{ duration: 0.2 }}
>
{children}
</motion.div>
);
}
Common mistakes / pitfalls
- Unmounting without
AnimatePresence(exit animations never run) - Animating layout without
layout - Putting Motion in a huge client tree
- Animating large lists without virtualization
Signals
- GitHub stars
- 391
- Forks
- 7
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
motion- Source
- github.com/asymmetric-al/core