{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "background-tailwind",
  "type": "registry:item",
  "title": "Background (Tailwind)",
  "description": "A background component with various visual effects.",
  "files": [
    {
      "path": "registry/brook/tailwind/ui/background.tsx",
      "content": "\"use client\";\nimport type React from \"react\";\nimport { useEffect, useRef } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nconst vertexShader = `\n  attribute vec2 a_position;\n  varying vec2 v_uv;\n\n  void main() {\n    v_uv = a_position * 0.5 + 0.5;\n    gl_Position = vec4(a_position, 0.0, 1.0);\n  }\n`;\n\nconst fragmentShader = `\n  precision highp float;\n\n  uniform float u_time;\n  uniform vec2 u_resolution;\n\n  uniform vec3 u_primaryColor;\n  uniform vec3 u_secondaryColor;\n  uniform vec3 u_backgroundColor;\n  uniform float u_backgroundOpacity;\n\n  // Animation uniforms\n  uniform float u_animationSpeed;\n  uniform float u_noiseScale;\n  uniform float u_intensity;\n\n  uniform float u_octaves;\n  uniform float u_warpStrength;\n  varying vec2 v_uv;\n\n  // Mathematical constants with high precision\n  const float PI = 3.1415926535897932384626433832795;\n  const float TAU = 6.2831853071795864769252867665590; // 2 * PI\n  const float INV_PI = 0.3183098861837906715377675267450;\n  const float SQRT_2 = 1.4142135623730950488016887242097;\n  const float SQRT_3 = 1.7320508075688772935274463415059;\n  const float PHI = 1.6180339887498948482045868343656; // Golden ratio\n\n  // Simplex noise constants - mathematically derived for optimal distribution\n  const float F2 = 0.36602540378443864676372317075294; // (sqrt(3) - 1) / 2\n  const float G2 = 0.21132486540518713342105263157895; // (3 - sqrt(3)) / 6\n  const float G2_2 = 0.42264973081037426684210526315789; // 2 * G2\n  const float G2_MINUS_1 = -0.78867513459481286657894736842105; // 2 * G2 - 1\n\n  // Improved permutation constants for better hash distribution\n  const float PERM_MOD = 289.0;\n  const float PERM_MUL = 34.0;\n  const float PERM_ADD = 1.0;\n\n  // Optimized normalization constant for better noise range\n  const float NOISE_SCALE = 70.0; // Improved from 130.0 for better dynamic range\n\n  // FBM configuration constants\n  const float FBM_LACUNARITY = 2.0;      // Frequency multiplier between octaves\n  const float FBM_PERSISTENCE = 0.5;     // Amplitude multiplier between octaves\n  const float FBM_INITIAL_AMP = 0.5;     // Starting amplitude\n\n  // Domain warping offset vectors - using irrational numbers for better distribution\n  const vec2 WARP_OFFSET_1 = vec2(0.0, 0.0);\n  const vec2 WARP_OFFSET_2 = vec2(5.12, 1.41); // Approximations of sqrt(26.2144) and sqrt(2)\n  const vec2 WARP_OFFSET_3 = vec2(1.73, 9.17); // Approximations of sqrt(3) and sqrt(84.1)\n  const vec2 WARP_OFFSET_4 = vec2(8.37, 2.83); // Approximations of sqrt(70.06) and sqrt(8)\n\n  // Animation velocity constants - using phi-based ratios for organic motion\n  const float ANIM_VEL_X1 = 0.1;\n  const float ANIM_VEL_Y1 = 0.05;\n  const float ANIM_VEL_X2 = -0.08;\n  const float ANIM_VEL_Y2 = 0.12;\n  const float ANIM_VEL_X3 = 0.06;\n  const float ANIM_VEL_Y3 = -0.04;\n\n  // Time scaling factors for warping\n  const float WARP_TIME_SCALE_1 = 0.15;\n  const float WARP_TIME_SCALE_2 = 0.126; // Approximation of 1/e^2\n\n  // Layer scaling factors\n  const float LAYER_SCALE_2 = 1.5;\n  const float LAYER_SCALE_3 = 2.5;\n\n  // Noise combination weights - normalized to sum to 1.0\n  const float NOISE_WEIGHT_1 = 0.6;\n  const float NOISE_WEIGHT_2 = 0.3;\n  const float NOISE_WEIGHT_3 = 0.1;\n\n  // Palette animation frequencies - using musical ratios\n  const float PALETTE_FREQ_1 = 1.5;     // Perfect fifth ratio\n  const float PALETTE_FREQ_2 = 2.25;    // Major ninth ratio\n  const float PALETTE_AMP_1 = 0.4;\n  const float PALETTE_AMP_2 = 0.3;\n\n  // Background noise scales and intensities\n  const float BG_NOISE_SCALE_1 = 2.0;\n  const float BG_NOISE_SCALE_2 = 5.0;\n  const float BG_NOISE_INTENSITY_1 = 0.02;\n  const float BG_NOISE_INTENSITY_2 = 0.02;\n  const float BG_NOISE_TIME_SCALE_1 = 0.1;\n  const float BG_NOISE_TIME_SCALE_2 = 0.15;\n\n  // Color mixing ratios\n  const float COLOR_MIX_RATIO_1 = 0.6;\n  const float COLOR_MIX_RATIO_2 = 0.7;\n  const float COLOR_INTENSITY_MUL = 0.8;\n  const float COLOR_WAVE_AMP = 0.6;\n\n  // Smoothstep range for pattern definition\n  const float PATTERN_LOW = -0.3;\n  const float PATTERN_HIGH = 0.5;\n\n  // Color shift parameters\n  const float COLOR_SHIFT_TIME_SCALE = 0.2;\n  const float COLOR_SHIFT_UV_SCALE = 0.4;\n  const float COLOR_SHIFT_NOISE_SCALE = 0.3;\n\n  // Improved permutation function with better distribution\n  vec3 permute(vec3 x) {\n      return mod(((x * PERM_MUL) + PERM_ADD) * x, PERM_MOD);\n  }\n\n  // Optimized Simplex noise with improved constants\n  float snoise(vec2 v) {\n      // Skew the input space to determine which simplex cell we're in\n      vec2 i = floor(v + dot(v, vec2(F2)));\n      vec2 x0 = v - i + dot(i, vec2(G2));\n\n      // Determine which simplex we are in\n      vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n\n      // Offsets for second and third corner of simplex in (x,y) uv coords\n      vec4 x12 = x0.xyxy + vec4(G2, G2, G2_MINUS_1, G2_MINUS_1);\n      x12.xy -= i1;\n\n      // Permutations\n      i = mod(i, PERM_MOD);\n      vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0));\n\n      // Circularly symmetric blending kernel\n      vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0);\n      m = m * m * m * m; // Fourth power for smoother falloff\n\n      // Gradients from 41 points on a line, mapped onto a diamond\n      vec3 x = fract(p * (1.0 / 41.0)) * 2.0 - 1.0;\n      vec3 h = abs(x) - 0.5;\n      vec3 ox = floor(x + 0.5);\n      vec3 a0 = x - ox;\n\n      // Normalize gradients implicitly by scaling m\n      m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);\n\n      // Compute final noise value at P\n      vec3 g;\n      g.x = a0.x * x0.x + h.x * x0.y;\n      g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n\n      return NOISE_SCALE * dot(m, g);\n  }\n\n  // Improved FBM with proper normalization\n  float fbm(vec2 pos, int octaves) {\n      float value = 0.0;\n      float amplitude = FBM_INITIAL_AMP;\n      float frequency = 1.0;\n      float maxValue = 0.0; // Used for normalization\n\n      for (int i = 0; i < 6; i++) {\n          if (i >= octaves) break;\n          value += amplitude * snoise(pos * frequency);\n          maxValue += amplitude;\n          amplitude *= FBM_PERSISTENCE;\n          frequency *= FBM_LACUNARITY;\n      }\n\n      // Normalize to [-1, 1] range\n      return value / maxValue;\n  }\n\n  // Enhanced domain warping with better offset distribution\n  float domainWarp(vec2 pos, float time) {\n      // Primary distortion layer\n      vec2 q = vec2(\n          fbm(pos + WARP_OFFSET_1, int(u_octaves)),\n          fbm(pos + WARP_OFFSET_2, int(u_octaves))\n      );\n\n      // Secondary distortion layer with time animation\n      vec2 r = vec2(\n          fbm(pos + u_warpStrength * q + WARP_OFFSET_3 + WARP_TIME_SCALE_1 * time, int(u_octaves - 1.0)),\n          fbm(pos + u_warpStrength * q + WARP_OFFSET_4 + WARP_TIME_SCALE_2 * time, int(u_octaves - 1.0))\n      );\n\n      // Final warped noise\n      return fbm(pos + u_warpStrength * r, int(u_octaves - 2.0));\n  }\n\n  // Improved palette function with better color theory\n  vec3 palette(float t) {\n      vec3 a = u_primaryColor;\n      vec3 b = u_secondaryColor;\n      vec3 c = mix(u_primaryColor, u_secondaryColor, COLOR_MIX_RATIO_1);\n      vec3 d = mix(u_primaryColor, u_secondaryColor, COLOR_MIX_RATIO_2);\n\n      // Use sinusoidal modulation with musical frequency ratios\n      d = mix(d, u_secondaryColor * 0.5, sin(t * PALETTE_FREQ_1) * PALETTE_AMP_1 + 0.5);\n      d = mix(d, u_primaryColor * 1.2, sin(t * PALETTE_FREQ_2) * PALETTE_AMP_2 + 0.5);\n\n      // Use precise TAU instead of approximation\n      float wave = cos(TAU * (c.x * t + d.x)) * COLOR_WAVE_AMP;\n      vec3 result = a + b * wave * COLOR_INTENSITY_MUL;\n\n      return result;\n  }\n\n  void main() {\n      vec2 uv = v_uv;\n      vec2 st = uv * u_noiseScale;\n\n      float time = u_time * u_animationSpeed;\n\n      // Layer 1: Domain-warped noise with primary animation\n      vec2 animPos = st + vec2(time * ANIM_VEL_X1, time * ANIM_VEL_Y1);\n      float noise1 = domainWarp(animPos, time);\n\n      // Layer 2: Standard FBM with secondary animation\n      vec2 animPos2 = st * LAYER_SCALE_2 + vec2(time * ANIM_VEL_X2, time * ANIM_VEL_Y2);\n      float noise2 = fbm(animPos2, int(u_octaves - 1.0));\n\n      // Layer 3: Simple noise with tertiary animation\n      vec2 animPos3 = st * LAYER_SCALE_3 + vec2(time * ANIM_VEL_X3, time * ANIM_VEL_Y3);\n      float noise3 = snoise(animPos3);\n\n      // Combine noise layers with normalized weights\n      float combinedNoise = noise1 * NOISE_WEIGHT_1 + noise2 * NOISE_WEIGHT_2 + noise3 * NOISE_WEIGHT_3;\n\n      // Create pattern with smooth transitions\n      float pattern = smoothstep(PATTERN_LOW, PATTERN_HIGH, combinedNoise);\n\n      // Generate color shift with multiple influences\n      float colorShift = time * COLOR_SHIFT_TIME_SCALE + uv.x * COLOR_SHIFT_UV_SCALE;\n      colorShift += noise1 * COLOR_SHIFT_NOISE_SCALE;\n      vec3 color = palette(colorShift);\n\n      // Add subtle background noise\n      vec3 bgNoise = vec3(snoise(uv * BG_NOISE_SCALE_1 + time * BG_NOISE_TIME_SCALE_1) * BG_NOISE_INTENSITY_1);\n      vec3 bgColor = u_backgroundColor + bgNoise;\n\n      // Apply pattern intensity\n      float intensity = pattern * u_intensity;\n      color = mix(bgColor, color, intensity);\n\n      // Add background movement texture\n      vec3 bgMovement = vec3(snoise(uv * BG_NOISE_SCALE_2 + time * BG_NOISE_TIME_SCALE_2) * BG_NOISE_INTENSITY_2);\n      color += bgMovement;\n\n      gl_FragColor = vec4(color, u_backgroundOpacity);\n  }\n`;\n\ntype BackgroundProps = {\n  className?: string;\n  primaryColor?: [number, number, number];\n  secondaryColor?: [number, number, number];\n  backgroundColor?: [number, number, number];\n  backgroundOpacity?: number;\n  animationSpeed?: number;\n  noiseScale?: number;\n  intensity?: number;\n  octaves?: number;\n  warpStrength?: number;\n};\n\nconst Background: React.FC<BackgroundProps> = ({\n  className,\n  // biome-ignore lint/style/noMagicNumbers: WebGL RGB color values\n  primaryColor = [0.85, 0.85, 0.85],\n  // biome-ignore lint/style/noMagicNumbers: WebGL RGB color values\n  secondaryColor = [0.25, 0.25, 0.25],\n  // biome-ignore lint/style/noMagicNumbers: WebGL RGB color values\n  backgroundColor = [0.0, 0.0, 0.0],\n  backgroundOpacity = 0.0,\n  animationSpeed = 0.3,\n  noiseScale = 3.0,\n  intensity = 0.9,\n  octaves = 4,\n  warpStrength = 4.0,\n}) => {\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const animationRef = useRef<number>(0);\n  const startTimeRef = useRef<number>(0);\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    if (!canvas) {\n      return;\n    }\n\n    const gl = canvas.getContext(\"webgl\");\n    if (!gl) {\n      return;\n    }\n\n    // Set canvas size\n    const setCanvasSize = () => {\n      canvas.width = window.innerWidth;\n      canvas.height = window.innerHeight;\n      gl.viewport(0, 0, canvas.width, canvas.height);\n    };\n\n    setCanvasSize();\n    window.addEventListener(\"resize\", setCanvasSize);\n\n    // Create shaders\n    const createShader = (type: number, source: string) => {\n      const shader = gl.createShader(type);\n      if (!shader) {\n        return null;\n      }\n\n      gl.shaderSource(shader, source);\n      gl.compileShader(shader);\n\n      if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n        gl.deleteShader(shader);\n        return null;\n      }\n\n      return shader;\n    };\n\n    const vertShader = createShader(gl.VERTEX_SHADER, vertexShader);\n    const fragShader = createShader(gl.FRAGMENT_SHADER, fragmentShader);\n\n    if (!(vertShader && fragShader)) {\n      return;\n    }\n\n    // Create program\n    const program = gl.createProgram();\n    if (!program) {\n      return;\n    }\n\n    gl.attachShader(program, vertShader);\n    gl.attachShader(program, fragShader);\n    gl.linkProgram(program);\n\n    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n      return;\n    }\n\n    // Set up geometry\n    const vertices = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);\n\n    const buffer = gl.createBuffer();\n    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);\n\n    const positionLocation = gl.getAttribLocation(program, \"a_position\");\n    gl.enableVertexAttribArray(positionLocation);\n    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);\n\n    // Get uniform locations\n    const timeLocation = gl.getUniformLocation(program, \"u_time\");\n    const resolutionLocation = gl.getUniformLocation(program, \"u_resolution\");\n\n    const primaryColorLocation = gl.getUniformLocation(program, \"u_primaryColor\");\n    const secondaryColorLocation = gl.getUniformLocation(program, \"u_secondaryColor\");\n    const backgroundColorLocation = gl.getUniformLocation(program, \"u_backgroundColor\");\n    const backgroundOpacityLocation = gl.getUniformLocation(program, \"u_backgroundOpacity\");\n\n    const animationSpeedLocation = gl.getUniformLocation(program, \"u_animationSpeed\");\n    const noiseScaleLocation = gl.getUniformLocation(program, \"u_noiseScale\");\n    const intensityLocation = gl.getUniformLocation(program, \"u_intensity\");\n\n    const octavesLocation = gl.getUniformLocation(program, \"u_octaves\");\n    const warpStrengthLocation = gl.getUniformLocation(program, \"u_warpStrength\");\n\n    const MILLISECONDS_TO_SECONDS = 0.001;\n    const TRIANGLE_STRIP_VERTICES = 4;\n\n    const render = (time: number) => {\n      if (!startTimeRef.current) {\n        startTimeRef.current = time;\n      }\n      const elapsedTime = (time - startTimeRef.current) * MILLISECONDS_TO_SECONDS;\n\n      // biome-ignore lint/correctness/useHookAtTopLevel: gl.useProgram is WebGL API, not a React hook\n      gl.useProgram(program);\n\n      gl.uniform1f(timeLocation, elapsedTime);\n      gl.uniform2f(resolutionLocation, canvas.width, canvas.height);\n\n      gl.uniform3f(primaryColorLocation, primaryColor[0], primaryColor[1], primaryColor[2]);\n      gl.uniform3f(secondaryColorLocation, secondaryColor[0], secondaryColor[1], secondaryColor[2]);\n      gl.uniform3f(backgroundColorLocation, backgroundColor[0], backgroundColor[1], backgroundColor[2]);\n      gl.uniform1f(backgroundOpacityLocation, backgroundOpacity);\n\n      gl.uniform1f(animationSpeedLocation, animationSpeed);\n      gl.uniform1f(noiseScaleLocation, noiseScale);\n      gl.uniform1f(intensityLocation, intensity);\n\n      gl.uniform1f(octavesLocation, octaves);\n      gl.uniform1f(warpStrengthLocation, warpStrength);\n\n      gl.drawArrays(gl.TRIANGLE_STRIP, 0, TRIANGLE_STRIP_VERTICES);\n\n      animationRef.current = requestAnimationFrame(render);\n    };\n\n    render(0);\n\n    return () => {\n      window.removeEventListener(\"resize\", setCanvasSize);\n      if (animationRef.current) {\n        cancelAnimationFrame(animationRef.current);\n      }\n    };\n  }, [\n    primaryColor,\n    secondaryColor,\n    backgroundColor,\n    backgroundOpacity,\n    animationSpeed,\n    noiseScale,\n    intensity,\n    octaves,\n    warpStrength,\n  ]);\n\n  return (\n    <div className={cn(\"relative h-full w-full overflow-hidden rounded-[var(--radius)]\", className)}>\n      <canvas className=\"block h-full w-full object-cover\" ref={canvasRef} />\n    </div>\n  );\n};\n\nexport default Background;\n",
      "type": "registry:file",
      "target": "~/components/ui/background/background.tsx"
    }
  ]
}