install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/TerminalSkills/skills/motion" ~/.claude/skills/comeonoliver-skillshub-motion && rm -rf "$T"
manifest:
skills/TerminalSkills/skills/motion/SKILL.mdsource content
Motion (formerly Framer Motion) — Animation for React
You are an expert in Motion, the production-ready animation library for React (formerly Framer Motion). You help developers create fluid animations, layout transitions, scroll-linked effects, gesture interactions, shared layout animations, and exit animations — using a declarative API where animations are defined as props rather than imperative code.
Core Capabilities
Basic Animations
import { motion, AnimatePresence } from "motion/react"; // Animate on mount function FadeIn({ children }: { children: React.ReactNode }) { return ( <motion.div initial={{ opacity: 0, y: 20 }} // Starting state animate={{ opacity: 1, y: 0 }} // Target state transition={{ duration: 0.5, ease: "easeOut" }} > {children} </motion.div> ); } // Hover and tap interactions function InteractiveCard({ title }: { title: string }) { return ( <motion.div className="card" whileHover={{ scale: 1.05, boxShadow: "0 10px 30px rgba(0,0,0,0.12)" }} whileTap={{ scale: 0.95 }} transition={{ type: "spring", stiffness: 300, damping: 20 }} > <h3>{title}</h3> </motion.div> ); } // Exit animations function NotificationList({ notifications }: { notifications: Notification[] }) { return ( <AnimatePresence> {notifications.map((n) => ( <motion.div key={n.id} initial={{ opacity: 0, x: 100 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -100, height: 0 }} // Animate out! transition={{ type: "spring", damping: 25 }} > {n.message} </motion.div> ))} </AnimatePresence> ); }
Layout Animations
// Automatic layout animation function ExpandableCard({ isExpanded, onClick, children }: Props) { return ( <motion.div layout // Animate ANY layout change onClick={onClick} style={{ width: isExpanded ? 400 : 200, height: isExpanded ? 300 : 100, }} transition={{ layout: { type: "spring", stiffness: 200 } }} > <motion.h3 layout="position">{/* Only animate position, not size */}</motion.h3> <AnimatePresence> {isExpanded && ( <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} > {children} </motion.div> )} </AnimatePresence> </motion.div> ); } // Shared layout animation (element moves between components) function TabLayout({ activeTab }: { activeTab: string }) { return ( <div className="tabs"> {tabs.map((tab) => ( <button key={tab.id} onClick={() => setActive(tab.id)}> {tab.label} {activeTab === tab.id && ( <motion.div layoutId="activeTab" // Same layoutId = shared animation className="underline" transition={{ type: "spring", stiffness: 500, damping: 30 }} /> )} </button> ))} </div> ); }
Scroll Animations
import { motion, useScroll, useTransform } from "motion/react"; function ParallaxHero() { const { scrollY } = useScroll(); const y = useTransform(scrollY, [0, 500], [0, -150]); const opacity = useTransform(scrollY, [0, 300], [1, 0]); return ( <motion.div style={{ y, opacity }} className="hero"> <h1>Welcome</h1> </motion.div> ); } // Scroll-triggered entrance function ScrollReveal({ children }: { children: React.ReactNode }) { return ( <motion.div initial={{ opacity: 0, y: 50 }} whileInView={{ opacity: 1, y: 0 }} // Animate when in viewport viewport={{ once: true, margin: "-100px" }} transition={{ duration: 0.6 }} > {children} </motion.div> ); }
Installation
npm install motion
Best Practices
prop — Add to any element; automatically animates when size/position changes; works with CSSlayout- AnimatePresence — Wrap lists/conditionals to enable exit animations; key prop required for each child
- Spring physics — Use
for natural motion; tunetype: "spring"
(speed) andstiffness
(bounciness)damping - Scroll animations — Use
for entrance,whileInView
+useScroll
for parallaxuseTransform - Shared layout — Same
on two elements = animated transition between them (tab indicators, cards)layoutId - Gesture props —
,whileHover
,whileTap
for interactive micro-animationswhileDrag
— Animate only position changes, not size; prevents text reflow during animationlayout="position"- Performance — Motion uses the GPU-accelerated
andtransform
; avoids layout thrashingopacity