{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "LineWaves-TS-CSS",
	"title": "LineWaves",
	"description": "Animated line wave pattern with colorful warped distortion.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:file",
			"path": "LineWaves.css",
			"target": "@components/LineWaves.css",
			"content": ".line-waves-container {\n  width: 100%;\n  height: 100%;\n}"
		},
		{
			"type": "registry:component",
			"path": "LineWaves.tsx",
			"content": "import { Renderer, Program, Mesh, Triangle } from 'ogl';\nimport { useEffect, useRef } from 'react';\n\nimport './LineWaves.css';\n\ninterface LineWavesProps {\n  speed?: number;\n  innerLineCount?: number;\n  outerLineCount?: number;\n  warpIntensity?: number;\n  rotation?: number;\n  edgeFadeWidth?: number;\n  colorCycleSpeed?: number;\n  brightness?: number;\n  color1?: string;\n  color2?: string;\n  color3?: string;\n  enableMouseInteraction?: boolean;\n  mouseInfluence?: number;\n  lightMode?: boolean;\n}\n\nfunction hexToVec3(hex: string): [number, number, number] {\n  const h = hex.replace('#', '');\n  return [\n    parseInt(h.slice(0, 2), 16) / 255,\n    parseInt(h.slice(2, 4), 16) / 255,\n    parseInt(h.slice(4, 6), 16) / 255\n  ];\n}\n\nconst vertexShader = `\nattribute vec2 uv;\nattribute vec2 position;\nvarying vec2 vUv;\nvoid main() {\n  vUv = uv;\n  gl_Position = vec4(position, 0, 1);\n}\n`;\n\nconst fragmentShader = `\nprecision highp float;\n\nuniform float uTime;\nuniform vec3 uResolution;\nuniform float uSpeed;\nuniform float uInnerLines;\nuniform float uOuterLines;\nuniform float uWarpIntensity;\nuniform float uRotation;\nuniform float uEdgeFadeWidth;\nuniform float uColorCycleSpeed;\nuniform float uBrightness;\nuniform vec3 uColor1;\nuniform vec3 uColor2;\nuniform vec3 uColor3;\nuniform vec2 uMouse;\nuniform float uMouseInfluence;\nuniform bool uEnableMouse;\nuniform float uLightMode;\n\n#define HALF_PI 1.5707963\n\nfloat hashF(float n) {\n  return fract(sin(n * 127.1) * 43758.5453123);\n}\n\nfloat smoothNoise(float x) {\n  float i = floor(x);\n  float f = fract(x);\n  float u = f * f * (3.0 - 2.0 * f);\n  return mix(hashF(i), hashF(i + 1.0), u);\n}\n\nfloat displaceA(float coord, float t) {\n  float result = sin(coord * 2.123) * 0.2;\n  result += sin(coord * 3.234 + t * 4.345) * 0.1;\n  result += sin(coord * 0.589 + t * 0.934) * 0.5;\n  return result;\n}\n\nfloat displaceB(float coord, float t) {\n  float result = sin(coord * 1.345) * 0.3;\n  result += sin(coord * 2.734 + t * 3.345) * 0.2;\n  result += sin(coord * 0.189 + t * 0.934) * 0.3;\n  return result;\n}\n\nvec2 rotate2D(vec2 p, float angle) {\n  float c = cos(angle);\n  float s = sin(angle);\n  return vec2(p.x * c - p.y * s, p.x * s + p.y * c);\n}\n\nvoid main() {\n  vec2 coords = gl_FragCoord.xy / uResolution.xy;\n  coords = coords * 2.0 - 1.0;\n  coords = rotate2D(coords, uRotation);\n\n  float halfT = uTime * uSpeed * 0.5;\n  float fullT = uTime * uSpeed;\n\n  float mouseWarp = 0.0;\n  if (uEnableMouse) {\n    vec2 mPos = rotate2D(uMouse * 2.0 - 1.0, uRotation);\n    float mDist = length(coords - mPos);\n    mouseWarp = uMouseInfluence * exp(-mDist * mDist * 4.0);\n  }\n\n  float warpAx = coords.x + displaceA(coords.y, halfT) * uWarpIntensity + mouseWarp;\n  float warpAy = coords.y - displaceA(coords.x * cos(fullT) * 1.235, halfT) * uWarpIntensity;\n  float warpBx = coords.x + displaceB(coords.y, halfT) * uWarpIntensity + mouseWarp;\n  float warpBy = coords.y - displaceB(coords.x * sin(fullT) * 1.235, halfT) * uWarpIntensity;\n\n  vec2 fieldA = vec2(warpAx, warpAy);\n  vec2 fieldB = vec2(warpBx, warpBy);\n  vec2 blended = mix(fieldA, fieldB, mix(fieldA, fieldB, 0.5));\n\n  float fadeTop = smoothstep(uEdgeFadeWidth, uEdgeFadeWidth + 0.4, blended.y);\n  float fadeBottom = smoothstep(-uEdgeFadeWidth, -(uEdgeFadeWidth + 0.4), blended.y);\n  float vMask = 1.0 - max(fadeTop, fadeBottom);\n\n  float tileCount = mix(uOuterLines, uInnerLines, vMask);\n  float scaledY = blended.y * tileCount;\n  float nY = smoothNoise(abs(scaledY));\n\n  float ridge = pow(\n    step(abs(nY - blended.x) * 2.0, HALF_PI) * cos(2.0 * (nY - blended.x)),\n    5.0\n  );\n\n  float lines = 0.0;\n  for (float i = 1.0; i < 3.0; i += 1.0) {\n    lines += pow(max(fract(scaledY), fract(-scaledY)), i * 2.0);\n  }\n\n  float pattern = vMask * lines;\n\n  float cycleT = fullT * uColorCycleSpeed;\n  float rChannel = (pattern + lines * ridge) * (cos(blended.y + cycleT * 0.234) * 0.5 + 1.0);\n  float gChannel = (pattern + vMask * ridge) * (sin(blended.x + cycleT * 1.745) * 0.5 + 1.0);\n  float bChannel = (pattern + lines * ridge) * (cos(blended.x + cycleT * 0.534) * 0.5 + 1.0);\n\n  vec3 col = (rChannel * uColor1 + gChannel * uColor2 + bChannel * uColor3) * uBrightness;\n  float alpha = clamp(length(col), 0.0, 1.0);\n\n  if (uLightMode > 0.5) {\n    vec3 weights = pow(max(vec3(rChannel, gChannel, bChannel), vec3(0.0)), vec3(3.0));\n    float weightSum = max(weights.r + weights.g + weights.b, 0.0001);\n    vec3 chroma = (weights.r * uColor1 + weights.g * uColor2 + weights.b * uColor3) / weightSum;\n    float neutral = min(chroma.r, min(chroma.g, chroma.b));\n    chroma = max(chroma - vec3(neutral * 0.92), vec3(0.0));\n    float peak = max(chroma.r, max(chroma.g, chroma.b));\n    chroma = pow(clamp(chroma / max(peak, 0.0001), 0.0, 1.0), vec3(1.08));\n    float ink = clamp(max(rChannel, max(gChannel, bChannel)) * uBrightness * 1.15, 0.0, 0.92);\n    gl_FragColor = vec4(mix(vec3(1.0), chroma, ink), 1.0);\n  } else {\n    gl_FragColor = vec4(col, alpha);\n  }\n}\n`;\n\nexport default function LineWaves({\n  speed = 0.3,\n  innerLineCount = 32.0,\n  outerLineCount = 36.0,\n  warpIntensity = 1.0,\n  rotation = -45,\n  edgeFadeWidth = 0.0,\n  colorCycleSpeed = 1.0,\n  brightness = 0.2,\n  color1 = '#ffffff',\n  color2 = '#ffffff',\n  color3 = '#ffffff',\n  enableMouseInteraction = true,\n  mouseInfluence = 2.0,\n  lightMode = false\n}: LineWavesProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    if (!containerRef.current) return;\n    const container = containerRef.current;\n    const renderer = new Renderer({ alpha: true, premultipliedAlpha: false });\n    const gl = renderer.gl;\n    gl.clearColor(0, 0, 0, 0);\n\n    let program: Program;\n    let currentMouse = [0.5, 0.5];\n    let targetMouse = [0.5, 0.5];\n\n    function handleMouseMove(e: MouseEvent) {\n      const rect = gl.canvas.getBoundingClientRect();\n      targetMouse = [\n        (e.clientX - rect.left) / rect.width,\n        1.0 - (e.clientY - rect.top) / rect.height\n      ];\n    }\n\n    function handleMouseLeave() {\n      targetMouse = [0.5, 0.5];\n    }\n\n    function resize() {\n      renderer.setSize(container.offsetWidth, container.offsetHeight);\n      if (program) {\n        program.uniforms.uResolution.value = [gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height];\n      }\n    }\n    window.addEventListener('resize', resize);\n\n    resize();\n\n    const geometry = new Triangle(gl);\n    const rotationRad = (rotation * Math.PI) / 180;\n    program = new Program(gl, {\n      vertex: vertexShader,\n      fragment: fragmentShader,\n      uniforms: {\n        uTime: { value: 0 },\n        uResolution: { value: [gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height] },\n        uSpeed: { value: speed },\n        uInnerLines: { value: innerLineCount },\n        uOuterLines: { value: outerLineCount },\n        uWarpIntensity: { value: warpIntensity },\n        uRotation: { value: rotationRad },\n        uEdgeFadeWidth: { value: edgeFadeWidth },\n        uColorCycleSpeed: { value: colorCycleSpeed },\n        uBrightness: { value: brightness },\n        uColor1: { value: hexToVec3(color1) },\n        uColor2: { value: hexToVec3(color2) },\n        uColor3: { value: hexToVec3(color3) },\n        uMouse: { value: new Float32Array([0.5, 0.5]) },\n        uMouseInfluence: { value: mouseInfluence },\n        uEnableMouse: { value: enableMouseInteraction },\n        uLightMode: { value: lightMode ? 1 : 0 }\n      }\n    });\n\n    const mesh = new Mesh(gl, { geometry, program });\n    container.appendChild(gl.canvas);\n\n    if (enableMouseInteraction) {\n      gl.canvas.addEventListener('mousemove', handleMouseMove);\n      gl.canvas.addEventListener('mouseleave', handleMouseLeave);\n    }\n\n    let animationFrameId: number;\n\n    function update(time: number) {\n      animationFrameId = requestAnimationFrame(update);\n      program.uniforms.uTime.value = time * 0.001;\n\n      if (enableMouseInteraction) {\n        currentMouse[0] += 0.05 * (targetMouse[0] - currentMouse[0]);\n        currentMouse[1] += 0.05 * (targetMouse[1] - currentMouse[1]);\n        program.uniforms.uMouse.value[0] = currentMouse[0];\n        program.uniforms.uMouse.value[1] = currentMouse[1];\n      } else {\n        program.uniforms.uMouse.value[0] = 0.5;\n        program.uniforms.uMouse.value[1] = 0.5;\n      }\n\n      renderer.render({ scene: mesh });\n    }\n    animationFrameId = requestAnimationFrame(update);\n\n    return () => {\n      cancelAnimationFrame(animationFrameId);\n      window.removeEventListener('resize', resize);\n      if (enableMouseInteraction) {\n        gl.canvas.removeEventListener('mousemove', handleMouseMove);\n        gl.canvas.removeEventListener('mouseleave', handleMouseLeave);\n      }\n      container.removeChild(gl.canvas);\n      gl.getExtension('WEBGL_lose_context')?.loseContext();\n    };\n  }, [speed, innerLineCount, outerLineCount, warpIntensity, rotation, edgeFadeWidth, colorCycleSpeed, brightness, color1, color2, color3, enableMouseInteraction, mouseInfluence, lightMode]);\n\n  return <div ref={containerRef} className=\"line-waves-container\" />;\n}\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"ogl@^1.0.11"
	]
}