{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "vortex-background",
  "type": "registry:component",
  "title": "Vortex Background",
  "description": "Canvas 2D particle vortex, 700 particles spiral inward with rotating hue, perfect for hero sections",
  "dependencies": [],
  "files": [
    {
      "path": "components/kraavon-ui/VortexBackground.tsx",
      "content": "\"use client\";\n\nimport React, { useRef, useEffect, CSSProperties } from \"react\";\n\ninterface VortexBackgroundProps {\n  children?: React.ReactNode;\n  className?: string;\n  style?: CSSProperties;\n}\n\ninterface Particle {\n  angle: number;\n  radius: number;\n  speed: number;\n  size: number;\n  hueOffset: number;\n}\n\nconst PARTICLE_COUNT = 700;\nconst MAX_RADIUS = 600;\n\nfunction createParticle(maxRadius: number): Particle {\n  return {\n    angle: Math.random() * Math.PI * 2,\n    radius: Math.random() * maxRadius,\n    speed: 0.003 + Math.random() * 0.007,\n    size: 0.5 + Math.random() * 2,\n    hueOffset: Math.random() * 360,\n  };\n}\n\nexport function VortexBackground({ children, className, style }: VortexBackgroundProps) {\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const particlesRef = useRef<Particle[]>([]);\n  const animFrameRef = useRef<number>(0);\n  const hueRef = useRef<number>(0);\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    const initParticles = (maxRadius: number) => {\n      particlesRef.current = Array.from({ length: PARTICLE_COUNT }, () =>\n        createParticle(maxRadius)\n      );\n    };\n\n    const resize = () => {\n      canvas.width = canvas.offsetWidth;\n      canvas.height = canvas.offsetHeight;\n      const maxRadius = Math.sqrt(canvas.width ** 2 + canvas.height ** 2) / 2;\n      initParticles(maxRadius);\n    };\n\n    resize();\n\n    const ro = new ResizeObserver(resize);\n    ro.observe(canvas);\n\n    const draw = () => {\n      const w = canvas.width;\n      const h = canvas.height;\n      const cx = w / 2;\n      const cy = h / 2;\n      const maxRadius = Math.sqrt(w ** 2 + h ** 2) / 2;\n\n      ctx.fillStyle = \"rgba(0,0,0,0.04)\";\n      ctx.fillRect(0, 0, w, h);\n\n      hueRef.current = (hueRef.current + 0.3) % 360;\n\n      for (const p of particlesRef.current) {\n        p.angle += p.speed;\n        p.radius -= 0.4 + p.speed * 10;\n\n        if (p.radius < 1) {\n          p.angle = Math.random() * Math.PI * 2;\n          p.radius = maxRadius * (0.5 + Math.random() * 0.5);\n        }\n\n        const x = cx + Math.cos(p.angle) * p.radius;\n        const y = cy + Math.sin(p.angle) * p.radius;\n        const hue = (hueRef.current + p.hueOffset) % 360;\n        const alpha = Math.min(1, p.radius / (maxRadius * 0.3));\n\n        ctx.beginPath();\n        ctx.arc(x, y, p.size, 0, Math.PI * 2);\n        ctx.fillStyle = `hsla(${hue}, 100%, 65%, ${alpha})`;\n        ctx.fill();\n      }\n\n      animFrameRef.current = requestAnimationFrame(draw);\n    };\n\n    // Paint initial background\n    ctx.fillStyle = \"#050508\";\n    ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n    animFrameRef.current = requestAnimationFrame(draw);\n\n    return () => {\n      cancelAnimationFrame(animFrameRef.current);\n      ro.disconnect();\n    };\n  }, []);\n\n  return (\n    <div\n      className={className}\n      style={{\n        position: \"relative\",\n        background: \"#050508\",\n        overflow: \"hidden\",\n        ...style,\n      }}\n    >\n      <canvas\n        ref={canvasRef}\n        style={{\n          position: \"absolute\",\n          inset: 0,\n          width: \"100%\",\n          height: \"100%\",\n          display: \"block\",\n        }}\n      />\n      <div style={{ position: \"relative\", zIndex: 1 }}>{children}</div>\n    </div>\n  );\n}\n\nexport default VortexBackground;\n",
      "type": "registry:component"
    }
  ]
}