{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "nebula",
  "title": "Nebula",
  "description": "A deep space nebula effect with fractional distortion.",
  "dependencies": [
    "three",
    "@react-three/fiber",
    "clsx",
    "tailwind-merge"
  ],
  "files": [
    {
      "path": "registry/chamaac/nebula/nebula.tsx",
      "content": "\"use client\";\n\nimport React, { useRef, useMemo } from \"react\";\nimport { Canvas, useFrame, useThree } from \"@react-three/fiber\";\nimport * as THREE from \"three\";\nimport { cn } from \"@/lib/utils\";\n\nconst vertexShader = `\n  varying vec2 vUv;\n  void main() {\n    vUv = uv;\n    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n  }\n`;\n\nconst fragmentShader = `\nuniform float uTime;\nuniform vec3 uColor1;\nuniform vec3 uColor2;\nuniform vec3 uColor3;\nuniform float uSpeed;\n\nvarying vec2 vUv;\n\n// 2D Random\nfloat random(in vec2 st) {\n    return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);\n}\n\n// 2D Noise based on Morgan McGuire @morgan3d\n// https://www.shadertoy.com/view/4dS3Wd\nfloat noise(in vec2 st) {\n    vec2 i = floor(st);\n    vec2 f = fract(st);\n\n    // Four corners in 2D of a tile\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    // Smooth Interpolation\n\n    // Cubic Hermine Curve.  Same as SmoothStep()\n    vec2 u = f * f * (3.0 - 2.0 * f);\n    // u = smoothstep(0.,1.,f);\n\n    // Mix 4 coorners percentages\n    return mix(a, b, u.x) +\n        (c - a) * u.y * (1.0 - u.x) +\n        (d - b) * u.x * u.y;\n}\n\n#define OCTAVES 6\nfloat fbm(in vec2 st) {\n    // Initial values\n    float value = 0.0;\n    float amplitude = .5;\n    float frequency = 0.;\n    //\n    // Loop of octaves\n    for (int i = 0; i < OCTAVES; i++) {\n        value += amplitude * noise(st);\n        st *= 2.;\n        amplitude *= .5;\n    }\n    return value;\n}\n\nvoid main() {\n    vec2 st = vUv * 3.0;\n    float time = uTime * uSpeed;\n    \n    // Domain Warping\n    vec2 q = vec2(0.);\n    q.x = fbm(st + 0.00 * time); \n    q.y = fbm(st + vec2(1.0));\n\n    vec2 r = vec2(0.);\n    r.x = fbm(st + 1.0 * q + vec2(1.7, 9.2) + 0.15 * time); \n    r.y = fbm(st + 1.0 * q + vec2(8.3, 2.8) + 0.126 * time);\n\n    float f = fbm(st + r);\n\n    // Color Mixing\n    vec3 color = mix(uColor3, uColor2, clamp((f * f) * 4.0, 0.0, 1.0));\n    color = mix(color, uColor1, clamp(length(q), 0.0, 1.0));\n    color = mix(color, vec3(1.0), clamp(length(r.x), 0.0, 1.0));\n\n    // Darken edges\n    float vignette = 1.0 - smoothstep(0.5, 1.5, length(vUv - 0.5));\n    color *= vignette;\n\n\n    gl_FragColor = vec4((f * f * f + .6 * f * f + .5 * f) * color, 1.0);\n}\n`;\n\nconst NebulaMaterial = ({\n  speed,\n  color1,\n  color2,\n  color3,\n}: {\n  speed: number;\n  color1: string;\n  color2: string;\n  color3: string;\n}) => {\n  const materialRef = useRef<THREE.ShaderMaterial>(null);\n  const lastTimeRef = useRef(0);\n\n  const uniforms = useMemo(\n    () => ({\n      uTime: { value: 0 },\n      uSpeed: { value: speed },\n      uColor1: { value: new THREE.Color(color1) },\n      uColor2: { value: new THREE.Color(color2) },\n      uColor3: { value: new THREE.Color(color3) },\n    }),\n\n    [] // Initialize once\n  );\n\n  // Update uniforms when props change\n  React.useEffect(() => {\n    uniforms.uSpeed.value = speed;\n    uniforms.uColor1.value.set(color1);\n    uniforms.uColor2.value.set(color2);\n    uniforms.uColor3.value.set(color3);\n  }, [speed, color1, color2, color3, uniforms]);\n\n  useFrame((state) => {\n    if (!materialRef.current) return;\n    // Cap render to ~30 fps — nebula moves slowly so this is imperceptible\n    const elapsed = state.clock.getElapsedTime();\n    if (elapsed - lastTimeRef.current < 1 / 30) return;\n    lastTimeRef.current = elapsed;\n    materialRef.current.uniforms.uTime.value = elapsed;\n  });\n\n  const { viewport } = useThree();\n\n  return (\n    <mesh>\n      <planeGeometry args={[viewport.width, viewport.height]} />\n      <shaderMaterial\n        ref={materialRef}\n        vertexShader={vertexShader}\n        fragmentShader={fragmentShader}\n        uniforms={uniforms}\n      />\n    </mesh>\n  );\n};\n\ninterface NebulaProps {\n  className?: string;\n  speed?: number;\n  color1?: string; // Highlights/Fracture\n  color2?: string; // Nebula main\n  color3?: string; // Deep space\n}\n\nexport default function Nebula({\n  className,\n  speed = 2.0,\n  color1 = \"#5efff4\", // Cyan (Highlight)\n  color2 = \"#763b65\", // Magenta-ish (Nebula)\n  color3 = \"#1a0b2e\", // Deep purple (Deep Space)\n}: NebulaProps) {\n  return (\n    <div\n      className={cn(\n        \"absolute inset-0 w-full h-full pointer-events-none\",\n        className\n      )}\n    >\n      <Canvas\n        camera={{ position: [0, 0, 1] }}\n        dpr={[1, 2]}\n        gl={{ antialias: false, powerPreference: \"high-performance\" }}\n      >\n        <NebulaMaterial\n          speed={speed}\n          color3={color3}\n          color2={color2}\n          color1={color1}\n        />\n      </Canvas>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}