{
  "$schema": "https://www.cooki-ui.design/schema/registry-item.json",
  "name": "fluid-particle-cursor",
  "type": "registry:ui",
  "title": "Fluid Particle Stardust Cursor",
  "description": "Interactive stardust cursor trail emitting glowing fading chromatic particle motes that decay with physical drag and opacity dissipation.",
  "category": "cursors",
  "dependencies": [],
  "files": [
    {
      "path": "registry/cursors/fluid-particle-cursor/fluid-particle-cursor.tsx",
      "type": "registry:ui",
      "target": "components/ui/fluid-particle-cursor.tsx",
      "content": "import React, { useRef, useEffect } from 'react';\n\ninterface Particle {\n  x: number;\n  y: number;\n  vx: number;\n  vy: number;\n  size: number;\n  alpha: number;\n  color: string;\n}\n\nexport const FluidParticleCursor: React.FC = () => {\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const particlesRef = useRef<Particle[]>([]);\n  const animIdRef = useRef<number | null>(null);\n  const isRunningRef = useRef(false);\n\n  const startLoop = () => {\n    if (isRunningRef.current) return;\n    isRunningRef.current = true;\n\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n    const ctx = canvas.getContext('2d');\n    if (!ctx) return;\n\n    const render = () => {\n      if (particlesRef.current.length === 0) {\n        ctx.clearRect(0, 0, canvas.width, canvas.height);\n        isRunningRef.current = false;\n        animIdRef.current = null;\n        return;\n      }\n\n      ctx.clearRect(0, 0, canvas.width, canvas.height);\n\n      for (let i = particlesRef.current.length - 1; i >= 0; i--) {\n        const p = particlesRef.current[i];\n        p.x += p.vx;\n        p.y += p.vy;\n        p.alpha *= 0.94;\n        p.size *= 0.97;\n\n        if (p.alpha < 0.02 || p.size < 0.5) {\n          particlesRef.current.splice(i, 1);\n          continue;\n        }\n\n        ctx.save();\n        ctx.globalAlpha = p.alpha;\n        ctx.fillStyle = p.color;\n        ctx.shadowColor = p.color;\n        ctx.shadowBlur = 8;\n        ctx.beginPath();\n        ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);\n        ctx.fill();\n        ctx.restore();\n      }\n\n      animIdRef.current = requestAnimationFrame(render);\n    };\n\n    animIdRef.current = requestAnimationFrame(render);\n  };\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n\n    const handleResize = () => {\n      const rect = canvas.getBoundingClientRect();\n      if (rect.width > 0 && rect.height > 0) {\n        canvas.width = rect.width;\n        canvas.height = rect.height;\n      }\n    };\n\n    handleResize();\n    const observer = new ResizeObserver(handleResize);\n    observer.observe(canvas);\n\n    return () => {\n      observer.disconnect();\n      if (animIdRef.current) {\n        cancelAnimationFrame(animIdRef.current);\n      }\n    };\n  }, []);\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLCanvasElement>) => {\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n    const rect = canvas.getBoundingClientRect();\n    const x = e.clientX - rect.left;\n    const y = e.clientY - rect.top;\n\n    const colors = ['#6366f1', '#38bdf8', '#a855f7', '#34d399', '#f43f5e'];\n\n    for (let i = 0; i < 3; i++) {\n      particlesRef.current.push({\n        x,\n        y,\n        vx: (Math.random() - 0.5) * 2.5,\n        vy: (Math.random() - 0.5) * 2.5,\n        size: Math.random() * 3.5 + 2,\n        alpha: 1,\n        color: colors[Math.floor(Math.random() * colors.length)],\n      });\n    }\n\n    startLoop();\n  };\n\n  return (\n    <div className=\"relative w-full h-64 rounded-2xl overflow-hidden bg-zinc-950 border border-white/10 flex items-center justify-center\">\n      <div className=\"absolute inset-0 flex flex-col items-center justify-center pointer-events-none z-10\">\n        <span className=\"text-xs font-mono uppercase tracking-widest text-zinc-500\">\n          Move cursor to draw luminous stardust\n        </span>\n        <span className=\"text-[11px] font-mono text-zinc-600 mt-1\">Velocity Particle Dispersion</span>\n      </div>\n      <canvas\n        ref={canvasRef}\n        onMouseMove={handleMouseMove}\n        className=\"w-full h-full cursor-crosshair\"\n      />\n    </div>\n  );\n};\n"
    }
  ]
}