{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cursor-trail",
  "type": "registry:component",
  "title": "Cursor Trail",
  "description": "Smooth canvas cursor trail, fading particles follow mouse movement with configurable color and length",
  "dependencies": [],
  "files": [
    {
      "path": "components/kraavon-ui/CursorTrail.tsx",
      "content": "\"use client\";\n\nimport React, { useRef, useEffect, CSSProperties } from \"react\";\n\ninterface CursorTrailProps {\n  children?: React.ReactNode;\n  className?: string;\n  style?: CSSProperties;\n  color?: string;\n  size?: number;\n  trailLength?: number;\n}\n\ninterface TrailPoint {\n  x: number;\n  y: number;\n}\n\nexport function CursorTrail({\n  children,\n  className,\n  style,\n  color = \"#18B5FF\",\n  size = 12,\n  trailLength = 25,\n}: CursorTrailProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const trailRef = useRef<TrailPoint[]>([]);\n  const animFrameRef = useRef<number>(0);\n  const activeRef = useRef(false);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    const resize = () => {\n      canvas.width = container.offsetWidth;\n      canvas.height = container.offsetHeight;\n    };\n    resize();\n    const ro = new ResizeObserver(resize);\n    ro.observe(container);\n\n    const onMouseMove = (e: MouseEvent) => {\n      const rect = container.getBoundingClientRect();\n      const x = e.clientX - rect.left;\n      const y = e.clientY - rect.top;\n      trailRef.current.unshift({ x, y });\n      if (trailRef.current.length > trailLength) {\n        trailRef.current.length = trailLength;\n      }\n      if (!activeRef.current) {\n        activeRef.current = true;\n        animFrameRef.current = requestAnimationFrame(draw);\n      }\n    };\n\n    const onMouseLeave = () => {\n      activeRef.current = false;\n    };\n\n    container.addEventListener(\"mousemove\", onMouseMove);\n    container.addEventListener(\"mouseleave\", onMouseLeave);\n\n    const draw = () => {\n      ctx.clearRect(0, 0, canvas.width, canvas.height);\n\n      const points = trailRef.current;\n      if (points.length < 2) {\n        if (activeRef.current) animFrameRef.current = requestAnimationFrame(draw);\n        return;\n      }\n\n      // Draw connected trail line\n      ctx.beginPath();\n      ctx.moveTo(points[0].x, points[0].y);\n      for (let i = 1; i < points.length; i++) {\n        ctx.lineTo(points[i].x, points[i].y);\n      }\n      ctx.strokeStyle = color;\n      ctx.lineWidth = 1.5;\n      ctx.globalAlpha = 0.25;\n      ctx.stroke();\n      ctx.globalAlpha = 1;\n\n      // Draw circles oldest→newest (index len-1 → 0)\n      for (let i = points.length - 1; i >= 0; i--) {\n        const t = i / (points.length - 1); // 1 = oldest, 0 = newest\n        const radius = size * (1 - t);\n        const alpha = 1 - t;\n\n        if (radius <= 0) continue;\n\n        ctx.beginPath();\n        ctx.arc(points[i].x, points[i].y, radius, 0, Math.PI * 2);\n        ctx.fillStyle = color;\n        ctx.globalAlpha = alpha * 0.85;\n        ctx.fill();\n      }\n      ctx.globalAlpha = 1;\n\n      if (activeRef.current) {\n        animFrameRef.current = requestAnimationFrame(draw);\n      } else {\n        // Fade out by clearing\n        ctx.clearRect(0, 0, canvas.width, canvas.height);\n        trailRef.current = [];\n      }\n    };\n\n    return () => {\n      cancelAnimationFrame(animFrameRef.current);\n      container.removeEventListener(\"mousemove\", onMouseMove);\n      container.removeEventListener(\"mouseleave\", onMouseLeave);\n      ro.disconnect();\n    };\n  }, [color, size, trailLength]);\n\n  return (\n    <div\n      ref={containerRef}\n      className={className}\n      style={{ position: \"relative\", overflow: \"hidden\", ...style }}\n    >\n      <canvas\n        ref={canvasRef}\n        style={{\n          position: \"absolute\",\n          inset: 0,\n          pointerEvents: \"none\",\n          zIndex: 9999,\n        }}\n      />\n      {children}\n    </div>\n  );\n}\n\nexport default CursorTrail;\n",
      "type": "registry:component"
    }
  ]
}