{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "grid-beam",
  "type": "registry:ui",
  "description": "Canvas grid beam animation with palette presets, SVG dividers, and composable headless pieces via useGridBeam",
  "files": [
    {
      "path": "registry/default/ui/grid-beam.tsx",
      "content": "\"use client\"\n\nimport {\n  forwardRef,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n  useSyncExternalStore,\n  type ComponentProps,\n  type CSSProperties,\n  type MutableRefObject,\n  type RefObject,\n} from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\n// ─── Color palettes ───────────────────────────────────────────────\n\nexport type RGB = readonly [number, number, number]\n\nexport type PaletteBand = Readonly<{\n  color: RGB\n  op: number\n}>\n\nexport type GridBeamPaletteLayers = Readonly<{\n  h: readonly PaletteBand[]\n  v: readonly PaletteBand[]\n}>\n\nexport const PALETTES = {\n  colorful: {\n    dark: {\n      h: [\n        { color: [255, 50, 100] as const, op: 0.38 },\n        { color: [40, 180, 220] as const, op: 0.35 },\n        { color: [50, 200, 80] as const, op: 0.38 },\n        { color: [180, 40, 240] as const, op: 0.35 },\n        { color: [255, 160, 30] as const, op: 0.38 },\n        { color: [100, 70, 255] as const, op: 0.35 },\n      ],\n      v: [\n        { color: [40, 140, 255] as const, op: 0.38 },\n        { color: [240, 50, 180] as const, op: 0.35 },\n        { color: [30, 185, 170] as const, op: 0.38 },\n        { color: [255, 120, 40] as const, op: 0.38 },\n        { color: [100, 70, 255] as const, op: 0.35 },\n        { color: [50, 200, 80] as const, op: 0.38 },\n      ],\n    },\n    light: {\n      h: [\n        { color: [200, 30, 70] as const, op: 0.28 },\n        { color: [20, 140, 180] as const, op: 0.24 },\n        { color: [30, 160, 50] as const, op: 0.28 },\n        { color: [140, 20, 200] as const, op: 0.24 },\n        { color: [210, 120, 10] as const, op: 0.28 },\n        { color: [70, 40, 210] as const, op: 0.24 },\n      ],\n      v: [\n        { color: [20, 100, 210] as const, op: 0.28 },\n        { color: [200, 30, 140] as const, op: 0.24 },\n        { color: [15, 145, 130] as const, op: 0.28 },\n        { color: [210, 90, 20] as const, op: 0.28 },\n        { color: [70, 40, 210] as const, op: 0.24 },\n        { color: [30, 160, 50] as const, op: 0.28 },\n      ],\n    },\n  },\n  mono: {\n    dark: {\n      h: [\n        { color: [200, 200, 200] as const, op: 0.16 },\n        { color: [180, 180, 180] as const, op: 0.13 },\n        { color: [190, 190, 190] as const, op: 0.16 },\n        { color: [175, 175, 175] as const, op: 0.13 },\n        { color: [195, 195, 195] as const, op: 0.16 },\n        { color: [185, 185, 185] as const, op: 0.13 },\n      ],\n      v: [\n        { color: [185, 185, 185] as const, op: 0.16 },\n        { color: [170, 170, 170] as const, op: 0.13 },\n        { color: [195, 195, 195] as const, op: 0.16 },\n        { color: [180, 180, 180] as const, op: 0.13 },\n        { color: [190, 190, 190] as const, op: 0.16 },\n        { color: [175, 175, 175] as const, op: 0.13 },\n      ],\n    },\n    light: {\n      h: [\n        { color: [90, 90, 90] as const, op: 0.13 },\n        { color: [110, 110, 110] as const, op: 0.1 },\n        { color: [80, 80, 80] as const, op: 0.13 },\n        { color: [100, 100, 100] as const, op: 0.1 },\n        { color: [85, 85, 85] as const, op: 0.13 },\n        { color: [95, 95, 95] as const, op: 0.1 },\n      ],\n      v: [\n        { color: [100, 100, 100] as const, op: 0.13 },\n        { color: [80, 80, 80] as const, op: 0.1 },\n        { color: [90, 90, 90] as const, op: 0.13 },\n        { color: [110, 110, 110] as const, op: 0.1 },\n        { color: [85, 85, 85] as const, op: 0.13 },\n        { color: [95, 95, 95] as const, op: 0.1 },\n      ],\n    },\n  },\n  ocean: {\n    dark: {\n      h: [\n        { color: [100, 80, 255] as const, op: 0.38 },\n        { color: [60, 140, 255] as const, op: 0.35 },\n        { color: [80, 100, 220] as const, op: 0.38 },\n        { color: [130, 70, 255] as const, op: 0.35 },\n        { color: [50, 120, 230] as const, op: 0.38 },\n        { color: [110, 90, 240] as const, op: 0.35 },\n      ],\n      v: [\n        { color: [70, 130, 255] as const, op: 0.38 },\n        { color: [120, 80, 240] as const, op: 0.35 },\n        { color: [90, 110, 230] as const, op: 0.38 },\n        { color: [60, 100, 255] as const, op: 0.35 },\n        { color: [140, 100, 255] as const, op: 0.38 },\n        { color: [80, 120, 220] as const, op: 0.35 },\n      ],\n    },\n    light: {\n      h: [\n        { color: [60, 50, 180] as const, op: 0.28 },\n        { color: [40, 100, 210] as const, op: 0.24 },\n        { color: [50, 70, 190] as const, op: 0.28 },\n        { color: [90, 50, 200] as const, op: 0.24 },\n        { color: [30, 80, 200] as const, op: 0.28 },\n        { color: [70, 60, 210] as const, op: 0.24 },\n      ],\n      v: [\n        { color: [50, 90, 220] as const, op: 0.28 },\n        { color: [80, 60, 200] as const, op: 0.24 },\n        { color: [60, 80, 210] as const, op: 0.28 },\n        { color: [40, 70, 200] as const, op: 0.24 },\n        { color: [100, 80, 230] as const, op: 0.28 },\n        { color: [55, 85, 195] as const, op: 0.24 },\n      ],\n    },\n  },\n  sunset: {\n    dark: {\n      h: [\n        { color: [255, 100, 60] as const, op: 0.38 },\n        { color: [255, 180, 50] as const, op: 0.35 },\n        { color: [255, 80, 80] as const, op: 0.38 },\n        { color: [255, 140, 40] as const, op: 0.35 },\n        { color: [255, 200, 60] as const, op: 0.38 },\n        { color: [255, 120, 50] as const, op: 0.35 },\n      ],\n      v: [\n        { color: [255, 160, 70] as const, op: 0.38 },\n        { color: [255, 90, 60] as const, op: 0.35 },\n        { color: [255, 200, 50] as const, op: 0.38 },\n        { color: [255, 70, 70] as const, op: 0.35 },\n        { color: [255, 150, 40] as const, op: 0.38 },\n        { color: [255, 100, 80] as const, op: 0.35 },\n      ],\n    },\n    light: {\n      h: [\n        { color: [200, 70, 30] as const, op: 0.28 },\n        { color: [210, 140, 20] as const, op: 0.24 },\n        { color: [190, 50, 50] as const, op: 0.28 },\n        { color: [200, 100, 20] as const, op: 0.24 },\n        { color: [220, 160, 30] as const, op: 0.28 },\n        { color: [195, 80, 25] as const, op: 0.24 },\n      ],\n      v: [\n        { color: [210, 120, 40] as const, op: 0.28 },\n        { color: [190, 60, 40] as const, op: 0.24 },\n        { color: [220, 160, 25] as const, op: 0.28 },\n        { color: [185, 45, 45] as const, op: 0.24 },\n        { color: [200, 110, 20] as const, op: 0.28 },\n        { color: [195, 75, 50] as const, op: 0.24 },\n      ],\n    },\n  },\n} as const satisfies Record<\n  string,\n  Record<\"dark\" | \"light\", GridBeamPaletteLayers>\n>\n\nexport type GridBeamPaletteKey = keyof typeof PALETTES\n\nexport type GridBeamColorScheme = \"dark\" | \"light\"\n\nexport type GridBeamThemeProp = GridBeamColorScheme | \"auto\"\n\nfunction subscribePreferredColorScheme(onChange: () => void) {\n  const mq = window.matchMedia(\"(prefers-color-scheme: dark)\")\n  mq.addEventListener(\"change\", onChange)\n  return () => mq.removeEventListener(\"change\", onChange)\n}\n\nfunction getPreferredColorSchemeSnapshot(): GridBeamColorScheme {\n  return window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n    ? \"dark\"\n    : \"light\"\n}\n\nfunction useResolvedColorScheme(theme: GridBeamThemeProp): GridBeamColorScheme {\n  const systemScheme = useSyncExternalStore(\n    subscribePreferredColorScheme,\n    getPreferredColorSchemeSnapshot,\n    () => \"light\" as GridBeamColorScheme\n  )\n  if (theme === \"auto\") {\n    return systemScheme\n  }\n  return theme\n}\n\nexport function resolveGridBeamPalette(\n  colorVariant: GridBeamPaletteKey,\n  scheme: GridBeamColorScheme\n): GridBeamPaletteLayers {\n  const variant = PALETTES[colorVariant]\n  if (!variant) {\n    return PALETTES.colorful.dark\n  }\n  return variant[scheme] ?? PALETTES.colorful.dark\n}\n\nfunction smoothstep(t: number): number {\n  return t * t * (3 - 2 * t)\n}\n\nfunction gaussian(x: number, s: number): number {\n  return Math.exp(-(x * x) / (2 * s * s))\n}\n\nexport type BeamCanvasRuntimeConfig = Readonly<{\n  rows: number\n  cols: number\n  palette: GridBeamPaletteLayers\n  active: boolean\n  fadingOut: boolean\n  fadeStart: number | null\n  duration: number\n  strength: number\n  breathe: boolean\n}>\n\nfunction useBeamCanvas(\n  canvasRef: RefObject<HTMLCanvasElement | null>,\n  config: MutableRefObject<BeamCanvasRuntimeConfig>\n) {\n  const animRef = useRef<number | null>(null)\n  const startRef = useRef<number | null>(null)\n\n  // biome-ignore lint/correctness/useExhaustiveDependencies: animation reads latest `config.current` each frame; only canvas mount should restart the loop.\n  useEffect(() => {\n    const canvas = canvasRef.current\n    if (!canvas) {\n      return\n    }\n    const ctx = canvas.getContext(\"2d\", { alpha: true })\n    if (!ctx) {\n      return\n    }\n    const dpr = window.devicePixelRatio || 1\n\n    const resize = () => {\n      const rect = canvas.getBoundingClientRect()\n      canvas.width = rect.width * dpr\n      canvas.height = rect.height * dpr\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0)\n    }\n    resize()\n    const ro = new ResizeObserver(resize)\n    ro.observe(canvas)\n    startRef.current = performance.now()\n\n    // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: single canvas frame renderer; splitting would obscure the math.\n    const draw = (now: number) => {\n      const {\n        rows,\n        cols,\n        palette,\n        active,\n        fadingOut,\n        fadeStart,\n        duration,\n        strength,\n        breathe,\n      } = config.current\n      const rect = canvas.getBoundingClientRect()\n      const w = rect.width\n      const h = rect.height\n      ctx.clearRect(0, 0, w, h)\n\n      if (!(active || fadingOut)) {\n        animRef.current = requestAnimationFrame(draw)\n        return\n      }\n\n      const elapsed = (now - (startRef.current ?? now)) / 1000\n      let fade = 1\n      if (fadingOut && fadeStart) {\n        fade = Math.max(0, 1 - (now - fadeStart) / 600)\n        if (fade <= 0) {\n          animRef.current = requestAnimationFrame(draw)\n          return\n        }\n      } else if (active) {\n        fade = smoothstep(Math.min(1, elapsed / 0.8))\n      }\n\n      const cellW = w / cols\n      const cellH = h / rows\n      const gs = fade * strength\n      const br = breathe\n        ? 0.85 + 0.3 * Math.sin(elapsed * 1.4) + 0.1 * Math.sin(elapsed * 2.3)\n        : 1\n\n      const rgba = (r: number, g: number, b: number, a: number) =>\n        `rgba(${r},${g},${b},${Math.max(0, a).toFixed(4)})`\n\n      for (let r = 1; r < rows; r++) {\n        const y = r * cellH\n        const pal = palette.h[r % palette.h.length]\n        const [cr, cg, cb] = pal.color\n        const op = pal.op\n        const speed = 1 + (r % 3) * 0.12\n        const offset = r * 0.21 + (r % 2) * 0.35\n        const t = ((elapsed * speed) / duration + offset) % 1\n        const x = t * w\n\n        const bloomLen = cellW * 0.6 * br\n        const bloomH = 4\n        const bloomGrad = ctx.createRadialGradient(x, y, 0, x, y, bloomLen)\n        bloomGrad.addColorStop(0, rgba(cr, cg, cb, op * 0.3 * gs))\n        bloomGrad.addColorStop(0.4, rgba(cr, cg, cb, op * 0.12 * gs))\n        bloomGrad.addColorStop(1, \"transparent\")\n        ctx.save()\n        ctx.scale(1, bloomH / bloomLen)\n        ctx.fillStyle = bloomGrad\n        ctx.beginPath()\n        ctx.arc(x, (y * bloomLen) / bloomH, bloomLen, 0, Math.PI * 2)\n        ctx.fill()\n        ctx.restore()\n\n        const coreLen = cellW * 0.55 * br\n        const lineGrad = ctx.createLinearGradient(\n          x - coreLen,\n          y,\n          x + coreLen,\n          y\n        )\n        lineGrad.addColorStop(0, \"transparent\")\n        lineGrad.addColorStop(0.12, rgba(cr, cg, cb, op * 0.4 * gs))\n        lineGrad.addColorStop(\n          0.35,\n          rgba(\n            Math.min(255, cr + 60),\n            Math.min(255, cg + 60),\n            Math.min(255, cb + 60),\n            op * 0.8 * gs\n          )\n        )\n        lineGrad.addColorStop(\n          0.5,\n          rgba(\n            Math.min(255, cr + 100),\n            Math.min(255, cg + 100),\n            Math.min(255, cb + 100),\n            op * 1.0 * gs\n          )\n        )\n        lineGrad.addColorStop(\n          0.65,\n          rgba(\n            Math.min(255, cr + 60),\n            Math.min(255, cg + 60),\n            Math.min(255, cb + 60),\n            op * 0.8 * gs\n          )\n        )\n        lineGrad.addColorStop(0.88, rgba(cr, cg, cb, op * 0.4 * gs))\n        lineGrad.addColorStop(1, \"transparent\")\n        ctx.strokeStyle = lineGrad\n        ctx.lineWidth = 1.5\n        ctx.beginPath()\n        ctx.moveTo(x - coreLen, y)\n        ctx.lineTo(x + coreLen, y)\n        ctx.stroke()\n      }\n\n      for (let c = 1; c < cols; c++) {\n        const x = c * cellW\n        const pal = palette.v[c % palette.v.length]\n        const [cr, cg, cb] = pal.color\n        const op = pal.op\n        const speed = 1 + (c % 3) * 0.1\n        const offset = c * 0.26 + (c % 2) * 0.4\n        const t = ((elapsed * speed) / (duration * 1.2) + offset) % 1\n        const y = t * h\n\n        const bloomLen = cellH * 0.6 * br\n        const bloomW = 4\n        const bloomGrad = ctx.createRadialGradient(x, y, 0, x, y, bloomLen)\n        bloomGrad.addColorStop(0, rgba(cr, cg, cb, op * 0.3 * gs))\n        bloomGrad.addColorStop(0.4, rgba(cr, cg, cb, op * 0.12 * gs))\n        bloomGrad.addColorStop(1, \"transparent\")\n        ctx.save()\n        ctx.scale(bloomW / bloomLen, 1)\n        ctx.fillStyle = bloomGrad\n        ctx.beginPath()\n        ctx.arc((x * bloomLen) / bloomW, y, bloomLen, 0, Math.PI * 2)\n        ctx.fill()\n        ctx.restore()\n\n        const coreLen = cellH * 0.55 * br\n        const lineGrad = ctx.createLinearGradient(\n          x,\n          y - coreLen,\n          x,\n          y + coreLen\n        )\n        lineGrad.addColorStop(0, \"transparent\")\n        lineGrad.addColorStop(0.12, rgba(cr, cg, cb, op * 0.4 * gs))\n        lineGrad.addColorStop(\n          0.35,\n          rgba(\n            Math.min(255, cr + 60),\n            Math.min(255, cg + 60),\n            Math.min(255, cb + 60),\n            op * 0.8 * gs\n          )\n        )\n        lineGrad.addColorStop(\n          0.5,\n          rgba(\n            Math.min(255, cr + 100),\n            Math.min(255, cg + 100),\n            Math.min(255, cb + 100),\n            op * 1.0 * gs\n          )\n        )\n        lineGrad.addColorStop(\n          0.65,\n          rgba(\n            Math.min(255, cr + 60),\n            Math.min(255, cg + 60),\n            Math.min(255, cb + 60),\n            op * 0.8 * gs\n          )\n        )\n        lineGrad.addColorStop(0.88, rgba(cr, cg, cb, op * 0.4 * gs))\n        lineGrad.addColorStop(1, \"transparent\")\n        ctx.strokeStyle = lineGrad\n        ctx.lineWidth = 1.5\n        ctx.beginPath()\n        ctx.moveTo(x, y - coreLen)\n        ctx.lineTo(x, y + coreLen)\n        ctx.stroke()\n      }\n\n      for (let r = 1; r < rows; r++) {\n        for (let c = 1; c < cols; c++) {\n          const ix = c * cellW\n          const iy = r * cellH\n          const hSpeed = 1 + (r % 3) * 0.12\n          const hOffset = r * 0.21 + (r % 2) * 0.35\n          const ht = ((elapsed * hSpeed) / duration + hOffset) % 1\n          const hx = ht * w\n          const vSpeed = 1 + (c % 3) * 0.1\n          const vOffset = c * 0.26 + (c % 2) * 0.4\n          const vt = ((elapsed * vSpeed) / (duration * 1.2) + vOffset) % 1\n          const vy = vt * h\n\n          const proxH = gaussian((hx - ix) / cellW, 0.25)\n          const proxV = gaussian((vy - iy) / cellH, 0.25)\n          const prox = proxH * proxV\n\n          if (prox > 0.05) {\n            const pH = palette.h[r % palette.h.length]\n            const pV = palette.v[c % palette.v.length]\n            const mr = Math.floor((pH.color[0] + pV.color[0]) / 2)\n            const mg = Math.floor((pH.color[1] + pV.color[1]) / 2)\n            const mb = Math.floor((pH.color[2] + pV.color[2]) / 2)\n            const fr = 3.5 * Math.sqrt(prox)\n            const fop = prox * 0.6 * gs\n\n            const fg = ctx.createRadialGradient(ix, iy, 0, ix, iy, fr)\n            fg.addColorStop(\n              0,\n              rgba(\n                Math.min(255, mr + 140),\n                Math.min(255, mg + 140),\n                Math.min(255, mb + 140),\n                fop\n              )\n            )\n            fg.addColorStop(0.5, rgba(mr, mg, mb, fop * 0.4))\n            fg.addColorStop(1, \"transparent\")\n            ctx.fillStyle = fg\n            ctx.beginPath()\n            ctx.arc(ix, iy, fr, 0, Math.PI * 2)\n            ctx.fill()\n          }\n        }\n      }\n\n      animRef.current = requestAnimationFrame(draw)\n    }\n\n    animRef.current = requestAnimationFrame(draw)\n    return () => {\n      if (animRef.current !== null) {\n        cancelAnimationFrame(animRef.current)\n      }\n      ro.disconnect()\n    }\n  }, [canvasRef])\n}\n\nexport type UseGridBeamOptions = Readonly<{\n  rows?: number\n  cols?: number\n  colorVariant?: GridBeamPaletteKey\n  /** Resolved automatically when `\"auto\"` via `prefers-color-scheme`. */\n  theme?: GridBeamThemeProp\n  active?: boolean\n  duration?: number\n  strength?: number\n  breathe?: boolean\n}>\n\nexport type UseGridBeamResult = Readonly<{\n  canvasRef: RefObject<HTMLCanvasElement | null>\n  palette: GridBeamPaletteLayers\n  resolvedScheme: GridBeamColorScheme\n  rows: number\n  cols: number\n  fadingOut: boolean\n  fadeStart: number | null\n}>\n\n/**\n * Headless state for the grid beam canvas: palette resolution, fade-out when `active` becomes false,\n * and a ref to attach to {@link GridBeamCanvas}.\n */\nexport function useGridBeam({\n  rows: rowsProp = 3,\n  cols: colsProp = 4,\n  colorVariant = \"colorful\",\n  theme = \"dark\",\n  active = true,\n  duration = 3,\n  strength = 1,\n  breathe = true,\n}: UseGridBeamOptions): UseGridBeamResult {\n  const rows = Math.max(2, rowsProp)\n  const cols = Math.max(2, colsProp)\n\n  const canvasRef = useRef<HTMLCanvasElement>(null)\n  const [fadingOut, setFadingOut] = useState(false)\n  const [fadeStart, setFadeStart] = useState<number | null>(null)\n  const prevActive = useRef(active)\n\n  const resolvedScheme = useResolvedColorScheme(theme)\n\n  const palette = useMemo(\n    () => resolveGridBeamPalette(colorVariant, resolvedScheme),\n    [colorVariant, resolvedScheme]\n  )\n\n  useEffect(() => {\n    if (prevActive.current && !active) {\n      setFadingOut(true)\n      setFadeStart(performance.now())\n      const timer = window.setTimeout(() => setFadingOut(false), 700)\n      prevActive.current = active\n      return () => window.clearTimeout(timer)\n    }\n    prevActive.current = active\n  }, [active])\n\n  const configRef = useRef<BeamCanvasRuntimeConfig>({\n    rows,\n    cols,\n    palette,\n    active,\n    fadingOut,\n    fadeStart,\n    duration,\n    strength,\n    breathe,\n  })\n  configRef.current = {\n    rows,\n    cols,\n    palette,\n    active,\n    fadingOut,\n    fadeStart,\n    duration,\n    strength,\n    breathe,\n  }\n\n  useBeamCanvas(canvasRef, configRef)\n\n  return {\n    canvasRef,\n    palette,\n    resolvedScheme,\n    rows,\n    cols,\n    fadingOut,\n    fadeStart,\n  }\n}\n\nexport type GridBeamDividersProps = ComponentProps<\"svg\"> &\n  Readonly<{\n    rows: number\n    cols: number\n    /** Grid line color (default `var(--border)` from shadcn theme). */\n    dividerStroke?: string\n  }>\n\n/** SVG grid lines only — pair with {@link GridBeamCanvas} and your own layout. */\nexport function GridBeamDividers({\n  rows,\n  cols,\n  dividerStroke = \"var(--border)\",\n  className,\n  ...props\n}: GridBeamDividersProps) {\n  return (\n    <svg\n      aria-hidden\n      className={cn(\n        \"pointer-events-none absolute inset-0 z-1 h-full w-full\",\n        className\n      )}\n      preserveAspectRatio=\"none\"\n      role=\"presentation\"\n      {...props}\n    >\n      {Array.from({ length: rows - 1 }, (_, r) => {\n        const y = `${((r + 1) / rows) * 100}%`\n        return (\n          <line\n            key={`h-${rows}-${y}`}\n            stroke={dividerStroke}\n            strokeWidth={1}\n            x1=\"0\"\n            x2=\"100%\"\n            y1={y}\n            y2={y}\n          />\n        )\n      })}\n      {Array.from({ length: cols - 1 }, (_, c) => {\n        const x = `${((c + 1) / cols) * 100}%`\n        return (\n          <line\n            key={`v-${cols}-${x}`}\n            stroke={dividerStroke}\n            strokeWidth={1}\n            x1={x}\n            x2={x}\n            y1=\"0\"\n            y2=\"100%\"\n          />\n        )\n      })}\n    </svg>\n  )\n}\n\nexport type GridBeamCanvasProps = ComponentProps<\"canvas\"> &\n  Readonly<{\n    borderRadius?: number\n  }>\n\nexport const GridBeamCanvas = forwardRef<\n  HTMLCanvasElement,\n  GridBeamCanvasProps\n>(function GridBeamCanvas({ className, style, borderRadius, ...props }, ref) {\n  return (\n    <canvas\n      aria-hidden\n      className={cn(\n        \"pointer-events-none absolute inset-0 z-2 h-full w-full\",\n        className\n      )}\n      ref={ref}\n      style={{ borderRadius, ...style } as CSSProperties}\n      {...props}\n    />\n  )\n})\n\nexport type GridBeamContentProps = ComponentProps<\"div\">\n\n/** Slot above the beam layers — default `z-index` stacks content on top. */\nexport function GridBeamContent({ className, ...props }: GridBeamContentProps) {\n  return (\n    <div\n      className={cn(\"relative z-3\", className)}\n      data-slot=\"grid-beam-content\"\n      {...props}\n    />\n  )\n}\n\nexport type GridBeamProps = UseGridBeamOptions &\n  ComponentProps<\"div\"> &\n  Readonly<{\n    /** Corner radius for the root and canvas (divider SVG is rectangular). */\n    borderRadius?: number\n  }>\n\n/**\n * Opinionated composition: root + dividers + canvas + content slot.\n * For full control, call {@link useGridBeam} and assemble {@link GridBeamDividers}, {@link GridBeamCanvas}, {@link GridBeamContent} yourself.\n */\nexport function GridBeam({\n  children,\n  className,\n  style,\n  borderRadius,\n  rows,\n  cols,\n  colorVariant,\n  theme,\n  active,\n  duration,\n  strength,\n  breathe,\n  ...props\n}: GridBeamProps) {\n  const {\n    canvasRef,\n    rows: r,\n    cols: c,\n  } = useGridBeam({\n    rows,\n    cols,\n    colorVariant,\n    theme,\n    active,\n    duration,\n    strength,\n    breathe,\n  })\n\n  return (\n    <div\n      className={cn(\"relative overflow-hidden\", className)}\n      data-slot=\"grid-beam\"\n      style={{ borderRadius, ...style }}\n      {...props}\n    >\n      <GridBeamDividers cols={c} rows={r} />\n      <GridBeamCanvas borderRadius={borderRadius} ref={canvasRef} />\n      <GridBeamContent>{children}</GridBeamContent>\n    </div>\n  )\n}\n",
      "type": "registry:ui"
    }
  ]
}