{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "mouse-trail",
  "type": "registry:component",
  "title": "Mouse Trail",
  "author": "Toby Belhome",
  "description": "A cursor-trail animation that leaves small dots behind the mouse as it moves, with the dots fading out sequentially to create a snake-tail-like effect. Built with Tailwind CSS, React and Framer Motion.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "http://localhost:3000/r/mouse-trail.json"
  ],
  "files": [
    {
      "path": "examples/motion/animations/mouse-trail/01/mouse-trail.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { motion, AnimatePresence } from \"motion/react\";\n\ninterface Dot {\n  id: number;\n  x: number;\n  y: number;\n}\n\ninterface MouseTrailProps {\n  dotColor?: string;\n  dotSize?: number;\n  spacing?: number;\n  trailLength?: number;\n  fadeDuration?: number;\n}\n\nexport const MouseTrail = ({\n  dotColor = \"#a855f7\",\n  dotSize = 8,\n  spacing = 20,\n  trailLength = 20,\n  fadeDuration = 1000\n}: MouseTrailProps) => {\n  const [dots, setDots] = useState<Dot[]>([]);\n  const lastPositionRef = useRef({ x: 0, y: 0 });\n  const dotIdRef = useRef(0);\n\n  useEffect(() => {\n    const handleMouseMove = (e: MouseEvent) => {\n      const { clientX: x, clientY: y } = e;\n      const lastPos = lastPositionRef.current;\n\n      // Calculate distance from last dot\n      const distance = Math.sqrt(Math.pow(x - lastPos.x, 2) + Math.pow(y - lastPos.y, 2));\n\n      // Only add dot if we've moved far enough\n      if (distance >= spacing) {\n        const newDot: Dot = {\n          id: dotIdRef.current++,\n          x,\n          y\n        };\n\n        setDots((prevDots) => {\n          const updatedDots = [...prevDots, newDot];\n          // Keep only the most recent dots based on trail length\n          return updatedDots.slice(-trailLength);\n        });\n\n        lastPositionRef.current = { x, y };\n\n        // Remove dot after fade duration\n        setTimeout(() => {\n          setDots((prevDots) => prevDots.filter((d) => d.id !== newDot.id));\n        }, fadeDuration);\n      }\n    };\n\n    window.addEventListener(\"mousemove\", handleMouseMove);\n\n    return () => {\n      window.removeEventListener(\"mousemove\", handleMouseMove);\n    };\n  }, [spacing, trailLength, fadeDuration]);\n\n  return (\n    <div className=\"pointer-events-none fixed inset-0 z-50\">\n      <AnimatePresence>\n        {dots.map((dot) => (\n          <motion.div\n            key={dot.id}\n            className=\"absolute rounded-full\"\n            initial={{\n              left: dot.x - dotSize / 2,\n              top: dot.y - dotSize / 2,\n              opacity: 1,\n              scale: 0\n            }}\n            animate={{\n              opacity: 1,\n              scale: 1\n            }}\n            exit={{\n              opacity: 0,\n              scale: 0.5\n            }}\n            transition={{\n              duration: fadeDuration / 1000,\n              ease: \"easeOut\"\n            }}\n            style={{\n              width: dotSize,\n              height: dotSize,\n              backgroundColor: dotColor\n            }}\n          />\n        ))}\n      </AnimatePresence>\n    </div>\n  );\n};\n",
      "type": "registry:component",
      "target": "components/mouse-trail/mouse-trail.tsx"
    },
    {
      "path": "examples/motion/animations/mouse-trail/01/page.tsx",
      "content": "import { MouseTrail } from \"./mouse-trail\";\n\nexport default function Page() {\n  return (\n    <MouseTrail\n      dotColor=\"var(--color-primary)\"\n      dotSize={5}\n      spacing={10}\n      trailLength={20}\n      fadeDuration={500}\n    />\n  );\n}\n",
      "type": "registry:component",
      "target": "components/mouse-trail/mouse-trail-example.tsx"
    }
  ],
  "meta": {
    "isPro": false
  }
}