{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "DecayCard-JS-TW",
	"title": "DecayCard",
	"description": "Hover parallax effect that disintegrates the content of a card.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:component",
			"path": "DecayCard/DecayCard.jsx",
			"content": "import { useEffect, useRef } from 'react';\nimport { gsap } from 'gsap';\n\nconst DecayCard = ({\n  width = 300,\n  height = 400,\n  image = 'https://picsum.photos/300/400?grayscale',\n  baseFrequency = 0.015,\n  numOctaves = 5,\n  seed = 4,\n  maxDisplacement = 400,\n  movementBound = 50,\n  children\n}) => {\n  const svgRef = useRef(null);\n  const displacementMapRef = useRef(null);\n  const cursor = useRef({\n    x: typeof window !== 'undefined' ? window.innerWidth / 2 : 0,\n    y: typeof window !== 'undefined' ? window.innerHeight / 2 : 0\n  });\n  const cachedCursor = useRef({ ...cursor.current });\n  const winsize = useRef({\n    width: typeof window !== 'undefined' ? window.innerWidth : 0,\n    height: typeof window !== 'undefined' ? window.innerHeight : 0\n  });\n\n  useEffect(() => {\n    const lerp = (a, b, n) => (1 - n) * a + n * b;\n    const map = (x, a, b, c, d) => ((x - a) * (d - c)) / (b - a) + c;\n    const distance = (x1, x2, y1, y2) => Math.hypot(x1 - x2, y1 - y2);\n\n    const handleResize = () => {\n      winsize.current = { width: window.innerWidth, height: window.innerHeight };\n    };\n\n    const handleMouseMove = ev => {\n      cursor.current = { x: ev.clientX, y: ev.clientY };\n    };\n\n    window.addEventListener('resize', handleResize);\n    window.addEventListener('mousemove', handleMouseMove);\n\n    const imgValues = {\n      imgTransforms: { x: 0, y: 0, rz: 0 },\n      displacementScale: 0\n    };\n\n    const render = () => {\n      let targetX = lerp(imgValues.imgTransforms.x, map(cursor.current.x, 0, winsize.current.width, -120, 120), 0.1);\n      let targetY = lerp(imgValues.imgTransforms.y, map(cursor.current.y, 0, winsize.current.height, -120, 120), 0.1);\n      let targetRz = lerp(imgValues.imgTransforms.rz, map(cursor.current.x, 0, winsize.current.width, -10, 10), 0.1);\n\n      if (targetX > movementBound) targetX = movementBound + (targetX - movementBound) * 0.2;\n      if (targetX < -movementBound) targetX = -movementBound + (targetX + movementBound) * 0.2;\n      if (targetY > movementBound) targetY = movementBound + (targetY - movementBound) * 0.2;\n      if (targetY < -movementBound) targetY = -movementBound + (targetY + movementBound) * 0.2;\n\n      imgValues.imgTransforms.x = targetX;\n      imgValues.imgTransforms.y = targetY;\n      imgValues.imgTransforms.rz = targetRz;\n\n      if (svgRef.current) {\n        gsap.set(svgRef.current, {\n          x: imgValues.imgTransforms.x,\n          y: imgValues.imgTransforms.y,\n          rotateZ: imgValues.imgTransforms.rz\n        });\n      }\n\n      const cursorTravelledDistance = distance(\n        cachedCursor.current.x,\n        cursor.current.x,\n        cachedCursor.current.y,\n        cursor.current.y\n      );\n      imgValues.displacementScale = lerp(\n        imgValues.displacementScale,\n        map(cursorTravelledDistance, 0, 200, 0, maxDisplacement),\n        0.06\n      );\n\n      if (displacementMapRef.current) {\n        gsap.set(displacementMapRef.current, { attr: { scale: imgValues.displacementScale } });\n      }\n\n      cachedCursor.current = { ...cursor.current };\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    let rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      window.removeEventListener('resize', handleResize);\n      window.removeEventListener('mousemove', handleMouseMove);\n    };\n  }, [maxDisplacement, movementBound]);\n\n  return (\n    <div ref={svgRef} className=\"relative\" style={{ width: `${width}px`, height: `${height}px` }}>\n      <svg\n        viewBox=\"-60 -75 720 900\"\n        preserveAspectRatio=\"xMidYMid slice\"\n        className=\"relative w-full h-full block [will-change:transform]\"\n      >\n        <filter id=\"imgFilter\">\n          <feTurbulence\n            type=\"turbulence\"\n            baseFrequency={baseFrequency}\n            numOctaves={numOctaves}\n            seed={seed}\n            stitchTiles=\"stitch\"\n            x=\"0%\"\n            y=\"0%\"\n            width=\"100%\"\n            height=\"100%\"\n            result=\"turbulence1\"\n          />\n          <feDisplacementMap\n            ref={displacementMapRef}\n            in=\"SourceGraphic\"\n            in2=\"turbulence1\"\n            scale=\"0\"\n            xChannelSelector=\"R\"\n            yChannelSelector=\"B\"\n            x=\"0%\"\n            y=\"0%\"\n            width=\"100%\"\n            height=\"100%\"\n            result=\"displacementMap3\"\n          />\n        </filter>\n        <g>\n          <image\n            href={image}\n            x=\"0\"\n            y=\"0\"\n            width=\"600\"\n            height=\"750\"\n            filter=\"url(#imgFilter)\"\n            preserveAspectRatio=\"xMidYMid slice\"\n          />\n        </g>\n      </svg>\n      <div className=\"absolute bottom-[1.2em] left-[1em] tracking-[-0.5px] font-black text-[2.5rem] leading-[1.5em] first-line:text-[6rem]\">\n        {children}\n      </div>\n    </div>\n  );\n};\n\nexport default DecayCard;\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"gsap@^3.13.0"
	]
}