UNPKG

lightswind

Version:

A collection of beautifully crafted React Components, Blocks & Templates for Modern Developers. Create stunning web applications effortlessly by using our 160+ professional and animated react components.

301 lines 13.6 kB
"use strict"; 'use client'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = LiquidFluid; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const ogl_1 = require("ogl"); const framer_motion_1 = require("framer-motion"); const gsap_1 = require("gsap"); const defaultColors = ['#00fffc', '#fff', '#00fffc']; const baseVertex = /* glsl */ ` precision highp float; attribute vec2 position; attribute vec2 uv; varying vec2 vUv; void main() { vUv = uv; gl_Position = vec4(position, 0, 1); } `; const splatFrag = /* glsl */ ` precision highp float; varying vec2 vUv; uniform sampler2D tVelocity; uniform vec2 force; uniform vec2 center; uniform float radius; uniform float aspect; void main() { vec2 p = vUv - center; p.x *= aspect; float d = exp(-dot(p, p) / radius); vec3 base = texture2D(tVelocity, vUv).xyz; gl_FragColor = vec4(base + d * vec3(force, 0.0), 1.0); } `; const advectionFrag = /* glsl */ ` precision highp float; varying vec2 vUv; uniform sampler2D tVelocity; uniform sampler2D tSource; uniform float dt; uniform float dissipation; uniform vec2 fboSize; void main() { vec2 ratio = max(fboSize.x, fboSize.y) / fboSize; vec2 coord = vUv - dt * texture2D(tVelocity, vUv).xy * ratio; gl_FragColor = dissipation * texture2D(tSource, coord); } `; const divergenceFrag = /* glsl */ ` precision highp float; varying vec2 vUv; uniform sampler2D tVelocity; uniform vec2 px; void main() { float L = texture2D(tVelocity, vUv - vec2(px.x, 0.0)).x; float R = texture2D(tVelocity, vUv + vec2(px.x, 0.0)).x; float T = texture2D(tVelocity, vUv + vec2(0.0, px.y)).y; float B = texture2D(tVelocity, vUv - vec2(0.0, px.y)).y; float div = 0.5 * (R - L + T - B); gl_FragColor = vec4(div, 0.0, 0.0, 1.0); } `; const poissonFrag = /* glsl */ ` precision highp float; varying vec2 vUv; uniform sampler2D tPressure; uniform sampler2D tDivergence; uniform vec2 px; void main() { float L = texture2D(tPressure, vUv - vec2(px.x, 0.0)).x; float R = texture2D(tPressure, vUv + vec2(px.x, 0.0)).x; float T = texture2D(tPressure, vUv + vec2(0.0, px.y)).x; float B = texture2D(tPressure, vUv - vec2(0.0, px.y)).x; float div = texture2D(tDivergence, vUv).x; float p = (L + R + B + T - div) * 0.25; gl_FragColor = vec4(p, 0.0, 0.0, 1.0); } `; const pressureFrag = /* glsl */ ` precision highp float; varying vec2 vUv; uniform sampler2D tPressure; uniform sampler2D tVelocity; uniform vec2 px; void main() { float L = texture2D(tPressure, vUv - vec2(px.x, 0.0)).x; float R = texture2D(tPressure, vUv + vec2(px.x, 0.0)).x; float T = texture2D(tPressure, vUv + vec2(0.0, px.y)).x; float B = texture2D(tPressure, vUv - vec2(0.0, px.y)).x; vec2 vel = texture2D(tVelocity, vUv).xy; vel -= 0.5 * vec2(R - L, T - B); gl_FragColor = vec4(vel, 0.0, 1.0); } `; const outputFrag = /* glsl */ ` precision highp float; varying vec2 vUv; uniform sampler2D tVelocity; uniform sampler2D tPalette; void main() { vec2 vel = texture2D(tVelocity, vUv).xy; float len = length(vel); vec3 color = texture2D(tPalette, vec2(len, 0.5)).rgb; gl_FragColor = vec4(color, len); } `; function LiquidFluid({ mouseForce = 35, cursorSize = 80, iterationsPoisson = 32, dt = 0.014, resolution = 0.5, colors = defaultColors, style = {}, className = '', autoDemo = true, autoSpeed = 0.5, autoIntensity = 2.2, autoResumeDelay = 1000, }) { const containerRef = (0, react_1.useRef)(null); const canvasRef = (0, react_1.useRef)(null); const rendererRef = (0, react_1.useRef)(null); const glRef = (0, react_1.useRef)(null); const programsRef = (0, react_1.useRef)({}); const targetsRef = (0, react_1.useRef)({}); const meshRef = (0, react_1.useRef)(null); // Physics markers const mouse = (0, react_1.useRef)(new ogl_1.Vec2(0.5, 0.5)); const lastMouse = (0, react_1.useRef)(new ogl_1.Vec2(0.5, 0.5)); const velocity = (0, react_1.useRef)(new ogl_1.Vec2(0, 0)); const lastInputTime = (0, react_1.useRef)(0); const autoPos = (0, react_1.useRef)({ x: 0.5, y: 0.5 }); (0, react_1.useEffect)(() => { if (!canvasRef.current || !containerRef.current) return; const renderer = new ogl_1.Renderer({ canvas: canvasRef.current, alpha: true, dpr: 2, premultipliedAlpha: false }); const gl = renderer.gl; rendererRef.current = renderer; glRef.current = gl; const geometry = new ogl_1.Geometry(gl, { position: { size: 2, data: new Float32Array([-1, -1, 3, -1, -1, 3]) }, uv: { size: 2, data: new Float32Array([0, 0, 2, 0, 0, 2]) }, }); // Extensions const isIOS = /(iPad|iPhone|iPod)/i.test(navigator.userAgent); const floatType = isIOS ? gl.HALF_FLOAT || 0x8D61 : gl.FLOAT; gl.getExtension('OES_texture_float'); gl.getExtension('OES_texture_float_linear'); gl.getExtension('OES_texture_half_float'); gl.getExtension('OES_texture_half_float_linear'); const createTarget = (w, h) => new ogl_1.RenderTarget(gl, { width: w, height: h, type: floatType, format: gl.RGBA, internalFormat: isIOS ? gl.RGBA16F : gl.RGBA32F || gl.RGBA, minFilter: gl.LINEAR, magFilter: gl.LINEAR, depth: false, }); // Programs const programs = { advection: new ogl_1.Program(gl, { vertex: baseVertex, fragment: advectionFrag, uniforms: { tVelocity: { value: null }, tSource: { value: null }, dt: { value: dt }, dissipation: { value: 0.98 }, fboSize: { value: new ogl_1.Vec2() } } }), splat: new ogl_1.Program(gl, { vertex: baseVertex, fragment: splatFrag, uniforms: { tVelocity: { value: null }, force: { value: new ogl_1.Vec2() }, center: { value: new ogl_1.Vec2() }, radius: { value: cursorSize / 1000 }, aspect: { value: 1.0 } } }), divergence: new ogl_1.Program(gl, { vertex: baseVertex, fragment: divergenceFrag, uniforms: { tVelocity: { value: null }, px: { value: new ogl_1.Vec2() } } }), poisson: new ogl_1.Program(gl, { vertex: baseVertex, fragment: poissonFrag, uniforms: { tPressure: { value: null }, tDivergence: { value: null }, px: { value: new ogl_1.Vec2() } } }), pressure: new ogl_1.Program(gl, { vertex: baseVertex, fragment: pressureFrag, uniforms: { tPressure: { value: null }, tVelocity: { value: null }, px: { value: new ogl_1.Vec2() } } }), output: new ogl_1.Program(gl, { vertex: baseVertex, fragment: outputFrag, uniforms: { tVelocity: { value: null }, tPalette: { value: null } }, transparent: true }) }; programsRef.current = programs; const mainMesh = new ogl_1.Mesh(gl, { geometry, program: programs.output }); meshRef.current = mainMesh; // Palette const updatePalette = (cols) => { const data = new Uint8Array(cols.length * 4); cols.forEach((hex, i) => { const c = new ogl_1.Color(hex); data[i * 4 + 0] = Math.round(c.r * 255); data[i * 4 + 1] = Math.round(c.g * 255); data[i * 4 + 2] = Math.round(c.b * 255); data[i * 4 + 3] = 255; }); return new ogl_1.Texture(gl, { image: data, width: cols.length, height: 1, format: gl.RGBA, minFilter: gl.LINEAR, magFilter: gl.LINEAR, }); }; programs.output.uniforms.tPalette.value = updatePalette(colors); const handleResize = () => { const w = containerRef.current.clientWidth; const h = containerRef.current.clientHeight; renderer.setSize(w, h); const sw = Math.max(1, Math.floor(w * resolution)); const sh = Math.max(1, Math.floor(h * resolution)); targetsRef.current = { vel0: createTarget(sw, sh), vel1: createTarget(sw, sh), pressure0: createTarget(sw, sh), pressure1: createTarget(sw, sh), div: createTarget(sw, sh) }; }; handleResize(); window.addEventListener('resize', handleResize); // GSAP Auto Demo wandering let autoAnim = null; if (autoDemo) { autoAnim = gsap_1.gsap.to(autoPos.current, { x: 'random(0.2, 0.8)', y: 'random(0.2, 0.8)', duration: 2 / autoSpeed, repeat: -1, repeatRefresh: true, ease: 'sine.inOut' }); } return () => { window.removeEventListener('resize', handleResize); autoAnim?.kill(); }; }, [colors, resolution, autoDemo, autoSpeed]); (0, framer_motion_1.useAnimationFrame)((t) => { if (!glRef.current || !targetsRef.current.vel0) return; const renderer = rendererRef.current; const gl = glRef.current; const targets = targetsRef.current; const progs = programsRef.current; const mesh = meshRef.current; const camera = new ogl_1.Camera(gl); const sw = targets.vel0.width; const sh = targets.vel0.height; const px = new ogl_1.Vec2(1 / sw, 1 / sh); // Interaction const isAuto = autoDemo && Date.now() - lastInputTime.current > autoResumeDelay; const currentPos = isAuto ? new ogl_1.Vec2(autoPos.current.x, autoPos.current.y) : mouse.current; const diff = new ogl_1.Vec2().sub(currentPos, lastMouse.current); lastMouse.current.copy(currentPos); velocity.current.lerp(diff, 0.2); // Render passes // 1. Advection progs.advection.uniforms.tVelocity.value = targets.vel0.texture; progs.advection.uniforms.tSource.value = targets.vel0.texture; progs.advection.uniforms.fboSize.value.set(sw, sh); mesh.program = progs.advection; renderer.render({ scene: mesh, camera, target: targets.vel1 }); // 2. Splat const force = isAuto ? autoIntensity * 0.01 : mouseForce; if (velocity.current.len() > 0.0001) { progs.splat.uniforms.tVelocity.value = targets.vel1.texture; progs.splat.uniforms.center.value.copy(currentPos); progs.splat.uniforms.force.value.set(velocity.current.x * force, velocity.current.y * force); progs.splat.uniforms.aspect.value = sw / sh; mesh.program = progs.splat; renderer.render({ scene: mesh, camera, target: targets.vel1, clear: false }); } // 3. Divergence progs.divergence.uniforms.tVelocity.value = targets.vel1.texture; progs.divergence.uniforms.px.value.copy(px); mesh.program = progs.divergence; renderer.render({ scene: mesh, camera, target: targets.div }); // 4. Pressure Solve for (let i = 0; i < iterationsPoisson; i++) { progs.poisson.uniforms.tPressure.value = (i === 0 ? targets.pressure0 : targets.pressure0).texture; progs.poisson.uniforms.tDivergence.value = targets.div.texture; progs.poisson.uniforms.px.value.copy(px); mesh.program = progs.poisson; renderer.render({ scene: mesh, camera, target: targets.pressure1 }); [targets.pressure0, targets.pressure1] = [targets.pressure1, targets.pressure0]; } // 5. Apply Pressure progs.pressure.uniforms.tPressure.value = targets.pressure0.texture; progs.pressure.uniforms.tVelocity.value = targets.vel1.texture; progs.pressure.uniforms.px.value.copy(px); mesh.program = progs.pressure; renderer.render({ scene: mesh, camera, target: targets.vel0 }); // 6. Result progs.output.uniforms.tVelocity.value = targets.vel0.texture; mesh.program = progs.output; renderer.render({ scene: mesh, camera }); }); const handleInput = (e) => { const x = e.clientX || (e.touches && e.touches[0].clientX); const y = e.clientY || (e.touches && e.touches[0].clientY); if (x === undefined || y === undefined) return; lastInputTime.current = Date.now(); const rect = containerRef.current?.getBoundingClientRect(); if (!rect) return; mouse.current.set((x - rect.left) / rect.width, 1.0 - (y - rect.top) / rect.height); }; return ((0, jsx_runtime_1.jsx)("div", { ref: containerRef, className: `w-full h-full relative overflow-hidden bg-black touch-none cursor-crosshair ${className}`, style: style, onMouseMove: handleInput, onTouchMove: handleInput, children: (0, jsx_runtime_1.jsx)("canvas", { ref: canvasRef, className: "w-full h-full block" }) })); } //# sourceMappingURL=liquid-fluid.js.map