{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "plasma",
  "title": "Plasma",
  "description": "A mesmerizing plasma shader animation rendered with WebGL, perfect for dynamic backgrounds and previews.",
  "dependencies": [
    "react"
  ],
  "files": [
    {
      "path": "registry/gammaui/plasma.tsx",
      "content": "\"use client\"\n\nimport React, { useEffect, useRef } from \"react\"\n\nexport const Plasma: React.FC = () => {\n  const canvasRef = useRef<HTMLCanvasElement | null>(null)\n\n  // Vertex shader\n  const vsSource = `\n    attribute vec4 aVertexPosition;\n    void main() {\n      gl_Position = aVertexPosition;\n    }\n  `\n\n  // Fragment shader (same as before)\n  const fsSource = `precision highp float;\n    uniform vec2 iResolution;\n    uniform float iTime;\n\n    const float overallSpeed = 0.2;\n    const float gridSmoothWidth = 0.015;\n    const float axisWidth = 0.05;\n    const float majorLineWidth = 0.025;\n    const float minorLineWidth = 0.0125;\n    const float majorLineFrequency = 5.0;\n    const float minorLineFrequency = 1.0;\n    const vec4 gridColor = vec4(0.5);\n    const float scale = 5.0;\n    const vec4 lineColor = vec4(0.4, 0.2, 0.8, 1.0);\n    const float minLineWidth = 0.01;\n    const float maxLineWidth = 0.2;\n    const float lineSpeed = 1.0 * overallSpeed;\n    const float lineAmplitude = 1.0;\n    const float lineFrequency = 0.2;\n    const float warpSpeed = 0.2 * overallSpeed;\n    const float warpFrequency = 0.5;\n    const float warpAmplitude = 1.0;\n    const float offsetFrequency = 0.5;\n    const float offsetSpeed = 1.33 * overallSpeed;\n    const float minOffsetSpread = 0.6;\n    const float maxOffsetSpread = 2.0;\n    const int linesPerGroup = 16;\n\n    #define drawCircle(pos, radius, coord) smoothstep(radius + gridSmoothWidth, radius, length(coord - (pos)))\n    #define drawSmoothLine(pos, halfWidth, t) smoothstep(halfWidth, 0.0, abs(pos - (t)))\n    #define drawCrispLine(pos, halfWidth, t) smoothstep(halfWidth + gridSmoothWidth, halfWidth, abs(pos - (t)))\n    #define drawPeriodicLine(freq, width, t) drawCrispLine(freq / 2.0, width, abs(mod(t, freq) - (freq) / 2.0))\n\n    float drawGridLines(float axis) {\n      return drawCrispLine(0.0, axisWidth, axis)\n            + drawPeriodicLine(majorLineFrequency, majorLineWidth, axis)\n            + drawPeriodicLine(minorLineFrequency, minorLineWidth, axis);\n    }\n\n    float drawGrid(vec2 space) {\n      return min(1.0, drawGridLines(space.x) + drawGridLines(space.y));\n    }\n\n    float random(float t) {\n      return (cos(t) + cos(t * 1.3 + 1.3) + cos(t * 1.4 + 1.4)) / 3.0;\n    }\n\n    float getPlasmaY(float x, float horizontalFade, float offset) {\n      return random(x * lineFrequency + iTime * lineSpeed) * horizontalFade * lineAmplitude + offset;\n    }\n\n    void main() {\n      vec2 fragCoord = gl_FragCoord.xy;\n      vec4 fragColor;\n      vec2 uv = fragCoord.xy / iResolution.xy;\n      vec2 space = (fragCoord - iResolution.xy / 2.0) / iResolution.x * 2.0 * scale;\n\n      float horizontalFade = 1.0 - (cos(uv.x * 6.28) * 0.5 + 0.5);\n      float verticalFade = 1.0 - (cos(uv.y * 6.28) * 0.5 + 0.5);\n\n      space.y += random(space.x * warpFrequency + iTime * warpSpeed) * warpAmplitude * (0.5 + horizontalFade);\n      space.x += random(space.y * warpFrequency + iTime * warpSpeed + 2.0) * warpAmplitude * horizontalFade;\n\n      vec4 lines = vec4(0.0);\n      vec4 bgColor1 = vec4(0.1, 0.1, 0.3, 1.0);\n      vec4 bgColor2 = vec4(0.3, 0.1, 0.5, 1.0);\n\n      for(int l = 0; l < linesPerGroup; l++) {\n        float normalizedLineIndex = float(l) / float(linesPerGroup);\n        float offsetTime = iTime * offsetSpeed;\n        float offsetPosition = float(l) + space.x * offsetFrequency;\n        float rand = random(offsetPosition + offsetTime) * 0.5 + 0.5;\n        float halfWidth = mix(minLineWidth, maxLineWidth, rand * horizontalFade) / 2.0;\n        float offset = random(offsetPosition + offsetTime * (1.0 + normalizedLineIndex)) * mix(minOffsetSpread, maxOffsetSpread, horizontalFade);\n        float linePosition = getPlasmaY(space.x, horizontalFade, offset);\n        float line = drawSmoothLine(linePosition, halfWidth, space.y) / 2.0 + drawCrispLine(linePosition, halfWidth * 0.15, space.y);\n\n        float circleX = mod(float(l) + iTime * lineSpeed, 25.0) - 12.0;\n        vec2 circlePosition = vec2(circleX, getPlasmaY(circleX, horizontalFade, offset));\n        float circle = drawCircle(circlePosition, 0.01, space) * 4.0;\n\n        line = line + circle;\n        lines += line * lineColor * rand;\n      }\n\n      fragColor = mix(bgColor1, bgColor2, uv.x);\n      fragColor *= verticalFade;\n      fragColor.a = 1.0;\n      fragColor += lines;\n\n      gl_FragColor = fragColor;\n    }\n  `\n\n  const loadShader = (\n    gl: WebGLRenderingContext,\n    type: number,\n    source: string\n  ): WebGLShader | null => {\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(\"Shader compile error:\", gl.getShaderInfoLog(shader))\n      gl.deleteShader(shader)\n      return null\n    }\n    return shader\n  }\n\n  const initShaderProgram = (\n    gl: WebGLRenderingContext,\n    vsSource: string,\n    fsSource: string\n  ): WebGLProgram | null => {\n    const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource)\n    const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource)\n    if (!vertexShader || !fragmentShader) return null\n\n    const shaderProgram = gl.createProgram()\n    if (!shaderProgram) return null\n\n    gl.attachShader(shaderProgram, vertexShader)\n    gl.attachShader(shaderProgram, fragmentShader)\n    gl.linkProgram(shaderProgram)\n\n    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {\n      console.error(\n        \"Shader program link error:\",\n        gl.getProgramInfoLog(shaderProgram)\n      )\n      return null\n    }\n\n    return shaderProgram\n  }\n\n  useEffect(() => {\n    const canvas = canvasRef.current\n    if (!canvas) return\n    const gl = canvas.getContext(\"webgl\")\n    if (!gl) {\n      console.warn(\"WebGL not supported.\")\n      return\n    }\n\n    const shaderProgram = initShaderProgram(gl, vsSource, fsSource)\n    if (!shaderProgram) return\n\n    const positionBuffer = gl.createBuffer()\n    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)\n    const positions = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1])\n    gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW)\n\n    const programInfo = {\n      program: shaderProgram,\n      attribLocations: {\n        vertexPosition: gl.getAttribLocation(shaderProgram, \"aVertexPosition\"),\n      },\n      uniformLocations: {\n        resolution: gl.getUniformLocation(shaderProgram, \"iResolution\"),\n        time: gl.getUniformLocation(shaderProgram, \"iTime\"),\n      },\n    }\n\n    const resizeCanvas = () => {\n      const rect = canvas.getBoundingClientRect()\n      canvas.width = rect.width * window.devicePixelRatio\n      canvas.height = rect.height * window.devicePixelRatio\n      gl.viewport(0, 0, canvas.width, canvas.height)\n    }\n\n    resizeCanvas()\n    const observer = new ResizeObserver(resizeCanvas)\n    observer.observe(canvas)\n\n    const startTime = Date.now()\n    const render = () => {\n      const currentTime = (Date.now() - startTime) / 1000\n      gl.clearColor(0, 0, 0, 1)\n      gl.clear(gl.COLOR_BUFFER_BIT)\n      gl.useProgram(programInfo.program)\n\n      if (programInfo.uniformLocations.resolution)\n        gl.uniform2f(\n          programInfo.uniformLocations.resolution,\n          canvas.width,\n          canvas.height\n        )\n      if (programInfo.uniformLocations.time)\n        gl.uniform1f(programInfo.uniformLocations.time, currentTime)\n\n      gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)\n      gl.vertexAttribPointer(\n        programInfo.attribLocations.vertexPosition,\n        2,\n        gl.FLOAT,\n        false,\n        0,\n        0\n      )\n      gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition)\n      gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)\n      requestAnimationFrame(render)\n    }\n\n    requestAnimationFrame(render)\n    return () => observer.disconnect()\n  }, [])\n\n  // ❗ Remove fixed/full-screen styling:\n  return (\n    <canvas\n      ref={canvasRef}\n      className=\"h-full w-full rounded-xl\"\n      style={{ display: \"block\" }}\n    />\n  )\n}\n\nexport default Plasma\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}