{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"fluid-distortion","type":"registry:component","title":"Fluid Distortion","description":"A fluid distortion effect that follows the cursor.","meta":{"pro":false},"docs":"Usage: https://atelier-ui.com/r/fluid-distortion.md\nDocs: https://atelier-ui.com/docs/components/cursor/fluid-distortion","dependencies":["three","@types/three","@react-three/fiber","@react-three/drei","postprocessing"],"registryDependencies":["https://atelier-ui.com/r/webgl-portal.json","https://atelier-ui.com/r/agent-rules.json"],"files":[{"path":"registry/fluid-distortion/fluid-distortion.tsx","type":"registry:component","target":"components/fluid-distortion/fluid-distortion.tsx","content":"\"use client\"\n\nimport type { FboProps } from \"@react-three/drei\"\nimport { useFBO } from \"@react-three/drei\"\nimport { createPortal, extend, type ThreeElement, useFrame, useThree } from \"@react-three/fiber\"\nimport { BlendFunction, Effect } from \"postprocessing\"\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\"\nimport * as THREE from \"three\"\nimport { effectTeleport, webglTeleport } from \"../webgl-portal/webgl-portal\"\n\nconst baseVertex = /* glsl */ `\n#ifdef USE_V_UV\n  varying vec2 vUv;\n#endif\n\n#ifdef USE_OFFSETS\n  varying vec2 vL;\n  varying vec2 vR;\n  varying vec2 vT;\n  varying vec2 vB;\n  uniform vec2 texelSize;\n#endif\n\nvoid main() {\n  #ifdef USE_V_UV\n    vUv = uv;\n  #endif\n\n  #ifdef USE_OFFSETS\n    vL = uv - vec2(texelSize.x, 0.0);\n    vR = uv + vec2(texelSize.x, 0.0);\n    vT = uv + vec2(0.0, texelSize.y);\n    vB = uv - vec2(0.0, texelSize.y);\n  #endif\n\n  gl_Position = vec4(position, 1.0);\n}\n`\n\nconst advectionFrag = /* glsl */ `\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uVelocity;\nuniform sampler2D uSource;\nuniform vec2 texelSize;\nuniform float dt;\nuniform float uDissipation;\n\nvoid main() {\n    vec2 coord = vUv - dt * texture2D(uVelocity, vUv).xy * texelSize;\n    gl_FragColor = uDissipation * texture2D(uSource, coord);\n    gl_FragColor.a = 1.0;\n}\n`\n\nconst clearFrag = /* glsl */ `\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uClearValue;\n\nvoid main() { gl_FragColor = uClearValue * texture2D(uTexture, vUv); }\n`\n\nconst curlFrag = /* glsl */ `\nprecision highp float;\nvarying vec2 vL;\nvarying vec2 vR;\nvarying vec2 vT;\nvarying vec2 vB;\nuniform sampler2D uVelocity;\n\nvoid main() {\n    float L = texture2D(uVelocity, vL).y;\n    float R = texture2D(uVelocity, vR).y;\n    float T = texture2D(uVelocity, vT).x;\n    float B = texture2D(uVelocity, vB).x;\n    float vorticity = R - L - T + B;\n    gl_FragColor = vec4(vorticity, 0.0, 0.0, 1.0);\n}\n`\n\nconst divergenceFrag = /* glsl */ `\nprecision highp float;\n\nvarying highp vec2 vUv;\nvarying highp vec2 vL;\nvarying highp vec2 vR;\nvarying highp vec2 vT;\nvarying highp vec2 vB;\n\nuniform sampler2D uVelocity;\n\nvoid main() {\n    float L = texture2D(uVelocity, vL).x;\n    float R = texture2D(uVelocity, vR).x;\n    float T = texture2D(uVelocity, vT).y;\n    float B = texture2D(uVelocity, vB).y;\n    vec2 C = texture2D(uVelocity, vUv).xy;\n    if(vL.x < 0.0) { L = -C.x; }\n    if(vR.x > 1.0) { R = -C.x; }\n    if(vT.y > 1.0) { T = -C.y; }\n    if(vB.y < 0.0) { B = -C.y; }\n    float div = 0.5 * (R - L + T - B);\n    gl_FragColor = vec4(div, 0.0, 0.0, 1.0);\n}\n`\n\nconst gradientSubstractFrag = /* glsl */ `\nprecision highp float;\n\nvarying highp vec2 vUv;\nvarying highp vec2 vL;\nvarying highp vec2 vR;\nvarying highp vec2 vT;\nvarying highp vec2 vB;\nuniform sampler2D uPressure;\nuniform sampler2D uVelocity;\n\nvoid main() {\n    float L = texture2D(uPressure, vL).x;\n    float R = texture2D(uPressure, vR).x;\n    float T = texture2D(uPressure, vT).x;\n    float B = texture2D(uPressure, vB).x;\n    vec2 velocity = texture2D(uVelocity, vUv).xy;\n    velocity.xy -= vec2(R - L, T - B);\n    gl_FragColor = vec4(velocity, 0.0, 1.0);\n}\n`\n\nconst pressureFrag = /* glsl */ `\nprecision highp float;\n\nvarying highp vec2 vUv;\nvarying highp vec2 vL;\nvarying highp vec2 vR;\nvarying highp vec2 vT;\nvarying highp vec2 vB;\n\nuniform sampler2D uPressure;\nuniform sampler2D uDivergence;\n\nvoid main() {\n    float L = texture2D(uPressure, vL).x;\n    float R = texture2D(uPressure, vR).x;\n    float T = texture2D(uPressure, vT).x;\n    float B = texture2D(uPressure, vB).x;\n    float C = texture2D(uPressure, vUv).x;\n    float divergence = texture2D(uDivergence, vUv).x;\n    float pressure = (L + R + B + T - divergence) * 0.25;\n    gl_FragColor = vec4(pressure, 0.0, 0.0, 1.0);\n}\n`\n\nconst splatFrag = /* glsl */ `\nvarying vec2 vUv;\n\nuniform sampler2D uTarget;\nuniform float aspectRatio;\nuniform vec3 uColor;\nuniform vec2 uPointer;\nuniform float uRadius;\n\nvoid main() {\n    vec2 p = vUv - uPointer.xy;\n    p.x *= aspectRatio;\n    vec3 splat = exp(-dot(p, p) / uRadius) * uColor;\n    vec3 base = texture2D(uTarget, vUv).xyz;\n    gl_FragColor = vec4(base + splat, 1.0);\n}\n`\n\nconst vorticityFrag = /* glsl */ `\nprecision highp float;\n\nvarying vec2 vUv;\nvarying vec2 vL;\nvarying vec2 vR;\nvarying vec2 vT;\nvarying vec2 vB;\n\nuniform sampler2D uVelocity;\nuniform sampler2D uCurl;\nuniform float uCurlValue;\nuniform float dt;\n\nvoid main() {\n    float L = texture2D(uCurl, vL).x;\n    float R = texture2D(uCurl, vR).x;\n    float T = texture2D(uCurl, vT).x;\n    float B = texture2D(uCurl, vB).x;\n    float C = texture2D(uCurl, vUv).x;\n    vec2 force = vec2(abs(T) - abs(B), abs(R) - abs(L)) * 0.5;\n    force /= length(force) + 1.;\n    force *= uCurlValue * C;\n    force.y *= -1.;\n    vec2 vel = texture2D(uVelocity, vUv).xy;\n    gl_FragColor = vec4(vel + force * dt, 0.0, 1.0);\n}\n`\n\nconst compositeFrag = /* glsl */ `\nuniform sampler2D tFluid;\n\nuniform vec3 uColor;\nuniform vec3 uBackgroundColor;\n\nuniform float uDistort;\nuniform float uIntensity;\nuniform float uRainbow;\nuniform float uBlend;\nuniform float uShowBackground;\n\nvoid mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {\n    vec3 fluidColor = texture2D(tFluid, uv).rgb;\n    vec2 distortedUv = uv - fluidColor.rg * uDistort * 0.001;\n    vec4 texture = texture2D(inputBuffer, distortedUv);\n    float intensity = length(fluidColor) * uIntensity * 0.001;\n    vec3 selectedColor = uColor * length(fluidColor) * 0.01;\n    vec4 colorForFluidEffect = vec4(uRainbow == 1.0 ? fluidColor : selectedColor, 1.0);\n    vec4 computedBgColor = uShowBackground != 0.0 ? vec4(uBackgroundColor, 1.0) : vec4(0.0, 0.0, 0.0, 0.0);\n    outputColor = mix(texture, colorForFluidEffect, intensity);\n    vec4 computedFluidColor = mix(texture, colorForFluidEffect, uBlend * 0.01);\n    vec4 finalColor;\n\n    if(texture.a < 0.1) {\n        finalColor = mix(computedBgColor, colorForFluidEffect, intensity);\n    } else {\n        finalColor = mix(computedFluidColor, computedBgColor, 1.0 - texture.a);\n    }\n\n    outputColor = finalColor;\n}\n`\n\ndeclare module \"@react-three/fiber\" {\n    interface ThreeElements {\n        fluidEffect: ThreeElement<typeof FluidEffect>\n    }\n}\n\nexport type FluidDistortionProps = {\n    blend?: number\n    intensity?: number\n    distortion?: number\n    rainbow?: boolean\n    fluidColor?: string\n    backgroundColor?: string\n    showBackground?: boolean\n    blendFunction?: BlendFunction\n    densityDissipation?: number\n    pressure?: number\n    velocityDissipation?: number\n    force?: number\n    radius?: number\n    curl?: number\n    swirl?: number\n}\n\ntype Materials = {\n    splat: THREE.ShaderMaterial\n    curl: THREE.ShaderMaterial\n    clear: THREE.ShaderMaterial\n    divergence: THREE.ShaderMaterial\n    pressure: THREE.ShaderMaterial\n    gradientSubstract: THREE.ShaderMaterial\n    advection: THREE.ShaderMaterial\n    vorticity: THREE.ShaderMaterial\n}\n\ntype SplatStack = {\n    mouseX: number\n    mouseY: number\n    velocityX: number\n    velocityY: number\n}\n\ntype DoubleFBO = {\n    read: THREE.WebGLRenderTarget\n    write: THREE.WebGLRenderTarget\n    swap: () => void\n    dispose: () => void\n}\n\nconst DYE_RES = 512\nconst SIM_RES = 128\nconst REFRESH_RATE = 60\nconst EMPTY_TEXTURE = new THREE.Texture()\n\nfunction normalizeScreenHz(value: number, dt: number) {\n    return value ** (dt * REFRESH_RATE)\n}\n\nclass FluidEffect extends Effect {\n    private uTFluid: THREE.Uniform<THREE.Texture | null>\n    private uDistort: THREE.Uniform<number>\n    private uRainbow: THREE.Uniform<boolean>\n    private uIntensity: THREE.Uniform<number>\n    private uBlend: THREE.Uniform<number>\n    private uShowBackground: THREE.Uniform<boolean>\n    private uColor: THREE.Uniform<THREE.Color>\n    private uBackgroundColor: THREE.Uniform<THREE.Color>\n\n    constructor() {\n        const uTFluid = new THREE.Uniform<THREE.Texture | null>(null)\n        const uDistort = new THREE.Uniform(0)\n        const uRainbow = new THREE.Uniform(false)\n        const uIntensity = new THREE.Uniform(0)\n        const uBlend = new THREE.Uniform(0)\n        const uShowBackground = new THREE.Uniform(false)\n        const uColor = new THREE.Uniform(new THREE.Color())\n        const uBackgroundColor = new THREE.Uniform(new THREE.Color())\n\n        super(\"FluidEffect\", compositeFrag, {\n            uniforms: new Map<string, THREE.Uniform>([\n                [\"tFluid\", uTFluid],\n                [\"uDistort\", uDistort],\n                [\"uRainbow\", uRainbow],\n                [\"uIntensity\", uIntensity],\n                [\"uBlend\", uBlend],\n                [\"uShowBackground\", uShowBackground],\n                [\"uColor\", uColor],\n                [\"uBackgroundColor\", uBackgroundColor],\n            ]),\n        })\n\n        this.uTFluid = uTFluid\n        this.uDistort = uDistort\n        this.uRainbow = uRainbow\n        this.uIntensity = uIntensity\n        this.uBlend = uBlend\n        this.uShowBackground = uShowBackground\n        this.uColor = uColor\n        this.uBackgroundColor = uBackgroundColor\n    }\n\n    set tFluid(v: THREE.Texture) {\n        this.uTFluid.value = v\n    }\n    set distortion(v: number) {\n        this.uDistort.value = v\n    }\n    set rainbow(v: boolean) {\n        this.uRainbow.value = v\n    }\n    set intensity(v: number) {\n        this.uIntensity.value = v\n    }\n    set blend(v: number) {\n        this.uBlend.value = v\n    }\n    set showBackground(v: boolean) {\n        this.uShowBackground.value = v\n    }\n    set fluidColor(v: string) {\n        this.uColor.value.set(v)\n    }\n    set backgroundColor(v: string) {\n        this.uBackgroundColor.value.set(v)\n    }\n    set blendFunction(v: BlendFunction) {\n        this.blendMode.blendFunction = v\n    }\n}\n\nextend({ FluidEffect })\n\n// derived from useFBO: 2 render targets we swap between, so a shader can read from one and write to the other\nfunction useDoubleFBO(width: number, height: number, options: FboProps) {\n    const read = useFBO(width, height, options)\n    const write = useFBO(width, height, options)\n\n    const fbo = useMemo(\n        () => ({\n            read,\n            write,\n            swap() {\n                const temp = this.read\n                this.read = this.write\n                this.write = temp\n            },\n            dispose() {\n                read.dispose()\n                write.dispose()\n            },\n        }),\n        [read, write],\n    )\n\n    return fbo\n}\n\nconst FluidSimulation = ({\n    blend = 5,\n    force = 1.1,\n    radius = 0.65,\n    curl = 0.8,\n    swirl = 2,\n    intensity = 7,\n    distortion = 0.8,\n    fluidColor = \"#b4a6ff\",\n    backgroundColor = \"#070410\",\n    showBackground = false,\n    rainbow = false,\n    pressure = 0.7,\n    densityDissipation = 0.98,\n    velocityDissipation = 0.98,\n    blendFunction = BlendFunction.SET,\n}: FluidDistortionProps) => {\n    const size = useThree((three) => three.size)\n    const gl = useThree((three) => three.gl)\n    const [bufferScene] = useState(() => new THREE.Scene())\n    const bufferCamera = useMemo(() => new THREE.Camera(), [])\n    const meshRef = useRef<THREE.Mesh>(null)\n    const pointerRef = useRef(new THREE.Vector2())\n    const colorRef = useRef(new THREE.Vector3())\n    const splatStack = useRef<SplatStack[]>([])\n    const lastMouse = useRef<THREE.Vector2>(new THREE.Vector2())\n    const hasMoved = useRef<boolean>(false)\n    const rectRef = useRef<DOMRect | null>(null)\n\n    // cache rect so onPointerMove doesn't trigger layout on each event\n    useEffect(() => {\n        rectRef.current = gl.domElement.getBoundingClientRect()\n    }, [gl.domElement, size])\n\n    const densityFBO = useDoubleFBO(DYE_RES, DYE_RES, {\n        type: THREE.HalfFloatType,\n        format: THREE.RGBAFormat,\n        minFilter: THREE.LinearFilter,\n        depthBuffer: false,\n        generateMipmaps: false,\n    })\n\n    const velocityFBO = useDoubleFBO(SIM_RES, SIM_RES, {\n        type: THREE.HalfFloatType,\n        format: THREE.RGFormat,\n        minFilter: THREE.LinearFilter,\n        depthBuffer: false,\n        generateMipmaps: false,\n    })\n\n    const pressureFBO = useDoubleFBO(SIM_RES, SIM_RES, {\n        type: THREE.HalfFloatType,\n        format: THREE.RedFormat,\n        minFilter: THREE.NearestFilter,\n        depthBuffer: false,\n        generateMipmaps: false,\n    })\n\n    const divergenceFBO = useFBO(SIM_RES, SIM_RES, {\n        type: THREE.HalfFloatType,\n        format: THREE.RedFormat,\n        minFilter: THREE.NearestFilter,\n        depthBuffer: false,\n        generateMipmaps: false,\n    })\n\n    const curlFBO = useFBO(SIM_RES, SIM_RES, {\n        type: THREE.HalfFloatType,\n        format: THREE.RedFormat,\n        minFilter: THREE.NearestFilter,\n        depthBuffer: false,\n        generateMipmaps: false,\n    })\n\n    const materials = useMemo<Materials>(() => {\n        const advection = new THREE.ShaderMaterial({\n            name: \"Fluid/Advection\",\n            uniforms: {\n                uVelocity: { value: EMPTY_TEXTURE },\n                uSource: { value: EMPTY_TEXTURE },\n                dt: { value: 1 / REFRESH_RATE },\n                uDissipation: { value: 1.0 },\n                texelSize: { value: new THREE.Vector2() },\n            },\n            fragmentShader: advectionFrag,\n            vertexShader: baseVertex,\n            defines: { USE_V_UV: \"\" },\n            depthTest: false,\n            depthWrite: false,\n        })\n\n        const clear = new THREE.ShaderMaterial({\n            name: \"Fluid/Clear\",\n            uniforms: {\n                uTexture: { value: EMPTY_TEXTURE },\n                uClearValue: { value: 0 },\n                texelSize: { value: new THREE.Vector2() },\n            },\n            fragmentShader: clearFrag,\n            vertexShader: baseVertex,\n            defines: { USE_V_UV: \"\" },\n            depthTest: false,\n            depthWrite: false,\n        })\n\n        const curl = new THREE.ShaderMaterial({\n            name: \"Fluid/Curl\",\n            uniforms: {\n                uVelocity: { value: EMPTY_TEXTURE },\n                texelSize: { value: new THREE.Vector2() },\n            },\n            fragmentShader: curlFrag,\n            vertexShader: baseVertex,\n            defines: { USE_OFFSETS: \"\" },\n            depthTest: false,\n            depthWrite: false,\n        })\n\n        const divergence = new THREE.ShaderMaterial({\n            name: \"Fluid/Divergence\",\n            uniforms: {\n                uVelocity: { value: EMPTY_TEXTURE },\n                texelSize: { value: new THREE.Vector2() },\n            },\n            fragmentShader: divergenceFrag,\n            vertexShader: baseVertex,\n            defines: { USE_V_UV: \"\", USE_OFFSETS: \"\" },\n            depthTest: false,\n            depthWrite: false,\n        })\n\n        const gradientSubstract = new THREE.ShaderMaterial({\n            name: \"Fluid/GradientSubtract\",\n            uniforms: {\n                uPressure: { value: EMPTY_TEXTURE },\n                uVelocity: { value: EMPTY_TEXTURE },\n                texelSize: { value: new THREE.Vector2() },\n            },\n            fragmentShader: gradientSubstractFrag,\n            vertexShader: baseVertex,\n            defines: { USE_V_UV: \"\", USE_OFFSETS: \"\" },\n            depthTest: false,\n            depthWrite: false,\n        })\n\n        const pressure = new THREE.ShaderMaterial({\n            name: \"Fluid/Pressure\",\n            uniforms: {\n                uPressure: { value: EMPTY_TEXTURE },\n                uDivergence: { value: EMPTY_TEXTURE },\n                texelSize: { value: new THREE.Vector2() },\n            },\n            fragmentShader: pressureFrag,\n            vertexShader: baseVertex,\n            defines: { USE_V_UV: \"\", USE_OFFSETS: \"\" },\n            depthTest: false,\n            depthWrite: false,\n        })\n\n        const splat = new THREE.ShaderMaterial({\n            name: \"Fluid/Splat\",\n            uniforms: {\n                uTarget: { value: EMPTY_TEXTURE },\n                aspectRatio: { value: 1 },\n                uColor: { value: new THREE.Vector3() },\n                uPointer: { value: new THREE.Vector2() },\n                uRadius: { value: 0 },\n                texelSize: { value: new THREE.Vector2() },\n            },\n            fragmentShader: splatFrag,\n            vertexShader: baseVertex,\n            defines: { USE_V_UV: \"\" },\n            depthTest: false,\n            depthWrite: false,\n        })\n\n        const vorticity = new THREE.ShaderMaterial({\n            name: \"Fluid/Vorticity\",\n            uniforms: {\n                uVelocity: { value: EMPTY_TEXTURE },\n                uCurl: { value: EMPTY_TEXTURE },\n                uCurlValue: { value: 0 },\n                dt: { value: 1 / REFRESH_RATE },\n                texelSize: { value: new THREE.Vector2() },\n            },\n            fragmentShader: vorticityFrag,\n            vertexShader: baseVertex,\n            defines: { USE_V_UV: \"\", USE_OFFSETS: \"\" },\n            depthTest: false,\n            depthWrite: false,\n        })\n\n        return {\n            splat,\n            curl,\n            clear,\n            divergence,\n            pressure,\n            gradientSubstract,\n            advection,\n            vorticity,\n        }\n    }, [])\n\n    useEffect(() => {\n        const texelAspect = size.width / size.height\n        for (const material of Object.values(materials)) {\n            material.uniforms.texelSize.value.set(1 / (SIM_RES * texelAspect), 1 / SIM_RES)\n        }\n        materials.splat.uniforms.aspectRatio.value = size.width / size.height\n    }, [materials, size])\n\n    useEffect(() => {\n        return () => {\n            for (const material of Object.values(materials)) {\n                material.dispose()\n            }\n        }\n    }, [materials])\n\n    const onPointerMove = useCallback(\n        (event: PointerEvent) => {\n            const rect = rectRef.current\n            if (!rect) return\n\n            const x = event.clientX - rect.left\n            const y = event.clientY - rect.top\n\n            const deltaX = x - lastMouse.current.x\n            const deltaY = y - lastMouse.current.y\n\n            if (!hasMoved.current) {\n                hasMoved.current = true\n                lastMouse.current.set(x, y)\n                return\n            }\n\n            lastMouse.current.set(x, y)\n\n            splatStack.current.push({\n                mouseX: x / rect.width,\n                mouseY: 1.0 - y / rect.height,\n                velocityX: deltaX * force,\n                velocityY: -deltaY * force,\n            })\n        },\n        [force],\n    )\n\n    useEffect(() => {\n        function onPointerDown() {\n            hasMoved.current = false\n        }\n        addEventListener(\"pointermove\", onPointerMove, { passive: true })\n        addEventListener(\"pointerdown\", onPointerDown, { passive: true })\n        return () => {\n            removeEventListener(\"pointermove\", onPointerMove)\n            removeEventListener(\"pointerdown\", onPointerDown)\n        }\n    }, [onPointerMove])\n\n    const setRenderTarget = (fbo: THREE.WebGLRenderTarget | DoubleFBO) => {\n        // checking if it's a DoubleFBO\n        if (\"write\" in fbo) {\n            gl.setRenderTarget(fbo.write)\n            gl.clear()\n            gl.render(bufferScene, bufferCamera)\n            fbo.swap()\n        } else {\n            gl.setRenderTarget(fbo)\n            gl.clear()\n            gl.render(bufferScene, bufferCamera)\n        }\n    }\n\n    useFrame((_, delta) => {\n        const mesh = meshRef.current\n        if (!mesh) return\n\n        for (let i = splatStack.current.length - 1; i >= 0; i--) {\n            const { mouseX, mouseY, velocityX, velocityY } = splatStack.current[i]\n\n            pointerRef.current.set(mouseX, mouseY)\n            colorRef.current.set(velocityX, velocityY, 2.0)\n\n            mesh.material = materials.splat\n            materials.splat.uniforms.uTarget.value = velocityFBO.read.texture\n            materials.splat.uniforms.uPointer.value = pointerRef.current\n            materials.splat.uniforms.uColor.value = colorRef.current\n            materials.splat.uniforms.uRadius.value = radius / 100.0\n            setRenderTarget(velocityFBO)\n\n            materials.splat.uniforms.uTarget.value = densityFBO.read.texture\n            setRenderTarget(densityFBO)\n\n            splatStack.current.pop()\n        }\n\n        mesh.material = materials.curl\n        materials.curl.uniforms.uVelocity.value = velocityFBO.read.texture\n        setRenderTarget(curlFBO)\n\n        mesh.material = materials.vorticity\n        materials.vorticity.uniforms.uVelocity.value = velocityFBO.read.texture\n        materials.vorticity.uniforms.uCurl.value = curlFBO.texture\n        materials.vorticity.uniforms.uCurlValue.value = curl\n        setRenderTarget(velocityFBO)\n\n        mesh.material = materials.divergence\n        materials.divergence.uniforms.uVelocity.value = velocityFBO.read.texture\n        setRenderTarget(divergenceFBO)\n\n        mesh.material = materials.clear\n        materials.clear.uniforms.uTexture.value = pressureFBO.read.texture\n        materials.clear.uniforms.uClearValue.value = normalizeScreenHz(pressure, delta)\n        setRenderTarget(pressureFBO)\n\n        mesh.material = materials.pressure\n        materials.pressure.uniforms.uDivergence.value = divergenceFBO.texture\n\n        for (let i = 0; i < swirl; i++) {\n            materials.pressure.uniforms.uPressure.value = pressureFBO.read.texture\n            setRenderTarget(pressureFBO)\n        }\n\n        mesh.material = materials.gradientSubstract\n        materials.gradientSubstract.uniforms.uPressure.value = pressureFBO.read.texture\n        materials.gradientSubstract.uniforms.uVelocity.value = velocityFBO.read.texture\n        setRenderTarget(velocityFBO)\n\n        mesh.material = materials.advection\n        materials.advection.uniforms.uVelocity.value = velocityFBO.read.texture\n        materials.advection.uniforms.uSource.value = velocityFBO.read.texture\n        materials.advection.uniforms.uDissipation.value = normalizeScreenHz(\n            velocityDissipation,\n            delta,\n        )\n\n        setRenderTarget(velocityFBO)\n        materials.advection.uniforms.uVelocity.value = velocityFBO.read.texture\n        materials.advection.uniforms.uSource.value = densityFBO.read.texture\n        materials.advection.uniforms.uDissipation.value = normalizeScreenHz(\n            densityDissipation,\n            delta,\n        )\n\n        setRenderTarget(densityFBO)\n    })\n\n    return (\n        <>\n            {createPortal(\n                <mesh ref={meshRef} scale={[size.width, size.height, 1]}>\n                    <planeGeometry args={[2, 2]} />\n                </mesh>,\n                bufferScene,\n            )}\n            <effectTeleport.In>\n                <fluidEffect\n                    blend={blend}\n                    intensity={intensity}\n                    distortion={distortion}\n                    rainbow={rainbow}\n                    fluidColor={fluidColor}\n                    backgroundColor={backgroundColor}\n                    showBackground={showBackground}\n                    blendFunction={blendFunction}\n                    tFluid={densityFBO.read.texture}\n                />\n            </effectTeleport.In>\n        </>\n    )\n}\n\nexport const FluidDistortion = (props: FluidDistortionProps) => {\n    return (\n        <webglTeleport.In>\n            <FluidSimulation {...props} />\n        </webglTeleport.In>\n    )\n}\n"}]}