{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "mouse-image-trail",
  "type": "registry:block",
  "title": "Mouse image trail",
  "description": "Mouse image trail",
  "files": [
    {
      "path": "components/usages/mouseimagetrailusage.tsx",
      "content": "import React, { MouseEventHandler, ReactNode, useRef } from \"react\";\n\nimport { useAnimate } from \"motion/react\";\nimport { FiMousePointer } from \"react-icons/fi\";\n\nconst MouseImageTrailUsage = () => {\n\treturn (\n\t\t<MouseImageTrail\n\t\t\trenderImageBuffer={50}\n\t\t\trotationRange={25}\n\t\t\timages={[\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t]}\n\t\t>\n\t\t\t<section className=\"grid h-screen w-full place-content-center bg-background\">\n\t\t\t\t<p className=\"flex items-center gap-2 text-3xl font-bold uppercase text-secondary\">\n\t\t\t\t\t<FiMousePointer />\n\t\t\t\t\t<span>Hover me</span>\n\t\t\t\t</p>\n\t\t\t</section>\n\t\t</MouseImageTrail>\n\t);\n};\n\nconst MouseImageTrail = ({\n\tchildren,\n\t// List of image sources\n\timages,\n\t// Will render a new image every X pixels between mouse moves\n\trenderImageBuffer,\n\t// images will be rotated at a random number between zero and rotationRange,\n\t// alternating between a positive and negative rotation\n\trotationRange,\n}: {\n\tchildren: ReactNode;\n\timages: string[];\n\trenderImageBuffer: number;\n\trotationRange: number;\n}) => {\n\tconst [scope, animate] = useAnimate();\n\n\tconst lastRenderPosition = useRef({ x: 0, y: 0 });\n\tconst imageRenderCount = useRef(0);\n\n\tconst handleMouseMove: MouseEventHandler<HTMLDivElement> = (e) => {\n\t\tconst { clientX, clientY } = e;\n\n\t\tconst distance = calculateDistance(\n\t\t\tclientX,\n\t\t\tclientY,\n\t\t\tlastRenderPosition.current.x,\n\t\t\tlastRenderPosition.current.y\n\t\t);\n\n\t\tif (distance >= renderImageBuffer) {\n\t\t\tlastRenderPosition.current.x = clientX;\n\t\t\tlastRenderPosition.current.y = clientY;\n\n\t\t\trenderNextImage();\n\t\t}\n\t};\n\n\tconst calculateDistance = (\n\t\tx1: number,\n\t\ty1: number,\n\t\tx2: number,\n\t\ty2: number\n\t) => {\n\t\tconst deltaX = x2 - x1;\n\t\tconst deltaY = y2 - y1;\n\n\t\t// Using the Pythagorean theorem to calculate the distance\n\t\tconst distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\n\n\t\treturn distance;\n\t};\n\n\tconst renderNextImage = () => {\n\t\tconst imageIndex = imageRenderCount.current % images?.length;\n\t\tconst selector = `[data-mouse-move-index=\"${imageIndex}\"]`;\n\n\t\tconst el = document.querySelector(selector) as HTMLElement;\n\n\t\tel.style.top = `${lastRenderPosition.current.y}px`;\n\t\tel.style.left = `${lastRenderPosition.current.x}px`;\n\t\tel.style.zIndex = imageRenderCount.current.toString();\n\n\t\tconst rotation = Math.random() * rotationRange;\n\n\t\tanimate(\n\t\t\tselector,\n\t\t\t{\n\t\t\t\topacity: [0, 1],\n\t\t\t\ttransform: [\n\t\t\t\t\t`translate(-50%, -25%) scale(0.5) ${\n\t\t\t\t\t\timageIndex % 2\n\t\t\t\t\t\t\t? `rotate(${rotation}deg)`\n\t\t\t\t\t\t\t: `rotate(-${rotation}deg)`\n\t\t\t\t\t}`,\n\t\t\t\t\t`translate(-50%, -50%) scale(1) ${\n\t\t\t\t\t\timageIndex % 2\n\t\t\t\t\t\t\t? `rotate(-${rotation}deg)`\n\t\t\t\t\t\t\t: `rotate(${rotation}deg)`\n\t\t\t\t\t}`,\n\t\t\t\t],\n\t\t\t},\n\t\t\t{ type: \"spring\", damping: 15, stiffness: 200 }\n\t\t);\n\n\t\tanimate(\n\t\t\tselector,\n\t\t\t{\n\t\t\t\topacity: [1, 0],\n\t\t\t},\n\t\t\t{ ease: \"linear\", duration: 0.5, delay: 5 }\n\t\t);\n\n\t\timageRenderCount.current = imageRenderCount.current + 1;\n\t};\n\n\treturn (\n\t\t<div\n\t\t\tref={scope}\n\t\t\tclassName=\"relative overflow-hidden\"\n\t\t\tonMouseMove={handleMouseMove}\n\t\t>\n\t\t\t{children}\n\n\t\t\t{images?.map((img, index) => (\n\t\t\t\t<img\n\t\t\t\t\tclassName=\"pointer-events-none absolute left-0 top-0 h-48 w-auto rounded-xl border-2 border-black bg-background object-cover opacity-0\"\n\t\t\t\t\tsrc={img}\n\t\t\t\t\talt={`Mouse move image ${index}`}\n\t\t\t\t\tkey={index + \"image-trail\"}\n\t\t\t\t\tdata-mouse-move-index={index}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</div>\n\t);\n};\n\nexport default MouseImageTrailUsage;\n",
      "type": "registry:block",
      "target": "~/example.tsx"
    },
    {
      "path": "components/usages/mouseimagetrailusage.tsx",
      "content": "import React, { MouseEventHandler, ReactNode, useRef } from \"react\";\n\nimport { useAnimate } from \"motion/react\";\nimport { FiMousePointer } from \"react-icons/fi\";\n\nconst MouseImageTrailUsage = () => {\n\treturn (\n\t\t<MouseImageTrail\n\t\t\trenderImageBuffer={50}\n\t\t\trotationRange={25}\n\t\t\timages={[\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t\t\"/itjustworks.jpg\",\n\t\t\t]}\n\t\t>\n\t\t\t<section className=\"grid h-screen w-full place-content-center bg-background\">\n\t\t\t\t<p className=\"flex items-center gap-2 text-3xl font-bold uppercase text-secondary\">\n\t\t\t\t\t<FiMousePointer />\n\t\t\t\t\t<span>Hover me</span>\n\t\t\t\t</p>\n\t\t\t</section>\n\t\t</MouseImageTrail>\n\t);\n};\n\nconst MouseImageTrail = ({\n\tchildren,\n\t// List of image sources\n\timages,\n\t// Will render a new image every X pixels between mouse moves\n\trenderImageBuffer,\n\t// images will be rotated at a random number between zero and rotationRange,\n\t// alternating between a positive and negative rotation\n\trotationRange,\n}: {\n\tchildren: ReactNode;\n\timages: string[];\n\trenderImageBuffer: number;\n\trotationRange: number;\n}) => {\n\tconst [scope, animate] = useAnimate();\n\n\tconst lastRenderPosition = useRef({ x: 0, y: 0 });\n\tconst imageRenderCount = useRef(0);\n\n\tconst handleMouseMove: MouseEventHandler<HTMLDivElement> = (e) => {\n\t\tconst { clientX, clientY } = e;\n\n\t\tconst distance = calculateDistance(\n\t\t\tclientX,\n\t\t\tclientY,\n\t\t\tlastRenderPosition.current.x,\n\t\t\tlastRenderPosition.current.y\n\t\t);\n\n\t\tif (distance >= renderImageBuffer) {\n\t\t\tlastRenderPosition.current.x = clientX;\n\t\t\tlastRenderPosition.current.y = clientY;\n\n\t\t\trenderNextImage();\n\t\t}\n\t};\n\n\tconst calculateDistance = (\n\t\tx1: number,\n\t\ty1: number,\n\t\tx2: number,\n\t\ty2: number\n\t) => {\n\t\tconst deltaX = x2 - x1;\n\t\tconst deltaY = y2 - y1;\n\n\t\t// Using the Pythagorean theorem to calculate the distance\n\t\tconst distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\n\n\t\treturn distance;\n\t};\n\n\tconst renderNextImage = () => {\n\t\tconst imageIndex = imageRenderCount.current % images?.length;\n\t\tconst selector = `[data-mouse-move-index=\"${imageIndex}\"]`;\n\n\t\tconst el = document.querySelector(selector) as HTMLElement;\n\n\t\tel.style.top = `${lastRenderPosition.current.y}px`;\n\t\tel.style.left = `${lastRenderPosition.current.x}px`;\n\t\tel.style.zIndex = imageRenderCount.current.toString();\n\n\t\tconst rotation = Math.random() * rotationRange;\n\n\t\tanimate(\n\t\t\tselector,\n\t\t\t{\n\t\t\t\topacity: [0, 1],\n\t\t\t\ttransform: [\n\t\t\t\t\t`translate(-50%, -25%) scale(0.5) ${\n\t\t\t\t\t\timageIndex % 2\n\t\t\t\t\t\t\t? `rotate(${rotation}deg)`\n\t\t\t\t\t\t\t: `rotate(-${rotation}deg)`\n\t\t\t\t\t}`,\n\t\t\t\t\t`translate(-50%, -50%) scale(1) ${\n\t\t\t\t\t\timageIndex % 2\n\t\t\t\t\t\t\t? `rotate(-${rotation}deg)`\n\t\t\t\t\t\t\t: `rotate(${rotation}deg)`\n\t\t\t\t\t}`,\n\t\t\t\t],\n\t\t\t},\n\t\t\t{ type: \"spring\", damping: 15, stiffness: 200 }\n\t\t);\n\n\t\tanimate(\n\t\t\tselector,\n\t\t\t{\n\t\t\t\topacity: [1, 0],\n\t\t\t},\n\t\t\t{ ease: \"linear\", duration: 0.5, delay: 5 }\n\t\t);\n\n\t\timageRenderCount.current = imageRenderCount.current + 1;\n\t};\n\n\treturn (\n\t\t<div\n\t\t\tref={scope}\n\t\t\tclassName=\"relative overflow-hidden\"\n\t\t\tonMouseMove={handleMouseMove}\n\t\t>\n\t\t\t{children}\n\n\t\t\t{images?.map((img, index) => (\n\t\t\t\t<img\n\t\t\t\t\tclassName=\"pointer-events-none absolute left-0 top-0 h-48 w-auto rounded-xl border-2 border-black bg-background object-cover opacity-0\"\n\t\t\t\t\tsrc={img}\n\t\t\t\t\talt={`Mouse move image ${index}`}\n\t\t\t\t\tkey={index + \"image-trail\"}\n\t\t\t\t\tdata-mouse-move-index={index}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</div>\n\t);\n};\n\nexport default MouseImageTrailUsage;\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/mouse-image-trail.tsx",
      "content": "import React, { MouseEventHandler, ReactNode, useRef } from \"react\";\r\n\r\nimport { useAnimate } from \"motion/react\";\r\n\r\n// www.hover.dev/components/other#mouse-image-trail\r\n\r\nexport const MouseImageTrail = ({\r\n\tchildren,\r\n\t// List of image sources\r\n\timages,\r\n\t// Will render a new image every X pixels between mouse moves\r\n\trenderImageBuffer,\r\n\t// images will be rotated at a random number between zero and rotationRange,\r\n\t// alternating between a positive and negative rotation\r\n\trotationRange,\r\n}: {\r\n\tchildren: ReactNode;\r\n\timages: string[];\r\n\trenderImageBuffer: number;\r\n\trotationRange: number;\r\n}) => {\r\n\tconst [scope, animate] = useAnimate();\r\n\r\n\tconst lastRenderPosition = useRef({ x: 0, y: 0 });\r\n\tconst imageRenderCount = useRef(0);\r\n\r\n\tconst handleMouseMove: MouseEventHandler<HTMLDivElement> = (e) => {\r\n\t\tconst { clientX, clientY } = e;\r\n\r\n\t\tconst distance = calculateDistance(\r\n\t\t\tclientX,\r\n\t\t\tclientY,\r\n\t\t\tlastRenderPosition.current.x,\r\n\t\t\tlastRenderPosition.current.y\r\n\t\t);\r\n\r\n\t\tif (distance >= renderImageBuffer) {\r\n\t\t\tlastRenderPosition.current.x = clientX;\r\n\t\t\tlastRenderPosition.current.y = clientY;\r\n\r\n\t\t\trenderNextImage();\r\n\t\t}\r\n\t};\r\n\r\n\tconst calculateDistance = (\r\n\t\tx1: number,\r\n\t\ty1: number,\r\n\t\tx2: number,\r\n\t\ty2: number\r\n\t) => {\r\n\t\tconst deltaX = x2 - x1;\r\n\t\tconst deltaY = y2 - y1;\r\n\r\n\t\t// Using the Pythagorean theorem to calculate the distance\r\n\t\tconst distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\r\n\r\n\t\treturn distance;\r\n\t};\r\n\r\n\tconst renderNextImage = () => {\r\n\t\tconst imageIndex = imageRenderCount.current % images?.length;\r\n\t\tconst selector = `[data-mouse-move-index=\"${imageIndex}\"]`;\r\n\r\n\t\tconst el = document.querySelector(selector) as HTMLElement;\r\n\r\n\t\tel.style.top = `${lastRenderPosition.current.y}px`;\r\n\t\tel.style.left = `${lastRenderPosition.current.x}px`;\r\n\t\tel.style.zIndex = imageRenderCount.current.toString();\r\n\r\n\t\tconst rotation = Math.random() * rotationRange;\r\n\r\n\t\tanimate(\r\n\t\t\tselector,\r\n\t\t\t{\r\n\t\t\t\topacity: [0, 1],\r\n\t\t\t\ttransform: [\r\n\t\t\t\t\t`translate(-50%, -25%) scale(0.5) ${\r\n\t\t\t\t\t\timageIndex % 2\r\n\t\t\t\t\t\t\t? `rotate(${rotation}deg)`\r\n\t\t\t\t\t\t\t: `rotate(-${rotation}deg)`\r\n\t\t\t\t\t}`,\r\n\t\t\t\t\t`translate(-50%, -50%) scale(1) ${\r\n\t\t\t\t\t\timageIndex % 2\r\n\t\t\t\t\t\t\t? `rotate(-${rotation}deg)`\r\n\t\t\t\t\t\t\t: `rotate(${rotation}deg)`\r\n\t\t\t\t\t}`,\r\n\t\t\t\t],\r\n\t\t\t},\r\n\t\t\t{ type: \"spring\", damping: 15, stiffness: 200 }\r\n\t\t);\r\n\r\n\t\tanimate(\r\n\t\t\tselector,\r\n\t\t\t{\r\n\t\t\t\topacity: [1, 0],\r\n\t\t\t},\r\n\t\t\t{ ease: \"linear\", duration: 0.5, delay: 5 }\r\n\t\t);\r\n\r\n\t\timageRenderCount.current = imageRenderCount.current + 1;\r\n\t};\r\n\r\n\treturn (\r\n\t\t<div\r\n\t\t\tref={scope}\r\n\t\t\tclassName=\"relative overflow-hidden h-screen z-502\"\r\n\t\t\tonMouseMove={handleMouseMove}\r\n\t\t>\r\n\t\t\t{children}\r\n\r\n\t\t\t{images?.map((img, index) => (\r\n\t\t\t\t<img\r\n\t\t\t\t\tclassName=\"pointer-events-none absolute left-0 top-0 h-48 w-auto rounded-xl border-2 border-black bg-background object-cover opacity-0\"\r\n\t\t\t\t\tsrc={img}\r\n\t\t\t\t\talt={`Mouse move image ${index}`}\r\n\t\t\t\t\tkey={index + \"mouse-image-trail\"}\r\n\t\t\t\t\tdata-mouse-move-index={index}\r\n\t\t\t\t/>\r\n\t\t\t))}\r\n\t\t</div>\r\n\t);\r\n};\r\n",
      "type": "registry:ui"
    }
  ]
}