{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "waves-background",
  "title": "Waves Background",
  "description": "A container with fine, flowing line waves. Made for fintech and audio pages.",
  "dependencies": [
    "@paper-design/shaders-react"
  ],
  "files": [
    {
      "path": "registry/shaders/waves-background/waves-background.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Waves, type PaperShaderElement } from \"@paper-design/shaders-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst SCALE = 3\n// How fast the waves drift, in CSS pixels per second.\nconst DRIFT_SPEED = 40\n\ntype WavesBackgroundProps = React.ComponentProps<\"div\"> & {\n  colorBack?: string\n  /** Line color. Use a translucent color to keep the waves subtle. */\n  colorFront?: string\n  /** How often the waves crest. Lower values give longer, gentler waves. */\n  frequency?: number\n  /** Height of the crests. */\n  amplitude?: number\n  /** Distance between lines. */\n  spacing?: number\n  /** Line thickness. Around 0.01 gives hairlines. */\n  thickness?: number\n  /** Angle of the waves, in degrees. */\n  rotation?: number\n  /** Fade the waves out towards the top of the container. */\n  fade?: boolean\n  /** Let the waves drift slowly. Always off when the user prefers reduced motion. */\n  animate?: boolean\n}\n\nfunction WavesBackground({\n  colorBack = \"#050b16\",\n  colorFront = \"#34d39999\",\n  frequency = 0.1,\n  amplitude = 0.8,\n  spacing = 0.2,\n  thickness = 0.012,\n  rotation = -8,\n  fade = true,\n  animate = true,\n  className,\n  children,\n  style,\n  ...props\n}: WavesBackgroundProps) {\n  const ref = React.useRef<PaperShaderElement>(null)\n\n  // Paper's Waves shader is static, so drift it by moving its offset uniforms\n  // directly every frame, without re-rendering React.\n  React.useEffect(() => {\n    const element = ref.current\n    if (!element || !animate) return\n    if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return\n\n    // The wave shape repeats every (4 / frequency) pattern units, so wrapping\n    // the distance at one period keeps the loop seamless and the numbers small.\n    const period = frequency > 0 ? (100 * SCALE) / frequency : Infinity\n    const angle = (rotation * Math.PI) / 180\n    let size = { width: 0, height: 0 }\n    let distance = 0\n    let lastTime = 0\n    let frame: number | null = null\n\n    const tick = (time: number) => {\n      distance = (distance + ((time - lastTime) / 1000) * DRIFT_SPEED) % period\n      lastTime = time\n      if (size.width && size.height) {\n        // Offsets are in fractions of the canvas and get rotated with the\n        // pattern, so counter-rotate them to move along the waves.\n        element.paperShaderMount?.setUniforms({\n          u_offsetX: (-Math.cos(angle) * distance) / size.width,\n          u_offsetY: (-Math.sin(angle) * distance) / size.height,\n        })\n      }\n      frame = requestAnimationFrame(tick)\n    }\n\n    const resizeObserver = new ResizeObserver(([entry]) => {\n      const box = entry.borderBoxSize[0]\n      size = { width: box.inlineSize, height: box.blockSize }\n    })\n    resizeObserver.observe(element)\n\n    // Only animate while the background is on screen.\n    const intersectionObserver = new IntersectionObserver(([entry]) => {\n      if (entry.isIntersecting && frame === null) {\n        lastTime = performance.now()\n        frame = requestAnimationFrame(tick)\n      } else if (!entry.isIntersecting && frame !== null) {\n        cancelAnimationFrame(frame)\n        frame = null\n      }\n    })\n    intersectionObserver.observe(element)\n\n    return () => {\n      if (frame !== null) cancelAnimationFrame(frame)\n      resizeObserver.disconnect()\n      intersectionObserver.disconnect()\n    }\n  }, [animate, frequency, rotation])\n\n  return (\n    <div\n      data-slot=\"waves-background\"\n      className={cn(\"relative isolate overflow-hidden\", className)}\n      style={{ backgroundColor: colorBack, ...style }}\n      {...props}\n    >\n      <Waves\n        ref={ref}\n        aria-hidden\n        className={cn(\n          \"absolute inset-0 -z-10 size-full\",\n          fade && \"mask-t-from-20% mask-t-to-90%\"\n        )}\n        colorBack=\"#00000000\"\n        colorFront={colorFront}\n        // Between a sine and an irregular wave, so lines read like price curves.\n        shape={2.5}\n        frequency={frequency}\n        amplitude={amplitude}\n        spacing={spacing}\n        proportion={thickness}\n        softness={0}\n        rotation={rotation}\n        scale={SCALE}\n      />\n      {children}\n    </div>\n  )\n}\n\nexport { WavesBackground }\n",
      "type": "registry:component"
    }
  ],
  "categories": [
    "backgrounds"
  ],
  "type": "registry:component"
}