@jayf0x/fluidity-js 0.3.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +19 -2
- package/README.md +26 -18
- package/dist/index.js +17 -10
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -33,11 +33,27 @@ src/
|
|
|
33
33
|
tests/ ← Vitest + jsdom
|
|
34
34
|
demo/ ← standalone Vite 5 demo site (NOT the library; uses alias to src/)
|
|
35
35
|
dist/ ← built output (do not edit)
|
|
36
|
-
|
|
36
|
+
bugs.md ← known defects (see Working the backlog)
|
|
37
|
+
features.md ← features + improvements (see Working the backlog)
|
|
37
38
|
```
|
|
38
39
|
|
|
39
40
|
---
|
|
40
41
|
|
|
42
|
+
## Working the backlog
|
|
43
|
+
|
|
44
|
+
Two flat lists drive non-urgent work:
|
|
45
|
+
|
|
46
|
+
- **[bugs.md](./bugs.md)** — known defects.
|
|
47
|
+
- **[features.md](./features.md)** — new capabilities (Features) and enhancements (Improvements).
|
|
48
|
+
|
|
49
|
+
Rules:
|
|
50
|
+
|
|
51
|
+
- Pick the top relevant row, build the fix/feature, **add a test**, then **delete that row**.
|
|
52
|
+
- A new bug → add a one-line row to `bugs.md`; a new feature/improvement → `features.md`. Keep entries short: what + which files. No design essays.
|
|
53
|
+
- These files are the source of truth — GitHub Issues are not used for the backlog.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
41
57
|
## Commands
|
|
42
58
|
|
|
43
59
|
```bash
|
|
@@ -227,7 +243,8 @@ Full label reference: [CONTRIBUTING.md § Labels](./CONTRIBUTING.md#labels)
|
|
|
227
243
|
|----------|------------|
|
|
228
244
|
| Simulation config defaults + presets | [src/core/config.ts](./src/core/config.ts) |
|
|
229
245
|
| Ambient type declarations | [src/globals.d.ts](./src/globals.d.ts) |
|
|
230
|
-
|
|
|
246
|
+
| Known bugs | [bugs.md](./bugs.md) |
|
|
247
|
+
| Feature/improvement backlog | [features.md](./features.md) |
|
|
231
248
|
| Version history | [changelog.md](./changelog.md) |
|
|
232
249
|
| Demo examples | [demo/src/examples/](./demo/src/examples/) |
|
|
233
250
|
| npm | https://www.npmjs.com/package/@jayf0x/fluidity-js |
|
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
<p align="center"><strong>Demo & Examples →</strong></p>
|
|
15
15
|
</a>
|
|
16
16
|
|
|
17
|
+
> ⭐ **Star [this repository](https://github.com/jayf0x/fluidity) if you’d like to support its growth**
|
|
18
|
+
|
|
17
19
|
## Quickstart
|
|
18
20
|
|
|
19
21
|
Choose your weapon:
|
|
@@ -23,26 +25,32 @@ bun add @jayf0x/fluidity-js
|
|
|
23
25
|
# OR pnpm / aube / yarn / npm ...
|
|
24
26
|
```
|
|
25
27
|
|
|
28
|
+
**Text**:
|
|
29
|
+
|
|
26
30
|
```tsx
|
|
27
|
-
import {
|
|
31
|
+
import { FluidText } from '@jayf0x/fluidity-js';
|
|
28
32
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<FluidText text="Hello World" fontSize={140} color="#ffffff" />
|
|
34
|
-
</div>
|
|
35
|
-
);
|
|
36
|
-
};
|
|
33
|
+
<div style={{ width: '100%', height: 400 }}>
|
|
34
|
+
<FluidText text="Howdy World" fontSize={140} />
|
|
35
|
+
</div>;
|
|
36
|
+
```
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
**Image**:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { FluidImage } from '@jayf0x/fluidity-js';
|
|
42
|
+
|
|
43
|
+
<div style={{ width: '100%', height: '100vh' }}>
|
|
44
|
+
<FluidImage src="/hero.png" algorithm="aurora" />
|
|
45
|
+
</div>;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Text + Image**:
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<div style={{ width: '100%', height: 400 }}>
|
|
52
|
+
<FluidText text="Howdy World" backgroundSrc="/hero.png" />
|
|
53
|
+
</div>
|
|
46
54
|
```
|
|
47
55
|
|
|
48
56
|
---
|
|
@@ -207,7 +215,7 @@ Works in all modern browsers. Automatically picks the best renderer available
|
|
|
207
215
|
|
|
208
216
|
## Contributing
|
|
209
217
|
|
|
210
|
-
|
|
218
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup and [AGENTS.md](./AGENTS.md) for code conventions.
|
|
211
219
|
|
|
212
220
|
---
|
|
213
221
|
|
package/dist/index.js
CHANGED
|
@@ -164,8 +164,9 @@ function _(e, t, n, r, i = null, a = "cover") {
|
|
|
164
164
|
f.clearRect(0, 0, t, n), f.fillStyle = "black", f.fillRect(0, 0, t, n);
|
|
165
165
|
let { x: e, y: r, drawW: o, drawH: s } = g(i.width, i.height, t, n, a);
|
|
166
166
|
f.drawImage(i, e, r, o, s);
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
f.fillStyle = e, f.fillRect(0, 0, t, n), f.font = `${u} ${s}px ${l}`, f.textAlign = "center", f.textBaseline = "middle", f.fillText(o, t / 2, n / 2);
|
|
169
170
|
})(c);
|
|
170
171
|
let p = y(e, d);
|
|
171
172
|
f.fillStyle = "black", f.fillRect(0, 0, t, n), f.fillStyle = "white", f.font = `${u} ${s}px ${l}`, f.textAlign = "center", f.textBaseline = "middle", f.fillText(o, t / 2, n / 2);
|
|
@@ -203,8 +204,9 @@ function b(e, t, n, r, i = null, a = "cover") {
|
|
|
203
204
|
f.clearRect(0, 0, t, n), f.fillStyle = "black", f.fillRect(0, 0, t, n);
|
|
204
205
|
let { x: e, y: r, drawW: o, drawH: s } = g(i.width, i.height, t, n, a);
|
|
205
206
|
f.drawImage(i, e, r, o, s);
|
|
206
|
-
|
|
207
|
-
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
f.fillStyle = e, f.fillRect(0, 0, t, n), f.font = `${u} ${s}px ${l}`, f.textAlign = "center", f.textBaseline = "middle", f.fillText(o, t / 2, n / 2);
|
|
208
210
|
})(c);
|
|
209
211
|
let p = S(e, d, t, n);
|
|
210
212
|
f.fillStyle = "black", f.fillRect(0, 0, t, n), f.fillStyle = "white", f.font = `${u} ${s}px ${l}`, f.textAlign = "center", f.textBaseline = "middle", f.fillText(o, t / 2, n / 2);
|
|
@@ -1035,7 +1037,7 @@ var me = typeof requestAnimationFrame < "u" ? requestAnimationFrame.bind(globalT
|
|
|
1035
1037
|
for (let n = 0; n < t.pressureIterations; n++) e.uniform1i(i.uniforms.uPressure, 2), e.activeTexture(e.TEXTURE2), e.bindTexture(e.TEXTURE_2D, this.#c.read.tex), f(this.#c.write.fbo), this.#c.swap();
|
|
1036
1038
|
a.bind(), e.uniform2f(a.uniforms.texelSize, 1 / u, 1 / d), e.uniform1i(a.uniforms.uPressure, 0), e.activeTexture(e.TEXTURE0), e.bindTexture(e.TEXTURE_2D, this.#c.read.tex), e.uniform1i(a.uniforms.uVelocity, 1), e.activeTexture(e.TEXTURE1), e.bindTexture(e.TEXTURE_2D, this.#o.read.tex), e.uniform1i(a.uniforms.uObstacle, 2), e.activeTexture(e.TEXTURE2), e.bindTexture(e.TEXTURE_2D, this.#d), f(this.#o.write.fbo), this.#o.swap(), e.viewport(0, 0, this.#N, this.#P), e.bindFramebuffer(e.FRAMEBUFFER, null), e.clear(e.COLOR_BUFFER_BIT), l.bind(), e.uniform2f(l.uniforms.texelSize, 1 / this.#N, 1 / this.#P), e.uniform3fv(l.uniforms.uWaterColor, m(t.waterColor)), e.uniform3fv(l.uniforms.uGlowColor, m(t.glowColor)), e.uniform1f(l.uniforms.uRefraction, t.refraction), e.uniform1f(l.uniforms.uSpecularExp, t.specularExp), e.uniform1f(l.uniforms.uShine, t.shine), e.uniform1f(l.uniforms.uWarpStrength, t.warpStrength ?? .015), e.uniform1i(l.uniforms.uAlgorithm, ge[t.algorithm] ?? 0), e.uniform1i(l.uniforms.uEnableAlpha, +!!this.#Y), e.activeTexture(e.TEXTURE0), e.bindTexture(e.TEXTURE_2D, this.#a.read.tex), e.activeTexture(e.TEXTURE1), e.bindTexture(e.TEXTURE_2D, this.#d), e.activeTexture(e.TEXTURE2), e.bindTexture(e.TEXTURE_2D, this.#u), e.activeTexture(e.TEXTURE3), e.bindTexture(e.TEXTURE_2D, this.#f), e.activeTexture(e.TEXTURE4), e.bindTexture(e.TEXTURE_2D, this.#o.read.tex), e.uniform1i(l.uniforms.uTexture, 0), e.uniform1i(l.uniforms.uObstacle, 1), e.uniform1i(l.uniforms.uBackground, 2), e.uniform1i(l.uniforms.uCoverage, 3), e.uniform1i(l.uniforms.uVelocity, 4), f(null);
|
|
1037
1039
|
}
|
|
1038
|
-
}, _e = "const e={densityDissipation:.83,velocityDissipation:.91,pressureIterations:1,curl:0,splatRadius:.1,splatForce:.08,refraction:1,specularExp:0,shine:0,waterColor:`#000000`,glowColor:`#b3d9ff`,algorithm:`aurora`,warpStrength:.04};({...e}),typeof window<`u`&&1/(window.devicePixelRatio||1);const t={backgroundColor:`#0a0a0a`,backgroundSize:`cover`,mouseEnabled:!0,workerEnabled:!0};({...t}),{...t};const n={calm:{densityDissipation:.98,velocityDissipation:.81,curl:1e-4,splatRadius:.05,splatForce:.08,refraction:.15,shine:.03,glowColor:`#99d9ff`,waterColor:`#00050d`},sand:{densityDissipation:.95,velocityDissipation:.81,curl:1,splatRadius:.23,splatForce:.16,refraction:.8,specularExp:0,shine:.33,glowColor:`#070707`,waterColor:`#735420`},wave:{densityDissipation:.9,velocityDissipation:.2,curl:.2,splatRadius:.1,splatForce:.22,refraction:.35,shine:.2,glowColor:`#80ccff`,waterColor:`#000308`},neon:{densityDissipation:.75,velocityDissipation:.3,curl:.05,splatRadius:.18,splatForce:.29,refraction:.25,specularExp:.04,shine:.93,glowColor:`#ff33cc`,waterColor:`#0d0014`},smoke:{densityDissipation:.93,velocityDissipation:.71,curl:.04,splatRadius:.21,splatForce:.14,refraction:.08,shine:0,glowColor:`#808080`,waterColor:`#0f0f0f`}};function r(e){if(Array.isArray(e))return e;let t=e.slice(1,7);return t.length===3?[parseInt(t[0]+t[0],16)/255,parseInt(t[1]+t[1],16)/255,parseInt(t[2]+t[2],16)/255]:[parseInt(t.slice(0,2),16)/255,parseInt(t.slice(2,4),16)/255,parseInt(t.slice(4,6),16)/255]}function i(t={},r,i=e){return{...r?{...i,...n[r]}:i,...t}}const a=`precision highp float;\n attribute vec2 aPosition;\n varying vec2 vUv;\n varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB;\n uniform vec2 texelSize;\n void main () {\n vUv = aPosition * 0.5 + 0.5;\n vL = vUv - vec2(texelSize.x, 0.0);\n vR = vUv + vec2(texelSize.x, 0.0);\n vT = vUv + vec2(0.0, texelSize.y);\n vB = vUv - vec2(0.0, texelSize.y);\n gl_Position = vec4(aPosition, 0.0, 1.0);\n }`;function o(e,t=!0){let n={alpha:t,depth:!1,stencil:!1,antialias:!0,preserveDrawingBuffer:!1},r=e.getContext(`webgl2`,n),i=!!r;i||(r=e.getContext(`webgl`,n),r.getExtension(`EXT_color_buffer_half_float`));let a=i?null:r.getExtension(`OES_texture_half_float`),o=i?r.HALF_FLOAT:a.HALF_FLOAT_OES;return r.getExtension(`EXT_color_buffer_float`),r.getExtension(`OES_texture_half_float_linear`),{type:i?`webgl2`:`webgl1`,gl:r,isWebGL2:i,ext:{internalFormat:i?r.RGBA16F:r.RGBA,format:r.RGBA,type:o}}}async function s(e,t=!0){if(typeof navigator>`u`||!navigator.gpu)return null;try{let n=await navigator.gpu.requestAdapter();if(!n)return null;let r=await n.requestDevice(),i=e.getContext(`webgpu`);if(!i)return null;let a=navigator.gpu.getPreferredCanvasFormat();return i.configure({device:r,format:a,alphaMode:t?`premultiplied`:`opaque`}),{type:`webgpu`,adapter:n,device:r,context:i,format:a}}catch{return null}}var c=class{program;uniforms={};_gl;constructor(e,t,n){this._gl=e,this.program=e.createProgram(),e.attachShader(this.program,this._compile(e.VERTEX_SHADER,t)),e.attachShader(this.program,this._compile(e.FRAGMENT_SHADER,n)),e.linkProgram(this.program);let r=e.getProgramParameter(this.program,e.ACTIVE_UNIFORMS);for(let t=0;t<r;t++){let n=e.getActiveUniform(this.program,t).name;this.uniforms[n]=e.getUniformLocation(this.program,n)}}_compile(e,t){let n=this._gl,r=n.createShader(e);return n.shaderSource(r,t),n.compileShader(r),r}bind(){this._gl.useProgram(this.program)}dispose(){this._gl.deleteProgram(this.program)}};function l(e){return{advection:new c(e,a,`precision highp float;\n varying vec2 vUv;\n uniform sampler2D uVelocity;\n uniform sampler2D uSource;\n uniform sampler2D uObstacle;\n uniform vec2 texelSize;\n uniform float dt;\n uniform float dissipation;\n void main () {\n float obs = texture2D(uObstacle, vUv).r;\n vec2 coord = vUv - dt * texture2D(uVelocity, vUv).xy * texelSize;\n \n \n \n gl_FragColor = dissipation * texture2D(uSource, coord) * (1.0 - obs);\n }`),divergence:new c(e,a,`precision highp float;\n varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB;\n uniform sampler2D uVelocity;\n uniform sampler2D uObstacle;\n void main () {\n float L = texture2D(uVelocity, vL).x * (1.0 - texture2D(uObstacle, vL).r);\n float R = texture2D(uVelocity, vR).x * (1.0 - texture2D(uObstacle, vR).r);\n float T = texture2D(uVelocity, vT).y * (1.0 - texture2D(uObstacle, vT).r);\n float B = texture2D(uVelocity, vB).y * (1.0 - texture2D(uObstacle, vB).r);\n gl_FragColor = vec4(0.5 * (R - L + T - B), 0.0, 0.0, 1.0);\n }`),pressure:new c(e,a,`precision highp float;\n varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB;\n uniform sampler2D uPressure;\n uniform sampler2D uDivergence;\n uniform sampler2D uObstacle;\n void main () {\n float C = texture2D(uPressure, vUv).x;\n float L = mix(texture2D(uPressure, vL).x, C, texture2D(uObstacle, vL).r);\n float R = mix(texture2D(uPressure, vR).x, C, texture2D(uObstacle, vR).r);\n float T = mix(texture2D(uPressure, vT).x, C, texture2D(uObstacle, vT).r);\n float B = mix(texture2D(uPressure, vB).x, C, texture2D(uObstacle, vB).r);\n float div = texture2D(uDivergence, vUv).x;\n gl_FragColor = vec4((L + R + B + T - div) * 0.25, 0.0, 0.0, 1.0);\n }`),gradientSubtract:new c(e,a,`precision highp float;\n varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB;\n uniform sampler2D uPressure;\n uniform sampler2D uVelocity;\n uniform sampler2D uObstacle;\n void main () {\n float obs = texture2D(uObstacle, vUv).r;\n float C = texture2D(uPressure, vUv).x;\n float L = mix(texture2D(uPressure, vL).x, C, texture2D(uObstacle, vL).r);\n float R = mix(texture2D(uPressure, vR).x, C, texture2D(uObstacle, vR).r);\n float T = mix(texture2D(uPressure, vT).x, C, texture2D(uObstacle, vT).r);\n float B = mix(texture2D(uPressure, vB).x, C, texture2D(uObstacle, vB).r);\n vec2 vel = (texture2D(uVelocity, vUv).xy - vec2(R - L, T - B)) * (1.0 - obs);\n gl_FragColor = vec4(vel, 0.0, 1.0);\n }`),splat:new c(e,a,`precision highp float;\n varying vec2 vUv;\n uniform sampler2D uTarget;\n uniform float aspectRatio;\n uniform vec3 color;\n uniform vec2 point;\n uniform float radius;\n void main () {\n vec2 p = vUv - point.xy;\n p.x *= aspectRatio;\n vec3 splat = exp(-dot(p, p) / radius) * color;\n gl_FragColor = vec4(texture2D(uTarget, vUv).xyz + splat, 1.0);\n }`),curl:new c(e,a,`precision highp float;\n varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB;\n uniform sampler2D uVelocity;\n void 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 gl_FragColor = vec4(0.5 * (R - L - T + B), 0.0, 0.0, 1.0);\n }`),vorticity:new c(e,a,`precision highp float;\n varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB;\n uniform sampler2D uVelocity;\n uniform sampler2D uCurl;\n uniform float curl;\n uniform float dt;\n void 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 = 0.5 * vec2(abs(T) - abs(B), abs(R) - abs(L));\n force /= length(force) + 0.0001;\n force *= curl * 30.0 * C;\n gl_FragColor = vec4(texture2D(uVelocity, vUv).xy + force * dt, 0.0, 1.0);\n }`),display:new c(e,a,`precision highp float;\n varying vec2 vUv;\n uniform sampler2D uTexture;\n uniform sampler2D uObstacle;\n uniform sampler2D uBackground;\n uniform sampler2D uCoverage;\n uniform sampler2D uVelocity;\n uniform vec2 texelSize;\n uniform vec3 uWaterColor;\n uniform vec3 uGlowColor;\n uniform float uRefraction;\n uniform float uSpecularExp;\n uniform float uShine;\n uniform float uWarpStrength;\n uniform int uAlgorithm;\n uniform int uEnableAlpha;\n void main () {\n float obs = texture2D(uObstacle, vUv).r;\n \n \n float density = max(texture2D(uTexture, vUv).r, 0.0) * (1.0 - obs);\n float coverage = texture2D(uCoverage, vUv).r;\n \n \n \n \n float sx = texelSize.x * 6.0, sy = texelSize.y * 6.0;\n float d00 = max(texture2D(uTexture, vUv + vec2(-sx, -sy)).r, 0.0);\n float d10 = max(texture2D(uTexture, vUv + vec2(0.0, -sy)).r, 0.0);\n float d20 = max(texture2D(uTexture, vUv + vec2( sx, -sy)).r, 0.0);\n float d01 = max(texture2D(uTexture, vUv + vec2(-sx, 0.0)).r, 0.0);\n float d21 = max(texture2D(uTexture, vUv + vec2( sx, 0.0)).r, 0.0);\n float d02 = max(texture2D(uTexture, vUv + vec2(-sx, sy)).r, 0.0);\n float d12 = max(texture2D(uTexture, vUv + vec2(0.0, sy)).r, 0.0);\n float d22 = max(texture2D(uTexture, vUv + vec2( sx, sy)).r, 0.0);\n float gx = (d20 + 2.0*d21 + d22) - (d00 + 2.0*d01 + d02);\n float gy = (d02 + 2.0*d12 + d22) - (d00 + 2.0*d10 + d20);\n vec3 normal = normalize(vec3(gx, gy, 1.2));\n vec3 lightDir = normalize(vec3(0.5, 1.0, 0.5));\n vec3 halfV = normalize(lightDir + vec3(0.0, 0.0, 1.0));\n \n \n float specDen = density * min(density * 5.0, 1.0);\n float spec = pow(max(dot(normal, halfV), 0.0), uSpecularExp) * uShine * specDen;\n \n \n \n vec3 bgRaw = texture2D(uBackground, vUv).rgb;\n vec3 bg = mix(uWaterColor, bgRaw, coverage);\n vec3 color = bg;\n if (uAlgorithm == 1) {\n \n \n vec2 refrUv = clamp(vUv + normal.xy * uRefraction * density * 3.0, 0.0, 1.0);\n vec3 refrBg = mix(uWaterColor, texture2D(uBackground, mix(vUv, refrUv, 1.0 - obs)).rgb, coverage);\n color = refrBg + spec * uGlowColor * 2.5;\n color = mix(color, bg * 0.6, obs * 0.3);\n } else if (uAlgorithm == 2) {\n \n \n float inkD = min(density * 4.0, 1.0);\n vec2 refrUv = clamp(vUv + normal.xy * uRefraction * density * 0.4, 0.0, 1.0);\n vec3 refrBg = mix(uWaterColor, texture2D(uBackground, mix(vUv, refrUv, 1.0 - obs)).rgb, coverage);\n color = mix(refrBg, uWaterColor + spec * uGlowColor, inkD);\n color = mix(color, bg * 0.5, obs * 0.15);\n } else if (uAlgorithm == 3) {\n \n \n vec2 vel = texture2D(uVelocity, vUv).xy;\n float velMag = clamp(length(vel) * 20.0, 0.0, 1.0);\n vec2 warpUv = clamp(vUv + vel * uWarpStrength, 0.0, 1.0);\n vec3 warpBg = mix(uWaterColor, texture2D(uBackground, warpUv).rgb, coverage);\n color = mix(bg, warpBg, velMag * (1.0 - obs));\n color += spec * uGlowColor * velMag * 1.5;\n color += uWaterColor * density * 0.3;\n color = mix(color, bg * 0.5, obs * 0.2);\n } else if (uAlgorithm == 4) {\n \n \n vec2 rippleUv = clamp(vUv + normal.xy * uRefraction * density * 6.0, 0.0, 1.0);\n vec3 refrBg = mix(uWaterColor, texture2D(uBackground, mix(vUv, rippleUv, 1.0 - obs)).rgb, coverage);\n float fresnel = pow(clamp(1.0 - dot(normal, vec3(0.0, 0.0, 1.0)), 0.0, 1.0), 3.0) * density;\n color = refrBg;\n color += fresnel * uGlowColor * 2.0;\n color += spec * uGlowColor * density * 2.0;\n color = mix(color, bg * 0.5, obs * 0.2);\n } else {\n \n \n vec2 refrUv = vUv + normal.xy * uRefraction * density;\n vec3 refrBg = mix(uWaterColor, texture2D(uBackground, mix(vUv, refrUv, 1.0 - obs)).rgb, coverage);\n color = mix(refrBg, uWaterColor, min(density * 1.5, 0.8));\n color += spec * uGlowColor;\n color = mix(color, bg * 0.5, obs * 0.2);\n }\n \n \n float alpha = clamp(max(density * 1.5, coverage), 0.0, 1.0);\n if (uEnableAlpha == 1) {\n gl_FragColor = vec4(color * alpha, alpha);\n } else {\n gl_FragColor = vec4(color, 1.0);\n }\n }`)}}function u(e,t,n,r){e.activeTexture(e.TEXTURE0);let i=e.createTexture();e.bindTexture(e.TEXTURE_2D,i),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texImage2D(e.TEXTURE_2D,0,t.internalFormat,n,r,0,t.format,t.type,null);let a=e.createFramebuffer();return e.bindFramebuffer(e.FRAMEBUFFER,a),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,i,0),{tex:i,fbo:a,width:n,height:r}}function d(e,t,n,r){let i=u(e,t,n,r),a=u(e,t,n,r);return{get read(){return i},get write(){return a},swap(){[i,a]=[a,i]},dispose(){e.deleteTexture(i.tex),e.deleteFramebuffer(i.fbo),e.deleteTexture(a.tex),e.deleteFramebuffer(a.fbo)}}}function f(e){let t=e.createBuffer();return e.bindBuffer(e.ARRAY_BUFFER,t),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,-1,1,1,1,1,-1]),e.STATIC_DRAW),e.vertexAttribPointer(0,2,e.FLOAT,!1,0,0),e.enableVertexAttribArray(0),function(t){e.bindFramebuffer(e.FRAMEBUFFER,t),e.drawArrays(e.TRIANGLE_FAN,0,4)}}const p={arrayStride:8,attributes:[{shaderLocation:0,offset:0,format:`float32x2`}]},m=new Float32Array([-1,-1,-1,1,1,-1,1,-1,-1,1,1,1]);function h(e){let t=e.createBuffer({size:m.byteLength,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST});return e.queue.writeBuffer(t,0,m),t}function g(e,t,n,r){let i=e.createTexture({size:[n,r],format:t,usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC});return{tex:i,view:i.createView(),width:n,height:r}}function _(e,t,n,r){let i=g(e,t,n,r),a=g(e,t,n,r);return{get read(){return i},get write(){return a},swap(){[i,a]=[a,i]},dispose(){i.tex.destroy(),a.tex.destroy()}}}function v(e,t,n,r){let i=e.createShaderModule({code:t});return e.createRenderPipeline({layout:`auto`,vertex:{module:i,entryPoint:`vs`,buffers:[p]},fragment:{module:i,entryPoint:`fs`,targets:[{format:n,...r?{blend:r}:{}}]},primitive:{topology:`triangle-list`}})}const y={color:{operation:`add`,srcFactor:`one`,dstFactor:`zero`},alpha:{operation:`add`,srcFactor:`one`,dstFactor:`zero`}};function b(e,t,n=!0){let r=`rgba16float`;return{advection:v(e,`struct U {\n texelSize : vec2f,\n dt : f32,\n dissipation: f32,\n}\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uVel : texture_2d<f32>;\n@group(0) @binding(3) var uSrc : texture_2d<f32>;\n@group(0) @binding(4) var uObs : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let obs = textureSample(uObs, samp, i.uv).r;\n let vel = textureSample(uVel, samp, i.uv).xy;\n let coord = i.uv - u.dt * vel * u.texelSize;\n let src = textureSample(uSrc, samp, coord);\n return u.dissipation * src * (1.0 - obs);\n}`,r),divergence:v(e,`struct U { texelSize: vec2f, _pad: vec2f }\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uVel : texture_2d<f32>;\n@group(0) @binding(3) var uObs : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let L = textureSample(uVel, samp, i.vL).x * (1.0 - textureSample(uObs, samp, i.vL).r);\n let R = textureSample(uVel, samp, i.vR).x * (1.0 - textureSample(uObs, samp, i.vR).r);\n let T = textureSample(uVel, samp, i.vT).y * (1.0 - textureSample(uObs, samp, i.vT).r);\n let B = textureSample(uVel, samp, i.vB).y * (1.0 - textureSample(uObs, samp, i.vB).r);\n return vec4f(0.5 * (R - L + T - B), 0.0, 0.0, 1.0);\n}`,r),pressure:v(e,`struct U { texelSize: vec2f, _pad: vec2f }\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uPres: texture_2d<f32>;\n@group(0) @binding(3) var uDiv : texture_2d<f32>;\n@group(0) @binding(4) var uObs : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let C = textureSample(uPres, samp, i.uv).x;\n let L = mix(textureSample(uPres, samp, i.vL).x, C, textureSample(uObs, samp, i.vL).r);\n let R = mix(textureSample(uPres, samp, i.vR).x, C, textureSample(uObs, samp, i.vR).r);\n let T = mix(textureSample(uPres, samp, i.vT).x, C, textureSample(uObs, samp, i.vT).r);\n let B = mix(textureSample(uPres, samp, i.vB).x, C, textureSample(uObs, samp, i.vB).r);\n let dv = textureSample(uDiv, samp, i.uv).x;\n return vec4f((L + R + B + T - dv) * 0.25, 0.0, 0.0, 1.0);\n}`,r),gradientSubtract:v(e,`struct U { texelSize: vec2f, _pad: vec2f }\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uPres: texture_2d<f32>;\n@group(0) @binding(3) var uVel : texture_2d<f32>;\n@group(0) @binding(4) var uObs : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let obs = textureSample(uObs, samp, i.uv).r;\n let C = textureSample(uPres, samp, i.uv).x;\n let L = mix(textureSample(uPres, samp, i.vL).x, C, textureSample(uObs, samp, i.vL).r);\n let R = mix(textureSample(uPres, samp, i.vR).x, C, textureSample(uObs, samp, i.vR).r);\n let T = mix(textureSample(uPres, samp, i.vT).x, C, textureSample(uObs, samp, i.vT).r);\n let B = mix(textureSample(uPres, samp, i.vB).x, C, textureSample(uObs, samp, i.vB).r);\n let vel = (textureSample(uVel, samp, i.uv).xy - vec2f(R - L, T - B)) * (1.0 - obs);\n return vec4f(vel, 0.0, 1.0);\n}`,r),splat:v(e,`struct U {\n texelSize : vec2f,\n aspectRatio: f32,\n radius : f32,\n color : vec4f, \n point : vec2f,\n _pad : vec2f,\n}\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uTgt : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n var p = i.uv - u.point;\n p.x *= u.aspectRatio;\n let sp = exp(-dot(p, p) / u.radius) * u.color.xyz;\n return vec4f(textureSample(uTgt, samp, i.uv).xyz + sp, 1.0);\n}`,r),curl:v(e,`struct U { texelSize: vec2f, _pad: vec2f }\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uVel : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let L = textureSample(uVel, samp, i.vL).y;\n let R = textureSample(uVel, samp, i.vR).y;\n let T = textureSample(uVel, samp, i.vT).x;\n let B = textureSample(uVel, samp, i.vB).x;\n return vec4f(0.5 * (R - L - T + B), 0.0, 0.0, 1.0);\n}`,r),vorticity:v(e,`struct U {\n texelSize: vec2f,\n curl : f32,\n dt : f32,\n}\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uVel : texture_2d<f32>;\n@group(0) @binding(3) var uCrl : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let L = textureSample(uCrl, samp, i.vL).x;\n let R = textureSample(uCrl, samp, i.vR).x;\n let T = textureSample(uCrl, samp, i.vT).x;\n let B = textureSample(uCrl, samp, i.vB).x;\n let C = textureSample(uCrl, samp, i.uv).x;\n var force = 0.5 * vec2f(abs(T) - abs(B), abs(R) - abs(L));\n force /= length(force) + 0.0001;\n force *= u.curl * 30.0 * C;\n let vel = textureSample(uVel, samp, i.uv).xy + force * u.dt;\n return vec4f(vel, 0.0, 1.0);\n}`,r),display:v(e,`struct U {\n texelSize : vec2f,\n refraction : f32,\n specularExp : f32,\n waterColor : vec4f,\n glowColor : vec4f,\n shine : f32,\n warpStrength: f32,\n algorithm : i32,\n enableAlpha : i32,\n}\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uTex : texture_2d<f32>;\n@group(0) @binding(3) var uObs : texture_2d<f32>;\n@group(0) @binding(4) var uBg : texture_2d<f32>;\n@group(0) @binding(5) var uCov : texture_2d<f32>;\n@group(0) @binding(6) var uVel : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let obs = textureSample(uObs, samp, i.uv).r;\n let density = max(textureSample(uTex, samp, i.uv).r, 0.0) * (1.0 - obs);\n let cov = textureSample(uCov, samp, i.uv).r;\n let sx = u.texelSize.x * 6.0;\n let sy = u.texelSize.y * 6.0;\n let d00 = max(textureSample(uTex, samp, i.uv + vec2f(-sx, -sy)).r, 0.0);\n let d10 = max(textureSample(uTex, samp, i.uv + vec2f(0.0, -sy)).r, 0.0);\n let d20 = max(textureSample(uTex, samp, i.uv + vec2f( sx, -sy)).r, 0.0);\n let d01 = max(textureSample(uTex, samp, i.uv + vec2f(-sx, 0.0)).r, 0.0);\n let d21 = max(textureSample(uTex, samp, i.uv + vec2f( sx, 0.0)).r, 0.0);\n let d02 = max(textureSample(uTex, samp, i.uv + vec2f(-sx, sy)).r, 0.0);\n let d12 = max(textureSample(uTex, samp, i.uv + vec2f(0.0, sy)).r, 0.0);\n let d22 = max(textureSample(uTex, samp, i.uv + vec2f( sx, sy)).r, 0.0);\n let gx = (d20 + 2.0*d21 + d22) - (d00 + 2.0*d01 + d02);\n let gy = (d02 + 2.0*d12 + d22) - (d00 + 2.0*d10 + d20);\n let norm = normalize(vec3f(gx, gy, 1.2));\n let ldir = normalize(vec3f(0.5, 1.0, 0.5));\n let halfV = normalize(ldir + vec3f(0.0, 0.0, 1.0));\n let specDen = density * min(density * 5.0, 1.0);\n let spec = pow(max(dot(norm, halfV), 0.0), u.specularExp) * u.shine * specDen;\n let bgRaw = textureSample(uBg, samp, i.uv).rgb;\n let wc = u.waterColor.rgb;\n let gc = u.glowColor.rgb;\n let bg = mix(wc, bgRaw, cov);\n var color = bg;\n if (u.algorithm == 1) {\n let ruv = clamp(i.uv + norm.xy * u.refraction * density * 3.0, vec2f(0.0), vec2f(1.0));\n let rbg = mix(wc, textureSample(uBg, samp, mix(i.uv, ruv, 1.0 - obs)).rgb, cov);\n color = rbg + spec * gc * 2.5;\n color = mix(color, bg * 0.6, obs * 0.3);\n } else if (u.algorithm == 2) {\n let inkD = min(density * 4.0, 1.0);\n let ruv = clamp(i.uv + norm.xy * u.refraction * density * 0.4, vec2f(0.0), vec2f(1.0));\n let rbg = mix(wc, textureSample(uBg, samp, mix(i.uv, ruv, 1.0 - obs)).rgb, cov);\n color = mix(rbg, wc + spec * gc, inkD);\n color = mix(color, bg * 0.5, obs * 0.15);\n } else if (u.algorithm == 3) {\n let vel = textureSample(uVel, samp, i.uv).xy;\n let velMag = clamp(length(vel) * 20.0, 0.0, 1.0);\n let wuv = clamp(i.uv + vel * u.warpStrength, vec2f(0.0), vec2f(1.0));\n let wbg = mix(wc, textureSample(uBg, samp, wuv).rgb, cov);\n color = mix(bg, wbg, velMag * (1.0 - obs));\n color += spec * gc * velMag * 1.5;\n color += wc * density * 0.3;\n color = mix(color, bg * 0.5, obs * 0.2);\n } else if (u.algorithm == 4) {\n let ruv = clamp(i.uv + norm.xy * u.refraction * density * 6.0, vec2f(0.0), vec2f(1.0));\n let rbg = mix(wc, textureSample(uBg, samp, mix(i.uv, ruv, 1.0 - obs)).rgb, cov);\n let fres = pow(clamp(1.0 - dot(norm, vec3f(0.0, 0.0, 1.0)), 0.0, 1.0), 3.0) * density;\n color = rbg;\n color += fres * gc * 2.0;\n color += spec * gc * density * 2.0;\n color = mix(color, bg * 0.5, obs * 0.2);\n } else {\n let ruv = i.uv + norm.xy * u.refraction * density;\n let rbg = mix(wc, textureSample(uBg, samp, mix(i.uv, ruv, 1.0 - obs)).rgb, cov);\n color = mix(rbg, wc, min(density * 1.5, 0.8));\n color += spec * gc;\n color = mix(color, bg * 0.5, obs * 0.2);\n }\n let alpha = clamp(max(density * 1.5, cov), 0.0, 1.0);\n if (u.enableAlpha == 1) {\n return vec4f(color * alpha, alpha);\n }\n return vec4f(color, 1.0);\n}`,t,n?void 0:y)}}function x(e){return e.createSampler({magFilter:`linear`,minFilter:`linear`,addressModeU:`clamp-to-edge`,addressModeV:`clamp-to-edge`})}function S(e,t){return e.createBuffer({size:t,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST})}function C(e,t,n,r,i,a){let o=new Float32Array([n,r,i,a]);e.queue.writeBuffer(t,0,o)}function w(e,t,n,r){let i=new Float32Array([n,r,0,0]);e.queue.writeBuffer(t,0,i)}function T(e,t,n,r,i,a){let o=new Float32Array([n,r,i,a]);e.queue.writeBuffer(t,0,o)}function E(e,t,n,r,i,a,o,s,c,l,u){let d=new Float32Array(12);d[0]=n,d[1]=r,d[2]=i,d[3]=a,d[4]=o,d[5]=s,d[6]=c,d[7]=0,d[8]=l,d[9]=u,d[10]=0,d[11]=0,e.queue.writeBuffer(t,0,d)}function D(e,t,n,r,i,a,o,s,c,l,u,d){let f=new Float32Array(16),p=new Int32Array(f.buffer);f[0]=n,f[1]=r,f[2]=i,f[3]=a,f[4]=o[0],f[5]=o[1],f[6]=o[2],f[7]=0,f[8]=s[0],f[9]=s[1],f[10]=s[2],f[11]=0,f[12]=c,f[13]=l,p[14]=u,p[15]=+!!d,e.queue.writeBuffer(t,0,f)}function O(e,t,n,r,i){let a=e.beginRenderPass({colorAttachments:[{view:i,clearValue:[0,0,0,0],loadOp:`clear`,storeOp:`store`}]});a.setPipeline(t),a.setBindGroup(0,n),a.setVertexBuffer(0,r),a.draw(6),a.end()}function k(e,t,n,r,i){let a=e.beginRenderPass({colorAttachments:[{view:i,clearValue:[0,0,0,0],loadOp:`clear`,storeOp:`store`}]});a.setPipeline(t),a.setBindGroup(0,n),a.setVertexBuffer(0,r),a.draw(6),a.end()}function A(e,t,n,r,i=`cover`){let a;a=i===`cover`?Math.max(n/e,r/t):i===`contain`?Math.min(n/e,r/t):typeof i==`string`&&i.endsWith(`%`)?Math.min(n/e,r/t)*(parseFloat(i)/100):typeof i==`string`&&i.endsWith(`px`)?parseFloat(i)/Math.max(e,t):typeof i==`number`?i:Math.max(n/e,r/t);let o=e*a,s=t*a;return{x:(n-o)/2,y:(r-s)/2,drawW:o,drawH:s}}function j(e,t,n,r,i=null,a=`cover`){let{text:o,fontSize:s,color:c,fontFamily:l=`sans-serif`,fontWeight:u=900}=r,d=new OffscreenCanvas(t,n),f=d.getContext(`2d`);(e=>{if(i){f.clearRect(0,0,t,n),f.fillStyle=`black`,f.fillRect(0,0,t,n);let{x:e,y:r,drawW:o,drawH:s}=A(i.width,i.height,t,n,a);f.drawImage(i,e,r,o,s)}else f.fillStyle=`black`,f.fillRect(0,0,t,n);f.fillStyle=e,f.font=`${u} ${s}px ${l}`,f.textAlign=`center`,f.textBaseline=`middle`,f.fillText(o,t/2,n/2)})(c);let p=N(e,d);f.fillStyle=`black`,f.fillRect(0,0,t,n),f.fillStyle=`white`,f.font=`${u} ${s}px ${l}`,f.textAlign=`center`,f.textBaseline=`middle`,f.fillText(o,t/2,n/2);let m=N(e,d);return{backgroundTex:p,obstacleTex:m,coverageTex:m}}function M(e,t,n,r,i=0,a=`cover`,o=null,s=`cover`){let c=new OffscreenCanvas(n,r),l=c.getContext(`2d`),{x:u,y:d,drawW:f,drawH:p}=A(t.width,t.height,n,r,a);if(l.clearRect(0,0,n,r),l.fillStyle=`black`,l.fillRect(0,0,n,r),o){let{x:e,y:t,drawW:a,drawH:c}=A(o.width,o.height,n,r,s);l.filter=`brightness(${i}) blur(8px)`,l.drawImage(o,e,t,a,c),l.filter=`none`}l.drawImage(t,u,d,f,p);let m=N(e,c);l.clearRect(0,0,n,r),l.fillStyle=`black`,l.fillRect(0,0,n,r),l.filter=`brightness(${i}) blur(8px)`,l.drawImage(t,u,d,f,p),l.filter=`none`;let h=N(e,c);return l.clearRect(0,0,n,r),l.fillStyle=`black`,l.fillRect(0,0,n,r),l.fillStyle=`white`,l.fillRect(Math.max(0,u),Math.max(0,d),Math.min(f,n-Math.max(0,u)),Math.min(p,r-Math.max(0,d))),{backgroundTex:m,obstacleTex:h,coverageTex:N(e,c)}}function N(e,t){let n=e.createTexture();return e.bindTexture(e.TEXTURE_2D,n),e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,!0),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),n}function P(e,t,n,r,i=null,a=`cover`){let{text:o,fontSize:s,color:c,fontFamily:l=`sans-serif`,fontWeight:u=900}=r,d=new OffscreenCanvas(t,n),f=d.getContext(`2d`);(e=>{if(i){f.clearRect(0,0,t,n),f.fillStyle=`black`,f.fillRect(0,0,t,n);let{x:e,y:r,drawW:o,drawH:s}=A(i.width,i.height,t,n,a);f.drawImage(i,e,r,o,s)}else f.fillStyle=`black`,f.fillRect(0,0,t,n);f.fillStyle=e,f.font=`${u} ${s}px ${l}`,f.textAlign=`center`,f.textBaseline=`middle`,f.fillText(o,t/2,n/2)})(c);let p=I(e,d,t,n);f.fillStyle=`black`,f.fillRect(0,0,t,n),f.fillStyle=`white`,f.font=`${u} ${s}px ${l}`,f.textAlign=`center`,f.textBaseline=`middle`,f.fillText(o,t/2,n/2);let m=I(e,d,t,n);return{backgroundTex:p,backgroundView:p.createView(),obstacleTex:m,obstacleView:m.createView(),coverageTex:m,coverageView:m.createView(),sharedCoverage:!0}}function F(e,t,n,r,i=0,a=`cover`,o=null,s=`cover`){let c=new OffscreenCanvas(n,r),l=c.getContext(`2d`),{x:u,y:d,drawW:f,drawH:p}=A(t.width,t.height,n,r,a);if(l.clearRect(0,0,n,r),l.fillStyle=`black`,l.fillRect(0,0,n,r),o){let{x:e,y:t,drawW:a,drawH:c}=A(o.width,o.height,n,r,s);l.filter=`brightness(${i}) blur(8px)`,l.drawImage(o,e,t,a,c),l.filter=`none`}l.drawImage(t,u,d,f,p);let m=I(e,c,n,r);l.clearRect(0,0,n,r),l.fillStyle=`black`,l.fillRect(0,0,n,r),l.filter=`brightness(${i}) blur(8px)`,l.drawImage(t,u,d,f,p),l.filter=`none`;let h=I(e,c,n,r);l.clearRect(0,0,n,r),l.fillStyle=`black`,l.fillRect(0,0,n,r),l.fillStyle=`white`,l.fillRect(Math.max(0,u),Math.max(0,d),Math.min(f,n-Math.max(0,u)),Math.min(p,r-Math.max(0,d)));let g=I(e,c,n,r);return{backgroundTex:m,backgroundView:m.createView(),obstacleTex:h,obstacleView:h.createView(),coverageTex:g,coverageView:g.createView(),sharedCoverage:!1}}function I(e,t,n,r){let i=e.createTexture({size:[n,r],format:`rgba8unorm`,usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});return e.queue.copyExternalImageToTexture({source:t},{texture:i},[n,r]),i}async function L(e){let t=await fetch(e);if(!t.ok)throw Error(`Failed to fetch image: ${e} (${t.status})`);let n=await t.blob();return createImageBitmap(n)}const R=typeof requestAnimationFrame<`u`?requestAnimationFrame.bind(globalThis):e=>setTimeout(e,1e3/60),z=typeof cancelAnimationFrame<`u`?cancelAnimationFrame.bind(globalThis):clearTimeout,B=.016,V={standard:0,glass:1,ink:2,aurora:3,ripple:4};var H=class e{#e;#t=null;#n=null;#r=null;#i=null;#a=null;#o=null;#s=null;#c=null;#l=null;#u=null;#d=null;#f=null;#p=null;#m=null;#h=null;#g=null;#_=null;#v=null;#y=null;#b=null;#x=null;#S=null;#C=null;#w=null;#T=null;#E=null;#D=null;#O=null;#k=null;#A=null;#j=null;#M=null;#N=0;#P=0;#F=0;#I=0;#L=1;#R=1;#z=.5;#B=null;#V=`cover`;#H;#U={x:0,y:0,dx:0,dy:0,targetX:0,targetY:0,moved:!1};#W=!1;#G=null;#K=null;#q=!1;#J=!1;#Y=!0;constructor(e,t={},n={},r,a=!0){if(this.#e=e,this.#R=Math.max(.1,Math.min(1,n.dpr??1)),this.#z=Math.max(.1,Math.min(1,n.sim??.5)),this.#H=i(t),this.#Y=a,r)this.#p=r,this.#X(r);else{let{gl:t,ext:n}=o(e,a);this.#t=t,this.#n=n,this.#r=l(t),this.#i=f(t),t.clearColor(0,0,0,+!a)}}static async create(t,n={},r={},i=!0,a=!0){return new e(t,n,r,(i?await s(t,a):null)??void 0,a)}setTextSource(e){this.#G={type:`text`,opts:e},this.#Z(),this.#$(),this.#ee()}async setImageSource(e,t=0,n=`cover`){let r=await L(e);if(this.#J){r.close();return}this.#G={type:`image`,bitmap:r,effect:t,size:n},this.#Z(),this.#$(),this.#ee()}setImageBitmap(e,t=0,n=`cover`){this.#G={type:`image`,bitmap:e,effect:t,size:n},this.#Z(),this.#$(),this.#ee()}setBackground(e,t=`cover`){this.#B&&this.#B!==e&&this.#B.close(),this.#B=e,this.#V=t??`cover`,this.#G&&this.#N>0&&this.#P>0&&this.#$()}handleMove(e,t,n=1){if(!this.#W){this.#U.x=this.#U.targetX=e,this.#U.y=this.#U.targetY=t,this.#W=!0;return}this.#U.moved=!0,this.#U.dx=(e-this.#U.targetX)*n,this.#U.dy=(t-this.#U.targetY)*n,this.#U.targetX=e,this.#U.targetY=t}splat(e,t,n,r,i=1){!this.#q||this.#N===0||(this.#p?this.#ae(e,t,n,r,i):this.#oe(e,t,n,r,i))}updateQuality(e){e.dpr!==void 0&&(this.#R=Math.max(.1,Math.min(1,e.dpr))),e.sim!==void 0&&(this.#z=Math.max(.1,Math.min(1,e.sim)))}resize(e,t,n){if(n===void 0?typeof window<`u`&&window.devicePixelRatio&&(this.#L=window.devicePixelRatio):this.#L=n,e!==void 0&&e>0){if(t===void 0||t<=0)return;this.#N=this.#e.width=e,this.#P=this.#e.height=t,this.#F=Math.max(1,Math.round(e*this.#z)),this.#I=Math.max(1,Math.round(t*this.#z)),this.#Q()}else this.#Z();this.#G&&this.#$(),this.#ee()}updateConfig(e){Object.assign(this.#H,e)}destroy(){if(this.#J=!0,this.stop(),this.#te(),this.#ne(),this.#B&&=(this.#B.close(),null),this.#p)this.#C?.destroy(),this.#w?.destroy(),this.#T?.destroy(),this.#E?.destroy(),this.#D?.destroy(),this.#O?.destroy(),this.#k?.destroy(),this.#A?.destroy(),this.#j?.destroy(),this.#M?.destroy(),this.#h?.destroy(),this.#p.device.destroy();else{let e=this.#t;for(let e of Object.values(this.#r))e.dispose();e.getExtension(`WEBGL_lose_context`)?.loseContext()}}start(){if(this.#K!==null)return;let e=()=>{this.#re(),this.#K=R(e)};this.#K=R(e)}stop(){this.#K!==null&&(z(this.#K),this.#K=null)}get isRunning(){return this.#K!==null}#X(e){let{device:t,format:n}=e;this.#m=b(t,n,this.#Y),this.#h=h(t),this.#g=x(t),this.#C=S(t,16),this.#w=S(t,16),this.#T=S(t,16),this.#E=S(t,16),this.#D=S(t,16),this.#O=S(t,48),this.#k=S(t,48),this.#A=S(t,16),this.#j=S(t,16),this.#M=S(t,64)}#Z(){let e=this.#e;`clientWidth`in e&&e.clientWidth>0?(this.#L=(typeof window<`u`&&window.devicePixelRatio||1)*this.#R,this.#N=e.width=Math.round(e.clientWidth*this.#L),this.#P=e.height=Math.round(e.clientHeight*this.#L)):(this.#N=e.width,this.#P=e.height),!(this.#N===0||this.#P===0)&&(this.#F=Math.max(1,Math.round(this.#N*this.#z)),this.#I=Math.max(1,Math.round(this.#P*this.#z)),this.#Q())}#Q(){if(this.#te(),this.#p){let{device:e}=this.#p,t=`rgba16float`,n=this.#F,r=this.#I;this.#_=_(e,t,n,r),this.#v=_(e,t,n,r),this.#b=_(e,t,n,r),this.#y=g(e,t,n,r),this.#x=g(e,t,n,r)}else{let e=this.#t,t=this.#n,n=this.#F,r=this.#I;this.#a=d(e,t,n,r),this.#o=d(e,t,n,r),this.#c=d(e,t,n,r),this.#s=u(e,t,n,r),this.#l=u(e,t,n,r)}}#$(){if(!(!this.#G||this.#N===0||this.#P===0)){if(this.#ne(),this.#p){let{device:e}=this.#p;this.#G.type===`text`?this.#S=P(e,this.#N,this.#P,this.#G.opts,this.#B,this.#V):this.#S=F(e,this.#G.bitmap,this.#N,this.#P,this.#G.effect,this.#G.size,this.#B,this.#V)}else{let e=this.#t;if(this.#G.type===`text`){let{backgroundTex:t,obstacleTex:n,coverageTex:r}=j(e,this.#N,this.#P,this.#G.opts,this.#B,this.#V);this.#u=t,this.#d=n,this.#f=r}else{let{backgroundTex:t,obstacleTex:n,coverageTex:r}=M(e,this.#G.bitmap,this.#N,this.#P,this.#G.effect,this.#G.size,this.#B,this.#V);this.#u=t,this.#d=n,this.#f=r}}this.#q=!0}}#ee(){this.#q&&!this.isRunning&&this.start()}#te(){if(this.#p)this.#_?.dispose(),this.#v?.dispose(),this.#b?.dispose(),this.#y?.tex.destroy(),this.#x?.tex.destroy(),this.#_=this.#v=this.#b=null,this.#y=this.#x=null;else{let e=this.#t;this.#a?.dispose(),this.#o?.dispose(),this.#c?.dispose(),this.#s&&(e.deleteTexture(this.#s.tex),e.deleteFramebuffer(this.#s.fbo)),this.#l&&(e.deleteTexture(this.#l.tex),e.deleteFramebuffer(this.#l.fbo)),this.#a=this.#o=this.#c=this.#s=this.#l=null}}#ne(){if(this.#p)this.#S&&=(this.#S.backgroundTex.destroy(),this.#S.obstacleTex.destroy(),this.#S.sharedCoverage||this.#S.coverageTex.destroy(),null);else{let e=this.#t;this.#u&&e.deleteTexture(this.#u),this.#d&&e.deleteTexture(this.#d),this.#f&&this.#f!==this.#d&&e.deleteTexture(this.#f),this.#u=this.#d=this.#f=null}}#re(){!this.#q||this.#N===0||(this.#p?this.#ie():this.#se())}#ie(){let e=this.#p,t=e.device,n=this.#m,i=this.#h,a=this.#g,o=this.#H,s=this.#S;if(!this.#_||!this.#v)return;this.#U.x+=(this.#U.targetX-this.#U.x)*.15,this.#U.y+=(this.#U.targetY-this.#U.y)*.15;let c=this.#F,l=this.#I,u=this.#N,d=this.#P,f=1/c,p=1/l;C(t,this.#C,f,p,B,o.velocityDissipation),w(t,this.#T,f,p),w(t,this.#E,f,p),w(t,this.#D,f,p),w(t,this.#A,f,p),T(t,this.#j,f,p,o.curl,B),D(t,this.#M,1/u,1/d,o.refraction,o.specularExp,r(o.waterColor),r(o.glowColor),o.shine,o.warpStrength??.015,V[o.algorithm]??0,this.#Y);let m=t.createCommandEncoder(),h=(e,n)=>t.createBindGroup({layout:e.getBindGroupLayout(0),entries:n}),g={binding:1,resource:a};{let e=h(n.advection,[{binding:0,resource:{buffer:this.#C}},g,{binding:2,resource:this.#v.read.view},{binding:3,resource:this.#v.read.view},{binding:4,resource:s.obstacleView}]);O(m,n.advection,e,i,this.#v.write.view)}this.#v.swap();{C(t,this.#w,f,p,B,o.densityDissipation);let e=h(n.advection,[{binding:0,resource:{buffer:this.#w}},g,{binding:2,resource:this.#v.read.view},{binding:3,resource:this.#_.read.view},{binding:4,resource:s.obstacleView}]);O(m,n.advection,e,i,this.#_.write.view)}this.#_.swap();{let e=h(n.curl,[{binding:0,resource:{buffer:this.#A}},g,{binding:2,resource:this.#v.read.view}]);O(m,n.curl,e,i,this.#x.view)}{let e=h(n.vorticity,[{binding:0,resource:{buffer:this.#j}},g,{binding:2,resource:this.#v.read.view},{binding:3,resource:this.#x.view}]);O(m,n.vorticity,e,i,this.#v.write.view)}if(this.#v.swap(),this.#U.moved){let e=this.#U.x*this.#L/u,r=this.#U.y*this.#L/d;E(t,this.#O,f,p,u/d,o.splatRadius,this.#U.dx*o.splatForce,this.#U.dy*o.splatForce,0,e,r);{let e=h(n.splat,[{binding:0,resource:{buffer:this.#O}},g,{binding:2,resource:this.#v.read.view}]);O(m,n.splat,e,i,this.#v.write.view)}this.#v.swap(),E(t,this.#k,f,p,u/d,o.splatRadius,1,1,1,e,r);{let e=h(n.splat,[{binding:0,resource:{buffer:this.#k}},g,{binding:2,resource:this.#_.read.view}]);O(m,n.splat,e,i,this.#_.write.view)}this.#_.swap(),this.#U.moved=!1}{let e=h(n.divergence,[{binding:0,resource:{buffer:this.#T}},g,{binding:2,resource:this.#v.read.view},{binding:3,resource:s.obstacleView}]);O(m,n.divergence,e,i,this.#y.view)}for(let e=0;e<o.pressureIterations;e++){let e=h(n.pressure,[{binding:0,resource:{buffer:this.#E}},g,{binding:2,resource:this.#b.read.view},{binding:3,resource:this.#y.view},{binding:4,resource:s.obstacleView}]);O(m,n.pressure,e,i,this.#b.write.view),this.#b.swap()}{let e=h(n.gradientSubtract,[{binding:0,resource:{buffer:this.#D}},g,{binding:2,resource:this.#b.read.view},{binding:3,resource:this.#v.read.view},{binding:4,resource:s.obstacleView}]);O(m,n.gradientSubtract,e,i,this.#v.write.view)}this.#v.swap();{let t=e.context.getCurrentTexture().createView(),r=h(n.display,[{binding:0,resource:{buffer:this.#M}},g,{binding:2,resource:this.#_.read.view},{binding:3,resource:s.obstacleView},{binding:4,resource:s.backgroundView},{binding:5,resource:s.coverageView},{binding:6,resource:this.#v.read.view}]);k(m,n.display,r,i,t)}t.queue.submit([m.finish()])}#ae(e,t,n,r,i){let a=this.#p.device,o=this.#m.splat,s=this.#h,c=this.#g,l=this.#H,u=this.#F,d=this.#I,f=1/u,p=1/d,m=a.createCommandEncoder(),h={binding:1,resource:c},g=e=>a.createBindGroup({layout:o.getBindGroupLayout(0),entries:e}),_=e*this.#L/this.#N,v=t*this.#L/this.#P;E(a,this.#O,f,p,this.#N/this.#P,l.splatRadius,n*l.splatForce*i,r*l.splatForce*i,0,_,v),O(m,o,g([{binding:0,resource:{buffer:this.#O}},h,{binding:2,resource:this.#v.read.view}]),s,this.#v.write.view),this.#v.swap(),E(a,this.#k,f,p,this.#N/this.#P,l.splatRadius,i,i,i,_,v),O(m,o,g([{binding:0,resource:{buffer:this.#k}},h,{binding:2,resource:this.#_.read.view}]),s,this.#_.write.view),this.#_.swap(),a.queue.submit([m.finish()])}#oe(e,t,n,r,i){let a=this.#t,o=this.#H,s=this.#r.splat,c=this.#i;a.viewport(0,0,this.#F,this.#I),s.bind(),a.uniform1f(s.uniforms.aspectRatio,this.#N/this.#P),a.uniform2f(s.uniforms.point,e*this.#L/this.#N,1-t*this.#L/this.#P),a.uniform1f(s.uniforms.radius,o.splatRadius),a.uniform1i(s.uniforms.uTarget,0),a.activeTexture(a.TEXTURE0),a.bindTexture(a.TEXTURE_2D,this.#o.read.tex),a.uniform3f(s.uniforms.color,n*o.splatForce*i,-r*o.splatForce*i,0),c(this.#o.write.fbo),this.#o.swap(),a.activeTexture(a.TEXTURE0),a.bindTexture(a.TEXTURE_2D,this.#a.read.tex),a.uniform3f(s.uniforms.color,i,i,i),c(this.#a.write.fbo),this.#a.swap()}#se(){if(!this.#a||!this.#o)return;let e=this.#t,t=this.#H,{advection:n,divergence:i,pressure:a,gradientSubtract:o,splat:s,curl:c,vorticity:l,display:u}=this.#r;this.#U.x+=(this.#U.targetX-this.#U.x)*.15,this.#U.y+=(this.#U.targetY-this.#U.y)*.15;let d=this.#F,f=this.#I,p=this.#i;e.viewport(0,0,d,f),n.bind(),e.uniform2f(n.uniforms.texelSize,1/d,1/f),e.uniform1f(n.uniforms.dt,B),e.uniform1i(n.uniforms.uObstacle,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#d),e.uniform1f(n.uniforms.dissipation,t.velocityDissipation),e.uniform1i(n.uniforms.uVelocity,1),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),e.uniform1i(n.uniforms.uSource,1),p(this.#o.write.fbo),this.#o.swap(),e.uniform1f(n.uniforms.dissipation,t.densityDissipation),e.uniform1i(n.uniforms.uSource,2),e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,this.#a.read.tex),p(this.#a.write.fbo),this.#a.swap(),c.bind(),e.uniform2f(c.uniforms.texelSize,1/d,1/f),e.uniform1i(c.uniforms.uVelocity,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),p(this.#l.fbo),l.bind(),e.uniform2f(l.uniforms.texelSize,1/d,1/f),e.uniform1f(l.uniforms.curl,t.curl),e.uniform1f(l.uniforms.dt,B),e.uniform1i(l.uniforms.uVelocity,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),e.uniform1i(l.uniforms.uCurl,1),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.#l.tex),p(this.#o.write.fbo),this.#o.swap(),this.#U.moved&&(s.bind(),e.uniform1f(s.uniforms.aspectRatio,this.#N/this.#P),e.uniform2f(s.uniforms.point,this.#U.x*this.#L/this.#N,1-this.#U.y*this.#L/this.#P),e.uniform1f(s.uniforms.radius,t.splatRadius),e.uniform1i(s.uniforms.uTarget,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),e.uniform3f(s.uniforms.color,this.#U.dx*t.splatForce,-this.#U.dy*t.splatForce,0),p(this.#o.write.fbo),this.#o.swap(),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#a.read.tex),e.uniform3f(s.uniforms.color,1,1,1),p(this.#a.write.fbo),this.#a.swap(),this.#U.moved=!1),i.bind(),e.uniform2f(i.uniforms.texelSize,1/d,1/f),e.uniform1i(i.uniforms.uVelocity,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),e.uniform1i(i.uniforms.uObstacle,1),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.#d),p(this.#s.fbo),a.bind(),e.uniform2f(a.uniforms.texelSize,1/d,1/f),e.uniform1i(a.uniforms.uDivergence,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#s.tex),e.uniform1i(a.uniforms.uObstacle,1),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.#d);for(let n=0;n<t.pressureIterations;n++)e.uniform1i(a.uniforms.uPressure,2),e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,this.#c.read.tex),p(this.#c.write.fbo),this.#c.swap();o.bind(),e.uniform2f(o.uniforms.texelSize,1/d,1/f),e.uniform1i(o.uniforms.uPressure,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#c.read.tex),e.uniform1i(o.uniforms.uVelocity,1),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),e.uniform1i(o.uniforms.uObstacle,2),e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,this.#d),p(this.#o.write.fbo),this.#o.swap(),e.viewport(0,0,this.#N,this.#P),e.bindFramebuffer(e.FRAMEBUFFER,null),e.clear(e.COLOR_BUFFER_BIT),u.bind(),e.uniform2f(u.uniforms.texelSize,1/this.#N,1/this.#P),e.uniform3fv(u.uniforms.uWaterColor,r(t.waterColor)),e.uniform3fv(u.uniforms.uGlowColor,r(t.glowColor)),e.uniform1f(u.uniforms.uRefraction,t.refraction),e.uniform1f(u.uniforms.uSpecularExp,t.specularExp),e.uniform1f(u.uniforms.uShine,t.shine),e.uniform1f(u.uniforms.uWarpStrength,t.warpStrength??.015),e.uniform1i(u.uniforms.uAlgorithm,V[t.algorithm]??0),e.uniform1i(u.uniforms.uEnableAlpha,+!!this.#Y),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#a.read.tex),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.#d),e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,this.#u),e.activeTexture(e.TEXTURE3),e.bindTexture(e.TEXTURE_2D,this.#f),e.activeTexture(e.TEXTURE4),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),e.uniform1i(u.uniforms.uTexture,0),e.uniform1i(u.uniforms.uObstacle,1),e.uniform1i(u.uniforms.uBackground,2),e.uniform1i(u.uniforms.uCoverage,3),e.uniform1i(u.uniforms.uVelocity,4),p(null)}};let U=null,W;const G=new Promise(e=>{W=e});self.onmessage=async e=>{let{type:t,...n}=e.data;try{switch(t){case`init`:{let{canvas:e,width:t,height:r,config:i,dpr:a,quality:o,useWebGPU:s,enableAlpha:c}=n;e.width=t,e.height=r,U=await H.create(e,i,o??{},s??!0,c??!0),U.resize(t,r,a||1),W(),self.postMessage({type:`ready`});break}case`setTextSource`:if(await G,!U)return;U.setTextSource(n.opts);break;case`setImageSource`:if(await G,!U)return;await U.setImageSource(n.src,n.effect,n.size);break;case`setImageBitmap`:if(await G,!U)return;U.setImageBitmap(n.bitmap,n.effect,n.size);break;case`setBackground`:if(await G,!U)return;U.setBackground(n.bitmap,n.size);break;case`splat`:if(await G,!U)return;U.splat(n.x,n.y,n.vx,n.vy,n.strength??1);break;case`move`:if(await G,!U)return;U.handleMove(n.x,n.y,n.strength??1);break;case`resize`:if(await G,!U)return;U.resize(n.width,n.height,n.dpr);break;case`updateQuality`:if(await G,!U)return;U.updateQuality(n.quality);break;case`updateConfig`:if(await G,!U)return;U.updateConfig(n.config);break;case`destroy`:await G,U?.destroy(),U=null;break;default:}}catch(e){self.postMessage({type:`error`,message:e?.message??String(e)})}};", ve = typeof self < "u" && self.Blob && new Blob(["URL.revokeObjectURL(import.meta.url);", _e], { type: "text/javascript;charset=utf-8" });
|
|
1040
|
+
}, _e = "const e={densityDissipation:.83,velocityDissipation:.91,pressureIterations:1,curl:0,splatRadius:.1,splatForce:.08,refraction:1,specularExp:0,shine:0,waterColor:`#000000`,glowColor:`#b3d9ff`,algorithm:`aurora`,warpStrength:.04};({...e}),typeof window<`u`&&1/(window.devicePixelRatio||1);const t={backgroundColor:`#0a0a0a`,backgroundSize:`cover`,mouseEnabled:!0,workerEnabled:!0};({...t}),{...t};const n={calm:{densityDissipation:.98,velocityDissipation:.81,curl:1e-4,splatRadius:.05,splatForce:.08,refraction:.15,shine:.03,glowColor:`#99d9ff`,waterColor:`#00050d`},sand:{densityDissipation:.95,velocityDissipation:.81,curl:1,splatRadius:.23,splatForce:.16,refraction:.8,specularExp:0,shine:.33,glowColor:`#070707`,waterColor:`#735420`},wave:{densityDissipation:.9,velocityDissipation:.2,curl:.2,splatRadius:.1,splatForce:.22,refraction:.35,shine:.2,glowColor:`#80ccff`,waterColor:`#000308`},neon:{densityDissipation:.75,velocityDissipation:.3,curl:.05,splatRadius:.18,splatForce:.29,refraction:.25,specularExp:.04,shine:.93,glowColor:`#ff33cc`,waterColor:`#0d0014`},smoke:{densityDissipation:.93,velocityDissipation:.71,curl:.04,splatRadius:.21,splatForce:.14,refraction:.08,shine:0,glowColor:`#808080`,waterColor:`#0f0f0f`}};function r(e){if(Array.isArray(e))return e;let t=e.slice(1,7);return t.length===3?[parseInt(t[0]+t[0],16)/255,parseInt(t[1]+t[1],16)/255,parseInt(t[2]+t[2],16)/255]:[parseInt(t.slice(0,2),16)/255,parseInt(t.slice(2,4),16)/255,parseInt(t.slice(4,6),16)/255]}function i(t={},r,i=e){return{...r?{...i,...n[r]}:i,...t}}const a=`precision highp float;\n attribute vec2 aPosition;\n varying vec2 vUv;\n varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB;\n uniform vec2 texelSize;\n void main () {\n vUv = aPosition * 0.5 + 0.5;\n vL = vUv - vec2(texelSize.x, 0.0);\n vR = vUv + vec2(texelSize.x, 0.0);\n vT = vUv + vec2(0.0, texelSize.y);\n vB = vUv - vec2(0.0, texelSize.y);\n gl_Position = vec4(aPosition, 0.0, 1.0);\n }`;function o(e,t=!0){let n={alpha:t,depth:!1,stencil:!1,antialias:!0,preserveDrawingBuffer:!1},r=e.getContext(`webgl2`,n),i=!!r;i||(r=e.getContext(`webgl`,n),r.getExtension(`EXT_color_buffer_half_float`));let a=i?null:r.getExtension(`OES_texture_half_float`),o=i?r.HALF_FLOAT:a.HALF_FLOAT_OES;return r.getExtension(`EXT_color_buffer_float`),r.getExtension(`OES_texture_half_float_linear`),{type:i?`webgl2`:`webgl1`,gl:r,isWebGL2:i,ext:{internalFormat:i?r.RGBA16F:r.RGBA,format:r.RGBA,type:o}}}async function s(e,t=!0){if(typeof navigator>`u`||!navigator.gpu)return null;try{let n=await navigator.gpu.requestAdapter();if(!n)return null;let r=await n.requestDevice(),i=e.getContext(`webgpu`);if(!i)return null;let a=navigator.gpu.getPreferredCanvasFormat();return i.configure({device:r,format:a,alphaMode:t?`premultiplied`:`opaque`}),{type:`webgpu`,adapter:n,device:r,context:i,format:a}}catch{return null}}var c=class{program;uniforms={};_gl;constructor(e,t,n){this._gl=e,this.program=e.createProgram(),e.attachShader(this.program,this._compile(e.VERTEX_SHADER,t)),e.attachShader(this.program,this._compile(e.FRAGMENT_SHADER,n)),e.linkProgram(this.program);let r=e.getProgramParameter(this.program,e.ACTIVE_UNIFORMS);for(let t=0;t<r;t++){let n=e.getActiveUniform(this.program,t).name;this.uniforms[n]=e.getUniformLocation(this.program,n)}}_compile(e,t){let n=this._gl,r=n.createShader(e);return n.shaderSource(r,t),n.compileShader(r),r}bind(){this._gl.useProgram(this.program)}dispose(){this._gl.deleteProgram(this.program)}};function l(e){return{advection:new c(e,a,`precision highp float;\n varying vec2 vUv;\n uniform sampler2D uVelocity;\n uniform sampler2D uSource;\n uniform sampler2D uObstacle;\n uniform vec2 texelSize;\n uniform float dt;\n uniform float dissipation;\n void main () {\n float obs = texture2D(uObstacle, vUv).r;\n vec2 coord = vUv - dt * texture2D(uVelocity, vUv).xy * texelSize;\n \n \n \n gl_FragColor = dissipation * texture2D(uSource, coord) * (1.0 - obs);\n }`),divergence:new c(e,a,`precision highp float;\n varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB;\n uniform sampler2D uVelocity;\n uniform sampler2D uObstacle;\n void main () {\n float L = texture2D(uVelocity, vL).x * (1.0 - texture2D(uObstacle, vL).r);\n float R = texture2D(uVelocity, vR).x * (1.0 - texture2D(uObstacle, vR).r);\n float T = texture2D(uVelocity, vT).y * (1.0 - texture2D(uObstacle, vT).r);\n float B = texture2D(uVelocity, vB).y * (1.0 - texture2D(uObstacle, vB).r);\n gl_FragColor = vec4(0.5 * (R - L + T - B), 0.0, 0.0, 1.0);\n }`),pressure:new c(e,a,`precision highp float;\n varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB;\n uniform sampler2D uPressure;\n uniform sampler2D uDivergence;\n uniform sampler2D uObstacle;\n void main () {\n float C = texture2D(uPressure, vUv).x;\n float L = mix(texture2D(uPressure, vL).x, C, texture2D(uObstacle, vL).r);\n float R = mix(texture2D(uPressure, vR).x, C, texture2D(uObstacle, vR).r);\n float T = mix(texture2D(uPressure, vT).x, C, texture2D(uObstacle, vT).r);\n float B = mix(texture2D(uPressure, vB).x, C, texture2D(uObstacle, vB).r);\n float div = texture2D(uDivergence, vUv).x;\n gl_FragColor = vec4((L + R + B + T - div) * 0.25, 0.0, 0.0, 1.0);\n }`),gradientSubtract:new c(e,a,`precision highp float;\n varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB;\n uniform sampler2D uPressure;\n uniform sampler2D uVelocity;\n uniform sampler2D uObstacle;\n void main () {\n float obs = texture2D(uObstacle, vUv).r;\n float C = texture2D(uPressure, vUv).x;\n float L = mix(texture2D(uPressure, vL).x, C, texture2D(uObstacle, vL).r);\n float R = mix(texture2D(uPressure, vR).x, C, texture2D(uObstacle, vR).r);\n float T = mix(texture2D(uPressure, vT).x, C, texture2D(uObstacle, vT).r);\n float B = mix(texture2D(uPressure, vB).x, C, texture2D(uObstacle, vB).r);\n vec2 vel = (texture2D(uVelocity, vUv).xy - vec2(R - L, T - B)) * (1.0 - obs);\n gl_FragColor = vec4(vel, 0.0, 1.0);\n }`),splat:new c(e,a,`precision highp float;\n varying vec2 vUv;\n uniform sampler2D uTarget;\n uniform float aspectRatio;\n uniform vec3 color;\n uniform vec2 point;\n uniform float radius;\n void main () {\n vec2 p = vUv - point.xy;\n p.x *= aspectRatio;\n vec3 splat = exp(-dot(p, p) / radius) * color;\n gl_FragColor = vec4(texture2D(uTarget, vUv).xyz + splat, 1.0);\n }`),curl:new c(e,a,`precision highp float;\n varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB;\n uniform sampler2D uVelocity;\n void 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 gl_FragColor = vec4(0.5 * (R - L - T + B), 0.0, 0.0, 1.0);\n }`),vorticity:new c(e,a,`precision highp float;\n varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB;\n uniform sampler2D uVelocity;\n uniform sampler2D uCurl;\n uniform float curl;\n uniform float dt;\n void 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 = 0.5 * vec2(abs(T) - abs(B), abs(R) - abs(L));\n force /= length(force) + 0.0001;\n force *= curl * 30.0 * C;\n gl_FragColor = vec4(texture2D(uVelocity, vUv).xy + force * dt, 0.0, 1.0);\n }`),display:new c(e,a,`precision highp float;\n varying vec2 vUv;\n uniform sampler2D uTexture;\n uniform sampler2D uObstacle;\n uniform sampler2D uBackground;\n uniform sampler2D uCoverage;\n uniform sampler2D uVelocity;\n uniform vec2 texelSize;\n uniform vec3 uWaterColor;\n uniform vec3 uGlowColor;\n uniform float uRefraction;\n uniform float uSpecularExp;\n uniform float uShine;\n uniform float uWarpStrength;\n uniform int uAlgorithm;\n uniform int uEnableAlpha;\n void main () {\n float obs = texture2D(uObstacle, vUv).r;\n \n \n float density = max(texture2D(uTexture, vUv).r, 0.0) * (1.0 - obs);\n float coverage = texture2D(uCoverage, vUv).r;\n \n \n \n \n float sx = texelSize.x * 6.0, sy = texelSize.y * 6.0;\n float d00 = max(texture2D(uTexture, vUv + vec2(-sx, -sy)).r, 0.0);\n float d10 = max(texture2D(uTexture, vUv + vec2(0.0, -sy)).r, 0.0);\n float d20 = max(texture2D(uTexture, vUv + vec2( sx, -sy)).r, 0.0);\n float d01 = max(texture2D(uTexture, vUv + vec2(-sx, 0.0)).r, 0.0);\n float d21 = max(texture2D(uTexture, vUv + vec2( sx, 0.0)).r, 0.0);\n float d02 = max(texture2D(uTexture, vUv + vec2(-sx, sy)).r, 0.0);\n float d12 = max(texture2D(uTexture, vUv + vec2(0.0, sy)).r, 0.0);\n float d22 = max(texture2D(uTexture, vUv + vec2( sx, sy)).r, 0.0);\n float gx = (d20 + 2.0*d21 + d22) - (d00 + 2.0*d01 + d02);\n float gy = (d02 + 2.0*d12 + d22) - (d00 + 2.0*d10 + d20);\n vec3 normal = normalize(vec3(gx, gy, 1.2));\n vec3 lightDir = normalize(vec3(0.5, 1.0, 0.5));\n vec3 halfV = normalize(lightDir + vec3(0.0, 0.0, 1.0));\n \n \n float specDen = density * min(density * 5.0, 1.0);\n float spec = pow(max(dot(normal, halfV), 0.0), uSpecularExp) * uShine * specDen;\n \n \n \n vec3 bgRaw = texture2D(uBackground, vUv).rgb;\n vec3 bg = mix(uWaterColor, bgRaw, coverage);\n vec3 color = bg;\n if (uAlgorithm == 1) {\n \n \n vec2 refrUv = clamp(vUv + normal.xy * uRefraction * density * 3.0, 0.0, 1.0);\n vec3 refrBg = mix(uWaterColor, texture2D(uBackground, mix(vUv, refrUv, 1.0 - obs)).rgb, coverage);\n color = refrBg + spec * uGlowColor * 2.5;\n color = mix(color, bg * 0.6, obs * 0.3);\n } else if (uAlgorithm == 2) {\n \n \n float inkD = min(density * 4.0, 1.0);\n vec2 refrUv = clamp(vUv + normal.xy * uRefraction * density * 0.4, 0.0, 1.0);\n vec3 refrBg = mix(uWaterColor, texture2D(uBackground, mix(vUv, refrUv, 1.0 - obs)).rgb, coverage);\n color = mix(refrBg, uWaterColor + spec * uGlowColor, inkD);\n color = mix(color, bg * 0.5, obs * 0.15);\n } else if (uAlgorithm == 3) {\n \n \n vec2 vel = texture2D(uVelocity, vUv).xy;\n float velMag = clamp(length(vel) * 20.0, 0.0, 1.0);\n vec2 warpUv = clamp(vUv + vel * uWarpStrength, 0.0, 1.0);\n vec3 warpBg = mix(uWaterColor, texture2D(uBackground, warpUv).rgb, coverage);\n color = mix(bg, warpBg, velMag * (1.0 - obs));\n color += spec * uGlowColor * velMag * 1.5;\n color += uWaterColor * density * 0.3;\n color = mix(color, bg * 0.5, obs * 0.2);\n } else if (uAlgorithm == 4) {\n \n \n vec2 rippleUv = clamp(vUv + normal.xy * uRefraction * density * 6.0, 0.0, 1.0);\n vec3 refrBg = mix(uWaterColor, texture2D(uBackground, mix(vUv, rippleUv, 1.0 - obs)).rgb, coverage);\n float fresnel = pow(clamp(1.0 - dot(normal, vec3(0.0, 0.0, 1.0)), 0.0, 1.0), 3.0) * density;\n color = refrBg;\n color += fresnel * uGlowColor * 2.0;\n color += spec * uGlowColor * density * 2.0;\n color = mix(color, bg * 0.5, obs * 0.2);\n } else {\n \n \n vec2 refrUv = vUv + normal.xy * uRefraction * density;\n vec3 refrBg = mix(uWaterColor, texture2D(uBackground, mix(vUv, refrUv, 1.0 - obs)).rgb, coverage);\n color = mix(refrBg, uWaterColor, min(density * 1.5, 0.8));\n color += spec * uGlowColor;\n color = mix(color, bg * 0.5, obs * 0.2);\n }\n \n \n float alpha = clamp(max(density * 1.5, coverage), 0.0, 1.0);\n if (uEnableAlpha == 1) {\n gl_FragColor = vec4(color * alpha, alpha);\n } else {\n gl_FragColor = vec4(color, 1.0);\n }\n }`)}}function u(e,t,n,r){e.activeTexture(e.TEXTURE0);let i=e.createTexture();e.bindTexture(e.TEXTURE_2D,i),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texImage2D(e.TEXTURE_2D,0,t.internalFormat,n,r,0,t.format,t.type,null);let a=e.createFramebuffer();return e.bindFramebuffer(e.FRAMEBUFFER,a),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,i,0),{tex:i,fbo:a,width:n,height:r}}function d(e,t,n,r){let i=u(e,t,n,r),a=u(e,t,n,r);return{get read(){return i},get write(){return a},swap(){[i,a]=[a,i]},dispose(){e.deleteTexture(i.tex),e.deleteFramebuffer(i.fbo),e.deleteTexture(a.tex),e.deleteFramebuffer(a.fbo)}}}function f(e){let t=e.createBuffer();return e.bindBuffer(e.ARRAY_BUFFER,t),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,-1,1,1,1,1,-1]),e.STATIC_DRAW),e.vertexAttribPointer(0,2,e.FLOAT,!1,0,0),e.enableVertexAttribArray(0),function(t){e.bindFramebuffer(e.FRAMEBUFFER,t),e.drawArrays(e.TRIANGLE_FAN,0,4)}}const p={arrayStride:8,attributes:[{shaderLocation:0,offset:0,format:`float32x2`}]},m=new Float32Array([-1,-1,-1,1,1,-1,1,-1,-1,1,1,1]);function h(e){let t=e.createBuffer({size:m.byteLength,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST});return e.queue.writeBuffer(t,0,m),t}function g(e,t,n,r){let i=e.createTexture({size:[n,r],format:t,usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC});return{tex:i,view:i.createView(),width:n,height:r}}function _(e,t,n,r){let i=g(e,t,n,r),a=g(e,t,n,r);return{get read(){return i},get write(){return a},swap(){[i,a]=[a,i]},dispose(){i.tex.destroy(),a.tex.destroy()}}}function v(e,t,n,r){let i=e.createShaderModule({code:t});return e.createRenderPipeline({layout:`auto`,vertex:{module:i,entryPoint:`vs`,buffers:[p]},fragment:{module:i,entryPoint:`fs`,targets:[{format:n,...r?{blend:r}:{}}]},primitive:{topology:`triangle-list`}})}const y={color:{operation:`add`,srcFactor:`one`,dstFactor:`zero`},alpha:{operation:`add`,srcFactor:`one`,dstFactor:`zero`}};function b(e,t,n=!0){let r=`rgba16float`;return{advection:v(e,`struct U {\n texelSize : vec2f,\n dt : f32,\n dissipation: f32,\n}\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uVel : texture_2d<f32>;\n@group(0) @binding(3) var uSrc : texture_2d<f32>;\n@group(0) @binding(4) var uObs : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let obs = textureSample(uObs, samp, i.uv).r;\n let vel = textureSample(uVel, samp, i.uv).xy;\n let coord = i.uv - u.dt * vel * u.texelSize;\n let src = textureSample(uSrc, samp, coord);\n return u.dissipation * src * (1.0 - obs);\n}`,r),divergence:v(e,`struct U { texelSize: vec2f, _pad: vec2f }\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uVel : texture_2d<f32>;\n@group(0) @binding(3) var uObs : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let L = textureSample(uVel, samp, i.vL).x * (1.0 - textureSample(uObs, samp, i.vL).r);\n let R = textureSample(uVel, samp, i.vR).x * (1.0 - textureSample(uObs, samp, i.vR).r);\n let T = textureSample(uVel, samp, i.vT).y * (1.0 - textureSample(uObs, samp, i.vT).r);\n let B = textureSample(uVel, samp, i.vB).y * (1.0 - textureSample(uObs, samp, i.vB).r);\n return vec4f(0.5 * (R - L + T - B), 0.0, 0.0, 1.0);\n}`,r),pressure:v(e,`struct U { texelSize: vec2f, _pad: vec2f }\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uPres: texture_2d<f32>;\n@group(0) @binding(3) var uDiv : texture_2d<f32>;\n@group(0) @binding(4) var uObs : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let C = textureSample(uPres, samp, i.uv).x;\n let L = mix(textureSample(uPres, samp, i.vL).x, C, textureSample(uObs, samp, i.vL).r);\n let R = mix(textureSample(uPres, samp, i.vR).x, C, textureSample(uObs, samp, i.vR).r);\n let T = mix(textureSample(uPres, samp, i.vT).x, C, textureSample(uObs, samp, i.vT).r);\n let B = mix(textureSample(uPres, samp, i.vB).x, C, textureSample(uObs, samp, i.vB).r);\n let dv = textureSample(uDiv, samp, i.uv).x;\n return vec4f((L + R + B + T - dv) * 0.25, 0.0, 0.0, 1.0);\n}`,r),gradientSubtract:v(e,`struct U { texelSize: vec2f, _pad: vec2f }\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uPres: texture_2d<f32>;\n@group(0) @binding(3) var uVel : texture_2d<f32>;\n@group(0) @binding(4) var uObs : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let obs = textureSample(uObs, samp, i.uv).r;\n let C = textureSample(uPres, samp, i.uv).x;\n let L = mix(textureSample(uPres, samp, i.vL).x, C, textureSample(uObs, samp, i.vL).r);\n let R = mix(textureSample(uPres, samp, i.vR).x, C, textureSample(uObs, samp, i.vR).r);\n let T = mix(textureSample(uPres, samp, i.vT).x, C, textureSample(uObs, samp, i.vT).r);\n let B = mix(textureSample(uPres, samp, i.vB).x, C, textureSample(uObs, samp, i.vB).r);\n let vel = (textureSample(uVel, samp, i.uv).xy - vec2f(R - L, T - B)) * (1.0 - obs);\n return vec4f(vel, 0.0, 1.0);\n}`,r),splat:v(e,`struct U {\n texelSize : vec2f,\n aspectRatio: f32,\n radius : f32,\n color : vec4f, \n point : vec2f,\n _pad : vec2f,\n}\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uTgt : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n var p = i.uv - u.point;\n p.x *= u.aspectRatio;\n let sp = exp(-dot(p, p) / u.radius) * u.color.xyz;\n return vec4f(textureSample(uTgt, samp, i.uv).xyz + sp, 1.0);\n}`,r),curl:v(e,`struct U { texelSize: vec2f, _pad: vec2f }\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uVel : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let L = textureSample(uVel, samp, i.vL).y;\n let R = textureSample(uVel, samp, i.vR).y;\n let T = textureSample(uVel, samp, i.vT).x;\n let B = textureSample(uVel, samp, i.vB).x;\n return vec4f(0.5 * (R - L - T + B), 0.0, 0.0, 1.0);\n}`,r),vorticity:v(e,`struct U {\n texelSize: vec2f,\n curl : f32,\n dt : f32,\n}\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uVel : texture_2d<f32>;\n@group(0) @binding(3) var uCrl : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let L = textureSample(uCrl, samp, i.vL).x;\n let R = textureSample(uCrl, samp, i.vR).x;\n let T = textureSample(uCrl, samp, i.vT).x;\n let B = textureSample(uCrl, samp, i.vB).x;\n let C = textureSample(uCrl, samp, i.uv).x;\n var force = 0.5 * vec2f(abs(T) - abs(B), abs(R) - abs(L));\n force /= length(force) + 0.0001;\n force *= u.curl * 30.0 * C;\n let vel = textureSample(uVel, samp, i.uv).xy + force * u.dt;\n return vec4f(vel, 0.0, 1.0);\n}`,r),display:v(e,`struct U {\n texelSize : vec2f,\n refraction : f32,\n specularExp : f32,\n waterColor : vec4f,\n glowColor : vec4f,\n shine : f32,\n warpStrength: f32,\n algorithm : i32,\n enableAlpha : i32,\n}\n@group(0) @binding(0) var<uniform> u : U;\n@group(0) @binding(1) var samp : sampler;\n@group(0) @binding(2) var uTex : texture_2d<f32>;\n@group(0) @binding(3) var uObs : texture_2d<f32>;\n@group(0) @binding(4) var uBg : texture_2d<f32>;\n@group(0) @binding(5) var uCov : texture_2d<f32>;\n@group(0) @binding(6) var uVel : texture_2d<f32>;\n@vertex fn vs(@location(0) a: vec2f) -> VSOut {\n var o: VSOut;\n o.uv = vec2f(a.x * 0.5 + 0.5, 0.5 - a.y * 0.5);\n o.vL = o.uv - vec2f(u.texelSize.x, 0.0);\n o.vR = o.uv + vec2f(u.texelSize.x, 0.0);\n o.vT = o.uv + vec2f(0.0, u.texelSize.y);\n o.vB = o.uv - vec2f(0.0, u.texelSize.y);\n o.pos = vec4f(a, 0.0, 1.0);\n return o;\n}\n@fragment fn fs(i: VSOut) -> @location(0) vec4f {\n let obs = textureSample(uObs, samp, i.uv).r;\n let density = max(textureSample(uTex, samp, i.uv).r, 0.0) * (1.0 - obs);\n let cov = textureSample(uCov, samp, i.uv).r;\n let sx = u.texelSize.x * 6.0;\n let sy = u.texelSize.y * 6.0;\n let d00 = max(textureSample(uTex, samp, i.uv + vec2f(-sx, -sy)).r, 0.0);\n let d10 = max(textureSample(uTex, samp, i.uv + vec2f(0.0, -sy)).r, 0.0);\n let d20 = max(textureSample(uTex, samp, i.uv + vec2f( sx, -sy)).r, 0.0);\n let d01 = max(textureSample(uTex, samp, i.uv + vec2f(-sx, 0.0)).r, 0.0);\n let d21 = max(textureSample(uTex, samp, i.uv + vec2f( sx, 0.0)).r, 0.0);\n let d02 = max(textureSample(uTex, samp, i.uv + vec2f(-sx, sy)).r, 0.0);\n let d12 = max(textureSample(uTex, samp, i.uv + vec2f(0.0, sy)).r, 0.0);\n let d22 = max(textureSample(uTex, samp, i.uv + vec2f( sx, sy)).r, 0.0);\n let gx = (d20 + 2.0*d21 + d22) - (d00 + 2.0*d01 + d02);\n let gy = (d02 + 2.0*d12 + d22) - (d00 + 2.0*d10 + d20);\n let norm = normalize(vec3f(gx, gy, 1.2));\n let ldir = normalize(vec3f(0.5, 1.0, 0.5));\n let halfV = normalize(ldir + vec3f(0.0, 0.0, 1.0));\n let specDen = density * min(density * 5.0, 1.0);\n let spec = pow(max(dot(norm, halfV), 0.0), u.specularExp) * u.shine * specDen;\n let bgRaw = textureSample(uBg, samp, i.uv).rgb;\n let wc = u.waterColor.rgb;\n let gc = u.glowColor.rgb;\n let bg = mix(wc, bgRaw, cov);\n var color = bg;\n if (u.algorithm == 1) {\n let ruv = clamp(i.uv + norm.xy * u.refraction * density * 3.0, vec2f(0.0), vec2f(1.0));\n let rbg = mix(wc, textureSample(uBg, samp, mix(i.uv, ruv, 1.0 - obs)).rgb, cov);\n color = rbg + spec * gc * 2.5;\n color = mix(color, bg * 0.6, obs * 0.3);\n } else if (u.algorithm == 2) {\n let inkD = min(density * 4.0, 1.0);\n let ruv = clamp(i.uv + norm.xy * u.refraction * density * 0.4, vec2f(0.0), vec2f(1.0));\n let rbg = mix(wc, textureSample(uBg, samp, mix(i.uv, ruv, 1.0 - obs)).rgb, cov);\n color = mix(rbg, wc + spec * gc, inkD);\n color = mix(color, bg * 0.5, obs * 0.15);\n } else if (u.algorithm == 3) {\n let vel = textureSample(uVel, samp, i.uv).xy;\n let velMag = clamp(length(vel) * 20.0, 0.0, 1.0);\n let wuv = clamp(i.uv + vel * u.warpStrength, vec2f(0.0), vec2f(1.0));\n let wbg = mix(wc, textureSample(uBg, samp, wuv).rgb, cov);\n color = mix(bg, wbg, velMag * (1.0 - obs));\n color += spec * gc * velMag * 1.5;\n color += wc * density * 0.3;\n color = mix(color, bg * 0.5, obs * 0.2);\n } else if (u.algorithm == 4) {\n let ruv = clamp(i.uv + norm.xy * u.refraction * density * 6.0, vec2f(0.0), vec2f(1.0));\n let rbg = mix(wc, textureSample(uBg, samp, mix(i.uv, ruv, 1.0 - obs)).rgb, cov);\n let fres = pow(clamp(1.0 - dot(norm, vec3f(0.0, 0.0, 1.0)), 0.0, 1.0), 3.0) * density;\n color = rbg;\n color += fres * gc * 2.0;\n color += spec * gc * density * 2.0;\n color = mix(color, bg * 0.5, obs * 0.2);\n } else {\n let ruv = i.uv + norm.xy * u.refraction * density;\n let rbg = mix(wc, textureSample(uBg, samp, mix(i.uv, ruv, 1.0 - obs)).rgb, cov);\n color = mix(rbg, wc, min(density * 1.5, 0.8));\n color += spec * gc;\n color = mix(color, bg * 0.5, obs * 0.2);\n }\n let alpha = clamp(max(density * 1.5, cov), 0.0, 1.0);\n if (u.enableAlpha == 1) {\n return vec4f(color * alpha, alpha);\n }\n return vec4f(color, 1.0);\n}`,t,n?void 0:y)}}function x(e){return e.createSampler({magFilter:`linear`,minFilter:`linear`,addressModeU:`clamp-to-edge`,addressModeV:`clamp-to-edge`})}function S(e,t){return e.createBuffer({size:t,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST})}function C(e,t,n,r,i,a){let o=new Float32Array([n,r,i,a]);e.queue.writeBuffer(t,0,o)}function w(e,t,n,r){let i=new Float32Array([n,r,0,0]);e.queue.writeBuffer(t,0,i)}function T(e,t,n,r,i,a){let o=new Float32Array([n,r,i,a]);e.queue.writeBuffer(t,0,o)}function E(e,t,n,r,i,a,o,s,c,l,u){let d=new Float32Array(12);d[0]=n,d[1]=r,d[2]=i,d[3]=a,d[4]=o,d[5]=s,d[6]=c,d[7]=0,d[8]=l,d[9]=u,d[10]=0,d[11]=0,e.queue.writeBuffer(t,0,d)}function D(e,t,n,r,i,a,o,s,c,l,u,d){let f=new Float32Array(16),p=new Int32Array(f.buffer);f[0]=n,f[1]=r,f[2]=i,f[3]=a,f[4]=o[0],f[5]=o[1],f[6]=o[2],f[7]=0,f[8]=s[0],f[9]=s[1],f[10]=s[2],f[11]=0,f[12]=c,f[13]=l,p[14]=u,p[15]=+!!d,e.queue.writeBuffer(t,0,f)}function O(e,t,n,r,i){let a=e.beginRenderPass({colorAttachments:[{view:i,clearValue:[0,0,0,0],loadOp:`clear`,storeOp:`store`}]});a.setPipeline(t),a.setBindGroup(0,n),a.setVertexBuffer(0,r),a.draw(6),a.end()}function k(e,t,n,r,i){let a=e.beginRenderPass({colorAttachments:[{view:i,clearValue:[0,0,0,0],loadOp:`clear`,storeOp:`store`}]});a.setPipeline(t),a.setBindGroup(0,n),a.setVertexBuffer(0,r),a.draw(6),a.end()}function A(e,t,n,r,i=`cover`){let a;a=i===`cover`?Math.max(n/e,r/t):i===`contain`?Math.min(n/e,r/t):typeof i==`string`&&i.endsWith(`%`)?Math.min(n/e,r/t)*(parseFloat(i)/100):typeof i==`string`&&i.endsWith(`px`)?parseFloat(i)/Math.max(e,t):typeof i==`number`?i:Math.max(n/e,r/t);let o=e*a,s=t*a;return{x:(n-o)/2,y:(r-s)/2,drawW:o,drawH:s}}function j(e,t,n,r,i=null,a=`cover`){let{text:o,fontSize:s,color:c,fontFamily:l=`sans-serif`,fontWeight:u=900}=r,d=new OffscreenCanvas(t,n),f=d.getContext(`2d`);(e=>{if(i){f.clearRect(0,0,t,n),f.fillStyle=`black`,f.fillRect(0,0,t,n);let{x:e,y:r,drawW:o,drawH:s}=A(i.width,i.height,t,n,a);f.drawImage(i,e,r,o,s);return}f.fillStyle=e,f.fillRect(0,0,t,n),f.font=`${u} ${s}px ${l}`,f.textAlign=`center`,f.textBaseline=`middle`,f.fillText(o,t/2,n/2)})(c);let p=N(e,d);f.fillStyle=`black`,f.fillRect(0,0,t,n),f.fillStyle=`white`,f.font=`${u} ${s}px ${l}`,f.textAlign=`center`,f.textBaseline=`middle`,f.fillText(o,t/2,n/2);let m=N(e,d);return{backgroundTex:p,obstacleTex:m,coverageTex:m}}function M(e,t,n,r,i=0,a=`cover`,o=null,s=`cover`){let c=new OffscreenCanvas(n,r),l=c.getContext(`2d`),{x:u,y:d,drawW:f,drawH:p}=A(t.width,t.height,n,r,a);if(l.clearRect(0,0,n,r),l.fillStyle=`black`,l.fillRect(0,0,n,r),o){let{x:e,y:t,drawW:a,drawH:c}=A(o.width,o.height,n,r,s);l.filter=`brightness(${i}) blur(8px)`,l.drawImage(o,e,t,a,c),l.filter=`none`}l.drawImage(t,u,d,f,p);let m=N(e,c);l.clearRect(0,0,n,r),l.fillStyle=`black`,l.fillRect(0,0,n,r),l.filter=`brightness(${i}) blur(8px)`,l.drawImage(t,u,d,f,p),l.filter=`none`;let h=N(e,c);return l.clearRect(0,0,n,r),l.fillStyle=`black`,l.fillRect(0,0,n,r),l.fillStyle=`white`,l.fillRect(Math.max(0,u),Math.max(0,d),Math.min(f,n-Math.max(0,u)),Math.min(p,r-Math.max(0,d))),{backgroundTex:m,obstacleTex:h,coverageTex:N(e,c)}}function N(e,t){let n=e.createTexture();return e.bindTexture(e.TEXTURE_2D,n),e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,!0),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),n}function P(e,t,n,r,i=null,a=`cover`){let{text:o,fontSize:s,color:c,fontFamily:l=`sans-serif`,fontWeight:u=900}=r,d=new OffscreenCanvas(t,n),f=d.getContext(`2d`);(e=>{if(i){f.clearRect(0,0,t,n),f.fillStyle=`black`,f.fillRect(0,0,t,n);let{x:e,y:r,drawW:o,drawH:s}=A(i.width,i.height,t,n,a);f.drawImage(i,e,r,o,s);return}f.fillStyle=e,f.fillRect(0,0,t,n),f.font=`${u} ${s}px ${l}`,f.textAlign=`center`,f.textBaseline=`middle`,f.fillText(o,t/2,n/2)})(c);let p=I(e,d,t,n);f.fillStyle=`black`,f.fillRect(0,0,t,n),f.fillStyle=`white`,f.font=`${u} ${s}px ${l}`,f.textAlign=`center`,f.textBaseline=`middle`,f.fillText(o,t/2,n/2);let m=I(e,d,t,n);return{backgroundTex:p,backgroundView:p.createView(),obstacleTex:m,obstacleView:m.createView(),coverageTex:m,coverageView:m.createView(),sharedCoverage:!0}}function F(e,t,n,r,i=0,a=`cover`,o=null,s=`cover`){let c=new OffscreenCanvas(n,r),l=c.getContext(`2d`),{x:u,y:d,drawW:f,drawH:p}=A(t.width,t.height,n,r,a);if(l.clearRect(0,0,n,r),l.fillStyle=`black`,l.fillRect(0,0,n,r),o){let{x:e,y:t,drawW:a,drawH:c}=A(o.width,o.height,n,r,s);l.filter=`brightness(${i}) blur(8px)`,l.drawImage(o,e,t,a,c),l.filter=`none`}l.drawImage(t,u,d,f,p);let m=I(e,c,n,r);l.clearRect(0,0,n,r),l.fillStyle=`black`,l.fillRect(0,0,n,r),l.filter=`brightness(${i}) blur(8px)`,l.drawImage(t,u,d,f,p),l.filter=`none`;let h=I(e,c,n,r);l.clearRect(0,0,n,r),l.fillStyle=`black`,l.fillRect(0,0,n,r),l.fillStyle=`white`,l.fillRect(Math.max(0,u),Math.max(0,d),Math.min(f,n-Math.max(0,u)),Math.min(p,r-Math.max(0,d)));let g=I(e,c,n,r);return{backgroundTex:m,backgroundView:m.createView(),obstacleTex:h,obstacleView:h.createView(),coverageTex:g,coverageView:g.createView(),sharedCoverage:!1}}function I(e,t,n,r){let i=e.createTexture({size:[n,r],format:`rgba8unorm`,usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});return e.queue.copyExternalImageToTexture({source:t},{texture:i},[n,r]),i}async function L(e){let t=await fetch(e);if(!t.ok)throw Error(`Failed to fetch image: ${e} (${t.status})`);let n=await t.blob();return createImageBitmap(n)}const R=typeof requestAnimationFrame<`u`?requestAnimationFrame.bind(globalThis):e=>setTimeout(e,1e3/60),z=typeof cancelAnimationFrame<`u`?cancelAnimationFrame.bind(globalThis):clearTimeout,B=.016,V={standard:0,glass:1,ink:2,aurora:3,ripple:4};var H=class e{#e;#t=null;#n=null;#r=null;#i=null;#a=null;#o=null;#s=null;#c=null;#l=null;#u=null;#d=null;#f=null;#p=null;#m=null;#h=null;#g=null;#_=null;#v=null;#y=null;#b=null;#x=null;#S=null;#C=null;#w=null;#T=null;#E=null;#D=null;#O=null;#k=null;#A=null;#j=null;#M=null;#N=0;#P=0;#F=0;#I=0;#L=1;#R=1;#z=.5;#B=null;#V=`cover`;#H;#U={x:0,y:0,dx:0,dy:0,targetX:0,targetY:0,moved:!1};#W=!1;#G=null;#K=null;#q=!1;#J=!1;#Y=!0;constructor(e,t={},n={},r,a=!0){if(this.#e=e,this.#R=Math.max(.1,Math.min(1,n.dpr??1)),this.#z=Math.max(.1,Math.min(1,n.sim??.5)),this.#H=i(t),this.#Y=a,r)this.#p=r,this.#X(r);else{let{gl:t,ext:n}=o(e,a);this.#t=t,this.#n=n,this.#r=l(t),this.#i=f(t),t.clearColor(0,0,0,+!a)}}static async create(t,n={},r={},i=!0,a=!0){return new e(t,n,r,(i?await s(t,a):null)??void 0,a)}setTextSource(e){this.#G={type:`text`,opts:e},this.#Z(),this.#$(),this.#ee()}async setImageSource(e,t=0,n=`cover`){let r=await L(e);if(this.#J){r.close();return}this.#G={type:`image`,bitmap:r,effect:t,size:n},this.#Z(),this.#$(),this.#ee()}setImageBitmap(e,t=0,n=`cover`){this.#G={type:`image`,bitmap:e,effect:t,size:n},this.#Z(),this.#$(),this.#ee()}setBackground(e,t=`cover`){this.#B&&this.#B!==e&&this.#B.close(),this.#B=e,this.#V=t??`cover`,this.#G&&this.#N>0&&this.#P>0&&this.#$()}handleMove(e,t,n=1){if(!this.#W){this.#U.x=this.#U.targetX=e,this.#U.y=this.#U.targetY=t,this.#W=!0;return}this.#U.moved=!0,this.#U.dx=(e-this.#U.targetX)*n,this.#U.dy=(t-this.#U.targetY)*n,this.#U.targetX=e,this.#U.targetY=t}splat(e,t,n,r,i=1){!this.#q||this.#N===0||(this.#p?this.#ae(e,t,n,r,i):this.#oe(e,t,n,r,i))}updateQuality(e){e.dpr!==void 0&&(this.#R=Math.max(.1,Math.min(1,e.dpr))),e.sim!==void 0&&(this.#z=Math.max(.1,Math.min(1,e.sim)))}resize(e,t,n){if(n===void 0?typeof window<`u`&&window.devicePixelRatio&&(this.#L=window.devicePixelRatio):this.#L=n,e!==void 0&&e>0){if(t===void 0||t<=0)return;this.#N=this.#e.width=e,this.#P=this.#e.height=t,this.#F=Math.max(1,Math.round(e*this.#z)),this.#I=Math.max(1,Math.round(t*this.#z)),this.#Q()}else this.#Z();this.#G&&this.#$(),this.#ee()}updateConfig(e){Object.assign(this.#H,e)}destroy(){if(this.#J=!0,this.stop(),this.#te(),this.#ne(),this.#B&&=(this.#B.close(),null),this.#p)this.#C?.destroy(),this.#w?.destroy(),this.#T?.destroy(),this.#E?.destroy(),this.#D?.destroy(),this.#O?.destroy(),this.#k?.destroy(),this.#A?.destroy(),this.#j?.destroy(),this.#M?.destroy(),this.#h?.destroy(),this.#p.device.destroy();else{let e=this.#t;for(let e of Object.values(this.#r))e.dispose();e.getExtension(`WEBGL_lose_context`)?.loseContext()}}start(){if(this.#K!==null)return;let e=()=>{this.#re(),this.#K=R(e)};this.#K=R(e)}stop(){this.#K!==null&&(z(this.#K),this.#K=null)}get isRunning(){return this.#K!==null}#X(e){let{device:t,format:n}=e;this.#m=b(t,n,this.#Y),this.#h=h(t),this.#g=x(t),this.#C=S(t,16),this.#w=S(t,16),this.#T=S(t,16),this.#E=S(t,16),this.#D=S(t,16),this.#O=S(t,48),this.#k=S(t,48),this.#A=S(t,16),this.#j=S(t,16),this.#M=S(t,64)}#Z(){let e=this.#e;`clientWidth`in e&&e.clientWidth>0?(this.#L=(typeof window<`u`&&window.devicePixelRatio||1)*this.#R,this.#N=e.width=Math.round(e.clientWidth*this.#L),this.#P=e.height=Math.round(e.clientHeight*this.#L)):(this.#N=e.width,this.#P=e.height),!(this.#N===0||this.#P===0)&&(this.#F=Math.max(1,Math.round(this.#N*this.#z)),this.#I=Math.max(1,Math.round(this.#P*this.#z)),this.#Q())}#Q(){if(this.#te(),this.#p){let{device:e}=this.#p,t=`rgba16float`,n=this.#F,r=this.#I;this.#_=_(e,t,n,r),this.#v=_(e,t,n,r),this.#b=_(e,t,n,r),this.#y=g(e,t,n,r),this.#x=g(e,t,n,r)}else{let e=this.#t,t=this.#n,n=this.#F,r=this.#I;this.#a=d(e,t,n,r),this.#o=d(e,t,n,r),this.#c=d(e,t,n,r),this.#s=u(e,t,n,r),this.#l=u(e,t,n,r)}}#$(){if(!(!this.#G||this.#N===0||this.#P===0)){if(this.#ne(),this.#p){let{device:e}=this.#p;this.#G.type===`text`?this.#S=P(e,this.#N,this.#P,this.#G.opts,this.#B,this.#V):this.#S=F(e,this.#G.bitmap,this.#N,this.#P,this.#G.effect,this.#G.size,this.#B,this.#V)}else{let e=this.#t;if(this.#G.type===`text`){let{backgroundTex:t,obstacleTex:n,coverageTex:r}=j(e,this.#N,this.#P,this.#G.opts,this.#B,this.#V);this.#u=t,this.#d=n,this.#f=r}else{let{backgroundTex:t,obstacleTex:n,coverageTex:r}=M(e,this.#G.bitmap,this.#N,this.#P,this.#G.effect,this.#G.size,this.#B,this.#V);this.#u=t,this.#d=n,this.#f=r}}this.#q=!0}}#ee(){this.#q&&!this.isRunning&&this.start()}#te(){if(this.#p)this.#_?.dispose(),this.#v?.dispose(),this.#b?.dispose(),this.#y?.tex.destroy(),this.#x?.tex.destroy(),this.#_=this.#v=this.#b=null,this.#y=this.#x=null;else{let e=this.#t;this.#a?.dispose(),this.#o?.dispose(),this.#c?.dispose(),this.#s&&(e.deleteTexture(this.#s.tex),e.deleteFramebuffer(this.#s.fbo)),this.#l&&(e.deleteTexture(this.#l.tex),e.deleteFramebuffer(this.#l.fbo)),this.#a=this.#o=this.#c=this.#s=this.#l=null}}#ne(){if(this.#p)this.#S&&=(this.#S.backgroundTex.destroy(),this.#S.obstacleTex.destroy(),this.#S.sharedCoverage||this.#S.coverageTex.destroy(),null);else{let e=this.#t;this.#u&&e.deleteTexture(this.#u),this.#d&&e.deleteTexture(this.#d),this.#f&&this.#f!==this.#d&&e.deleteTexture(this.#f),this.#u=this.#d=this.#f=null}}#re(){!this.#q||this.#N===0||(this.#p?this.#ie():this.#se())}#ie(){let e=this.#p,t=e.device,n=this.#m,i=this.#h,a=this.#g,o=this.#H,s=this.#S;if(!this.#_||!this.#v)return;this.#U.x+=(this.#U.targetX-this.#U.x)*.15,this.#U.y+=(this.#U.targetY-this.#U.y)*.15;let c=this.#F,l=this.#I,u=this.#N,d=this.#P,f=1/c,p=1/l;C(t,this.#C,f,p,B,o.velocityDissipation),w(t,this.#T,f,p),w(t,this.#E,f,p),w(t,this.#D,f,p),w(t,this.#A,f,p),T(t,this.#j,f,p,o.curl,B),D(t,this.#M,1/u,1/d,o.refraction,o.specularExp,r(o.waterColor),r(o.glowColor),o.shine,o.warpStrength??.015,V[o.algorithm]??0,this.#Y);let m=t.createCommandEncoder(),h=(e,n)=>t.createBindGroup({layout:e.getBindGroupLayout(0),entries:n}),g={binding:1,resource:a};{let e=h(n.advection,[{binding:0,resource:{buffer:this.#C}},g,{binding:2,resource:this.#v.read.view},{binding:3,resource:this.#v.read.view},{binding:4,resource:s.obstacleView}]);O(m,n.advection,e,i,this.#v.write.view)}this.#v.swap();{C(t,this.#w,f,p,B,o.densityDissipation);let e=h(n.advection,[{binding:0,resource:{buffer:this.#w}},g,{binding:2,resource:this.#v.read.view},{binding:3,resource:this.#_.read.view},{binding:4,resource:s.obstacleView}]);O(m,n.advection,e,i,this.#_.write.view)}this.#_.swap();{let e=h(n.curl,[{binding:0,resource:{buffer:this.#A}},g,{binding:2,resource:this.#v.read.view}]);O(m,n.curl,e,i,this.#x.view)}{let e=h(n.vorticity,[{binding:0,resource:{buffer:this.#j}},g,{binding:2,resource:this.#v.read.view},{binding:3,resource:this.#x.view}]);O(m,n.vorticity,e,i,this.#v.write.view)}if(this.#v.swap(),this.#U.moved){let e=this.#U.x*this.#L/u,r=this.#U.y*this.#L/d;E(t,this.#O,f,p,u/d,o.splatRadius,this.#U.dx*o.splatForce,this.#U.dy*o.splatForce,0,e,r);{let e=h(n.splat,[{binding:0,resource:{buffer:this.#O}},g,{binding:2,resource:this.#v.read.view}]);O(m,n.splat,e,i,this.#v.write.view)}this.#v.swap(),E(t,this.#k,f,p,u/d,o.splatRadius,1,1,1,e,r);{let e=h(n.splat,[{binding:0,resource:{buffer:this.#k}},g,{binding:2,resource:this.#_.read.view}]);O(m,n.splat,e,i,this.#_.write.view)}this.#_.swap(),this.#U.moved=!1}{let e=h(n.divergence,[{binding:0,resource:{buffer:this.#T}},g,{binding:2,resource:this.#v.read.view},{binding:3,resource:s.obstacleView}]);O(m,n.divergence,e,i,this.#y.view)}for(let e=0;e<o.pressureIterations;e++){let e=h(n.pressure,[{binding:0,resource:{buffer:this.#E}},g,{binding:2,resource:this.#b.read.view},{binding:3,resource:this.#y.view},{binding:4,resource:s.obstacleView}]);O(m,n.pressure,e,i,this.#b.write.view),this.#b.swap()}{let e=h(n.gradientSubtract,[{binding:0,resource:{buffer:this.#D}},g,{binding:2,resource:this.#b.read.view},{binding:3,resource:this.#v.read.view},{binding:4,resource:s.obstacleView}]);O(m,n.gradientSubtract,e,i,this.#v.write.view)}this.#v.swap();{let t=e.context.getCurrentTexture().createView(),r=h(n.display,[{binding:0,resource:{buffer:this.#M}},g,{binding:2,resource:this.#_.read.view},{binding:3,resource:s.obstacleView},{binding:4,resource:s.backgroundView},{binding:5,resource:s.coverageView},{binding:6,resource:this.#v.read.view}]);k(m,n.display,r,i,t)}t.queue.submit([m.finish()])}#ae(e,t,n,r,i){let a=this.#p.device,o=this.#m.splat,s=this.#h,c=this.#g,l=this.#H,u=this.#F,d=this.#I,f=1/u,p=1/d,m=a.createCommandEncoder(),h={binding:1,resource:c},g=e=>a.createBindGroup({layout:o.getBindGroupLayout(0),entries:e}),_=e*this.#L/this.#N,v=t*this.#L/this.#P;E(a,this.#O,f,p,this.#N/this.#P,l.splatRadius,n*l.splatForce*i,r*l.splatForce*i,0,_,v),O(m,o,g([{binding:0,resource:{buffer:this.#O}},h,{binding:2,resource:this.#v.read.view}]),s,this.#v.write.view),this.#v.swap(),E(a,this.#k,f,p,this.#N/this.#P,l.splatRadius,i,i,i,_,v),O(m,o,g([{binding:0,resource:{buffer:this.#k}},h,{binding:2,resource:this.#_.read.view}]),s,this.#_.write.view),this.#_.swap(),a.queue.submit([m.finish()])}#oe(e,t,n,r,i){let a=this.#t,o=this.#H,s=this.#r.splat,c=this.#i;a.viewport(0,0,this.#F,this.#I),s.bind(),a.uniform1f(s.uniforms.aspectRatio,this.#N/this.#P),a.uniform2f(s.uniforms.point,e*this.#L/this.#N,1-t*this.#L/this.#P),a.uniform1f(s.uniforms.radius,o.splatRadius),a.uniform1i(s.uniforms.uTarget,0),a.activeTexture(a.TEXTURE0),a.bindTexture(a.TEXTURE_2D,this.#o.read.tex),a.uniform3f(s.uniforms.color,n*o.splatForce*i,-r*o.splatForce*i,0),c(this.#o.write.fbo),this.#o.swap(),a.activeTexture(a.TEXTURE0),a.bindTexture(a.TEXTURE_2D,this.#a.read.tex),a.uniform3f(s.uniforms.color,i,i,i),c(this.#a.write.fbo),this.#a.swap()}#se(){if(!this.#a||!this.#o)return;let e=this.#t,t=this.#H,{advection:n,divergence:i,pressure:a,gradientSubtract:o,splat:s,curl:c,vorticity:l,display:u}=this.#r;this.#U.x+=(this.#U.targetX-this.#U.x)*.15,this.#U.y+=(this.#U.targetY-this.#U.y)*.15;let d=this.#F,f=this.#I,p=this.#i;e.viewport(0,0,d,f),n.bind(),e.uniform2f(n.uniforms.texelSize,1/d,1/f),e.uniform1f(n.uniforms.dt,B),e.uniform1i(n.uniforms.uObstacle,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#d),e.uniform1f(n.uniforms.dissipation,t.velocityDissipation),e.uniform1i(n.uniforms.uVelocity,1),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),e.uniform1i(n.uniforms.uSource,1),p(this.#o.write.fbo),this.#o.swap(),e.uniform1f(n.uniforms.dissipation,t.densityDissipation),e.uniform1i(n.uniforms.uSource,2),e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,this.#a.read.tex),p(this.#a.write.fbo),this.#a.swap(),c.bind(),e.uniform2f(c.uniforms.texelSize,1/d,1/f),e.uniform1i(c.uniforms.uVelocity,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),p(this.#l.fbo),l.bind(),e.uniform2f(l.uniforms.texelSize,1/d,1/f),e.uniform1f(l.uniforms.curl,t.curl),e.uniform1f(l.uniforms.dt,B),e.uniform1i(l.uniforms.uVelocity,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),e.uniform1i(l.uniforms.uCurl,1),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.#l.tex),p(this.#o.write.fbo),this.#o.swap(),this.#U.moved&&(s.bind(),e.uniform1f(s.uniforms.aspectRatio,this.#N/this.#P),e.uniform2f(s.uniforms.point,this.#U.x*this.#L/this.#N,1-this.#U.y*this.#L/this.#P),e.uniform1f(s.uniforms.radius,t.splatRadius),e.uniform1i(s.uniforms.uTarget,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),e.uniform3f(s.uniforms.color,this.#U.dx*t.splatForce,-this.#U.dy*t.splatForce,0),p(this.#o.write.fbo),this.#o.swap(),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#a.read.tex),e.uniform3f(s.uniforms.color,1,1,1),p(this.#a.write.fbo),this.#a.swap(),this.#U.moved=!1),i.bind(),e.uniform2f(i.uniforms.texelSize,1/d,1/f),e.uniform1i(i.uniforms.uVelocity,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),e.uniform1i(i.uniforms.uObstacle,1),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.#d),p(this.#s.fbo),a.bind(),e.uniform2f(a.uniforms.texelSize,1/d,1/f),e.uniform1i(a.uniforms.uDivergence,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#s.tex),e.uniform1i(a.uniforms.uObstacle,1),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.#d);for(let n=0;n<t.pressureIterations;n++)e.uniform1i(a.uniforms.uPressure,2),e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,this.#c.read.tex),p(this.#c.write.fbo),this.#c.swap();o.bind(),e.uniform2f(o.uniforms.texelSize,1/d,1/f),e.uniform1i(o.uniforms.uPressure,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#c.read.tex),e.uniform1i(o.uniforms.uVelocity,1),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),e.uniform1i(o.uniforms.uObstacle,2),e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,this.#d),p(this.#o.write.fbo),this.#o.swap(),e.viewport(0,0,this.#N,this.#P),e.bindFramebuffer(e.FRAMEBUFFER,null),e.clear(e.COLOR_BUFFER_BIT),u.bind(),e.uniform2f(u.uniforms.texelSize,1/this.#N,1/this.#P),e.uniform3fv(u.uniforms.uWaterColor,r(t.waterColor)),e.uniform3fv(u.uniforms.uGlowColor,r(t.glowColor)),e.uniform1f(u.uniforms.uRefraction,t.refraction),e.uniform1f(u.uniforms.uSpecularExp,t.specularExp),e.uniform1f(u.uniforms.uShine,t.shine),e.uniform1f(u.uniforms.uWarpStrength,t.warpStrength??.015),e.uniform1i(u.uniforms.uAlgorithm,V[t.algorithm]??0),e.uniform1i(u.uniforms.uEnableAlpha,+!!this.#Y),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.#a.read.tex),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.#d),e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,this.#u),e.activeTexture(e.TEXTURE3),e.bindTexture(e.TEXTURE_2D,this.#f),e.activeTexture(e.TEXTURE4),e.bindTexture(e.TEXTURE_2D,this.#o.read.tex),e.uniform1i(u.uniforms.uTexture,0),e.uniform1i(u.uniforms.uObstacle,1),e.uniform1i(u.uniforms.uBackground,2),e.uniform1i(u.uniforms.uCoverage,3),e.uniform1i(u.uniforms.uVelocity,4),p(null)}};let U=null,W;const G=new Promise(e=>{W=e});self.onmessage=async e=>{let{type:t,...n}=e.data;try{switch(t){case`init`:{let{canvas:e,width:t,height:r,config:i,dpr:a,quality:o,useWebGPU:s,enableAlpha:c}=n;e.width=t,e.height=r,U=await H.create(e,i,o??{},s??!0,c??!0),U.resize(t,r,a||1),W(),self.postMessage({type:`ready`});break}case`setTextSource`:if(await G,!U)return;U.setTextSource(n.opts);break;case`setImageSource`:if(await G,!U)return;await U.setImageSource(n.src,n.effect,n.size);break;case`setImageBitmap`:if(await G,!U)return;U.setImageBitmap(n.bitmap,n.effect,n.size);break;case`setBackground`:if(await G,!U)return;U.setBackground(n.bitmap,n.size);break;case`splat`:if(await G,!U)return;U.splat(n.x,n.y,n.vx,n.vy,n.strength??1);break;case`move`:if(await G,!U)return;U.handleMove(n.x,n.y,n.strength??1);break;case`resize`:if(await G,!U)return;U.resize(n.width,n.height,n.dpr);break;case`updateQuality`:if(await G,!U)return;U.updateQuality(n.quality);break;case`updateConfig`:if(await G,!U)return;U.updateConfig(n.config);break;case`destroy`:await G,U?.destroy(),U=null;break;default:}}catch(e){self.postMessage({type:`error`,message:e?.message??String(e)})}};", ve = typeof self < "u" && self.Blob && new Blob(["URL.revokeObjectURL(import.meta.url);", _e], { type: "text/javascript;charset=utf-8" });
|
|
1039
1041
|
function ye(e) {
|
|
1040
1042
|
let t;
|
|
1041
1043
|
try {
|
|
@@ -1066,8 +1068,9 @@ var be = typeof Worker < "u" && typeof OffscreenCanvas < "u", xe = class {
|
|
|
1066
1068
|
#o;
|
|
1067
1069
|
#s = null;
|
|
1068
1070
|
#c = null;
|
|
1071
|
+
#l = null;
|
|
1069
1072
|
constructor(e, { workerEnabled: t = !0, webGPUEnabled: n = !0, alphaEnabled: r = !0, quality: i = {}, config: a = {} } = {}) {
|
|
1070
|
-
this.#a = Math.max(.1, Math.min(1, i.dpr ?? 1)), this.#o = Math.max(.1, Math.min(1, i.sim ?? .5)), this.#r = n, this.#i = r, this.#n = t && be, this.#n ? this.#
|
|
1073
|
+
this.#a = Math.max(.1, Math.min(1, i.dpr ?? 1)), this.#o = Math.max(.1, Math.min(1, i.sim ?? .5)), this.#r = n, this.#i = r, this.#n = t && be, this.#n ? this.#d(e, a) : this.#u(e, a);
|
|
1071
1074
|
}
|
|
1072
1075
|
setTextSource(e) {
|
|
1073
1076
|
this.#e ? this.#e.postMessage({
|
|
@@ -1098,7 +1101,10 @@ var be = typeof Worker < "u" && typeof OffscreenCanvas < "u", xe = class {
|
|
|
1098
1101
|
bitmap: e ?? null,
|
|
1099
1102
|
size: t
|
|
1100
1103
|
}, n);
|
|
1101
|
-
} else this.#t
|
|
1104
|
+
} else this.#t ? this.#t.setBackground(e ?? null, t) : this.#l = {
|
|
1105
|
+
bitmap: e ?? null,
|
|
1106
|
+
size: t
|
|
1107
|
+
};
|
|
1102
1108
|
}
|
|
1103
1109
|
splat(e, t, n, r, i = 1) {
|
|
1104
1110
|
this.#e ? this.#e.postMessage({
|
|
@@ -1148,7 +1154,7 @@ var be = typeof Worker < "u" && typeof OffscreenCanvas < "u", xe = class {
|
|
|
1148
1154
|
this.#e = null, e.postMessage({ type: "destroy" }), setTimeout(() => e.terminate(), 50);
|
|
1149
1155
|
} else this.#t?.destroy(), this.#t = null;
|
|
1150
1156
|
}
|
|
1151
|
-
#
|
|
1157
|
+
#u(e, t) {
|
|
1152
1158
|
let n = {
|
|
1153
1159
|
dpr: this.#a,
|
|
1154
1160
|
sim: this.#o
|
|
@@ -1159,16 +1165,17 @@ var be = typeof Worker < "u" && typeof OffscreenCanvas < "u", xe = class {
|
|
|
1159
1165
|
let { src: t, effect: n, size: r } = this.#c;
|
|
1160
1166
|
e.setImageSource(t, n, r), this.#c = null;
|
|
1161
1167
|
}
|
|
1168
|
+
this.#l &&= (e.setBackground(this.#l.bitmap, this.#l.size), null);
|
|
1162
1169
|
}).catch((e) => {}) : this.#t = new Q(e, t, n, void 0, this.#i);
|
|
1163
1170
|
}
|
|
1164
|
-
#
|
|
1171
|
+
#d(e, t) {
|
|
1165
1172
|
let n = (typeof window < "u" && window.devicePixelRatio || 1) * this.#a, r = Math.round(e.clientWidth * n), i = Math.round(e.clientHeight * n);
|
|
1166
1173
|
e.width = r, e.height = i;
|
|
1167
1174
|
let a;
|
|
1168
1175
|
try {
|
|
1169
1176
|
a = e.transferControlToOffscreen();
|
|
1170
1177
|
} catch {
|
|
1171
|
-
this.#n = !1, this.#
|
|
1178
|
+
this.#n = !1, this.#u(e, t);
|
|
1172
1179
|
return;
|
|
1173
1180
|
}
|
|
1174
1181
|
let o = this.#e = new ye();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jayf0x/fluidity-js",
|
|
3
|
-
"version": "0.3
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "WebGPU-first real-time Navier-Stokes fluid simulation for React — interactive water, ink, glass, aurora, and ripple effects on text and images. Falls back to WebGL2/WebGL1. Runs in a Web Worker.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.js",
|