{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreifjscnxsstdob2nkyegzjdvop3h3zvurv46lsxa4q76i6wu44tvya",
    "uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3mpszbsjpw6g2"
  },
  "coverImage": {
    "$type": "blob",
    "ref": {
      "$link": "bafkreidbfjvupqywfyzlrwehttbtdjfyj2ngnjn6mdez7a4b3f3gd5vtf4"
    },
    "mimeType": "image/webp",
    "size": 86130
  },
  "path": "/dev48v/spring-vs-tween-and-3-more-i-built-a-framer-motion-playground-with-the-code-beside-each-demo-5c3n",
  "publishedAt": "2026-07-04T11:35:43.000Z",
  "site": "https://dev.to",
  "tags": [
    "react",
    "javascript",
    "webdev",
    "css",
    "https://framer-motion-lab.vercel.app/",
    "https://github.com/dev48v/framer-motion-lab"
  ],
  "textContent": "The Framer Motion docs list every prop, but they can't make you _feel_ the difference between a spring and a tween, or what `stiffness` and `damping` actually do to a motion. So I built four live demos with the code next to each — drag the sliders, fling the box, and it lands.\n\n**▶ Live demo:** https://framer-motion-lab.vercel.app/\n**Source (React 19 + Framer Motion 11):** https://github.com/dev48v/framer-motion-lab\n\n##  The one insight worth the whole lab\n\nA **tween** has a fixed `duration` — it always takes the same time, regardless of distance:\n\n\n\n    <motion.div animate={{ x: 260 }}\n      transition={{ type: \"tween\", duration: 0.6, ease: \"easeInOut\" }} />\n\n\nA **spring** has _no duration_. It's physics — `stiffness`, `damping`, `mass` — and it settles naturally:\n\n\n\n    <motion.div animate={{ x: 260 }}\n      transition={{ type: \"spring\", stiffness: 300, damping: 18, mass: 1 }} />\n\n\nIn the lab you drag those three sliders and watch the box go from **bouncy** (underdamped, damping ratio ζ < 1) to **snappy** (critically damped) to **sluggish** (overdamped) — with the live ζ shown. The reason springs win for anything interactive: they handle _interruptions_ gracefully. Grab a spring mid-animation and it flows to the new target; a tween has to restart its clock.\n\n##  The other three, in one prop each\n\n**Gestures** — no state, no handlers:\n\n\n\n    <motion.div whileHover={{ scale: 1.12, rotate: 3 }} whileTap={{ scale: 0.92 }} />\n\n\n**Drag** with a rubber-band edge:\n\n\n\n    const area = useRef(null);\n    <div ref={area}>\n      <motion.div drag dragConstraints={area} dragElastic={0.2} />\n    </div>\n\n\n**Stagger** — one variant definition orchestrates a whole list:\n\n\n\n    const container = { show: { transition: { staggerChildren: 0.09 } } };\n    const item = { hidden: { opacity: 0, y: 18 }, show: { opacity: 1, y: 0 } };\n    <motion.ul variants={container} initial=\"hidden\" animate=\"show\">\n      {items.map(t => <motion.li key={t} variants={item} />)}\n    </motion.ul>\n\n\nThat's the part that surprises people: the parent's `staggerChildren` sequences the children automatically — you don't compute delays per item.\n\nEvery demo is live and the code updates with your settings. If it made Framer Motion click, a star helps others find it: https://github.com/dev48v/framer-motion-lab",
  "title": "Spring vs Tween, and 3 More: I Built a Framer Motion Playground With the Code Beside Each Demo"
}