{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cosmic-background",
  "type": "registry:ui",
  "title": "Cosmic Background",
  "description": "A modern cosmic background featuring smooth motion and immersive depth effects.",
  "author": "Ahdeetai <https://aditya.is-cool.dev>",
  "registryDependencies": [],
  "dependencies": ["three"],
  "files": [
    {
      "type": "registry:ui",
      "path": "components/ui/cosmic-background.tsx",
      "content": "'use client';\nimport React, { useRef, useEffect, useState } from 'react';\nimport * as THREE from 'three';\n\ninterface CosmicBackgroundProps {\n  variant?: 'aurora' | 'cosmic' | 'neon';\n  intensity?: number;\n  speed?: number;\n  interactive?: boolean;\n  quality?: 'low' | 'medium' | 'high' | 'ultra';\n  overlay?: boolean;\n  className?: string;\n  children?: React.ReactNode;\n}\n\nconst checkWebGLSupport = (): boolean => {\n  try {\n    const canvas = document.createElement('canvas');\n    const gl =\n      canvas.getContext('webgl2') ||\n      canvas.getContext('webgl') ||\n      canvas.getContext('experimental-webgl');\n    return !!gl;\n  } catch (e) {\n    return false;\n  }\n};\n\nconst CosmicBackground: React.FC<CosmicBackgroundProps> = ({\n  variant = 'aurora',\n  intensity = 1.0,\n  speed = 1.0,\n  interactive = true,\n  quality = 'high',\n  overlay = false,\n  className = '',\n  children,\n}) => {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const rafRef = useRef<number | null>(null);\n  const rendererRef = useRef<THREE.WebGLRenderer | null>(null);\n  const materialRef = useRef<THREE.ShaderMaterial | null>(null);\n  const sceneRef = useRef<THREE.Scene | null>(null);\n  const cameraRef = useRef<THREE.OrthographicCamera | null>(null);\n  const mouseRef = useRef<THREE.Vector2>(new THREE.Vector2(0.5, 0.5));\n  const targetMouseRef = useRef<THREE.Vector2>(new THREE.Vector2(0.5, 0.5));\n  const timeRef = useRef<number>(0);\n  const [webGLSupported] = useState<boolean>(() =>\n    typeof window !== 'undefined' ? checkWebGLSupport() : true,\n  );\n\n  const variantConfigs = {\n    aurora: {\n      colors: ['#0a1628', '#1a3a52', '#2d5f7e', '#45a29e', '#66fcf1'],\n      flowSpeed: 0.15,\n      complexity: 3.5,\n      waveCount: 4,\n      glowIntensity: 1.8,\n    },\n    cosmic: {\n      colors: ['#0d0221', '#240046', '#3c096c', '#5a189a', '#9d4edd'],\n      flowSpeed: 0.08,\n      complexity: 5.0,\n      waveCount: 6,\n      glowIntensity: 2.2,\n    },\n    neon: {\n      colors: ['#000000', '#ff006e', '#fb5607', '#ffbe0b', '#8338ec'],\n      flowSpeed: 0.2,\n      complexity: 4.2,\n      waveCount: 5,\n      glowIntensity: 2.5,\n    },\n  };\n\n  const config = variantConfigs[variant];\n\n  useEffect(() => {\n    if (!containerRef.current || !webGLSupported) return;\n\n    const container = containerRef.current;\n    const width = container.clientWidth;\n    const height = container.clientHeight;\n\n    const isMobile =\n      /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(\n        navigator.userAgent,\n      );\n    const isLowEndDevice =\n      isMobile ||\n      (navigator.hardwareConcurrency && navigator.hardwareConcurrency <= 4);\n\n    let effectiveQuality = quality;\n    if (isLowEndDevice && quality === 'ultra') effectiveQuality = 'medium';\n    if (isMobile && quality !== 'low') effectiveQuality = 'low';\n\n    const qualitySettings = {\n      low: { pixelRatio: 0.5, precision: 'mediump' as const, octaves: 3 },\n      medium: { pixelRatio: 0.75, precision: 'mediump' as const, octaves: 4 },\n      high: {\n        pixelRatio: Math.min(window.devicePixelRatio, 1.5),\n        precision: 'highp' as const,\n        octaves: 5,\n      },\n      ultra: {\n        pixelRatio: Math.min(window.devicePixelRatio, 2),\n        precision: 'highp' as const,\n        octaves: 6,\n      },\n    };\n\n    const settings = qualitySettings[effectiveQuality];\n\n    const scene = new THREE.Scene();\n    sceneRef.current = scene;\n    const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);\n    cameraRef.current = camera;\n\n    let renderer: THREE.WebGLRenderer;\n    try {\n      renderer = new THREE.WebGLRenderer({\n        antialias: effectiveQuality === 'ultra',\n        alpha: true,\n        powerPreference:\n          effectiveQuality === 'low' ? 'low-power' : 'high-performance',\n        precision: settings.precision,\n        stencil: false,\n        depth: false,\n      });\n    } catch (error) {\n      console.error('WebGL initialization failed:', error);\n      return;\n    }\n\n    renderer.setSize(width, height);\n    renderer.setPixelRatio(settings.pixelRatio);\n    container.appendChild(renderer.domElement);\n    rendererRef.current = renderer;\n\n    const vertexShader = `\n      varying vec2 vUv;\n      void main() {\n        vUv = uv;\n        gl_Position = vec4(position, 1.0);\n      }\n    `;\n\n    const fragmentShader = `\n      precision ${settings.precision} float;\n      \n      uniform float uTime;\n      uniform vec2 uResolution;\n      uniform vec2 uMouse;\n      uniform vec3 uColors[5];\n      uniform float uIntensity;\n      uniform float uSpeed;\n      uniform float uComplexity;\n      uniform int uWaveCount;\n      uniform float uGlowIntensity;\n      uniform bool uInteractive;\n      varying vec2 vUv;\n\n      const float PI = 3.14159265359;\n      const float TAU = 6.28318530718;\n\n      vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\n      vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\n      vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); }\n\n      float snoise(vec2 v) {\n        const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439);\n        vec2 i = floor(v + dot(v, C.yy));\n        vec2 x0 = v - i + dot(i, C.xx);\n        vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n        vec4 x12 = x0.xyxy + C.xxzz;\n        x12.xy -= i1;\n        i = mod289(i);\n        vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0));\n        vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);\n        m = m*m; m = m*m;\n        vec3 x = 2.0 * fract(p * C.www) - 1.0;\n        vec3 h = abs(x) - 0.5;\n        vec3 ox = floor(x + 0.5);\n        vec3 a0 = x - ox;\n        m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h);\n        vec3 g;\n        g.x = a0.x * x0.x + h.x * x0.y;\n        g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n        return 130.0 * dot(m, g);\n      }\n\n      float fbm(vec2 p, int octaves) {\n        float value = 0.0;\n        float amplitude = 0.5;\n        float frequency = 1.0;\n        \n        for(int i = 0; i < ${settings.octaves}; i++) {\n          if(i >= octaves) break;\n          value += amplitude * snoise(p * frequency);\n          frequency *= 2.0;\n          amplitude *= 0.5;\n        }\n        return value;\n      }\n\n      vec2 domainWarp(vec2 p, float time) {\n        float warp1 = fbm(p + time * 0.1, ${settings.octaves});\n        float warp2 = fbm(p + vec2(warp1 * 4.0) + time * 0.15, ${settings.octaves});\n        return p + vec2(warp1, warp2) * 0.3;\n      }\n\n      vec3 palette(float t) {\n        vec3 a = uColors[0];\n        vec3 b = uColors[1];\n        vec3 c = uColors[2];\n        vec3 d = uColors[3];\n        vec3 e = uColors[4];\n        \n        float step1 = smoothstep(0.0, 0.25, t);\n        float step2 = smoothstep(0.25, 0.5, t);\n        float step3 = smoothstep(0.5, 0.75, t);\n        float step4 = smoothstep(0.75, 1.0, t);\n        \n        vec3 color = mix(a, b, step1);\n        color = mix(color, c, step2);\n        color = mix(color, d, step3);\n        color = mix(color, e, step4);\n        \n        return color;\n      }\n\n      void main() {\n        vec2 uv = vUv;\n        vec2 p = (uv - 0.5) * 2.0;\n        p.x *= uResolution.x / uResolution.y;\n\n        vec2 mouseInfluence = vec2(0.0);\n        if(uInteractive) {\n          vec2 mousePos = (uMouse - 0.5) * 2.0;\n          mousePos.x *= uResolution.x / uResolution.y;\n          float mouseDist = length(p - mousePos);\n          mouseInfluence = (mousePos - p) * (0.3 / (mouseDist + 0.5));\n        }\n\n        vec2 warpedP = domainWarp(p + mouseInfluence, uTime * uSpeed);\n        \n        float pattern = 0.0;\n        float amplitude = 1.0;\n        \n        for(int i = 0; i < 6; i++) {\n          if(i >= uWaveCount) break;\n          \n          float freq = pow(2.0, float(i));\n          float timeOffset = uTime * uSpeed * (0.3 + float(i) * 0.1);\n          \n          vec2 offset = vec2(\n            cos(timeOffset + float(i)),\n            sin(timeOffset * 1.3 + float(i))\n          ) * 0.5;\n          \n          float wave = fbm((warpedP + offset) * freq * uComplexity, ${settings.octaves});\n          pattern += wave * amplitude;\n          amplitude *= 0.6;\n        }\n\n        pattern = pattern * 0.5 + 0.5;\n        \n        float radialGrad = 1.0 - length(p) * 0.4;\n        pattern *= radialGrad;\n\n        vec3 color = palette(pattern);\n        \n        float glow = pow(pattern, 2.0) * uGlowIntensity;\n        color += glow * 0.5;\n\n        color *= uIntensity;\n\n        float grain = fract(sin(dot(uv * uTime, vec2(12.9898, 78.233))) * 43758.5453);\n        color -= grain * 0.03;\n\n        gl_FragColor = vec4(color, 1.0);\n      }\n    `;\n\n    const parseColor = (hex: string): THREE.Vector3 => {\n      const color = new THREE.Color(hex);\n      return new THREE.Vector3(color.r, color.g, color.b);\n    };\n\n    const colorArray = config.colors.map(parseColor);\n\n    const material = new THREE.ShaderMaterial({\n      vertexShader,\n      fragmentShader,\n      uniforms: {\n        uTime: { value: 0 },\n        uResolution: { value: new THREE.Vector2(width, height) },\n        uMouse: { value: mouseRef.current },\n        uColors: { value: colorArray },\n        uIntensity: { value: intensity },\n        uSpeed: { value: config.flowSpeed * speed },\n        uComplexity: { value: config.complexity },\n        uWaveCount: { value: config.waveCount },\n        uGlowIntensity: { value: config.glowIntensity },\n        uInteractive: { value: interactive },\n      },\n      transparent: true,\n      depthWrite: false,\n      depthTest: false,\n    });\n    materialRef.current = material;\n\n    const geometry = new THREE.PlaneGeometry(2, 2);\n    const mesh = new THREE.Mesh(geometry, material);\n    scene.add(mesh);\n\n    const handleMouseMove = (event: MouseEvent) => {\n      if (!interactive) return;\n      const rect = container.getBoundingClientRect();\n      const x = (event.clientX - rect.left) / rect.width;\n      const y = 1.0 - (event.clientY - rect.top) / rect.height;\n      targetMouseRef.current.set(x, y);\n    };\n\n    if (interactive) {\n      container.addEventListener('mousemove', handleMouseMove, {\n        passive: true,\n      });\n    }\n\n    let lastTime = performance.now();\n    const targetFPS = effectiveQuality === 'low' ? 30 : 60;\n    const frameTime = 1000 / targetFPS;\n\n    const animate = (currentTime: number) => {\n      if (\n        !materialRef.current ||\n        !rendererRef.current ||\n        !sceneRef.current ||\n        !cameraRef.current\n      )\n        return;\n\n      const deltaTime = currentTime - lastTime;\n\n      if (deltaTime >= frameTime) {\n        timeRef.current += 0.016;\n        materialRef.current.uniforms.uTime.value = timeRef.current;\n\n        mouseRef.current.lerp(targetMouseRef.current, 0.1);\n        materialRef.current.uniforms.uMouse.value = mouseRef.current;\n\n        rendererRef.current.render(sceneRef.current, cameraRef.current);\n        lastTime = currentTime - (deltaTime % frameTime);\n      }\n\n      rafRef.current = requestAnimationFrame(animate);\n    };\n    rafRef.current = requestAnimationFrame(animate);\n\n    let resizeTimeout: number | null = null;\n    const handleResize = () => {\n      if (resizeTimeout) clearTimeout(resizeTimeout);\n      resizeTimeout = window.setTimeout(() => {\n        if (\n          !rendererRef.current ||\n          !materialRef.current ||\n          !containerRef.current\n        )\n          return;\n        const newWidth = containerRef.current.clientWidth;\n        const newHeight = containerRef.current.clientHeight;\n        rendererRef.current.setSize(newWidth, newHeight);\n        materialRef.current.uniforms.uResolution.value.set(newWidth, newHeight);\n      }, 150);\n    };\n\n    window.addEventListener('resize', handleResize, { passive: true });\n\n    return () => {\n      window.removeEventListener('resize', handleResize);\n      if (interactive) {\n        container.removeEventListener('mousemove', handleMouseMove);\n      }\n      if (rafRef.current) {\n        cancelAnimationFrame(rafRef.current);\n      }\n      if (rendererRef.current) {\n        rendererRef.current.dispose();\n        rendererRef.current.forceContextLoss();\n        if (container.contains(rendererRef.current.domElement)) {\n          container.removeChild(rendererRef.current.domElement);\n        }\n      }\n      if (materialRef.current) {\n        materialRef.current.dispose();\n      }\n      geometry.dispose();\n    };\n  }, [\n    variant,\n    intensity,\n    speed,\n    interactive,\n    quality,\n    webGLSupported,\n    config.colors,\n    config.complexity,\n    config.flowSpeed,\n    config.glowIntensity,\n    config.waveCount,\n  ]);\n\n  if (!webGLSupported) {\n    return (\n      <div\n        className={`w-full h-full flex items-center justify-center bg-linear-to-br from-gray-900 to-gray-800 ${className}`}\n      >\n        <div className='text-gray-400 text-sm'>WebGL not supported</div>\n      </div>\n    );\n  }\n\n  return (\n    <div className={`relative ${className}`}>\n      <div ref={containerRef} className='absolute inset-0 w-full h-full' />\n      {children && <div className='relative z-10'>{children}</div>}\n    </div>\n  );\n};\n\nexport { CosmicBackground };\n"
    }
  ]
}
