{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "neon-flow",
  "title": "Neon Flow",
  "description": "Staggered neon trails that sweep across a dark field - colors are prop-driven for easy theming.",
  "files": [
    {
      "path": "components/backgrounds/NeonFlowBackground.tsx",
      "content": "'use client';\n\nimport React, { useEffect, useRef, type ReactNode } from 'react';\n\ntype NeonFlowBackgroundProps = {\n  children?: ReactNode;\n  className?: string;\n  containerClassName?: string;\n  backgroundFill?: string;\n  colors?: string[];\n};\n\nconst PATHS = [\n  'M-380 -189C-380 -189 -312 216 152 343C616 470 684 875 684 875',\n  'M-358 -213C-358 -213 -290 192 174 319C638 446 706 851 706 851',\n  'M-336 -237C-336 -237 -268 168 196 295C660 422 728 827 728 827',\n  'M-314 -261C-314 -261 -246 144 218 271C682 398 750 803 750 803',\n  'M-292 -285C-292 -285 -224 120 240 247C704 374 772 779 772 779',\n  'M-270 -309C-270 -309 -202 96 262 223C726 350 794 755 794 755',\n  'M-248 -333C-248 -333 -180 72 284 199C748 326 816 731 816 731',\n  'M-226 -357C-226 -357 -158 48 306 175C770 302 838 707 838 707',\n  'M-204 -381C-204 -381 -136 24 328 151C792 278 860 683 860 683',\n  'M-182 -405C-182 -405 -114 0 350 127C814 254 882 659 882 659',\n  'M-160 -429C-160 -429 -92 -24 372 103C836 230 904 635 904 635',\n  'M-138 -453C-138 -453 -70 -48 394 79C858 206 926 611 926 611',\n  'M-116 -477C-116 -477 -48 -72 416 55C880 182 948 587 948 587',\n  'M-94 -501C-94 -501 -26 -96 438 31C902 158 970 563 970 563',\n  'M-72 -525C-72 -525 -4 -120 460 7C924 134 992 539 992 539',\n  'M-50 -549C-50 -549 18 -144 482 -17C946 110 1014 515 1014 515',\n  'M-28 -573C-28 -573 40 -168 504 -41C968 86 1036 491 1036 491',\n  'M-6 -597C-6 -597 62 -192 526 -65C990 62 1058 467 1058 467',\n  'M16 -621C16 -621 84 -216 548 -89C1012 38 1080 443 1080 443',\n  'M38 -645C38 -645 106 -240 570 -113C1034 14 1102 419 1102 419',\n];\n\nconst DEFAULT_COLORS = ['#18CCFC', '#6344F5', '#AE48FF'];\nconst PATH_LENGTH = 1400;\n\nexport default function NeonFlowBackground({\n  children,\n  className = '',\n  containerClassName = '',\n  backgroundFill = '#0a0a0a',\n  colors = DEFAULT_COLORS,\n}: NeonFlowBackgroundProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    const container = containerRef.current;\n    if (!canvas || !container) return;\n\n    const ctx = canvas.getContext('2d');\n    if (!ctx) return;\n\n    const paths = PATHS.map((path) => new Path2D(path));\n    const [start, mid, end] = [\n      colors[0] ?? DEFAULT_COLORS[0],\n      colors[1] ?? colors[0] ?? DEFAULT_COLORS[1],\n      colors[2] ?? colors[1] ?? colors[0] ?? DEFAULT_COLORS[2],\n    ];\n    const motion = window.matchMedia('(prefers-reduced-motion: reduce)');\n    let reducedMotion = motion.matches;\n    let width = 0;\n    let height = 0;\n    let dpr = 1;\n    let raf = 0;\n    let startedAt = performance.now();\n\n    const resize = () => {\n      const rect = container.getBoundingClientRect();\n      dpr = Math.min(window.devicePixelRatio || 1, 2);\n      width = Math.max(1, Math.floor(rect.width));\n      height = Math.max(1, Math.floor(rect.height));\n      canvas.width = Math.floor(width * dpr);\n      canvas.height = Math.floor(height * dpr);\n      canvas.style.width = `${width}px`;\n      canvas.style.height = `${height}px`;\n    };\n\n    const draw = (now: number) => {\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n      ctx.fillStyle = backgroundFill;\n      ctx.fillRect(0, 0, width, height);\n\n      const scale = Math.max(width / 696, height / 316);\n      ctx.save();\n      ctx.translate((width - 696 * scale) / 2, (height - 316 * scale) / 2);\n      ctx.scale(scale, scale);\n      ctx.translate(696, 0);\n      ctx.scale(-1, 1);\n      ctx.translate(348, 158);\n      ctx.rotate((22 * Math.PI) / 180);\n      ctx.translate(-348, -158);\n      ctx.lineCap = 'round';\n\n      ctx.strokeStyle = 'rgba(255, 255, 255, 0.03)';\n      ctx.lineWidth = 0.5;\n      paths.forEach((path) => ctx.stroke(path));\n\n      if (!reducedMotion) {\n        const gradient = ctx.createLinearGradient(696, 0, 0, 316);\n        gradient.addColorStop(0, 'transparent');\n        gradient.addColorStop(0.2, start);\n        gradient.addColorStop(0.5, mid);\n        gradient.addColorStop(0.8, end);\n        gradient.addColorStop(1, 'transparent');\n        ctx.strokeStyle = gradient;\n        ctx.lineWidth = 1;\n\n        paths.forEach((path, index) => {\n          const elapsed = now - startedAt - index * 150;\n          if (elapsed < 0) return;\n\n          const duration = (4 + (index % 5) * 0.8) * 1000;\n          const progress = (elapsed % duration) / duration;\n          const eased = 0.5 - Math.cos(progress * Math.PI) / 2;\n          ctx.globalAlpha =\n            progress < 1 / 3\n              ? progress * 1.8\n              : progress > 2 / 3\n                ? (1 - progress) * 1.8\n                : 0.6;\n          ctx.setLineDash([(1 - eased) * PATH_LENGTH, PATH_LENGTH]);\n          ctx.stroke(path);\n        });\n      }\n\n      ctx.restore();\n      ctx.globalAlpha = 1;\n      ctx.setLineDash([]);\n      if (!reducedMotion) raf = requestAnimationFrame(draw);\n    };\n\n    const onMotionChange = () => {\n      cancelAnimationFrame(raf);\n      reducedMotion = motion.matches;\n      startedAt = performance.now();\n      draw(startedAt);\n    };\n\n    resize();\n    draw(startedAt);\n    const observer = new ResizeObserver(() => {\n      resize();\n      if (reducedMotion) draw(performance.now());\n    });\n    observer.observe(container);\n    motion.addEventListener('change', onMotionChange);\n\n    return () => {\n      cancelAnimationFrame(raf);\n      observer.disconnect();\n      motion.removeEventListener('change', onMotionChange);\n    };\n  }, [backgroundFill, colors]);\n\n  return (\n    <div\n      ref={containerRef}\n      className={[\n        'relative flex min-h-[420px] w-full flex-col items-center justify-center overflow-hidden',\n        containerClassName,\n      ]\n        .filter(Boolean)\n        .join(' ')}\n      style={{ backgroundColor: backgroundFill }}\n    >\n      <canvas\n        ref={canvasRef}\n        className='pointer-events-none absolute inset-0 z-0 h-full w-full'\n        aria-hidden\n      />\n      <div\n        className={['relative z-10 px-6 text-center', className]\n          .filter(Boolean)\n          .join(' ')}\n      >\n        {children}\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "@components/backgrounds/NeonFlowBackground.tsx"
    }
  ],
  "categories": [
    "backgrounds"
  ],
  "type": "registry:component"
}