{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "ShapeBlur-JS-TW",
	"title": "ShapeBlur",
	"description": "Morphing blurred geometric shape. The effect occurs on hover.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:component",
			"path": "ShapeBlur/ShapeBlur.jsx",
			"content": "import { useEffect, useRef } from 'react';\nimport * as THREE from 'three';\n\nconst vertexShader = /* glsl */ `\nvarying vec2 v_texcoord;\nvoid main() {\n    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n    v_texcoord = uv;\n}\n`;\n\nconst fragmentShader = /* glsl */ `\nvarying vec2 v_texcoord;\n\nuniform vec2 u_mouse;\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\n\nuniform float u_shapeSize;\nuniform float u_roundness;\nuniform float u_borderSize;\nuniform float u_circleSize;\nuniform float u_circleEdge;\n\n#ifndef PI\n#define PI 3.1415926535897932384626433832795\n#endif\n#ifndef TWO_PI\n#define TWO_PI 6.2831853071795864769252867665590\n#endif\n\n#ifndef VAR\n#define VAR 0\n#endif\n\n#ifndef FNC_COORD\n#define FNC_COORD\nvec2 coord(in vec2 p) {\n    p = p / u_resolution.xy;\n    if (u_resolution.x > u_resolution.y) {\n        p.x *= u_resolution.x / u_resolution.y;\n        p.x += (u_resolution.y - u_resolution.x) / u_resolution.y / 2.0;\n    } else {\n        p.y *= u_resolution.y / u_resolution.x;\n        p.y += (u_resolution.x - u_resolution.y) / u_resolution.x / 2.0;\n    }\n    p -= 0.5;\n    p *= vec2(-1.0, 1.0);\n    return p;\n}\n#endif\n\n#define st0 coord(gl_FragCoord.xy)\n#define mx coord(u_mouse * u_pixelRatio)\n\nfloat sdRoundRect(vec2 p, vec2 b, float r) {\n    vec2 d = abs(p - 0.5) * 4.2 - b + vec2(r);\n    return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - r;\n}\nfloat sdCircle(in vec2 st, in vec2 center) {\n    return length(st - center) * 2.0;\n}\nfloat sdPoly(in vec2 p, in float w, in int sides) {\n    float a = atan(p.x, p.y) + PI;\n    float r = TWO_PI / float(sides);\n    float d = cos(floor(0.5 + a / r) * r - a) * length(max(abs(p) * 1.0, 0.0));\n    return d * 2.0 - w;\n}\n\nfloat aastep(float threshold, float value) {\n    float afwidth = length(vec2(dFdx(value), dFdy(value))) * 0.70710678118654757;\n    return smoothstep(threshold - afwidth, threshold + afwidth, value);\n}\nfloat fill(in float x) { return 1.0 - aastep(0.0, x); }\nfloat fill(float x, float size, float edge) {\n    return 1.0 - smoothstep(size - edge, size + edge, x);\n}\nfloat stroke(in float d, in float t) { return (1.0 - aastep(t, abs(d))); }\nfloat stroke(float x, float size, float w, float edge) {\n    float d = smoothstep(size - edge, size + edge, x + w * 0.5) - smoothstep(size - edge, size + edge, x - w * 0.5);\n    return clamp(d, 0.0, 1.0);\n}\n\nfloat strokeAA(float x, float size, float w, float edge) {\n    float afwidth = length(vec2(dFdx(x), dFdy(x))) * 0.70710678;\n    float d = smoothstep(size - edge - afwidth, size + edge + afwidth, x + w * 0.5)\n            - smoothstep(size - edge - afwidth, size + edge + afwidth, x - w * 0.5);\n    return clamp(d, 0.0, 1.0);\n}\n\nvoid main() {\n    vec2 st = st0 + 0.5;\n    vec2 posMouse = mx * vec2(1., -1.) + 0.5;\n\n    float size = u_shapeSize;\n    float roundness = u_roundness;\n    float borderSize = u_borderSize;\n    float circleSize = u_circleSize;\n    float circleEdge = u_circleEdge;\n\n    float sdfCircle = fill(\n        sdCircle(st, posMouse),\n        circleSize,\n        circleEdge\n    );\n\n    float sdf;\n    if (VAR == 0) {\n        sdf = sdRoundRect(st, vec2(size), roundness);\n        sdf = strokeAA(sdf, 0.0, borderSize, sdfCircle) * 4.0;\n    } else if (VAR == 1) {\n        sdf = sdCircle(st, vec2(0.5));\n        sdf = fill(sdf, 0.6, sdfCircle) * 1.2;\n    } else if (VAR == 2) {\n        sdf = sdCircle(st, vec2(0.5));\n        sdf = strokeAA(sdf, 0.58, 0.02, sdfCircle) * 4.0;\n    } else if (VAR == 3) {\n        sdf = sdPoly(st - vec2(0.5, 0.45), 0.3, 3);\n        sdf = fill(sdf, 0.05, sdfCircle) * 1.4;\n    }\n\n    vec3 color = vec3(1.0);\n    float alpha = sdf;\n    gl_FragColor = vec4(color.rgb, alpha);\n}\n`;\n\nconst ShapeBlur = ({\n  className = '',\n  variation = 0,\n  pixelRatioProp = 2,\n  shapeSize = 1.2,\n  roundness = 0.4,\n  borderSize = 0.05,\n  circleSize = 0.3,\n  circleEdge = 0.5\n}) => {\n  const mountRef = useRef();\n  const materialRef = useRef();\n\n  useEffect(() => {\n    const mount = mountRef.current;\n    if (!mount) return;\n\n    let active = true;\n    let animationFrameId;\n    let time = 0,\n      lastTime = 0;\n\n    const vMouse = new THREE.Vector2();\n    const vMouseDamp = new THREE.Vector2();\n    const vResolution = new THREE.Vector2();\n\n    let w = 1,\n      h = 1;\n\n    const scene = new THREE.Scene();\n    const camera = new THREE.OrthographicCamera();\n    camera.position.z = 1;\n\n    const renderer = new THREE.WebGLRenderer({ alpha: true });\n    renderer.setClearColor(0x000000, 0);\n    mount.appendChild(renderer.domElement);\n\n    const geo = new THREE.PlaneGeometry(1, 1);\n    const material = new THREE.ShaderMaterial({\n      vertexShader,\n      fragmentShader,\n      uniforms: {\n        u_mouse: { value: vMouseDamp },\n        u_resolution: { value: vResolution },\n        u_pixelRatio: { value: pixelRatioProp },\n        u_shapeSize: { value: shapeSize },\n        u_roundness: { value: roundness },\n        u_borderSize: { value: borderSize },\n        u_circleSize: { value: circleSize },\n        u_circleEdge: { value: circleEdge }\n      },\n      defines: { VAR: variation },\n      transparent: true\n    });\n    materialRef.current = material;\n\n    const quad = new THREE.Mesh(geo, material);\n    scene.add(quad);\n\n    const onPointerMove = e => {\n      const rect = mount.getBoundingClientRect();\n      vMouse.set(e.clientX - rect.left, e.clientY - rect.top);\n    };\n\n    document.addEventListener('mousemove', onPointerMove);\n    document.addEventListener('pointermove', onPointerMove);\n\n    const resize = () => {\n      if (!active) return;\n      w = mount.clientWidth;\n      h = mount.clientHeight;\n      const dpr = Math.min(window.devicePixelRatio, 2);\n\n      renderer.setSize(w, h);\n      renderer.setPixelRatio(dpr);\n\n      camera.left = -w / 2;\n      camera.right = w / 2;\n      camera.top = h / 2;\n      camera.bottom = -h / 2;\n      camera.updateProjectionMatrix();\n\n      quad.scale.set(w, h, 1);\n      vResolution.set(w, h).multiplyScalar(dpr);\n      material.uniforms.u_pixelRatio.value = dpr;\n    };\n\n    resize();\n    window.addEventListener('resize', resize);\n\n    const ro = new ResizeObserver(() => {\n      if (!active) return;\n      resize();\n    });\n    ro.observe(mount);\n\n    const update = () => {\n      if (!active) return;\n      time = performance.now() * 0.001;\n      const dt = time - lastTime;\n      lastTime = time;\n\n      ['x', 'y'].forEach(k => {\n        vMouseDamp[k] = THREE.MathUtils.damp(vMouseDamp[k], vMouse[k], 8, dt);\n      });\n\n      renderer.render(scene, camera);\n      animationFrameId = requestAnimationFrame(update);\n    };\n    update();\n\n    return () => {\n      active = false;\n\n      cancelAnimationFrame(animationFrameId);\n      window.removeEventListener('resize', resize);\n      ro.disconnect();\n      document.removeEventListener('mousemove', onPointerMove);\n      document.removeEventListener('pointermove', onPointerMove);\n      if (mount.contains(renderer.domElement)) {\n        mount.removeChild(renderer.domElement);\n      }\n      geo.dispose();\n      material.dispose();\n      materialRef.current = null;\n      renderer.dispose();\n      renderer.forceContextLoss();\n    };\n  }, [variation]);\n\n  useEffect(() => {\n    const mat = materialRef.current;\n    if (!mat) return;\n    mat.uniforms.u_pixelRatio.value = pixelRatioProp;\n    mat.uniforms.u_shapeSize.value = shapeSize;\n    mat.uniforms.u_roundness.value = roundness;\n    mat.uniforms.u_borderSize.value = borderSize;\n    mat.uniforms.u_circleSize.value = circleSize;\n    mat.uniforms.u_circleEdge.value = circleEdge;\n  }, [pixelRatioProp, shapeSize, roundness, borderSize, circleSize, circleEdge]);\n\n  return <div ref={mountRef} className={`w-full h-full ${className}`} />;\n};\n\nexport default ShapeBlur;\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"three@^0.180.0"
	]
}