[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-80192":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":8,"language":10,"languages":8,"totalLinesOfCode":8,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":14,"forks30d":14,"starsTrendScore":18,"compositeScore":19,"rankGlobal":8,"rankLanguage":8,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":21,"topics":24,"createdAt":8,"pushedAt":8,"updatedAt":25,"readmeContent":26,"aiSummary":27,"trendingCount":14,"starSnapshotCount":14,"syncStatus":28,"lastSyncTime":29,"discoverSource":30},80192,"three-fluid-fx","artcodev\u002Fthree-fluid-fx","artcodev",null,"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com","JavaScript",97,14,1,0,3,4,15,9,3.53,"MIT License",false,"main",true,[],"2026-06-12 02:03:59","# three-fluid-fx\n\n> A drop-in 2D Stable-Fluids solver for [three.js](https:\u002F\u002Fthreejs.org\u002F),\n> tuned for real-time visual effects. Ships WebGL\u002FGLSL and WebGPU\u002FTSL\n> pipelines.\n\n**Built to remove the pain of wiring a fluid sim into a three.js project.**\nIf you've ever needed one of these and ended up reading a SIGGRAPH paper\nto get there — this library is for you.\n\n🌊 **[Live Demo & Documentation](https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002F)** &nbsp;·&nbsp; 📖 **[Interactive Tutorials](https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Ftutorials\u002Feffects-guide\u002F)**\n\n\u003Ctable>\n  \u003Ctr>\n    \u003Ctd width=\"50%\" align=\"center\">\n      \u003Ca href=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fexamples\u002Fglsl\u002Fminimal\u002Foverlay\u002F\">\n        \u003Cimg src=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fassets\u002Fpreviews\u002Ffx-example-overlay.png\" width=\"100%\" alt=\"Fluid cursor overlay\" \u002F>\n      \u003C\u002Fa>\n      \u003Cbr\u002F>\n      \u003Cstrong>Fluid cursor overlay\u003C\u002Fstrong>\n      \u003Cbr\u002F>\n      Coloured ink \u002F trail that follows the pointer.\n      \u003Cbr\u002F>\n      \u003Ca href=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fexamples\u002Fglsl\u002Fminimal\u002Foverlay\u002F\">live demo\u003C\u002Fa>\n      ·\n      \u003Ca href=\"examples\u002Fglsl\u002Fminimal\u002Foverlay\u002Fmain.ts\">source\u003C\u002Fa>\n    \u003C\u002Ftd>\n    \u003Ctd width=\"50%\" align=\"center\">\n      \u003Ca href=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fexamples\u002Fglsl\u002Fminimal\u002Fdistortion\u002F\">\n        \u003Cimg src=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fassets\u002Fpreviews\u002Ffx-example-distortion.png\" width=\"100%\" alt=\"Fluid screen distortion\" \u002F>\n      \u003C\u002Fa>\n      \u003Cbr\u002F>\n      \u003Cstrong>Fluid screen distortion (UV refraction)\u003C\u002Fstrong>\n      \u003Cbr\u002F>\n      Smear \u002F heat-haze \u002F liquid-lens by sampling your scene with \u003Ccode>tFluid.rg\u003C\u002Fcode>.\n      \u003Cbr\u002F>\n      \u003Ca href=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fexamples\u002Fglsl\u002Fminimal\u002Fdistortion\u002F\">live demo\u003C\u002Fa>\n      ·\n      \u003Ca href=\"examples\u002Fglsl\u002Fminimal\u002Fdistortion\u002Fmain.ts\">source\u003C\u002Fa>\n    \u003C\u002Ftd>\n  \u003C\u002Ftr>\n  \u003Ctr>\n    \u003Ctd width=\"50%\" align=\"center\">\n      \u003Ca href=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fexamples\u002Fglsl\u002Fminimal\u002Fparticles-trefoil\u002F\">\n        \u003Cimg src=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fassets\u002Fpreviews\u002Ffx-example-particles-trefoil.png\" width=\"100%\" alt=\"Particle displacement\" \u002F>\n      \u003C\u002Fa>\n      \u003Cbr\u002F>\n      \u003Cstrong>Particle displacement (vertex shader)\u003C\u002Fstrong>\n      \u003Cbr\u002F>\n      Push procedural particle positions with the velocity field — no GPGPU required.\n      \u003Cbr\u002F>\n      \u003Ca href=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fexamples\u002Fglsl\u002Fminimal\u002Fparticles-trefoil\u002F\">live demo\u003C\u002Fa>\n      ·\n      \u003Ca href=\"examples\u002Fglsl\u002Fminimal\u002Fparticles-trefoil\u002Fmain.ts\">source\u003C\u002Fa>\n    \u003C\u002Ftd>\n    \u003Ctd width=\"50%\" align=\"center\">\n      \u003Ca href=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fexamples\u002Fglsl\u002Fminimal\u002Fparticles-3d\u002F\">\n        \u003Cimg src=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fassets\u002Fpreviews\u002Ffx-example-particles-3d.png\" width=\"100%\" alt=\"GPGPU particle displacement\" \u002F>\n      \u003C\u002Fa>\n      \u003Cbr\u002F>\n      \u003Cstrong>GPGPU particle displacement\u003C\u002Fstrong>\n      \u003Cbr\u002F>\n      Full ping-pong particle system advected by the velocity texture (2D and 3D).\n      \u003Cbr\u002F>\n      \u003Ca href=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fexamples\u002Fglsl\u002Fminimal\u002Fparticles-3d\u002F\">live demo (3D)\u003C\u002Fa>\n      ·\n      \u003Ca href=\"examples\u002Fglsl\u002Fminimal\u002Fparticles-2d\u002Fmain.ts\">2D source\u003C\u002Fa>\n      ·\n      \u003Ca href=\"examples\u002Fglsl\u002Fminimal\u002Fparticles-3d\u002Fmain.ts\">3D source\u003C\u002Fa>\n    \u003C\u002Ftd>\n  \u003C\u002Ftr>\n  \u003Ctr>\n    \u003Ctd colspan=\"2\" align=\"center\">\n      \u003Ca href=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fexamples\u002Ftsl\u002Fminimal\u002Ffluid-text\u002F\">\n        \u003Cimg src=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fassets\u002Fpreviews\u002Ffx-example-fluid-text.png\" width=\"70%\" alt=\"Fluid text effect\" \u002F>\n      \u003C\u002Fa>\n      \u003Cbr\u002F>\n      \u003Cstrong>Fluid text (DOM typography → CanvasTexture)\u003C\u002Fstrong>\n      \u003Cbr\u002F>\n      Mirror ordinary HTML text into a Three.js plane, then run it through fluid distortion and Art Ink overlay.\n      \u003Cbr\u002F>\n      \u003Ca href=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Fexamples\u002Ftsl\u002Fminimal\u002Ffluid-text\u002F\">live demo\u003C\u002Fa>\n      ·\n      \u003Ca href=\"https:\u002F\u002Fthree-fluid-fx.artcreativecode.com\u002Ftutorials\u002Ftsl\u002Fminimal\u002Ffluid-text\u002F\">tutorial\u003C\u002Fa>\n      ·\n      \u003Ca href=\"examples\u002Ftsl\u002Fminimal\u002Ffluid-text\u002Fmain.ts\">minimal source\u003C\u002Fa>\n      ·\n      \u003Ca href=\"examples\u002Ftsl\u002Ffull\u002Ffluid-text\u002Fmain.ts\">full source\u003C\u002Fa>\n    \u003C\u002Ftd>\n  \u003C\u002Ftr>\n\u003C\u002Ftable>\n\nYou bring a three.js scene; the library hands you solver outputs and a\nfive-line API. In the WebGL\u002FGLSL pipeline those outputs are textures\n(`velocityTexture`, `densityTexture`). In the WebGPU\u002FTSL pipeline they are\nboth raw textures and `TextureNode`s. Everything else — how to composite them,\nwhat to distort, which particles to push — stays in your shaders, where it\nbelongs.\n\n> ℹ️ **Not a new algorithm.** This is a three.js-focused _packaging_ of\n> Jos Stam's _Stable Fluids_ (SIGGRAPH 1999), with vorticity confinement\n> (Fedkiw 2001) and optional BFECC advection. See\n> [Acknowledgements & scope](#acknowledgements--scope) for prior art and credits.\n\n### Don't use this if you need\n\n- ❌ CFD-grade physical accuracy (this is not Navier-Stokes engineering)\n- ❌ free-surface water with splashes (use FLIP \u002F SPH)\n- ❌ 3D volumetric fluid (smoke volumes, fire as a volume) — this is 2D only\n- ❌ rigid-body collision coupling — the solver doesn't know about your scene\n\n### Why it's \"easy\"\n\n- **Plain-property API.** No `configure()` calls; write `fluid.curlStrength = 0.7` any time.\n- **Profile presets.** One option (`profile: 'balanced'`) sets resolution + iterations.\n- **Drop-in helper** for pointer splats; everything else is opt-in and tree-shakable.\n- **No DOM dependency** in the solver itself — runs in OffscreenCanvas \u002F Worker.\n- **Plain-JS friendly** — `.d.ts` is opt-in metadata, never required at runtime.\n\n### Tech facts\n\n- Tree-shakable ESM + CJS bundles (~13 KB gzipped for the full GLSL pipeline\n  with all 20 passes, ~11 KB gzipped for the TSL pipeline). `three` stays a\n  peer dependency.\n- WebGL2 \u002F HalfFloat FBOs in the default GLSL pipeline; WebGPU\u002FWGSL compute in\n  the TSL pipeline.\n- GLSL pipeline: 20 `Pass` subclasses, compatible with three.js\n  `EffectComposer` and the standard post-processing pipeline (see below).\n- TSL pipeline: `RenderPipeline`-ready node functions and WGSL-backed fluid\n  simulation via `three-fluid-fx\u002Ftsl`.\n- Drop-in across React-Three-Fiber, plain three.js, or `\u003Cscript>`-based pages.\n\n### WebGL post-processing passes\n\nThe default `three-fluid-fx` entry is compatible with three.js\n`EffectComposer` and the standard post-processing pipeline. It ships 20 `Pass`\nsubclasses that chain alongside\n`RenderPass`, `OutputPass`, `BloomPass`, etc. without configuration:\n\n- **5 distortion passes** — `SimpleDistortionPass`, `RGBShiftDistortionPass`,\n  `ChromaticDistortionPass`, `WaterDistortionPass`, `WaterCausticsDistortionPass`\n- **15 overlay passes** — `DefaultOverlayPass`, `VolumeCursorOverlayPass`,\n  `TrailOverlayPass`, `OilOverlayPass`, `VelocityOverlayPass`,\n  `ColorfulOverlayPass`, `RainbowFishOverlayPass`, `GlazeOverlayPass`,\n  `BurnOverlayPass`, `SmokeOverlayPass`, `ArtInkOverlayPass`,\n  `RainbowInkOverlayPass`, `ColorWaterOverlayPass`, `LiquidLensOverlayPass`,\n  `DensityTintOverlayPass`\n\nEach pass exposes plain properties (`intensity`, `vibrance`, `cursorColor`, …)\nand reads from `tDiffuse` — the convention `ShaderPass.textureID` uses by\ndefault — so chaining \"just works\":\n\n```ts\nimport { EffectComposer } from 'three\u002Faddons\u002Fpostprocessing\u002FEffectComposer.js'\nimport { RenderPass } from 'three\u002Faddons\u002Fpostprocessing\u002FRenderPass.js'\nimport { OutputPass } from 'three\u002Faddons\u002Fpostprocessing\u002FOutputPass.js'\nimport { ChromaticDistortionPass } from 'three-fluid-fx'\n\nconst distortion = new ChromaticDistortionPass(fluid)\ndistortion.intensity = 0.5\n\nconst composer = new EffectComposer(renderer)\ncomposer.addPass(new RenderPass(scene, camera))\ncomposer.addPass(distortion)\ncomposer.addPass(new OutputPass()) \u002F\u002F canonical final pass: tone mapping + sRGB\n\n\u002F\u002F Loop:\nfluid.step(dt)\ncomposer.render(dt)\n```\n\n### WebGPU \u002F TSL nodes\n\nThe `three-fluid-fx\u002Ftsl` entry uses a WGSL compute solver and exposes TSL node\nfunctions for composition. These are meant for `WebGPURenderer` and\n`RenderPipeline`, not `EffectComposer`:\n\n```ts\nimport { RenderPipeline, WebGPURenderer } from 'three\u002Fwebgpu'\nimport { pass } from 'three\u002Ftsl'\nimport { attachPointerSplats, FluidSimulation, simpleDistortion } from 'three-fluid-fx\u002Ftsl'\n\nconst renderer = new WebGPURenderer()\nawait renderer.init()\n\nconst fluid = new FluidSimulation(renderer)\nattachPointerSplats(renderer.domElement, fluid)\n\nconst scenePass = pass(scene, camera)\nconst pipeline = new RenderPipeline(renderer)\npipeline.outputNode = simpleDistortion(scenePass, fluid.densityNode, 1)\n\nrenderer.setAnimationLoop(() => {\n  fluid.step(1 \u002F 60)\n  pipeline.render()\n})\n```\n\n## Install\n\n```bash\nnpm install three-fluid-fx three\n# or\npnpm add three-fluid-fx three\n```\n\nRequires `three >= 0.183.0`. The default subpath `three-fluid-fx` is the\nWebGL\u002FGLSL pipeline. Use `three-fluid-fx\u002Ftsl` for the WebGPU\u002FTSL pipeline; it\nrequires a WebGPU-capable browser\u002Fruntime.\n\n## Quick start\n\n```ts\nimport { WebGLRenderer, Timer } from 'three'\nimport { FluidSimulation, attachPointerSplats } from 'three-fluid-fx'\n\nconst renderer = new WebGLRenderer({ antialias: true })\nconst fluid = new FluidSimulation(renderer, {\n  splatRadius: 0.001,\n  splatForce: 6,\n})\n\n\u002F\u002F live-tunable, just plain properties\nfluid.curlStrength = 0.7\nfluid.splatForce = 8 \u002F\u002F change at any time, picked up next frame\n\n\u002F\u002F optional helper for mouse\u002Ftouch — reads splatRadius\u002FsplatForce from fluid\nattachPointerSplats(renderer.domElement, fluid)\n\nconst clock = new Timer()\nrenderer.setAnimationLoop(() => {\n  clock.update()\n  fluid.step(clock.getDelta())\n  \u002F\u002F sample fluid.velocityTexture \u002F fluid.densityTexture in your own material\n})\n```\n\n### Plain JavaScript (no bundler, no TypeScript)\n\n```html\n\u003Cdiv id=\"stage\" style=\"width: 100vw; height: 100vh\">\u003C\u002Fdiv>\n\n\u003Cscript type=\"importmap\">\n  {\n    \"imports\": {\n      \"three\": \"https:\u002F\u002Fesm.sh\u002Fthree@0.183.0\",\n      \"three-fluid-fx\": \"https:\u002F\u002Fesm.sh\u002Fthree-fluid-fx@0.1.0\"\n    }\n  }\n\u003C\u002Fscript>\n\n\u003Cscript type=\"module\">\n  import { WebGLRenderer } from 'three'\n  import { attachPointerSplats, FluidSimulation } from 'three-fluid-fx'\n\n  const stage = document.getElementById('stage')\n  const renderer = new WebGLRenderer({ antialias: true })\n  stage.appendChild(renderer.domElement)\n\n  const fluid = new FluidSimulation(renderer, {\n    splatRadius: 0.001,\n    splatForce: 6,\n  })\n\n  attachPointerSplats(renderer.domElement, fluid)\n\n  function frame() {\n    const width = stage.clientWidth\n    const height = stage.clientHeight\n    renderer.setSize(width, height, false)\n    fluid.resize(width, height)\n    fluid.step(1 \u002F 60)\n    requestAnimationFrame(frame)\n  }\n  requestAnimationFrame(frame)\n\u003C\u002Fscript>\n```\n\n## API\n\n### `class FluidSimulation`\n\n```ts\nnew FluidSimulation(renderer: WebGLRenderer, options?: FluidSimulationOptions)\n```\n\nAll tunables are **plain properties** — write to them at any time, the solver picks\nthe new value on the next `step()`. This makes Tweakpane \u002F dat.gui \u002F any UI integration\na one-liner: `pane.addBinding(fluid, 'curlStrength', { min: 0, max: 2 })`.\n\n### Quality profiles\n\nBaseline resolution and Jacobi-iteration counts are picked at construction\ntime. `resize(width, height)` reshapes the internal targets to the viewport\naspect, but it does not change the selected profile's base resolution. Use a\nprofile preset:\n\n```ts\nimport { FluidSimulation, FLUID_PROFILES } from 'three-fluid-fx'\n\nnew FluidSimulation(renderer, { profile: 'performance' }) \u002F\u002F mobile \u002F weak GPU\nnew FluidSimulation(renderer, { profile: 'balanced' }) \u002F\u002F default — desktop\nnew FluidSimulation(renderer, { profile: 'quality' }) \u002F\u002F presentation \u002F high-end\n```\n\n|             | sim FBO | dye FBO | pressure iters | relative cost |\n| ----------- | ------- | ------- | -------------- | ------------- |\n| performance | 128²    | 256²    | 6              | 1×            |\n| balanced    | 256²    | 512²    | 12             | ~6×           |\n| quality     | 384²    | 1024²   | 20             | ~25×          |\n\nIndividual options always override profile values:\n\n```ts\nnew FluidSimulation(renderer, {\n  profile: 'balanced',\n  pressureIterations: 8, \u002F\u002F overrides balanced default of 12\n})\n```\n\n| Property              | Default   | What it does                                      |\n| --------------------- | --------- | ------------------------------------------------- |\n| `pressureIterations`  | `12`      | Jacobi iterations for the balanced profile.       |\n| `curlStrength`        | `0.55`    | Vorticity confinement strength.                   |\n| `enableVorticity`     | `false`   | Toggle the curl + vorticity passes (Fedkiw 2001). |\n| `bfecc`               | `true`    | BFECC advection (sharper, ~5× cost in advect).    |\n| `velocityDissipation` | `0.985`   | Per-second decay of velocity field.               |\n| `densityDissipation`  | `0.91`    | Per-second decay of density field.                |\n| `dyeDissipation`      | `0.91`    | Per-second decay of the optional dye field.       |\n| `pressureDissipation` | `0.8`     | Decay of residual pressure between frames.        |\n| `splatRadius`         | `0.00042` | Default radius for `addSplat()` (UV² units).      |\n| `splatForce`          | `6`       | Default force for `attachPointerSplats`.          |\n| `reflectWalls`        | `true`    | Reflect flow from the viewport edges.             |\n| `enableDye`           | `false`   | Update the optional per-stroke dye texture.       |\n\nRead-only outputs:\n\n```ts\nfluid.velocityTexture \u002F\u002F THREE.Texture, .xy is the post-advection flow field\nfluid.velocityProjectedTexture \u002F\u002F THREE.Texture, projected pre-advection flow snapshot\nfluid.densityTexture \u002F\u002F THREE.Texture, .rg is flow-like display data, .b is density\nfluid.dyeTexture \u002F\u002F THREE.Texture, .rgb is the optional colored dye field\n```\n\nTSL\u002FWebGPU exposes the same simulation state as `TextureNode`s, which are the\ninputs expected by the TSL effect factories:\n\n```ts\nfluid.velocityNode \u002F\u002F TextureNode, .xy is the post-advection flow field\nfluid.densityNode \u002F\u002F TextureNode, .rg is flow-like display data, .b is density\nfluid.dyeNode \u002F\u002F TextureNode, .rgb is the optional colored dye field\nfluid.pressureNode \u002F\u002F TextureNode, advanced\u002Fdebug pressure field\nfluid.divergenceNode \u002F\u002F TextureNode, advanced\u002Fdebug divergence field\nfluid.curlNode \u002F\u002F TextureNode, advanced\u002Fdebug curl field\n```\n\nGLSL passes and TSL factories are paired by effect family:\n\n| GLSL pass class                     | TSL factory                 |\n| ----------------------------------- | --------------------------- |\n| `SimpleDistortionPass`              | `simpleDistortion()`        |\n| `RGBShiftDistortionPass`            | `rgbShiftDistortion()`      |\n| `ChromaticDistortionPass`           | `chromaticDistortion()`     |\n| `WaterDistortionPass`               | `waterDistortion()`         |\n| `WaterCausticsDistortionPass`       | `waterCausticsDistortion()` |\n| `DefaultOverlayPass`                | `defaultOverlay()`          |\n| `VolumeCursorOverlayPass`           | `volumeCursorOverlay()`     |\n| `TrailOverlayPass`                  | `trailOverlay()`            |\n| `OilOverlayPass`                    | `oilOverlay()`              |\n| `VelocityOverlayPass`               | `velocityOverlay()`         |\n| `ColorfulOverlayPass`               | `colorfulOverlay()`         |\n| `RainbowFishOverlayPass`            | `rainbowFishOverlay()`      |\n| `GlazeOverlayPass`                  | `glazeOverlay()`            |\n| `BurnOverlayPass`                   | `burnOverlay()`             |\n| `SmokeOverlayPass`                  | `smokeOverlay()`            |\n| `ArtInkOverlayPass`                 | `artInkOverlay()`           |\n| `RainbowInkOverlayPass`             | `rainbowInkOverlay()`       |\n| `ColorWaterOverlayPass`             | `colorWaterOverlay()`       |\n| `LiquidLensOverlayPass`             | `liquidLensOverlay()`       |\n| `DensityTintOverlayPass`            | `densityTintOverlay()`      |\n\nMethods:\n\n```ts\nfluid.resize(width, height)\nfluid.addSplat(x01, y01, dx, dy, { radius?, color?, dyeColor? })\nfluid.step(deltaSeconds)\nfluid.dispose()\n```\n\n### `attachPointerSplats(element, fluid)`\n\nAttaches pointer listeners and pushes splats into the solver. Splat radius and\nforce are read from `fluid.splatRadius` \u002F `fluid.splatForce` on every event —\nset them in the constructor or write them at runtime; live-tuning works\nwithout re-attaching. Returns a teardown function.\n\nOptions:\n\n```ts\nattachPointerSplats(renderer.domElement, fluid, {\n  coloredStrokes: true,\n  colorUpdateSpeed: 10,\n  colorize: (dx, dy, timeMs) => [Math.abs(dx) * 0.003, 0.08, Math.abs(dy) * 0.003],\n})\n```\n\n### `FullscreenPass(material)`\n\nTiny full-screen quad pass for compositing your shader on top of the solver's outputs.\nUse `FULLSCREEN_VERTEX` as your vertex shader.\n\n### `createSceneTarget(width, height)`\n\nConvenience factory for a `WebGLRenderTarget` configured for sRGB display sampling.\n\n## Tutorials\n\nThe site, tutorials, and live example pages now use one Astro engine. Source for\nthe hand-authored guides lives in `src\u002Fcontent\u002Ftutorials\u002F`; reusable tutorial UI\nlives in `src\u002Fcomponents\u002Ftutorials\u002F`; example route metadata lives in\n`src\u002Fdata\u002Fexamples.ts`. The static site build writes to `dist\u002F`.\n\n```bash\npnpm dev           # Astro site + live examples at http:\u002F\u002F127.0.0.1:4321\u002F\npnpm build         # typecheck + static site build -> dist\u002F\npnpm docs:dev      # alias for pnpm dev\npnpm docs:build    # Astro site build -> dist\u002F\n```\n\nThe public tutorial surface is Astro-only. General guides live at `\u002Ftutorials\u002F`,\nand every runnable demo has a personal walkthrough at\n`\u002Ftutorials\u002F\u003Cpipeline>\u002F\u003Clevel>\u002F\u003Cslug>\u002F`. The runnable demos live at\n`\u002Fexamples\u002F\u003Cpipeline>\u002F\u003Clevel>\u002F\u003Cslug>\u002F` and are generated from the same Astro\nmanifest while importing `examples\u002F\u003Cpipeline>\u002F\u003Clevel>\u002F\u003Cslug>\u002Fmain.ts`.\n\n### Core guides\n\nThese are source links. When `pnpm dev` is running, the same guides are served\nunder `http:\u002F\u002F127.0.0.1:4321\u002Ftutorials\u002F`.\n\n- [Getting Started](src\u002Fcontent\u002Ftutorials\u002Fgetting-started.mdx) — solver lifecycle, pointer splats, resize handling, outputs, profiles, and parameters.\n- [Effects Guide](src\u002Fcontent\u002Ftutorials\u002Feffects-guide.mdx) — overlay and distortion families, what they read, and when to use each one.\n- [Particles Guide](src\u002Fcontent\u002Ftutorials\u002Fparticles-guide.mdx) — procedural particles, GPGPU particles, camera data, and tuning without ambiguity.\n- [GLSL vs TSL](src\u002Fcontent\u002Ftutorials\u002Fglsl-vs-tsl.mdx) — choosing the WebGL\u002FGLSL or WebGPU\u002FTSL pipeline.\n\n### Demo walkthroughs\n\nPer-demo walkthrough content is generated from\n[src\u002Fdata\u002FexampleTutorials.ts](src\u002Fdata\u002FexampleTutorials.ts), with route\nmetadata in [src\u002Fdata\u002Fexamples.ts](src\u002Fdata\u002Fexamples.ts). When `pnpm dev` is\nrunning, walkthroughs live at `\u002Ftutorials\u002F\u003Cpipeline>\u002F\u003Clevel>\u002F\u003Cslug>\u002F`.\n\n- [Hello World source](examples\u002Fglsl\u002Fminimal\u002Fhelloworld\u002Fmain.ts) — smallest solver integration.\n- [Overlay source](examples\u002Fglsl\u002Ffull\u002Foverlay\u002Fmain.ts) — scene compositing, dye-aware strokes, and style controls.\n- [Distortion source](examples\u002Fglsl\u002Ffull\u002Fdistortion\u002Fmain.ts) — UV refraction, chromatic styles, water, and caustics.\n- [Simple Particles source](examples\u002Fglsl\u002Ffull\u002Fparticles-trefoil\u002Fmain.ts) — procedural particle displacement without GPGPU state.\n- [GPGPU Particles 2D source](examples\u002Fglsl\u002Ffull\u002Fparticles-2d\u002Fmain.ts) and [GPGPU Particles 3D source](examples\u002Fglsl\u002Ffull\u002Fparticles-3d\u002Fmain.ts) — persistent particle state driven by the fluid field.\n- [TSL Combined Demo source](examples\u002Ftsl\u002Ffull\u002Fcombined\u002Fmain.ts) — combined WebGPU composition surface.\n- [TSL Mega Demo source](examples\u002Ftsl\u002Ffull\u002Fmega\u002Fmain.ts) — hero-style morphing WebGPU particle composition.\n- [Fluid Text minimal source](examples\u002Ftsl\u002Fminimal\u002Ffluid-text\u002Fmain.ts) and [Fluid Text full source](examples\u002Ftsl\u002Ffull\u002Ffluid-text\u002Fmain.ts) — ordinary DOM typography mirrored into a `CanvasTexture`, then distorted and inked by the TSL fluid pipeline.\n\n## Repo layout\n\n```\nsrc\u002F\n├── core\u002F                                       ← published library (only three is required)\n│   ├── shared\u002F\n│   │   └── pointerSplats.ts                    ← pipeline-agnostic\n│   ├── glsl\u002F                                   ← WebGL\u002FGLSL entry: 'three-fluid-fx'\n│   │   ├── simulation\u002F\n│   │   ├── effects\u002F                            ← EffectComposer-ready Pass subclasses\n│   │   │   ├── distortion\u002F                     ←  5 distortion passes\n│   │   │   └── overlay\u002F                        ← 15 overlay passes\n│   │   └── index.ts\n│   └── tsl\u002F                                    ← WebGPU\u002FTSL entry: 'three-fluid-fx\u002Ftsl'\n│       ├── simulation\u002F                         ← WGSL compute solver\n│       ├── effects\u002F                            ← RenderPipeline\u002FTSL node functions\n│       └── index.ts\n├── content\u002Ftutorials\u002F                          ← Astro MDX tutorial source\n├── data\u002Fexamples.ts                            ← examples manifest \u002F route metadata\n├── components\u002F\n│   ├── examples\u002F                               ← catalog cards and shared example UI\n│   ├── site\u002F                                   ← header\u002Ffooter shared by site pages\n│   └── tutorials\u002F                              ← tutorial UI blocks\n├── layouts\u002F                                    ← site, tutorial, and fullscreen example shells\n├── pages\u002F\n│   ├── examples\u002F                               ← Astro-generated live example routes\n│   └── tutorials\u002F                              ← Astro-generated tutorial routes\n└── scripts\u002Fexample-pages.ts                    ← imports the selected example main.ts\n\nexamples\u002F\n├── extras\u002F                                     ← demo helpers (not published)\n│   ├── controls\u002F                               ← Tweakpane wrapper, param ranges\n│   ├── backgrounds\u002F{glsl,tsl}\u002F                 ← background implementations\n│   ├── particles\u002F{glsl,tsl}\u002F                   ← example particle systems\n│   ├── text\u002F                                   ← DOM text to CanvasTexture helpers\n│   └── resolveProfile.ts                       ← URL profile resolver (?profile=balanced)\n├── glsl\u002F{minimal,full}\u002F\u003Cslug>\u002Fmain.ts          ← WebGL runtime entrypoints\n└── tsl\u002F{minimal,full}\u002F\u003Cslug>\u002Fmain.ts           ← WebGPU runtime entrypoints\n\nexamples-js\u002F                                   ← generated from examples\u002F\n├── glsl\u002F{minimal,full}\u002F\u003Cslug>\u002Fmain.js\n└── tsl\u002F{minimal,full}\u002F\u003Cslug>\u002Fmain.js\n```\n\n## Develop\n\n```bash\npnpm install\npnpm dev               # Astro site + live examples at http:\u002F\u002F127.0.0.1:4321\u002F\npnpm build             # typecheck + Astro static build -> dist\u002F\npnpm build:js          # regenerate examples-js\u002F\npnpm build:lib         # library build (both pipelines + .d.ts) → dist-lib\u002F{glsl,tsl}\u002F\npnpm build:lib:glsl    # GLSL bundle only → dist-lib\u002Fglsl\u002F\npnpm build:lib:tsl     # TSL bundle only  → dist-lib\u002Ftsl\u002F\npnpm docs:dev          # alias for pnpm dev\npnpm docs:build        # Astro site build -> dist\u002F\n```\n\n## Notes on design\n\n- **No `configure(...)` method.** Properties are public; the solver re-reads them\n  each frame. This keeps GUI integration trivial.\n- **No GUI in the library.** Tweakpane is a dependency of the **examples**, not of\n  the library. Tree-shakers will drop nothing extra; users who don't need a GUI\n  never pay for one.\n- **GPGPU particles are not part of the library.** They live in\n  `examples\u002Fextras\u002Fparticles\u002F` as an example of how to use\n  `fluid.velocityTexture` to drive your own particle system.\n\n## Acknowledgements & scope\n\n**This library does not introduce new fluid-simulation algorithms.** The\nmathematics is Jos Stam's _Stable Fluids_ (SIGGRAPH 1999) with Fedkiw's\nvorticity confinement (2001) and optional BFECC advection — all 20+ years\nold and widely implemented. The WebGL adaptation patterns are well-trodden\nground, popularised by PavelDoGreat's WebGL-Fluid-Simulation and walked\nthrough clearly by the mofu-dev tutorial.\n\n**What this package contributes** is _packaging and ergonomics for three.js\nprojects_: tree-shakable npm entries with a plain-property API, profile\npresets, three.js-native texture outputs, and small helpers\n(`attachPointerSplats`, `FullscreenPass`). The solver is opinionated towards\nreal-time VFX — not CFD accuracy.\n\nIf you want to learn the algorithm, read Stam's paper and the mofu-dev\ntutorial. If you want to drop a velocity\u002Fdensity field into your three.js\nscene in five lines, use this.\n\n### Algorithms (not authored by this project)\n\n- Jos Stam, [_Stable Fluids_](https:\u002F\u002Fwww.dgp.toronto.edu\u002Fpeople\u002Fstam\u002Freality\u002FResearch\u002Fpdf\u002Fns.pdf) (SIGGRAPH 1999) — pressure projection method.\n- Fedkiw, Stam, Jensen, _Visual Simulation of Smoke_ (SIGGRAPH 2001) — vorticity confinement.\n- Kim, Liu, Llamas, Rossignac, _Advections with Significantly Reduced Dissipation and Diffusion_ (2007) — BFECC.\n\n### WebGL adaptations and tutorials this work studied\n\n- [PavelDoGreat\u002FWebGL-Fluid-Simulation](https:\u002F\u002Fgithub.com\u002FPavelDoGreat\u002FWebGL-Fluid-Simulation) (MIT) — popularised the WebGL adaptation techniques used here.\n- [mofu-dev — _Stable Fluids_](https:\u002F\u002Fmofu-dev.com\u002Fen\u002Fblog\u002Fstable-fluids\u002F) — clear walkthrough of the algorithm.\n- [mnmxmx\u002Ffluid-three](https:\u002F\u002Fgithub.com\u002Fmnmxmx\u002Ffluid-three) — the implementation accompanying the mofu-dev post.\n\n### What this project authored\n\nThe public API (`FluidSimulation`, `attachPointerSplats`, profile presets),\nthe three.js integration layer, the example tutorials and the packaging.\nThe shaders are derivatives of the prior-art shader code listed above.\n\n## License\n\nMIT © Artem Korenevych. See [LICENSE](LICENSE) and\n[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).\n","three-fluid-fx 是一个为 three.js 项目提供实时流体效果的2D稳定流体求解器。它支持WebGL\u002FGLSL和WebGPU\u002FTSL两种渲染管线，旨在简化将流体模拟集成到three.js项目中的过程，避免开发者需要深入研究复杂的学术论文。核心功能包括流体光标叠加、屏幕扭曲（UV折射）、粒子位移等，能够实现诸如彩色墨迹追踪、热浪效果及液态镜头等视觉特效。适用于需要在网页或应用中添加逼真流体动态效果的各种场景，如游戏开发、互动展示或艺术创作。",2,"2026-06-11 03:59:35","CREATED_QUERY"]