{"version":3,"file":"FluidGradient.mjs","names":[],"sources":["../../../src/awesome/FluidGradient/FluidGradient.tsx"],"sourcesContent":["'use client';\n\nimport { cx, useThemeMode } from 'antd-style';\nimport { type CSSProperties, memo, useEffect, useRef, useState } from 'react';\n\nimport { LANDING_PALETTE_DARK, LANDING_PALETTE_LIGHT } from '@/awesome/landingTokens';\n\nimport { styles } from './style';\nimport type { FluidGradientProps } from './type';\n\nconst VERTEX_SHADER = `#version 300 es\nin vec2 aPos;\nvoid main() {\n  gl_Position = vec4(aPos, 0.0, 1.0);\n}`;\n\nconst FRAGMENT_SHADER = `#version 300 es\nprecision highp float;\n\nuniform vec2 uRes;\nuniform float uTime;\nuniform vec3 uStopA;\nuniform vec3 uStopB;\nuniform vec3 uStopC;\nuniform float uIntensity;\n\nout vec4 fragColor;\n\nfloat hash(vec2 p) {\n  p = fract(p * vec2(234.34, 435.345));\n  p += dot(p, p + 34.23);\n  return fract(p.x * p.y);\n}\n\nfloat noise(vec2 p) {\n  vec2 i = floor(p);\n  vec2 f = fract(p);\n  vec2 u = f * f * (3.0 - 2.0 * f);\n  float a = hash(i);\n  float b = hash(i + vec2(1.0, 0.0));\n  float c = hash(i + vec2(0.0, 1.0));\n  float d = hash(i + vec2(1.0, 1.0));\n  return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n}\n\nfloat fbm(vec2 p) {\n  float value = 0.0;\n  float amplitude = 0.5;\n  for (int i = 0; i < 4; i++) {\n    value += amplitude * noise(p);\n    p = mat2(0.8, 0.6, -0.6, 0.8) * p * 2.0 + vec2(3.7, 1.3);\n    amplitude *= 0.5;\n  }\n  return value;\n}\n\nvoid main() {\n  vec2 uv = gl_FragCoord.xy / uRes;\n  vec2 p = vec2(uv.x * uRes.x / uRes.y, uv.y);\n\n  float t = uTime * 0.05;\n\n  vec2 q = vec2(fbm(p * 1.4 + t * 0.35), fbm(p * 1.4 - t * 0.28 + 5.2));\n  vec2 r = vec2(\n    fbm(p * 1.4 + 2.6 * q + vec2(1.7, 9.2) + t * 0.18),\n    fbm(p * 1.4 + 2.6 * q + vec2(8.3, 2.8) - t * 0.12)\n  );\n  float field = fbm(p * 1.4 + 2.6 * r);\n\n  vec3 color = mix(uStopA, uStopB, clamp(field * field * 2.4, 0.0, 1.0));\n  color = mix(color, uStopC, clamp(dot(q, vec2(0.7)) - 0.25, 0.0, 1.0));\n\n  float fade = smoothstep(0.02, 0.85, uv.y);\n  float alpha = fade * fade * uIntensity * smoothstep(0.14, 0.66, field);\n\n  fragColor = vec4(color * alpha, alpha);\n}`;\n\nconst hexToRgb = (hex: string): [number, number, number] => {\n  const value = hex.replace('#', '');\n  const full =\n    value.length === 3\n      ? value\n          .split('')\n          .map((char) => char + char)\n          .join('')\n      : value.slice(0, 6);\n  const channel = (offset: number) => Number.parseInt(full.slice(offset, offset + 2), 16) / 255;\n  return [channel(0), channel(2), channel(4)];\n};\n\nconst FluidGradient = memo<FluidGradientProps>(\n  ({ className, colors, intensity = 0.45, speed = 1, style, ...rest }) => {\n    const { isDarkMode } = useThemeMode();\n    const canvasRef = useRef<HTMLCanvasElement>(null);\n    const [ready, setReady] = useState(false);\n    const [canvasEpoch, setCanvasEpoch] = useState(0);\n    const palette = colors ?? (isDarkMode ? LANDING_PALETTE_DARK : LANDING_PALETTE_LIGHT);\n    const paletteRef = useRef({ colors: palette, intensity });\n    const speedRef = useRef(speed);\n    const repaintRef = useRef<(() => void) | undefined>(undefined);\n\n    useEffect(() => {\n      paletteRef.current = { colors: palette, intensity };\n      speedRef.current = speed;\n      repaintRef.current?.();\n    }, [palette[0], palette[1], palette[2], intensity, speed]);\n\n    useEffect(() => {\n      const canvas = canvasRef.current;\n      if (!canvas) return undefined;\n\n      const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');\n\n      let frameId = 0;\n      let inView = true;\n      let readySent = false;\n      let drawFrame: ((seconds: number) => void) | null = null;\n      let refreshPalette: (() => void) | null = null;\n      let sizeAndDraw: (() => boolean) | null = null;\n      let destroyResources: ((lose: boolean) => void) | null = null;\n\n      const buildResources = () => {\n        const gl = canvas.getContext('webgl2', {\n          alpha: true,\n          antialias: false,\n          depth: false,\n          stencil: false,\n          powerPreference: 'low-power',\n        });\n        if (!gl) return false;\n\n        const compileShader = (type: number, source: string) => {\n          const shader = gl.createShader(type);\n          if (!shader) return null;\n          gl.shaderSource(shader, source);\n          gl.compileShader(shader);\n          if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n            gl.deleteShader(shader);\n            return null;\n          }\n          return shader;\n        };\n\n        const vertexShader = compileShader(gl.VERTEX_SHADER, VERTEX_SHADER);\n        const fragmentShader = compileShader(gl.FRAGMENT_SHADER, FRAGMENT_SHADER);\n        if (!vertexShader || !fragmentShader) return false;\n\n        const program = gl.createProgram();\n        if (!program) return false;\n        gl.attachShader(program, vertexShader);\n        gl.attachShader(program, fragmentShader);\n        gl.linkProgram(program);\n        gl.deleteShader(vertexShader);\n        gl.deleteShader(fragmentShader);\n        if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n          gl.deleteProgram(program);\n          return false;\n        }\n        gl.useProgram(program);\n\n        const buffer = gl.createBuffer();\n        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);\n        const position = gl.getAttribLocation(program, 'aPos');\n        gl.enableVertexAttribArray(position);\n        gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);\n\n        const timeLocation = gl.getUniformLocation(program, 'uTime');\n        const stopLocations = ['uStopA', 'uStopB', 'uStopC'].map((name) =>\n          gl.getUniformLocation(program, name),\n        );\n\n        const intensityLocation = gl.getUniformLocation(program, 'uIntensity');\n\n        refreshPalette = () => {\n          const { colors: stops, intensity: peak } = paletteRef.current;\n          stops.map(hexToRgb).forEach((stop, index) => {\n            const location = stopLocations[index];\n            if (location) gl.uniform3f(location, stop[0], stop[1], stop[2]);\n          });\n          gl.uniform1f(intensityLocation, peak);\n        };\n        refreshPalette();\n\n        drawFrame = (seconds: number) => {\n          gl.uniform1f(timeLocation, seconds * speedRef.current);\n          gl.drawArrays(gl.TRIANGLES, 0, 3);\n          if (!readySent) {\n            readySent = true;\n            setReady(true);\n          }\n        };\n\n        sizeAndDraw = () => {\n          const dpr = Math.min(window.devicePixelRatio || 1, 1.5);\n          const width = Math.max(1, Math.round(canvas.clientWidth * dpr));\n          const height = Math.max(1, Math.round(canvas.clientHeight * dpr));\n          if (canvas.width !== width || canvas.height !== height) {\n            canvas.width = width;\n            canvas.height = height;\n            gl.viewport(0, 0, width, height);\n          }\n          return canvas.clientWidth > 0 && drawFrame !== null;\n        };\n\n        destroyResources = (lose: boolean) => {\n          gl.deleteBuffer(buffer);\n          gl.deleteProgram(program);\n          drawFrame = null;\n          refreshPalette = null;\n          sizeAndDraw = null;\n          destroyResources = null;\n          if (lose) gl.getExtension('WEBGL_lose_context')?.loseContext();\n        };\n\n        return true;\n      };\n\n      if (!buildResources()) return undefined;\n\n      const renderOnce = () => {\n        if (!sizeAndDraw?.()) return;\n        drawFrame?.(performance.now() / 1000);\n      };\n\n      const syncLoop = (milliseconds: number) => {\n        frameId = requestAnimationFrame(syncLoop);\n        if (sizeAndDraw?.()) drawFrame?.(milliseconds / 1000);\n      };\n\n      const updateLoop = () => {\n        const shouldAnimate =\n          inView && !document.hidden && !reducedMotion.matches && drawFrame !== null;\n\n        if (shouldAnimate) {\n          if (frameId === 0) frameId = requestAnimationFrame(syncLoop);\n          return;\n        }\n\n        if (frameId !== 0) {\n          cancelAnimationFrame(frameId);\n          frameId = 0;\n        }\n\n        if (!document.hidden) renderOnce();\n      };\n\n      const resizeObserver = new ResizeObserver(() => {\n        if (frameId === 0) renderOnce();\n      });\n      resizeObserver.observe(canvas);\n\n      const intersectionObserver = new IntersectionObserver(([entry]) => {\n        inView = entry.isIntersecting;\n        updateLoop();\n      });\n      intersectionObserver.observe(canvas);\n\n      const handleVisibilityChange = () => updateLoop();\n      document.addEventListener('visibilitychange', handleVisibilityChange);\n\n      const handleMotionPreferenceChange = () => updateLoop();\n      reducedMotion.addEventListener('change', handleMotionPreferenceChange);\n\n      repaintRef.current = () => {\n        refreshPalette?.();\n        if (frameId === 0) renderOnce();\n      };\n\n      const handleContextLost = (event: Event) => {\n        event.preventDefault();\n        if (frameId !== 0) {\n          cancelAnimationFrame(frameId);\n          frameId = 0;\n        }\n        setCanvasEpoch((value) => value + 1);\n      };\n      canvas.addEventListener('webglcontextlost', handleContextLost);\n\n      updateLoop();\n\n      return () => {\n        if (frameId !== 0) cancelAnimationFrame(frameId);\n        frameId = 0;\n        resizeObserver.disconnect();\n        intersectionObserver.disconnect();\n        repaintRef.current = undefined;\n        document.removeEventListener('visibilitychange', handleVisibilityChange);\n        reducedMotion.removeEventListener('change', handleMotionPreferenceChange);\n        canvas.removeEventListener('webglcontextlost', handleContextLost);\n        if (!canvas.isConnected) destroyResources?.(true);\n        else destroyResources?.(false);\n      };\n    }, [canvasEpoch]);\n\n    return (\n      <div\n        aria-hidden\n        className={cx(styles.root, className)}\n        data-ready={ready ? '' : undefined}\n        style={\n          {\n            '--fluid-stop-a': palette[0],\n            '--fluid-stop-b': palette[1],\n            '--fluid-stop-c': palette[2],\n            ...style,\n          } as CSSProperties\n        }\n        {...rest}\n      >\n        <canvas key={canvasEpoch} ref={canvasRef} />\n      </div>\n    );\n  },\n);\n\nFluidGradient.displayName = 'FluidGradient';\n\nexport default FluidGradient;\n"],"mappings":";;;;;;;AAUA,MAAM,gBAAgB;;;;;AAMtB,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8DxB,MAAM,YAAY,QAA0C;CAC1D,MAAM,QAAQ,IAAI,QAAQ,KAAK,EAAE;CACjC,MAAM,OACJ,MAAM,WAAW,IACb,MACG,MAAM,EAAE,CAAC,CACT,KAAK,SAAS,OAAO,IAAI,CAAC,CAC1B,KAAK,EAAE,IACV,MAAM,MAAM,GAAG,CAAC;CACtB,MAAM,WAAW,WAAmB,OAAO,SAAS,KAAK,MAAM,QAAQ,SAAS,CAAC,GAAG,EAAE,IAAI;CAC1F,OAAO;EAAC,QAAQ,CAAC;EAAG,QAAQ,CAAC;EAAG,QAAQ,CAAC;CAAC;AAC5C;AAEA,MAAM,gBAAgB,MACnB,EAAE,WAAW,QAAQ,YAAY,KAAM,QAAQ,GAAG,OAAO,GAAG,WAAW;CACtE,MAAM,EAAE,eAAe,aAAa;CACpC,MAAM,YAAY,OAA0B,IAAI;CAChD,MAAM,CAAC,OAAO,YAAY,SAAS,KAAK;CACxC,MAAM,CAAC,aAAa,kBAAkB,SAAS,CAAC;CAChD,MAAM,UAAU,WAAW,aAAa,uBAAuB;CAC/D,MAAM,aAAa,OAAO;EAAE,QAAQ;EAAS;CAAU,CAAC;CACxD,MAAM,WAAW,OAAO,KAAK;CAC7B,MAAM,aAAa,OAAiC,KAAA,CAAS;CAE7D,gBAAgB;EACd,WAAW,UAAU;GAAE,QAAQ;GAAS;EAAU;EAClD,SAAS,UAAU;EACnB,WAAW,UAAU;CACvB,GAAG;EAAC,QAAQ;EAAI,QAAQ;EAAI,QAAQ;EAAI;EAAW;CAAK,CAAC;CAEzD,gBAAgB;EACd,MAAM,SAAS,UAAU;EACzB,IAAI,CAAC,QAAQ,OAAO,KAAA;EAEpB,MAAM,gBAAgB,OAAO,WAAW,kCAAkC;EAE1E,IAAI,UAAU;EACd,IAAI,SAAS;EACb,IAAI,YAAY;EAChB,IAAI,YAAgD;EACpD,IAAI,iBAAsC;EAC1C,IAAI,cAAsC;EAC1C,IAAI,mBAAqD;EAEzD,MAAM,uBAAuB;GAC3B,MAAM,KAAK,OAAO,WAAW,UAAU;IACrC,OAAO;IACP,WAAW;IACX,OAAO;IACP,SAAS;IACT,iBAAiB;GACnB,CAAC;GACD,IAAI,CAAC,IAAI,OAAO;GAEhB,MAAM,iBAAiB,MAAc,WAAmB;IACtD,MAAM,SAAS,GAAG,aAAa,IAAI;IACnC,IAAI,CAAC,QAAQ,OAAO;IACpB,GAAG,aAAa,QAAQ,MAAM;IAC9B,GAAG,cAAc,MAAM;IACvB,IAAI,CAAC,GAAG,mBAAmB,QAAQ,GAAG,cAAc,GAAG;KACrD,GAAG,aAAa,MAAM;KACtB,OAAO;IACT;IACA,OAAO;GACT;GAEA,MAAM,eAAe,cAAc,GAAG,eAAe,aAAa;GAClE,MAAM,iBAAiB,cAAc,GAAG,iBAAiB,eAAe;GACxE,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,OAAO;GAE7C,MAAM,UAAU,GAAG,cAAc;GACjC,IAAI,CAAC,SAAS,OAAO;GACrB,GAAG,aAAa,SAAS,YAAY;GACrC,GAAG,aAAa,SAAS,cAAc;GACvC,GAAG,YAAY,OAAO;GACtB,GAAG,aAAa,YAAY;GAC5B,GAAG,aAAa,cAAc;GAC9B,IAAI,CAAC,GAAG,oBAAoB,SAAS,GAAG,WAAW,GAAG;IACpD,GAAG,cAAc,OAAO;IACxB,OAAO;GACT;GACA,GAAG,WAAW,OAAO;GAErB,MAAM,SAAS,GAAG,aAAa;GAC/B,GAAG,WAAW,GAAG,cAAc,MAAM;GACrC,GAAG,WAAW,GAAG,cAAc,IAAI,aAAa;IAAC;IAAI;IAAI;IAAG;IAAI;IAAI;GAAC,CAAC,GAAG,GAAG,WAAW;GACvF,MAAM,WAAW,GAAG,kBAAkB,SAAS,MAAM;GACrD,GAAG,wBAAwB,QAAQ;GACnC,GAAG,oBAAoB,UAAU,GAAG,GAAG,OAAO,OAAO,GAAG,CAAC;GAEzD,MAAM,eAAe,GAAG,mBAAmB,SAAS,OAAO;GAC3D,MAAM,gBAAgB;IAAC;IAAU;IAAU;GAAQ,CAAC,CAAC,KAAK,SACxD,GAAG,mBAAmB,SAAS,IAAI,CACrC;GAEA,MAAM,oBAAoB,GAAG,mBAAmB,SAAS,YAAY;GAErE,uBAAuB;IACrB,MAAM,EAAE,QAAQ,OAAO,WAAW,SAAS,WAAW;IACtD,MAAM,IAAI,QAAQ,CAAC,CAAC,SAAS,MAAM,UAAU;KAC3C,MAAM,WAAW,cAAc;KAC/B,IAAI,UAAU,GAAG,UAAU,UAAU,KAAK,IAAI,KAAK,IAAI,KAAK,EAAE;IAChE,CAAC;IACD,GAAG,UAAU,mBAAmB,IAAI;GACtC;GACA,eAAe;GAEf,aAAa,YAAoB;IAC/B,GAAG,UAAU,cAAc,UAAU,SAAS,OAAO;IACrD,GAAG,WAAW,GAAG,WAAW,GAAG,CAAC;IAChC,IAAI,CAAC,WAAW;KACd,YAAY;KACZ,SAAS,IAAI;IACf;GACF;GAEA,oBAAoB;IAClB,MAAM,MAAM,KAAK,IAAI,OAAO,oBAAoB,GAAG,GAAG;IACtD,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,cAAc,GAAG,CAAC;IAC9D,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,eAAe,GAAG,CAAC;IAChE,IAAI,OAAO,UAAU,SAAS,OAAO,WAAW,QAAQ;KACtD,OAAO,QAAQ;KACf,OAAO,SAAS;KAChB,GAAG,SAAS,GAAG,GAAG,OAAO,MAAM;IACjC;IACA,OAAO,OAAO,cAAc,KAAK,cAAc;GACjD;GAEA,oBAAoB,SAAkB;IACpC,GAAG,aAAa,MAAM;IACtB,GAAG,cAAc,OAAO;IACxB,YAAY;IACZ,iBAAiB;IACjB,cAAc;IACd,mBAAmB;IACnB,IAAI,MAAM,GAAG,aAAa,oBAAoB,CAAC,EAAE,YAAY;GAC/D;GAEA,OAAO;EACT;EAEA,IAAI,CAAC,eAAe,GAAG,OAAO,KAAA;EAE9B,MAAM,mBAAmB;GACvB,IAAI,CAAC,cAAc,GAAG;GACtB,YAAY,YAAY,IAAI,IAAI,GAAI;EACtC;EAEA,MAAM,YAAY,iBAAyB;GACzC,UAAU,sBAAsB,QAAQ;GACxC,IAAI,cAAc,GAAG,YAAY,eAAe,GAAI;EACtD;EAEA,MAAM,mBAAmB;GAIvB,IAFE,UAAU,CAAC,SAAS,UAAU,CAAC,cAAc,WAAW,cAAc,MAErD;IACjB,IAAI,YAAY,GAAG,UAAU,sBAAsB,QAAQ;IAC3D;GACF;GAEA,IAAI,YAAY,GAAG;IACjB,qBAAqB,OAAO;IAC5B,UAAU;GACZ;GAEA,IAAI,CAAC,SAAS,QAAQ,WAAW;EACnC;EAEA,MAAM,iBAAiB,IAAI,qBAAqB;GAC9C,IAAI,YAAY,GAAG,WAAW;EAChC,CAAC;EACD,eAAe,QAAQ,MAAM;EAE7B,MAAM,uBAAuB,IAAI,sBAAsB,CAAC,WAAW;GACjE,SAAS,MAAM;GACf,WAAW;EACb,CAAC;EACD,qBAAqB,QAAQ,MAAM;EAEnC,MAAM,+BAA+B,WAAW;EAChD,SAAS,iBAAiB,oBAAoB,sBAAsB;EAEpE,MAAM,qCAAqC,WAAW;EACtD,cAAc,iBAAiB,UAAU,4BAA4B;EAErE,WAAW,gBAAgB;GACzB,iBAAiB;GACjB,IAAI,YAAY,GAAG,WAAW;EAChC;EAEA,MAAM,qBAAqB,UAAiB;GAC1C,MAAM,eAAe;GACrB,IAAI,YAAY,GAAG;IACjB,qBAAqB,OAAO;IAC5B,UAAU;GACZ;GACA,gBAAgB,UAAU,QAAQ,CAAC;EACrC;EACA,OAAO,iBAAiB,oBAAoB,iBAAiB;EAE7D,WAAW;EAEX,aAAa;GACX,IAAI,YAAY,GAAG,qBAAqB,OAAO;GAC/C,UAAU;GACV,eAAe,WAAW;GAC1B,qBAAqB,WAAW;GAChC,WAAW,UAAU,KAAA;GACrB,SAAS,oBAAoB,oBAAoB,sBAAsB;GACvE,cAAc,oBAAoB,UAAU,4BAA4B;GACxE,OAAO,oBAAoB,oBAAoB,iBAAiB;GAChE,IAAI,CAAC,OAAO,aAAa,mBAAmB,IAAI;QAC3C,mBAAmB,KAAK;EAC/B;CACF,GAAG,CAAC,WAAW,CAAC;CAEhB,OACE,oBAAC,OAAD;EACE,eAAA;EACA,WAAW,GAAG,OAAO,MAAM,SAAS;EACpC,cAAY,QAAQ,KAAK,KAAA;EACzB,OACE;GACE,kBAAkB,QAAQ;GAC1B,kBAAkB,QAAQ;GAC1B,kBAAkB,QAAQ;GAC1B,GAAG;EACL;EAEF,GAAI;EAEJ,UAAA,oBAAC,UAAD,EAA0B,KAAK,UAAY,GAA9B,WAA8B;CACxC,CAAA;AAET,CACF;AAEA,cAAc,cAAc"}