{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "liquid-chrome",
  "type": "registry:ui",
  "title": "Liquid Chrome",
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Component for liquid-chrome",
  "files": [
    {
      "path": "components/ui/liquid-chrome.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"../lib/utils\";\nimport { useEffect, useRef } from \"react\";\n\ninterface LiquidChromeProps {\n  /** Additional CSS classes for custom styling */\n  className?: string;\n  /** Base color tint for the chrome. Default is white/silver. Use hex or rgb. */\n  baseColor?: [number, number, number];\n  /** Animation speed multiplier. Default is 1.0 */\n  speed?: number;\n  /** Detail level of the fluid waves. Higher is more detailed. Default is 0.4 */\n  amplitude?: number;\n  /** Enables mouse interaction if true */\n  interactive?: boolean;\n}\n\nconst vertexShaderSource = `\n  attribute vec2 position;\n  void main() {\n    gl_Position = vec4(position, 0.0, 1.0);\n  }\n`;\n\nconst fragmentShaderSource = `\n  precision highp float;\n\n  uniform vec2 u_resolution;\n  uniform float u_time;\n  uniform vec2 u_mouse;\n  uniform vec3 u_baseColor;\n  uniform float u_amplitude;\n\n  // Simple 2D noise\n  const mat2 m = mat2( 0.80,  0.60, -0.60,  0.80 );\n\n  float hash( vec2 p ) {\n      float h = dot(p,vec2(127.1,311.7));\n      return fract(sin(h)*43758.5453123);\n  }\n\n  float noise( in vec2 p ) {\n      vec2 i = floor( p );\n      vec2 f = fract( p );\n      vec2 u = f*f*(3.0-2.0*f);\n      return mix( mix( hash( i + vec2(0.0,0.0) ), \n                       hash( i + vec2(1.0,0.0) ), u.x),\n                  mix( hash( i + vec2(0.0,1.0) ), \n                       hash( i + vec2(1.0,1.0) ), u.x), u.y);\n  }\n\n  float fbm( vec2 p ) {\n      float f = 0.0;\n      f += 0.5000*noise( p ); p = m*p*2.02;\n      f += 0.2500*noise( p ); p = m*p*2.03;\n      f += 0.1250*noise( p ); p = m*p*2.01;\n      f += 0.0625*noise( p );\n      return f/0.9375;\n  }\n\n  void main() {\n    vec2 uv = gl_FragCoord.xy / u_resolution.xy;\n    vec2 p = -1.0 + 2.0 * uv;\n    if (u_resolution.y > 0.0) {\n        p.x *= u_resolution.x / u_resolution.y;\n    }\n\n    // Mouse interaction\n    vec2 mouse = (u_mouse - 0.5) * 2.0;\n    if (u_resolution.y > 0.0) {\n        mouse.x *= u_resolution.x / u_resolution.y;\n    }\n    \n    // Distort based on distance to mouse\n    vec2 diff = p - mouse;\n    float dist = length(diff);\n    vec2 distortion = vec2(0.0);\n    if (dist > 0.0) {\n        distortion = (diff / dist) * exp(-dist * 3.0) * 0.1;\n    }\n    p += distortion;\n\n    float time = u_time * 0.5;\n\n    // Domain warping\n    vec2 q = vec2(0.0);\n    q.x = fbm(p + vec2(0.0, 0.0) + time * 0.1);\n    q.y = fbm(p + vec2(5.2, 1.3) + time * 0.15);\n\n    vec2 r = vec2(0.0);\n    r.x = fbm(p + 4.0 * q + vec2(1.7, 9.2) + time * 0.2);\n    r.y = fbm(p + 4.0 * q + vec2(8.3, 2.8) + time * 0.25);\n\n    float f = fbm(p + r * 4.0 * u_amplitude);\n\n    // Color mixing (Chrome / Liquid Metal style)\n    vec3 col = u_baseColor;\n    \n    // Add bright highlights based on the warped noise\n    float highlight = smoothstep(0.4, 0.6, f);\n    float highlight2 = smoothstep(0.6, 0.8, f);\n    float dark = smoothstep(0.1, 0.3, f);\n    \n    col = mix(col, vec3(0.0), 1.0 - dark); // add shadows\n    col = mix(col, vec3(0.8, 0.8, 0.9), highlight); // add silver midtones\n    col = mix(col, vec3(1.0, 1.0, 1.0), highlight2); // add bright white specular\n    \n    // Vignette\n    float v = 16.0 * uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y);\n    col *= 0.5 + 0.5 * pow(max(0.0, v), 0.2);\n\n    gl_FragColor = vec4(col, 1.0);\n  }\n`;;\n\nexport function LiquidChrome({\n  className,\n  baseColor = [0.1, 0.1, 0.1],\n  speed = 1.0,\n  amplitude = 0.6,\n  interactive = true,\n}: LiquidChromeProps) {\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const colorRef = useRef(baseColor);\n  colorRef.current = baseColor;\n  const speedRef = useRef(speed);\n  speedRef.current = speed;\n  const amplitudeRef = useRef(amplitude);\n  amplitudeRef.current = amplitude;\n  const interactiveRef = useRef(interactive);\n  interactiveRef.current = interactive;\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n\n    const gl = canvas.getContext(\"webgl\");\n    if (!gl) {\n      console.error(\"WebGL not supported\");\n      return;\n    }\n\n    const vertexShader = gl.createShader(gl.VERTEX_SHADER)!;\n    gl.shaderSource(vertexShader, vertexShaderSource);\n    gl.compileShader(vertexShader);\n    if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {\n      console.error(\"Vertex shader error:\", gl.getShaderInfoLog(vertexShader));\n      return;\n    }\n\n    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)!;\n    gl.shaderSource(fragmentShader, fragmentShaderSource);\n    gl.compileShader(fragmentShader);\n    if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {\n      console.error(\"Fragment shader error:\", gl.getShaderInfoLog(fragmentShader));\n      return;\n    }\n\n    const program = gl.createProgram()!;\n    gl.attachShader(program, vertexShader);\n    gl.attachShader(program, fragmentShader);\n    gl.linkProgram(program);\n    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n      console.error(\"Program link error:\", gl.getProgramInfoLog(program));\n      return;\n    }\n    gl.useProgram(program);\n\n    const positionBuffer = gl.createBuffer();\n    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);\n    gl.bufferData(\n      gl.ARRAY_BUFFER,\n      new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),\n      gl.STATIC_DRAW\n    );\n\n    const positionLocation = gl.getAttribLocation(program, \"position\");\n    gl.enableVertexAttribArray(positionLocation);\n    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);\n\n    const resolutionLocation = gl.getUniformLocation(program, \"u_resolution\");\n    const timeLocation = gl.getUniformLocation(program, \"u_time\");\n    const mouseLocation = gl.getUniformLocation(program, \"u_mouse\");\n    const baseColorLocation = gl.getUniformLocation(program, \"u_baseColor\");\n    const amplitudeLocation = gl.getUniformLocation(program, \"u_amplitude\");\n\n    let mouse: [number, number] = [0.5, 0.5];\n    let animationFrameId: number;\n    let startTime = performance.now();\n\n    const resize = () => {\n      const rect = canvas.getBoundingClientRect();\n      const dpr = window.devicePixelRatio || 1;\n      canvas.width = rect.width * dpr;\n      canvas.height = rect.height * dpr;\n      gl.viewport(0, 0, canvas.width, canvas.height);\n      gl.uniform2f(resolutionLocation, canvas.width, canvas.height);\n    };\n\n    const handleMouseMove = (e: MouseEvent) => {\n      if (!interactiveRef.current) return;\n      const rect = canvas.getBoundingClientRect();\n      mouse[0] = (e.clientX - rect.left) / rect.width;\n      mouse[1] = 1.0 - (e.clientY - rect.top) / rect.height;\n    };\n\n    window.addEventListener(\"resize\", resize);\n    window.addEventListener(\"mousemove\", handleMouseMove);\n\n    resize();\n\n    const render = (time: number) => {\n      const elapsedTime = (time - startTime) * 0.001 * speedRef.current;\n\n      gl.uniform1f(timeLocation, elapsedTime);\n      gl.uniform2f(mouseLocation, mouse[0], mouse[1]);\n      gl.uniform3f(baseColorLocation, colorRef.current[0], colorRef.current[1], colorRef.current[2]);\n      gl.uniform1f(amplitudeLocation, amplitudeRef.current);\n\n      gl.drawArrays(gl.TRIANGLES, 0, 6);\n      animationFrameId = requestAnimationFrame(render);\n    };\n\n    animationFrameId = requestAnimationFrame(render);\n\n    return () => {\n      window.removeEventListener(\"resize\", resize);\n      window.removeEventListener(\"mousemove\", handleMouseMove);\n      cancelAnimationFrame(animationFrameId);\n    };\n  }, []);\n\n  return (\n    <canvas\n      ref={canvasRef}\n      className={cn(\"w-full h-full block\", className)}\n      style={{ touchAction: \"none\" }}\n    />\n  );\n}\n",
      "type": "registry:ui"
    }
  ]
}