{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "shader-lens-blur",
  "type": "registry:ui",
  "description": "WebGL shader component with lens blur effects and mouse interaction",
  "dependencies": [
    "motion",
    "three",
    "jotai"
  ],
  "files": [
    {
      "path": "registry/default/ui/shader-lens-blur.tsx",
      "content": "\"use client\"\n\nimport { useCallback, useEffect, useRef, useState } from \"react\"\nimport { atom, useAtom } from \"jotai\"\nimport { motion } from \"motion/react\"\nimport { useTheme } from \"next-themes\"\nimport * as THREE from \"three\"\n\nconst fragmentShader = `\nvarying vec2 v_texcoord;\n\nuniform vec2 u_mouse;\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_time;\nuniform vec3 u_color1;\nuniform vec3 u_color2;\nuniform vec3 u_color3;\nuniform vec3 u_color4;\nuniform float u_hoverStrength;\nuniform bool u_invertMouse;\nuniform bool u_isDarkMode;\n\n#define PI 3.1415926535897932384626433832795\n#define TWO_PI 6.2831853071795864769252867665590\n\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\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}\n\nfloat sdCircle(in vec2 st, in vec2 center) {\n    return length(st - center) * 2.0;\n}\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}\n\nfloat fill(float x, float size, float edge) {\n    return 1.0 - smoothstep(size - edge, size + edge, x);\n}\n\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\nvoid main() {\n    vec2 st = st0 + 0.5;\n    vec2 posMouse = mx + 0.5;\n    \n    float size = 1.2 + sin(u_time) * 0.1;\n    float roundness = 0.4 + sin(u_time * 0.5) * 0.1;\n    float borderSize = 0.05 + sin(u_time * 0.7) * 0.02;\n    float circleSize = 0.3 + sin(u_time * 0.8) * 0.05;\n    float circleEdge = 0.5 + sin(u_time * 0.6) * 0.1;\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 = stroke(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 = stroke(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 gradient = mix(\n        mix(u_color1, u_color2, 0.5 + 0.5 * cos(u_time + st.x + 0.0)),\n        mix(u_color3, u_color4, 0.5 + 0.5 * cos(u_time + st.y + 2.0)),\n        0.5 + 0.5 * cos(u_time + st.x + st.y + 4.0)\n    );\n    \n    vec3 shapeColor = sdf * gradient;\n    \n    float mouseEffect = u_invertMouse ? 1.0 - sdfCircle : sdfCircle;\n    shapeColor = mix(shapeColor, vec3(1.0) - shapeColor, u_hoverStrength * mouseEffect);\n    \n    if (u_isDarkMode) {\n        shapeColor = mix(shapeColor, vec3(1.0), 0.2);\n    } else {\n        shapeColor = mix(shapeColor, vec3(0.0), 0.1);\n    }\n    \n    gl_FragColor = vec4(shapeColor, sdf);\n}\n`\n\ninterface ShaderConfig {\n  variation: number\n  color1: string\n  color2: string\n  color3: string\n  color4: string\n  enableHover: boolean\n  invertMouse: boolean\n  width: string\n  height: string\n}\n\nconst initialState: ShaderConfig = {\n  variation: 3,\n  color1: \"#D5F981\",\n  color2: \"#A1BBE7\",\n  color3: \"#F2BAE2\",\n  color4: \"#68E8FA\",\n  enableHover: true,\n  invertMouse: true,\n  width: \"100%\",\n  height: \"400px\",\n}\n\nexport const configAtom = atom<ShaderConfig>(initialState)\n\nexport function ShaderLensBlur() {\n  const [config] = useAtom(configAtom)\n  const containerRef = useRef<HTMLDivElement>(null)\n  const canvasRef = useRef<HTMLCanvasElement>(null)\n  const rendererRef = useRef<THREE.WebGLRenderer | null>(null)\n  const sceneRef = useRef<THREE.Scene | null>(null)\n  const cameraRef = useRef<THREE.OrthographicCamera | null>(null)\n  const materialRef = useRef<THREE.ShaderMaterial | null>(null)\n  const rafRef = useRef<number | null>(null)\n  const pixelRatioRef = useRef(1)\n  const [isInteracting, setIsInteracting] = useState(false)\n  const { theme } = useTheme()\n\n  const updateSize = useCallback(() => {\n    if (\n      !containerRef.current ||\n      !canvasRef.current ||\n      !rendererRef.current ||\n      !cameraRef.current ||\n      !materialRef.current\n    )\n      return\n\n    const { clientWidth: w, clientHeight: h } = containerRef.current\n    const aspect = w / h\n\n    cameraRef.current.left = -aspect\n    cameraRef.current.right = aspect\n    cameraRef.current.top = 1\n    cameraRef.current.bottom = -1\n    cameraRef.current.updateProjectionMatrix()\n\n    const pixelRatio = Math.min(window.devicePixelRatio || 1, 2)\n    pixelRatioRef.current = pixelRatio\n\n    rendererRef.current.setPixelRatio(pixelRatio)\n    rendererRef.current.setSize(w, h)\n\n    const drawingBufferSize = rendererRef.current.getDrawingBufferSize(\n      new THREE.Vector2()\n    )\n    materialRef.current.uniforms.u_resolution.value.copy(drawingBufferSize)\n    materialRef.current.uniforms.u_pixelRatio.value = pixelRatio\n  }, [])\n\n  const updateMousePosition = useCallback(\n    (x: number, y: number) => {\n      if (!containerRef.current || !materialRef.current) return\n      const rect = containerRef.current.getBoundingClientRect()\n      const mouseX = x - rect.left\n      const mouseY = y - rect.top\n      if (isInteracting || config.enableHover) {\n        materialRef.current.uniforms.u_mouse.value.set(\n          mouseX,\n          rect.height - mouseY\n        )\n      }\n    },\n    [isInteracting, config.enableHover]\n  )\n\n  const animate = useCallback(\n    (time: number) => {\n      if (\n        !rendererRef.current ||\n        !sceneRef.current ||\n        !cameraRef.current ||\n        !materialRef.current\n      )\n        return\n\n      const pixelRatio = Math.min(window.devicePixelRatio || 1, 2)\n      if (pixelRatio !== pixelRatioRef.current) {\n        updateSize()\n      }\n\n      materialRef.current.uniforms.u_time.value = time * 0.001\n      materialRef.current.uniforms.u_hoverStrength.value =\n        isInteracting || config.enableHover ? 0.3 : 0\n\n      rendererRef.current.render(sceneRef.current, cameraRef.current)\n      rafRef.current = requestAnimationFrame(animate)\n    },\n    [config.enableHover, isInteracting, updateSize]\n  )\n\n  useEffect(() => {\n    if (!containerRef.current || !canvasRef.current) return\n\n    const scene = new THREE.Scene()\n    sceneRef.current = scene\n\n    const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0.1, 1000)\n    camera.position.z = 1\n    cameraRef.current = camera\n\n    const renderer = new THREE.WebGLRenderer({\n      canvas: canvasRef.current,\n      antialias: true,\n      alpha: true,\n    })\n    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))\n    renderer.setClearColor(0x000000, 0)\n    rendererRef.current = renderer\n\n    const geometry = new THREE.PlaneGeometry(2, 2)\n    const material = new THREE.ShaderMaterial({\n      vertexShader: `\n        varying vec2 v_texcoord;\n        void main() {\n          gl_Position = vec4(position, 1.0);\n          v_texcoord = uv;\n        }\n      `,\n      fragmentShader,\n      uniforms: {\n        u_mouse: { value: new THREE.Vector2() },\n        u_resolution: { value: new THREE.Vector2() },\n        u_pixelRatio: { value: Math.min(window.devicePixelRatio, 2) },\n        u_time: { value: 0 },\n        u_color1: { value: new THREE.Color(config.color1) },\n        u_color2: { value: new THREE.Color(config.color2) },\n        u_color3: { value: new THREE.Color(config.color3) },\n        u_color4: { value: new THREE.Color(config.color4) },\n        u_hoverStrength: { value: 0 },\n        u_invertMouse: { value: config.invertMouse },\n        u_isDarkMode: { value: theme === \"dark\" },\n      },\n      defines: {\n        VAR: config.variation,\n      },\n      transparent: true,\n      blending: THREE.NormalBlending,\n    })\n    materialRef.current = material\n\n    const mesh = new THREE.Mesh(geometry, material)\n    scene.add(mesh)\n\n    updateSize()\n    rafRef.current = requestAnimationFrame(animate)\n\n    const resizeObserver = new ResizeObserver(updateSize)\n    resizeObserver.observe(containerRef.current)\n\n    return () => {\n      if (rafRef.current) cancelAnimationFrame(rafRef.current)\n      if (rendererRef.current) rendererRef.current.dispose()\n      if (containerRef.current) resizeObserver.unobserve(containerRef.current)\n    }\n  }, [config, updateSize, animate, theme])\n\n  useEffect(() => {\n    const container = containerRef.current\n    if (!container) return\n\n    const handlePointerMove = (event: PointerEvent) =>\n      updateMousePosition(event.clientX, event.clientY)\n    const handleTouchMove = (event: TouchEvent) => {\n      if (event.touches.length > 0) {\n        const touch = event.touches[0]\n        updateMousePosition(touch.clientX, touch.clientY)\n      }\n    }\n    const handlePointerDown = () => setIsInteracting(true)\n    const handlePointerUp = () => setIsInteracting(false)\n    const handleTouchStart = () => setIsInteracting(true)\n    const handleTouchEnd = () => setIsInteracting(false)\n\n    container.addEventListener(\"pointermove\", handlePointerMove)\n    container.addEventListener(\"touchmove\", handleTouchMove)\n    container.addEventListener(\"pointerdown\", handlePointerDown)\n    container.addEventListener(\"pointerup\", handlePointerUp)\n    container.addEventListener(\"touchstart\", handleTouchStart)\n    container.addEventListener(\"touchend\", handleTouchEnd)\n\n    return () => {\n      container.removeEventListener(\"pointermove\", handlePointerMove)\n      container.removeEventListener(\"touchmove\", handleTouchMove)\n      container.removeEventListener(\"pointerdown\", handlePointerDown)\n      container.removeEventListener(\"pointerup\", handlePointerUp)\n      container.removeEventListener(\"touchstart\", handleTouchStart)\n      container.removeEventListener(\"touchend\", handleTouchEnd)\n    }\n  }, [updateMousePosition])\n\n  useEffect(() => {\n    if (materialRef.current) {\n      materialRef.current.uniforms.u_color1.value.set(config.color1)\n      materialRef.current.uniforms.u_color2.value.set(config.color2)\n      materialRef.current.uniforms.u_color3.value.set(config.color3)\n      materialRef.current.uniforms.u_color4.value.set(config.color4)\n      materialRef.current.uniforms.u_invertMouse.value = config.invertMouse\n      materialRef.current.uniforms.u_isDarkMode.value = theme === \"dark\"\n      materialRef.current.defines.VAR = config.variation\n      materialRef.current.needsUpdate = true\n    }\n  }, [config, theme])\n\n  return (\n    <motion.div\n      ref={containerRef}\n      initial={{ opacity: 0 }}\n      animate={{ opacity: 1 }}\n      transition={{ duration: 0.5 }}\n      className=\"relative\"\n      style={{\n        width: config.width,\n        height: config.height,\n        backgroundColor: \"black\",\n        borderRadius: \"8px\",\n      }}\n    >\n      <canvas ref={canvasRef} className=\"w-full h-full touch-none\" />\n      <div\n        className={`absolute bottom-4 left-4 text-sm ${\n          theme === \"dark\" ? \"text-neutral-300\" : \"text-neutral-200\"\n        }`}\n      >\n        {config.enableHover\n          ? `${\n              config.invertMouse ? \"Inverted mouse\" : \"Normal mouse\"\n            } interaction`\n          : \"Interact with the animation\"}{\" \"}\n        using mouse or touch\n      </div>\n    </motion.div>\n  )\n}\n\nexport default ShaderLensBlur\n// \"use client\"\n\n// // npm install jotai three\n// import React, { useCallback, useEffect, useRef, useState } from \"react\"\n// import { motion } from \"motion/react\"\n// import { atom, useAtom } from \"jotai\"\n// import * as THREE from \"three\"\n\n// const fragmentShader = `\n// varying vec2 v_texcoord;\n\n// uniform vec2 u_mouse;\n// uniform vec2 u_resolution;\n// uniform float u_pixelRatio;\n// uniform float u_time;\n// uniform vec3 u_color1;\n// uniform vec3 u_color2;\n// uniform vec3 u_color3;\n// uniform vec3 u_color4;\n// uniform float u_hoverStrength;\n// uniform bool u_invertMouse;\n\n// #define PI 3.1415926535897932384626433832795\n// #define TWO_PI 6.2831853071795864769252867665590\n\n// vec2 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\n// #define st0 coord(gl_FragCoord.xy)\n// #define mx coord(u_mouse)\n\n// float 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// }\n\n// float sdCircle(in vec2 st, in vec2 center) {\n//     return length(st - center) * 2.0;\n// }\n\n// float 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\n// float 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// }\n\n// float fill(float x, float size, float edge) {\n//     return 1.0 - smoothstep(size - edge, size + edge, x);\n// }\n\n// float 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\n// void main() {\n//     vec2 st = st0 + 0.5;\n//     vec2 posMouse = mx + 0.5;\n\n//     float size = 1.2 + sin(u_time) * 0.1;\n//     float roundness = 0.4 + sin(u_time * 0.5) * 0.1;\n//     float borderSize = 0.05 + sin(u_time * 0.7) * 0.02;\n//     float circleSize = 0.3 + sin(u_time * 0.8) * 0.05;\n//     float circleEdge = 0.5 + sin(u_time * 0.6) * 0.1;\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 = stroke(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 = stroke(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 gradient = mix(\n//         mix(u_color1, u_color2, 0.5 + 0.5 * cos(u_time + st.x + 0.0)),\n//         mix(u_color3, u_color4, 0.5 + 0.5 * cos(u_time + st.y + 2.0)),\n//         0.5 + 0.5 * cos(u_time + st.x + st.y + 4.0)\n//     );\n\n//     vec3 shapeColor = sdf * gradient;\n\n//     float mouseEffect = u_invertMouse ? 1.0 - sdfCircle : sdfCircle;\n//     shapeColor = mix(shapeColor, vec3(1.0) - shapeColor, u_hoverStrength * mouseEffect);\n\n//     gl_FragColor = vec4(shapeColor, sdf);\n// }\n// `\n\n// interface ShaderConfig {\n//   variation: number\n//   color1: string\n//   color2: string\n//   color3: string\n//   color4: string\n//   enableHover: boolean\n//   invertMouse: boolean\n//   width: string\n//   height: string\n// }\n\n// const initialState: ShaderConfig = {\n//   variation: 0,\n//   color1: \"#ff0000\",\n//   color2: \"#00ff00\",\n//   color3: \"#0000ff\",\n//   color4: \"#ffff00\",\n//   enableHover: true,\n//   invertMouse: true,\n//   width: \"100%\",\n//   height: \"400px\",\n// }\n\n// export const configAtom = atom<ShaderConfig>(initialState)\n\n// export function ShaderLensBlur() {\n//   const [config] = useAtom(configAtom)\n//   const containerRef = useRef<HTMLDivElement>(null)\n//   const canvasRef = useRef<HTMLCanvasElement>(null)\n//   const rendererRef = useRef<THREE.WebGLRenderer | null>(null)\n//   const sceneRef = useRef<THREE.Scene | null>(null)\n//   const cameraRef = useRef<THREE.OrthographicCamera | null>(null)\n//   const materialRef = useRef<THREE.ShaderMaterial | null>(null)\n//   const rafRef = useRef<number | null>(null)\n//   const [isInteracting, setIsInteracting] = useState(false)\n\n//   const updateSize = useCallback(() => {\n//     if (\n//       !containerRef.current ||\n//       !canvasRef.current ||\n//       !rendererRef.current ||\n//       !cameraRef.current ||\n//       !materialRef.current\n//     )\n//       return\n\n//     const { clientWidth: w, clientHeight: h } = containerRef.current\n//     const aspect = w / h\n\n//     cameraRef.current.left = -aspect\n//     cameraRef.current.right = aspect\n//     cameraRef.current.top = 1\n//     cameraRef.current.bottom = -1\n//     cameraRef.current.updateProjectionMatrix()\n\n//     rendererRef.current.setSize(w, h)\n//     materialRef.current.uniforms.u_resolution.value.set(w, h)\n//   }, [])\n\n//   const updateMousePosition = useCallback(\n//     (x: number, y: number) => {\n//       if (!containerRef.current || !materialRef.current) return\n//       const rect = containerRef.current.getBoundingClientRect()\n//       const mouseX = x - rect.left\n//       const mouseY = y - rect.top\n//       if (isInteracting || config.enableHover) {\n//         materialRef.current.uniforms.u_mouse.value.set(\n//           mouseX,\n//           rect.height - mouseY\n//         )\n//       }\n//     },\n//     [isInteracting, config.enableHover]\n//   )\n\n//   const animate = useCallback(\n//     (time: number) => {\n//       if (\n//         !rendererRef.current ||\n//         !sceneRef.current ||\n//         !cameraRef.current ||\n//         !materialRef.current\n//       )\n//         return\n\n//       materialRef.current.uniforms.u_time.value = time * 0.001\n//       materialRef.current.uniforms.u_hoverStrength.value =\n//         isInteracting || config.enableHover ? 0.3 : 0\n\n//       rendererRef.current.render(sceneRef.current, cameraRef.current)\n//       rafRef.current = requestAnimationFrame(animate)\n//     },\n//     [config.enableHover, isInteracting]\n//   )\n\n//   useEffect(() => {\n//     if (!containerRef.current || !canvasRef.current) return\n\n//     const scene = new THREE.Scene()\n//     sceneRef.current = scene\n\n//     const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0.1, 1000)\n//     camera.position.z = 1\n//     cameraRef.current = camera\n\n//     const renderer = new THREE.WebGLRenderer({\n//       canvas: canvasRef.current,\n//       antialias: true,\n//       alpha: true,\n//     })\n//     renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))\n//     renderer.setClearColor(0x000000, 0)\n//     rendererRef.current = renderer\n\n//     const geometry = new THREE.PlaneGeometry(2, 2)\n//     const material = new THREE.ShaderMaterial({\n//       vertexShader: `\n//         varying vec2 v_texcoord;\n//         void main() {\n//           gl_Position = vec4(position, 1.0);\n//           v_texcoord = uv;\n//         }\n//       `,\n//       fragmentShader,\n//       uniforms: {\n//         u_mouse: { value: new THREE.Vector2() },\n//         u_resolution: { value: new THREE.Vector2() },\n//         u_pixelRatio: { value: Math.min(window.devicePixelRatio, 2) },\n//         u_time: { value: 0 },\n//         u_color1: { value: new THREE.Color(config.color1) },\n//         u_color2: { value: new THREE.Color(config.color2) },\n//         u_color3: { value: new THREE.Color(config.color3) },\n//         u_color4: { value: new THREE.Color(config.color4) },\n//         u_hoverStrength: { value: 0 },\n//         u_invertMouse: { value: config.invertMouse },\n//       },\n//       defines: {\n//         VAR: config.variation,\n//       },\n//       transparent: true,\n//       blending: THREE.NormalBlending,\n//     })\n//     materialRef.current = material\n\n//     const mesh = new THREE.Mesh(geometry, material)\n//     scene.add(mesh)\n\n//     updateSize()\n//     rafRef.current = requestAnimationFrame(animate)\n\n//     const resizeObserver = new ResizeObserver(updateSize)\n//     resizeObserver.observe(containerRef.current)\n\n//     return () => {\n//       if (rafRef.current) cancelAnimationFrame(rafRef.current)\n//       if (rendererRef.current) rendererRef.current.dispose()\n//       if (containerRef.current) resizeObserver.unobserve(containerRef.current)\n//     }\n//   }, [config, updateSize, animate])\n\n//   useEffect(() => {\n//     const container = containerRef.current\n//     if (!container) return\n\n//     const handlePointerMove = (event: PointerEvent) =>\n//       updateMousePosition(event.clientX, event.clientY)\n//     const handleTouchMove = (event: TouchEvent) => {\n//       if (event.touches.length > 0) {\n//         const touch = event.touches[0]\n//         updateMousePosition(touch.clientX, touch.clientY)\n//       }\n//     }\n\n//     container.addEventListener(\"pointermove\", handlePointerMove)\n//     container.addEventListener(\"touchmove\", handleTouchMove)\n//     container.addEventListener(\"pointerdown\", () => setIsInteracting(true))\n//     container.addEventListener(\"pointerup\", () => setIsInteracting(false))\n//     container.addEventListener(\"touchstart\", () => setIsInteracting(true))\n//     container.addEventListener(\"touchend\", () => setIsInteracting(false))\n\n//     return () => {\n//       container.removeEventListener(\"pointermove\", handlePointerMove)\n//       container.removeEventListener(\"touchmove\", handleTouchMove)\n//       container.removeEventListener(\"pointerdown\", () => setIsInteracting(true))\n//       container.removeEventListener(\"pointerup\", () => setIsInteracting(false))\n//       container.removeEventListener(\"touchstart\", () => setIsInteracting(true))\n//       container.removeEventListener(\"touchend\", () => setIsInteracting(false))\n//     }\n//   }, [updateMousePosition])\n\n//   useEffect(() => {\n//     if (materialRef.current) {\n//       materialRef.current.uniforms.u_color1.value.set(config.color1)\n//       materialRef.current.uniforms.u_color2.value.set(config.color2)\n//       materialRef.current.uniforms.u_color3.value.set(config.color3)\n//       materialRef.current.uniforms.u_color4.value.set(config.color4)\n//       materialRef.current.uniforms.u_invertMouse.value = config.invertMouse\n//       materialRef.current.defines.VAR = config.variation\n//       materialRef.current.needsUpdate = true\n//     }\n//   }, [config])\n\n//   return (\n//     <motion.div\n//       ref={containerRef}\n//       initial={{ opacity: 0 }}\n//       animate={{ opacity: 1 }}\n//       transition={{ duration: 0.5 }}\n//       className=\"relative\"\n//       style={{\n//         width: config.width,\n//         height: config.height,\n//         backgroundColor: \"transparent\",\n//         borderRadius: \"8px\",\n//       }}\n//     >\n//       <canvas ref={canvasRef} className=\"w-full h-full touch-none\" />\n//       <div className=\"absolute bottom-4 left-4 text-white text-sm\">\n//         {config.enableHover\n//           ? `${\n//               config.invertMouse ? \"Inverted mouse\" : \"Normal mouse\"\n//             } interaction`\n//           : \"Interact with the animation\"}{\" \"}\n//         using mouse or touch\n//       </div>\n//     </motion.div>\n//   )\n// }\n\n// export default ShaderLensBlur\n",
      "type": "registry:ui"
    }
  ]
}