{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "desert-dune",
  "title": "Desert Dune",
  "description": "Soft layered waves in parallax drift - cool indigo tones by default, colors via props.",
  "files": [
    {
      "path": "components/backgrounds/DesertDuneBackground.tsx",
      "content": "'use client';\n\nimport React, { useEffect, useRef, type ReactNode } from 'react';\n\n// ---------------------------------------------------------------------------\n// Props\n// ---------------------------------------------------------------------------\n//\n// children           Content layered above the waves (headline, CTA, etc.)\n// className          Styles for the content wrapper\n// containerClassName Styles for the outer shell (size, layout)\n// skyColors          Vertical sky gradient [top, bottom]\n// waveColors         Wave fills back → front (light → dark)\n// speed              \"slow\" (default) or \"fast\"\n//\ntype DesertDuneBackgroundProps = {\n  children?: ReactNode;\n  className?: string;\n  containerClassName?: string;\n  skyColors?: [string, string];\n  waveColors?: string[];\n  speed?: 'slow' | 'fast';\n};\n\n// ---------------------------------------------------------------------------\n// Default palette — soft indigo / lilac\n// ---------------------------------------------------------------------------\nconst DEFAULT_SKY: [string, string] = ['#eef1ff', '#c8d4f5'];\nconst DEFAULT_WAVES = ['#a8b8f0', '#8a9fe3', '#6d86d4', '#556ec0', '#4258a8'];\n\n// ---------------------------------------------------------------------------\n// Build a filled wave silhouette — padded so edges stay covered while animating\n// ---------------------------------------------------------------------------\nfunction wavePath(\n  width: number,\n  height: number,\n  baseline: number,\n  amplitude: number,\n  phase: number,\n  frequency: number\n) {\n  const pad = Math.max(32, amplitude * 2);\n  const waveY = (x: number) =>\n    baseline +\n    Math.sin(x * frequency + phase) * amplitude +\n    Math.sin(x * frequency * 2.1 + phase * 1.3) * amplitude * 0.4;\n\n  let d = `M ${-pad} ${height} L ${-pad} ${waveY(-pad)}`;\n  for (let x = -pad; x <= width + pad; x += 4) {\n    d += ` L${x} ${waveY(x)}`;\n  }\n  d += ` L ${width + pad} ${height} Z`;\n  return d;\n}\n\nexport default function DesertDuneBackground({\n  children,\n  className = '',\n  containerClassName = '',\n  skyColors = DEFAULT_SKY,\n  waveColors = DEFAULT_WAVES,\n  speed = 'slow',\n}: DesertDuneBackgroundProps) {\n  // ---------------------------------------------------------------------------\n  // Refs\n  // ---------------------------------------------------------------------------\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const rafRef = useRef(0);\n  const timeRef = useRef(0);\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 step = speed === 'fast' ? 0.008 : 0.004;\n    let width = 0;\n    let height = 0;\n    let dpr = 1;\n    const prefersReducedMotion = window.matchMedia(\n      '(prefers-reduced-motion: reduce)'\n    ).matches;\n\n    // -------------------------------------------------------------------------\n    // Setup helpers\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      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    };\n\n    // -------------------------------------------------------------------------\n    // Draw loop — sky + layered waves\n    // -------------------------------------------------------------------------\n    const draw = () => {\n      timeRef.current += prefersReducedMotion ? 0 : step;\n      const t = timeRef.current;\n\n      const sky = ctx.createLinearGradient(0, 0, 0, height);\n      sky.addColorStop(0, skyColors[0]);\n      sky.addColorStop(1, skyColors[1]);\n      ctx.fillStyle = sky;\n      ctx.fillRect(0, 0, width, height);\n\n      const layers = waveColors;\n      const count = layers.length;\n\n      for (let i = 0; i < count; i++) {\n        const progress = i / Math.max(count - 1, 1);\n        const baseline = height * (0.48 + progress * 0.28);\n        const amplitude = height * (0.045 + (1 - progress) * 0.035);\n        const frequency = 0.006 + i * 0.0012;\n        // Parallax drift — farther layers move slower\n        const phase = t * (0.55 + i * 0.35) + i * 1.7;\n\n        const path = new Path2D(\n          wavePath(width, height, baseline, amplitude, phase, frequency)\n        );\n        ctx.fillStyle = layers[i];\n        ctx.fill(path);\n      }\n\n      if (!prefersReducedMotion) {\n        rafRef.current = requestAnimationFrame(draw);\n      }\n    };\n\n    // -------------------------------------------------------------------------\n    // Start + cleanup\n    // -------------------------------------------------------------------------\n    resize();\n    draw();\n\n    const observer = new ResizeObserver(resize);\n    observer.observe(container);\n\n    return () => {\n      cancelAnimationFrame(rafRef.current);\n      observer.disconnect();\n    };\n  }, [waveColors, skyColors, speed]);\n\n  // ---------------------------------------------------------------------------\n  // Render — canvas behind, content on top\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    >\n      <canvas\n        ref={canvasRef}\n        className='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/DesertDuneBackground.tsx"
    }
  ],
  "categories": [
    "backgrounds"
  ],
  "type": "registry:component"
}