{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "animated-gradient",
  "title": "Animated Gradient",
  "description": "WebGL-powered animated mist, lava, and plasma backgrounds with smooth silk-like flowing streams.",
  "dependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/spark-ui/animated-gradient.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { useEffect, useRef } from \"react\";\n\ninterface AnimatedGradientProps {\n  className?: string;\n  variant?: \"mist\" | \"lava\" | \"vortex\";\n  speed?: number;\n  opacity?: number;\n  children?: React.ReactNode;\n}\n\n\nconst VERTEX_SHADER = `\n  attribute vec2 a_position;\n  varying vec2 v_uv;\n  \n  void main() {\n    v_uv = a_position * 0.5 + 0.5;\n    gl_Position = vec4(a_position, 0.0, 1.0);\n  }\n`;\n\nconst MIST_SHADER = `\n  #ifdef GL_FRAGMENT_PRECISION_HIGH\n  precision highp float;\n  #else\n  precision mediump float;\n  #endif\n\n  varying vec2 v_uv;\n  uniform float u_time;\n  uniform vec2 u_resolution;\n\n  #define TWO_PI 6.28318530718\n  #define PI 3.14159265358979323846\n\n  float random(vec2 st) {\n    return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);\n  }\n\n  float noise(vec2 st) {\n    vec2 i = floor(st);\n    vec2 f = fract(st);\n    float a = random(i);\n    float b = random(i + vec2(1.0, 0.0));\n    float c = random(i + vec2(0.0, 1.0));\n    float d = random(i + vec2(1.0, 1.0));\n\n    vec2 u = f * f * (3.0 - 2.0 * f);\n\n    float x1 = mix(a, b, u.x);\n    float x2 = mix(c, d, u.x);\n    return mix(x1, x2, u.y);\n  }\n\n  void main() {\n      vec2 uv = v_uv;\n\n      // Mist preset timing parameters: speed = 39, offset = -235\n      float t = u_time * 0.975 - 1.175;\n\n      // Mist preset scale parameter: scale = 0.48\n      float noise_scale = 0.00338; // .0005 + .006 * 0.48\n\n      uv -= 0.5;\n      uv *= (noise_scale * u_resolution);\n      uv /= 1.5; // pixel ratio normalization\n      uv += 0.5;\n\n      // 70% Same: Distortion & Swirl loops preserved exactly for perfect motion fidelity\n      // Distortion: distortion = 4 (u_distortion = 0.08)\n      float n1 = noise(uv * 1.0 + t);\n      float n2 = noise(uv * 2.0 - t);\n      float angle = n1 * TWO_PI;\n      uv.x += 0.32 * n2 * cos(angle);\n      uv.y += 0.32 * n2 * sin(angle);\n\n      // Swirl: swirl = 65, swirlIterations = 5\n      for (int i = 1; i <= 5; i++) {\n          float fi = float(i);\n          uv.x += 0.65 / fi * cos(t + fi * 1.5 * uv.y);\n          uv.y += 0.65 / fi * cos(t + fi * 1.0 * uv.x);\n      }\n\n      // Edge shape shape-mixer calculation (shapeSize = 48, proportion = 33)\n      float sh = 1.0 - uv.y;\n      sh -= 0.5;\n      sh /= (noise_scale * u_resolution.y);\n      sh += 0.5;\n\n      float shape_scaling = 0.104; // 0.2 * (1.0 - 0.48)\n      float shape = smoothstep(0.45 - shape_scaling, 0.55 + shape_scaling, sh + 0.3 * (0.33 - 0.5));\n      float mixer = shape;\n\n      // 30% Premium Upgrade: Highly classy Parallax Fog & Cinematic Sweeping God Rays with Focused Ribbon\n      vec3 bg = vec3(0.0196, 0.0196, 0.0196);          // Obsidian background (#050505)\n      vec3 pink = vec3(1.0, 0.4, 0.7215);              // Pure elegant magenta core (#FF66B8)\n\n      // Exponent-sine bell curve to isolate mist into a beautiful center ribbon splaying dynamically\n      float mistFocus = pow(sin(mixer * PI), 4.2);\n\n      // Double-layer parallax mist density (blending broad background flow and fine parallax foreground)\n      float fineMist = noise(uv * 3.5 - t * 1.3) * 0.4 + noise(uv * 1.5 + t * 0.85) * 0.6;\n      float combinedDensity = mix(mixer, fineMist, 0.28) * mistFocus;\n\n      // Smooth constant-color gradient mapping\n      vec3 col = mix(bg, pink, smoothstep(0.0, 0.85, combinedDensity));\n\n      // Foreground parallax highlight glow, strictly bounded by the mist focus ribbon\n      float highlight = smoothstep(0.42, 0.88, fineMist) * smoothstep(0.12, 0.9, mixer) * mistFocus;\n      col = mix(col, pink * 1.15, highlight * 0.35);\n\n      // Sweeping Crepuscular God Rays (light shafts filtering through the moving fog ribbon)\n      vec2 raySource = vec2(0.2, 1.25); // light source positioned above the upper-left viewport\n      vec2 rayDir = normalize(v_uv - raySource);\n      float rayAngle = atan(rayDir.y, rayDir.x);\n      \n      // Sweep modulation using multiple low-frequency time-shifted sines\n      float rays = sin(rayAngle * 6.5 + t * 0.35) * 0.35 +\n                   sin(rayAngle * 12.0 - t * 0.22) * 0.25 +\n                   sin(rayAngle * 24.0 + t * 0.15) * 0.15;\n      rays = smoothstep(0.15, 0.82, rays * 0.5 + 0.5);\n\n      // Volumetric crepuscular light soft overlay, masked by fog density and center focus ribbon\n      float rayGlow = rays * smoothstep(0.15, 0.9, combinedDensity) * (1.1 - v_uv.y) * mistFocus * 0.7;\n      col += pink * rayGlow * 0.38;\n\n      // Cinematic Haze: micro-fine glowing particulate dust in illuminated center areas\n      float grain = random(gl_FragCoord.xy * 0.15 + t * 0.05);\n      float particles = step(0.988, grain) * smoothstep(0.2, 0.9, combinedDensity);\n      col += pink * particles * 0.32;\n\n      // Final contrast optimization\n      col = pow(col, vec3(0.92));\n\n      gl_FragColor = vec4(col, 1.0);\n  }\n`;\n\nconst LAVA_SHADER = `\n  #ifdef GL_FRAGMENT_PRECISION_HIGH\n  precision highp float;\n  #else\n  precision mediump float;\n  #endif\n\n  varying vec2 v_uv;\n  uniform float u_time;\n  uniform vec2 u_resolution;\n\n  #define PI 3.14159265359\n\n  float hash(vec2 p) {\n    return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);\n  }\n\n  float noise(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)), hash(i + vec2(1.0, 0.0)), u.x),\n               mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x), u.y);\n  }\n\n  // Limited to 2 octaves to eliminate jagged details and ensure broad, glassy waves\n  float fbm(vec2 p) {\n    float v = 0.0;\n    float a = 0.5;\n    vec2 shift = vec2(100.0);\n    mat2 rot = mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.5));\n    for (int i = 0; i < 2; ++i) {\n      v += a * noise(p);\n      p = rot * p * 2.0 + shift;\n      a *= 0.5;\n    }\n    return v;\n  }\n\n  void main() {\n    vec2 uv = v_uv;\n    float aspect = u_resolution.x / u_resolution.y;\n    uv.x *= aspect;\n    \n    // Smooth upward animation speed\n    float t = u_time * 0.22;\n    \n    // Slow gentle sideways sway of the flame body\n    float sway = sin(uv.x * 2.5 + u_time * 0.45) * 0.07;\n    \n    // Domain warping noise layers (wider waves for blurry glass look)\n    vec2 q = vec2(0.0);\n    q.x = fbm(uv * 2.0 + vec2(0.0, -t));\n    q.y = fbm(uv * 2.0 + vec2(t * 0.35, -t * 0.85));\n    \n    vec2 r = vec2(0.0);\n    r.x = fbm(uv * 2.2 + 2.8 * q + vec2(1.7, -t * 1.5));\n    r.y = fbm(uv * 2.2 + 2.8 * q + vec2(8.3, -t * 1.25));\n    \n    // Soft low-frequency noise (completely smoothed out)\n    float f = fbm(uv * 1.05 + 1.65 * r);\n    \n    // Vertical flame base offset with swaying peaks (lowered base multiplier from 1.35 to 1.15)\n    float fire = (1.0 - (uv.y + sway)) * 1.15; \n    \n    // Volumetric flame thresholds with extremely wide smoothstep windows for a blurry look\n    // Scale noise by (1.1 - uv.y) to suppress height and create gorgeous dark spots/channels at the top\n    float noiseGlow = f * 1.65 * (1.1 - uv.y);\n    float flameIntensity = fire + noiseGlow - 0.78;\n    \n    float flame = smoothstep(-0.25, 0.95, flameIntensity);\n    float orangeGlow = smoothstep(0.12, 0.98, flameIntensity);\n    float goldCore = smoothstep(0.38, 1.0, fire + f * 0.75 * (1.1 - uv.y) - 0.42);\n    \n    // Soft glowing volumetric smoke tips\n    float smoke = smoothstep(-0.3, 0.45, flameIntensity) * (1.0 - smoothstep(0.45, 0.95, flameIntensity));\n    \n    // Warm fire color definitions (no harsh bright yellows or whites!)\n    vec3 black = vec3(0.0, 0.0, 0.0);\n    vec3 deepRed = vec3(0.55, 0.015, 0.0);\n    vec3 brightOrange = vec3(0.92, 0.25, 0.0);\n    vec3 goldenOrange = vec3(0.96, 0.42, 0.02);\n    \n    // Blending volumetric color layers for a blurry glass bonfire effect\n    vec3 col = mix(black, deepRed, flame);\n    col = mix(col, brightOrange, orangeGlow);\n    col = mix(col, goldenOrange, goldCore);\n    \n    // Volumetric smoke tip glow for glowing depth\n    col += deepRed * smoke * 0.35;\n    \n    // Edge hot glow edge highlighting (wider transition for blurry glow)\n    float edge = smoothstep(0.25, 0.55, f) * (1.0 - smoothstep(0.55, 0.85, f));\n    col += edge * brightOrange * 0.18 * (1.0 - uv.y);\n    \n    // Contrast boost\n    col = pow(col, vec3(0.85));\n    \n    gl_FragColor = vec4(col, 1.0);\n  }\n`;\n\nconst VORTEX_SHADER = `\n  #ifdef GL_FRAGMENT_PRECISION_HIGH\n  precision highp float;\n  #else\n  precision mediump float;\n  #endif\n\n  varying vec2 v_uv;\n  uniform float u_time;\n  uniform vec2 u_resolution;\n  uniform float u_dark;\n\n  #define PI 3.14159265358979323846\n\n  float hash(vec2 p) {\n    return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);\n  }\n\n  float noise(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)), hash(i + vec2(1.0, 0.0)), u.x),\n               mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x), u.y);\n  }\n\n  // Limited to 2 octaves to eliminate jagged details and ensure broad, unbroken, glassy silk waves\n  float fbm(vec2 p) {\n    float v = 0.0;\n    float a = 0.5;\n    vec2 shift = vec2(100.0);\n    mat2 rot = mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.5));\n    for (int i = 0; i < 2; ++i) {\n      v += a * noise(p);\n      p = rot * p * 2.0 + shift;\n      a *= 0.5;\n    }\n    return v;\n  }\n\n  void main() {\n    vec2 uv = v_uv;\n    float aspect = u_resolution.x / u_resolution.y;\n    \n    // Smooth fluid motion speed\n    float t = u_time * 0.55;\n    \n    // Center of the vortex\n    vec2 center = vec2(0.5);\n    vec2 st = uv - center;\n    st.x *= aspect;\n    \n    float dist = length(st);\n    float angle = atan(st.y, st.x);\n    \n    // Natural fluid vortex swirl physics: decays smoothly away from center, damped at the absolute core to prevent breaking\n    float swirl = 3.2 / (dist + 0.3);\n    angle += swirl * 0.6 * smoothstep(0.04, 0.25, dist) + t * 0.3;\n    \n    // Smooth fluid radial ripples: damped near the center to prevent high-frequency coordinate tearing\n    float rippleMask = smoothstep(0.08, 0.35, dist);\n    dist += sin(angle * 2.0 - t * 1.2) * 0.015 * rippleMask * (1.0 - smoothstep(0.0, 0.9, dist));\n    \n    // Reconstruct twisted coordinates\n    vec2 twisted = vec2(cos(angle), sin(angle)) * dist;\n    twisted.x /= aspect;\n    twisted += center;\n    \n    // Scale coordinates for large, beautiful topography waves\n    vec2 flowCoord = twisted * 1.5;\n    \n    // Domain warping for natural marble fluid veins\n    vec2 q = vec2(\n      fbm(flowCoord - t * 0.04),\n      fbm(flowCoord + vec2(5.2, 1.3) + t * 0.02)\n    );\n    \n    vec2 r = flowCoord + q * 0.35;\n    float f = fbm(r);\n    \n    // Generate continuous, unbroken contour lines with beautiful dense spacing to avoid empty areas\n    float contour = sin(f * 18.0 - t * 1.2);\n    \n    // Pure monochrome black & white color scheme (no greys, vignettes, or halos)\n    // u_dark = 1.0 -> White lines on Solid Black background\n    // u_dark = 0.0 -> Black lines on Solid White background\n    vec3 bgColor = mix(vec3(1.0), vec3(0.0), u_dark);\n    vec3 lineColor = mix(vec3(0.0), vec3(1.0), u_dark);\n    \n    // Draw highly anti-aliased thin elegant lines (making them significantly thinner and sharper)\n    float line = smoothstep(0.965, 0.985, abs(contour));\n    \n    // Blend strictly between background and line color\n    vec3 col = mix(bgColor, lineColor, line);\n    \n    gl_FragColor = vec4(col, 1.0);\n  }\n`;\n\nconst FRAGMENT_SHADERS = {\n  mist: MIST_SHADER,\n  lava: LAVA_SHADER,\n  vortex: VORTEX_SHADER,\n} as const;\n\nexport function AnimatedGradient({\n  className,\n  variant = \"mist\",\n  speed = 1,\n  opacity = 1,\n  children,\n}: AnimatedGradientProps) {\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const animationRef = useRef<number>(0);\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n\n    const gl = canvas.getContext(\"webgl\", {\n      antialias: false,\n      alpha: false,\n      preserveDrawingBuffer: false,\n    });\n    if (!gl) return;\n\n    const resize = () => {\n      const dpr = Math.min(window.devicePixelRatio || 1, 2);\n      canvas.width = canvas.clientWidth * dpr;\n      canvas.height = canvas.clientHeight * dpr;\n      gl.viewport(0, 0, canvas.width, canvas.height);\n    };\n\n    resize();\n    window.addEventListener(\"resize\", resize);\n\n    const createShader = (type: number, source: string) => {\n      const shader = gl.createShader(type);\n      if (!shader) return null;\n      gl.shaderSource(shader, source);\n      gl.compileShader(shader);\n      if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n        console.error(gl.getShaderInfoLog(shader));\n        gl.deleteShader(shader);\n        return null;\n      }\n      return shader;\n    };\n\n    const vertexShader = createShader(gl.VERTEX_SHADER, VERTEX_SHADER);\n    const fragmentShaderSource =\n      FRAGMENT_SHADERS[variant] || FRAGMENT_SHADERS.mist;\n    const fragmentShader = createShader(\n      gl.FRAGMENT_SHADER,\n      fragmentShaderSource,\n    );\n\n    if (!vertexShader || !fragmentShader) {\n      if (vertexShader) gl.deleteShader(vertexShader);\n      if (fragmentShader) gl.deleteShader(fragmentShader);\n      return;\n    }\n\n    const program = gl.createProgram();\n    if (!program) {\n      gl.deleteShader(vertexShader);\n      gl.deleteShader(fragmentShader);\n      return;\n    }\n\n    gl.attachShader(program, vertexShader);\n    gl.attachShader(program, fragmentShader);\n    gl.linkProgram(program);\n\n    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n      console.error(gl.getProgramInfoLog(program));\n      gl.deleteShader(vertexShader);\n      gl.deleteShader(fragmentShader);\n      gl.deleteProgram(program);\n      return;\n    }\n\n    gl.useProgram(program);\n\n    const positions = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);\n    const buffer = gl.createBuffer();\n    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n    gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);\n\n    const positionLocation = gl.getAttribLocation(program, \"a_position\");\n    gl.enableVertexAttribArray(positionLocation);\n    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);\n\n    const timeLocation = gl.getUniformLocation(program, \"u_time\");\n    const resolutionLocation = gl.getUniformLocation(program, \"u_resolution\");\n    const darkLocation = gl.getUniformLocation(program, \"u_dark\");\n\n    const startTime = Date.now();\n\n    const render = () => {\n      const elapsed = (Date.now() - startTime) / 1000;\n      gl.uniform1f(timeLocation, elapsed * speed);\n      gl.uniform2f(resolutionLocation, canvas.width, canvas.height);\n\n      if (darkLocation) {\n        const isDark =\n          document.documentElement.classList.contains(\"dark\") ||\n          document.documentElement.getAttribute(\"data-theme\") === \"dark\" ||\n          (!document.documentElement.classList.contains(\"light\") &&\n            window.matchMedia &&\n            window.matchMedia(\"(prefers-color-scheme: dark)\").matches);\n        gl.uniform1f(darkLocation, isDark ? 1.0 : 0.0);\n      }\n\n      gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n      animationRef.current = requestAnimationFrame(render);\n    };\n\n    render();\n\n    return () => {\n      window.removeEventListener(\"resize\", resize);\n      if (animationRef.current) {\n        cancelAnimationFrame(animationRef.current);\n      }\n      gl.deleteShader(vertexShader);\n      gl.deleteShader(fragmentShader);\n      gl.deleteProgram(program);\n      gl.deleteBuffer(buffer);\n    };\n  }, [variant, speed]);\n\n  return (\n    <div className={cn(\"relative overflow-hidden bg-white dark:bg-black\", className)}>\n      <canvas ref={canvasRef} className=\"absolute inset-0 h-full w-full\" style={{ opacity }} />\n      {children && <div className=\"relative z-10 w-full h-full\">{children}</div>}\n    </div>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}