smithery.ai

framer-motion

Framer Motion animations - motion components, variants, gestures, layout animations. Use when adding UI animations, transitions, or interactive motion effects.

First seen Apr 1, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 6,338 B
  • docs SUMMARY.md 180 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 111 installs

SKILL.md

Framer Motion

Basic Animation

import { motion } from 'framer-motion'

function AnimatedBox() {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.5 }}
    >
      Hello World
    </motion.div>
  )
}

Animate Properties

<motion.div
  animate={{
    x: 100,
    y: 50,
    scale: 1.2,
    rotate: 180,
    opacity: 0.5,
    backgroundColor: '#ff0000',
    borderRadius: '50%',
  }}
  transition={{
    duration: 0.5,
    ease: 'easeInOut',
    delay: 0.2,
  }}
/>

Transition Types

// Spring (default)
transition={{ type: 'spring', stiffness: 100, damping: 10 }}

// Tween
transition={{ type: 'tween', duration: 0.5, ease: 'easeInOut' }}

// Inertia
transition={{ type: 'inertia', velocity: 50 }}

// Ease presets
ease: 'linear' | 'easeIn' | 'easeOut' | 'easeInOut' | 'circIn' | 'circOut' | 'backIn' | 'backOut' | 'anticipate'

Variants

const containerVariants = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: {
      staggerChildren: 0.1,
    },
  },
}

const itemVariants = {
  hidden: { opacity: 0, y: 20 },
  visible: { opacity: 1, y: 0 },
}

function List({ items }) {
  return (
    <motion.ul
      variants={containerVariants}
      initial="hidden"
      animate="visible"
    >
      {items.map((item) => (
        <motion.li key={item.id} variants={itemVariants}>
          {item.name}
        </motion.li>
      ))}
    </motion.ul>
  )
}

Hover, Tap, Focus

<motion.button
  whileHover={{ scale: 1.05, backgroundColor: '#3b82f6' }}
  whileTap={{ scale: 0.95 }}
  whileFocus={{ boxShadow: '0 0 0 3px rgba(59, 130, 246, 0.5)' }}
>
  Click me
</motion.button>

Drag

<motion.div
  drag                    // Enable both axes
  drag="x"                // Horizontal only
  dragConstraints={{ left: -100, right: 100, top: -50, bottom: 50 }}
  dragElastic={0.2}       // Elasticity outside constraints
  dragMomentum={true}     // Continue after release
  onDragStart={(e, info) => console.log(info.point)}
  onDrag={(e, info) => console.log(info.delta)}
  onDragEnd={(e, info) => console.log(info.velocity)}
/>

Scroll Animations

import { motion, useScroll, useTransform } from 'framer-motion'

function ParallaxSection() {
  const { scrollYProgress } = useScroll()
  const y = useTransform(scrollYProgress, [0, 1], [0, -200])
  const opacity = useTransform(scrollYProgress, [0, 0.5, 1], [1, 0.5, 0])

  return (
    <motion.div style={{ y, opacity }}>
      Parallax Content
    </motion.div>
  )
}

// Scroll-triggered animation
function ScrollTriggered() {
  return (
    <motion.div
      initial={{ opacity: 0, y: 50 }}
      whileInView={{ opacity: 1, y: 0 }}
      viewport={{ once: true, margin: '-100px' }}
      transition={{ duration: 0.6 }}
    >
      Appears on scroll
    </motion.div>
  )
}

Layout Animations

function LayoutExample() {
  const [isExpanded, setIsExpanded] = useState(false)

  return (
    <motion.div
      layout
      onClick={() => setIsExpanded(!isExpanded)}
      style={{
        width: isExpanded ? 300 : 100,
        height: isExpanded ? 200 : 100,
      }}
      transition={{ layout: { duration: 0.3 } }}
    />
  )
}

// Shared layout
import { LayoutGroup } from 'framer-motion'

function Tabs() {
  const [selected, setSelected] = useState(0)

  return (
    <LayoutGroup>
      {tabs.map((tab, i) => (
        <button key={tab} onClick={() => setSelected(i)}>
          {tab}
          {selected === i && (
            <motion.div layoutId="underline" className="underline" />
          )}
        </button>
      ))}
    </LayoutGroup>
  )
}

AnimatePresence (Exit Animations)

import { AnimatePresence, motion } from 'framer-motion'

function Modal({ isOpen, onClose }) {
  return (
    <AnimatePresence>
      {isOpen && (
        <motion.div
          initial={{ opacity: 0, scale: 0.9 }}
          animate={{ opacity: 1, scale: 1 }}
          exit={{ opacity: 0, scale: 0.9 }}
          transition={{ duration: 0.2 }}
        >
          <ModalContent onClose={onClose} />
        </motion.div>
      )}
    </AnimatePresence>
  )
}

useAnimate Hook

import { useAnimate } from 'framer-motion'

function SequenceAnimation() {
  const [scope, animate] = useAnimate()

  const handleClick = async () => {
    await animate(scope.current, { scale: 1.2 })
    await animate(scope.current, { rotate: 180 })
    await animate(scope.current, { scale: 1, rotate: 0 })
  }

  return (
    <motion.div ref={scope} onClick={handleClick}>
      Click for sequence
    </motion.div>
  )
}

Motion Values

import { motion, useMotionValue, useTransform } from 'framer-motion'

function MotionValueExample() {
  const x = useMotionValue(0)
  const opacity = useTransform(x, [-200, 0, 200], [0, 1, 0])
  const background = useTransform(
    x,
    [-200, 0, 200],
    ['#ff0000', '#00ff00', '#0000ff']
  )

  return (
    <motion.div
      drag="x"
      style={{ x, opacity, background }}
    />
  )
}

Stagger Children

const container = {
  hidden: { opacity: 0 },
  show: {
    opacity: 1,
    transition: {
      staggerChildren: 0.1,
      delayChildren: 0.3,
    },
  },
}

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} variants={item} />
  ))}
</motion.ul>

Loading Skeleton

function Skeleton() {
  return (
    <motion.div
      animate={{ opacity: [0.5, 1, 0.5] }}
      transition={{ duration: 1.5, repeat: Infinity }}
      className="bg-gray-200 rounded h-4"
    />
  )
}

Number Counter

import { motion, useSpring, useTransform } from 'framer-motion'

function Counter({ value }) {
  const spring = useSpring(0, { stiffness: 100, damping: 30 })
  const display = useTransform(spring, (v) => Math.round(v))

  useEffect(() => {
    spring.set(value)
  }, [value, spring])

  return <motion.span>{display}</motion.span>
}