{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "ColorBends-JS-CSS",
	"title": "ColorBends",
	"description": "Vibrant color bends with smooth flowing animation.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:file",
			"path": "ColorBends.css",
			"target": "@components/ColorBends.css",
			"content": ".color-bends-container {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  overflow: hidden;\n}\n"
		},
		{
			"type": "registry:component",
			"path": "ColorBends.jsx",
			"content": "import { useEffect, useRef } from 'react';\nimport * as THREE from 'three';\nimport './ColorBends.css';\n\nconst MAX_COLORS = 8;\n\nconst frag = `\n#define MAX_COLORS ${MAX_COLORS}\nuniform vec2 uCanvas;\nuniform float uTime;\nuniform float uSpeed;\nuniform vec2 uRot;\nuniform int uColorCount;\nuniform vec3 uColors[MAX_COLORS];\nuniform int uTransparent;\nuniform float uScale;\nuniform float uFrequency;\nuniform float uWarpStrength;\nuniform vec2 uPointer; // in NDC [-1,1]\nuniform float uMouseInfluence;\nuniform float uParallax;\nuniform float uNoise;\nuniform int uIterations;\nuniform float uIntensity;\nuniform float uBandWidth;\nvarying vec2 vUv;\n\nvoid main() {\n  float t = uTime * uSpeed;\n  vec2 p = vUv * 2.0 - 1.0;\n  p += uPointer * uParallax * 0.1;\n  vec2 rp = vec2(p.x * uRot.x - p.y * uRot.y, p.x * uRot.y + p.y * uRot.x);\n  vec2 q = vec2(rp.x * (uCanvas.x / uCanvas.y), rp.y);\n  q /= max(uScale, 0.0001);\n  q /= 0.5 + 0.2 * dot(q, q);\n  q += 0.2 * cos(t) - 7.56;\n  vec2 toward = (uPointer - rp);\n  q += toward * uMouseInfluence * 0.2;\n\n    for (int j = 0; j < 5; j++) {\n      if (j >= uIterations - 1) break;\n      vec2 rr = sin(1.5 * (q.yx * uFrequency) + 2.0 * cos(q * uFrequency));\n      q += (rr - q) * 0.15;\n    }\n\n    vec3 col = vec3(0.0);\n    float a = 1.0;\n\n    if (uColorCount > 0) {\n      vec2 s = q;\n      vec3 sumCol = vec3(0.0);\n      float cover = 0.0;\n      for (int i = 0; i < MAX_COLORS; ++i) {\n            if (i >= uColorCount) break;\n            s -= 0.01;\n            vec2 r = sin(1.5 * (s.yx * uFrequency) + 2.0 * cos(s * uFrequency));\n            float m0 = length(r + sin(5.0 * r.y * uFrequency - 3.0 * t + float(i)) / 4.0);\n            float kBelow = clamp(uWarpStrength, 0.0, 1.0);\n            float kMix = pow(kBelow, 0.3); // strong response across 0..1\n            float gain = 1.0 + max(uWarpStrength - 1.0, 0.0); // allow >1 to amplify displacement\n            vec2 disp = (r - s) * kBelow;\n            vec2 warped = s + disp * gain;\n            float m1 = length(warped + sin(5.0 * warped.y * uFrequency - 3.0 * t + float(i)) / 4.0);\n            float m = mix(m0, m1, kMix);\n            float w = 1.0 - exp(-uBandWidth / exp(uBandWidth * m));\n            sumCol += uColors[i] * w;\n            cover = max(cover, w);\n      }\n      col = clamp(sumCol, 0.0, 1.0);\n      a = uTransparent > 0 ? cover : 1.0;\n    } else {\n        vec2 s = q;\n        for (int k = 0; k < 3; ++k) {\n            s -= 0.01;\n            vec2 r = sin(1.5 * (s.yx * uFrequency) + 2.0 * cos(s * uFrequency));\n            float m0 = length(r + sin(5.0 * r.y * uFrequency - 3.0 * t + float(k)) / 4.0);\n            float kBelow = clamp(uWarpStrength, 0.0, 1.0);\n            float kMix = pow(kBelow, 0.3);\n            float gain = 1.0 + max(uWarpStrength - 1.0, 0.0);\n            vec2 disp = (r - s) * kBelow;\n            vec2 warped = s + disp * gain;\n            float m1 = length(warped + sin(5.0 * warped.y * uFrequency - 3.0 * t + float(k)) / 4.0);\n            float m = mix(m0, m1, kMix);\n            col[k] = 1.0 - exp(-uBandWidth / exp(uBandWidth * m));\n        }\n        a = uTransparent > 0 ? max(max(col.r, col.g), col.b) : 1.0;\n    }\n\n    col *= uIntensity;\n\n    if (uNoise > 0.0001) {\n      float n = fract(sin(dot(gl_FragCoord.xy + vec2(uTime), vec2(12.9898, 78.233))) * 43758.5453123);\n      col += (n - 0.5) * uNoise;\n      col = clamp(col, 0.0, 1.0);\n    }\n\n    vec3 rgb = (uTransparent > 0) ? col * a : col;\n    gl_FragColor = vec4(rgb, a);\n}\n`;\n\nconst vert = `\nvarying vec2 vUv;\nvoid main() {\n  vUv = uv;\n  gl_Position = vec4(position, 1.0);\n}\n`;\n\nexport default function ColorBends({\n  className,\n  style,\n  rotation = 90,\n  speed = 0.2,\n  colors = [],\n  transparent = true,\n  autoRotate = 0,\n  scale = 1,\n  frequency = 1,\n  warpStrength = 1,\n  mouseInfluence = 1,\n  parallax = 0.5,\n  noise = 0.15,\n  iterations = 1,\n  intensity = 1.5,\n  bandWidth = 6\n}) {\n  const containerRef = useRef(null);\n  const rendererRef = useRef(null);\n  const rafRef = useRef(null);\n  const materialRef = useRef(null);\n  const resizeObserverRef = useRef(null);\n  const rotationRef = useRef(rotation);\n  const autoRotateRef = useRef(autoRotate);\n  const pointerTargetRef = useRef(new THREE.Vector2(0, 0));\n  const pointerCurrentRef = useRef(new THREE.Vector2(0, 0));\n  const pointerSmoothRef = useRef(8);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const scene = new THREE.Scene();\n    const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);\n\n    const geometry = new THREE.PlaneGeometry(2, 2);\n    const uColorsArray = Array.from({ length: MAX_COLORS }, () => new THREE.Vector3(0, 0, 0));\n    const material = new THREE.ShaderMaterial({\n      vertexShader: vert,\n      fragmentShader: frag,\n      uniforms: {\n        uCanvas: { value: new THREE.Vector2(1, 1) },\n        uTime: { value: 0 },\n        uSpeed: { value: speed },\n        uRot: { value: new THREE.Vector2(1, 0) },\n        uColorCount: { value: 0 },\n        uColors: { value: uColorsArray },\n        uTransparent: { value: transparent ? 1 : 0 },\n        uScale: { value: scale },\n        uFrequency: { value: frequency },\n        uWarpStrength: { value: warpStrength },\n        uPointer: { value: new THREE.Vector2(0, 0) },\n        uMouseInfluence: { value: mouseInfluence },\n        uParallax: { value: parallax },\n        uNoise: { value: noise },\n        uIterations: { value: iterations },\n        uIntensity: { value: intensity },\n        uBandWidth: { value: bandWidth }\n      },\n      premultipliedAlpha: true,\n      transparent: true\n    });\n    materialRef.current = material;\n\n    const mesh = new THREE.Mesh(geometry, material);\n    scene.add(mesh);\n\n    const renderer = new THREE.WebGLRenderer({\n      antialias: false,\n      powerPreference: 'high-performance',\n      alpha: true\n    });\n    rendererRef.current = renderer;\n    renderer.outputColorSpace = THREE.SRGBColorSpace;\n    renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));\n    renderer.setClearColor(0x000000, transparent ? 0 : 1);\n    renderer.domElement.style.width = '100%';\n    renderer.domElement.style.height = '100%';\n    renderer.domElement.style.display = 'block';\n    container.appendChild(renderer.domElement);\n\n    const clock = new THREE.Clock();\n\n    const handleResize = () => {\n      const w = container.clientWidth || 1;\n      const h = container.clientHeight || 1;\n      renderer.setSize(w, h, false);\n      material.uniforms.uCanvas.value.set(w, h);\n    };\n\n    handleResize();\n\n    if ('ResizeObserver' in window) {\n      const ro = new ResizeObserver(handleResize);\n      ro.observe(container);\n      resizeObserverRef.current = ro;\n    } else {\n      window.addEventListener('resize', handleResize);\n    }\n\n    const loop = () => {\n      const dt = clock.getDelta();\n      const elapsed = clock.elapsedTime;\n      material.uniforms.uTime.value = elapsed;\n\n      const deg = (rotationRef.current % 360) + autoRotateRef.current * elapsed;\n      const rad = (deg * Math.PI) / 180;\n      const c = Math.cos(rad);\n      const s = Math.sin(rad);\n      material.uniforms.uRot.value.set(c, s);\n\n      const cur = pointerCurrentRef.current;\n      const tgt = pointerTargetRef.current;\n      const amt = Math.min(1, dt * pointerSmoothRef.current);\n      cur.lerp(tgt, amt);\n      material.uniforms.uPointer.value.copy(cur);\n      renderer.render(scene, camera);\n      rafRef.current = requestAnimationFrame(loop);\n    };\n    rafRef.current = requestAnimationFrame(loop);\n\n    return () => {\n      if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);\n      if (resizeObserverRef.current) resizeObserverRef.current.disconnect();\n      else window.removeEventListener('resize', handleResize);\n      geometry.dispose();\n      material.dispose();\n      renderer.dispose();\n      renderer.forceContextLoss();\n      if (renderer.domElement && renderer.domElement.parentElement === container) {\n        container.removeChild(renderer.domElement);\n      }\n    };\n  }, [bandWidth, frequency, intensity, iterations, mouseInfluence, noise, parallax, scale, speed, transparent, warpStrength]);\n\n  useEffect(() => {\n    const material = materialRef.current;\n    const renderer = rendererRef.current;\n    if (!material) return;\n\n    rotationRef.current = rotation;\n    autoRotateRef.current = autoRotate;\n    material.uniforms.uSpeed.value = speed;\n    material.uniforms.uScale.value = scale;\n    material.uniforms.uFrequency.value = frequency;\n    material.uniforms.uWarpStrength.value = warpStrength;\n    material.uniforms.uMouseInfluence.value = mouseInfluence;\n    material.uniforms.uParallax.value = parallax;\n    material.uniforms.uNoise.value = noise;\n    material.uniforms.uIterations.value = iterations;\n    material.uniforms.uIntensity.value = intensity;\n    material.uniforms.uBandWidth.value = bandWidth;\n\n    const toVec3 = hex => {\n      const h = hex.replace('#', '').trim();\n      const v =\n        h.length === 3\n          ? [parseInt(h[0] + h[0], 16), parseInt(h[1] + h[1], 16), parseInt(h[2] + h[2], 16)]\n          : [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];\n      return new THREE.Vector3(v[0] / 255, v[1] / 255, v[2] / 255);\n    };\n\n    const arr = (colors || []).filter(Boolean).slice(0, MAX_COLORS).map(toVec3);\n    for (let i = 0; i < MAX_COLORS; i++) {\n      const vec = material.uniforms.uColors.value[i];\n      if (i < arr.length) vec.copy(arr[i]);\n      else vec.set(0, 0, 0);\n    }\n    material.uniforms.uColorCount.value = arr.length;\n\n    material.uniforms.uTransparent.value = transparent ? 1 : 0;\n    if (renderer) renderer.setClearColor(0x000000, transparent ? 0 : 1);\n  }, [\n    rotation,\n    autoRotate,\n    speed,\n    scale,\n    frequency,\n    warpStrength,\n    mouseInfluence,\n    parallax,\n    noise,\n    iterations,\n    intensity,\n    bandWidth,\n    colors,\n    transparent\n  ]);\n\n  useEffect(() => {\n    const material = materialRef.current;\n    const container = containerRef.current;\n    if (!material || !container) return;\n\n    const handlePointerMove = e => {\n      const rect = container.getBoundingClientRect();\n      const x = ((e.clientX - rect.left) / (rect.width || 1)) * 2 - 1;\n      const y = -(((e.clientY - rect.top) / (rect.height || 1)) * 2 - 1);\n      pointerTargetRef.current.set(x, y);\n    };\n\n    container.addEventListener('pointermove', handlePointerMove);\n    return () => {\n      container.removeEventListener('pointermove', handlePointerMove);\n    };\n  }, []);\n\n  return <div ref={containerRef} className={`color-bends-container ${className}`} style={style} />;\n}\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"three@^0.180.0"
	]
}