smoke

@three-blocks/coreWebGPU
smoke(pointer : THREE.Vector2, simRes : number, dyeRes : number, iterations : number, densityDissipation : number, velocityDissipation : number, pressureDissipation : number, curlStrength : number, pressureFactor : number, radius : number, useBoundaries : boolean, pointerScale : number, neighborStride : number, speedFactor : number) : Node

Smoke Simulation (TSL) – a 2D velocity–pressure solver that runs in screen space.

Turns a fullscreen pass into a stylized, real-time smoke/ink flow using WebGPU compute through Three.js TSL. Uses StorageTexture resources and takes advantage of Tier2 read–write access whenever the adapter exposes it. It owns and ping-pongs its internal textures (velocity, pressure, density, curl, divergence) and updates itself every frame when used in a PostProcessing chain.

Features

  • Semi-Lagrangian advection for velocity and density
  • Vorticity confinement (curl) and divergence-free projection (pressure solve)
  • Configurable dissipation, pressure iterations and curl strength
  • Optional pointer-driven splats via a vec2 uniform (no global dispatcher)
  • Drop-in for post-processing: postProcessing.outputNode = smoke(pointer, 128, 512, ...)

Example: Basic postprocessing setup

Example: Interactive pointer-driven splats

import * as THREE from 'three/webgpu';
import { smoke } from '@three-blocks/core';

const pointer = new THREE.Vector2();

// Pass pointer as first argument - motion automatically injects splats
const fluidNode = smoke(pointer, 128, 512, 3, 0.97, 0.98, 0.8, 20, 0.2, 0.1, true, 45);

// Update pointer on mouse move (NDC coordinates: -1 to +1)
document.addEventListener('mousemove', (e) => {
  pointer.x = (e.clientX / window.innerWidth) * 2 - 1;
  pointer.y = -(e.clientY / window.innerHeight) * 2 + 1;
});
Parameters
pointeroptionalTHREE.Vector2
NDC-like pointer in [-1, 1]; when present, motion injects splats.
simResoptionalnumber
Square resolution for velocity/pressure buffers.
Default is 128.
dyeResoptionalnumber
Square resolution for density buffer.
Default is 512.
iterationsoptionalnumber
Pressure Jacobi iterations per solve.
Default is 3.
densityDissipationoptionalnumber
Density dissipation factor in [0, 1].
Default is 0.97.
velocityDissipationoptionalnumber
Velocity dissipation factor in [0, 1].
Default is 0.98.
pressureDissipationoptionalnumber
Damp factor for pressure clear step.
Default is 0.8.
curlStrengthoptionalnumber
Vorticity confinement scale.
Default is 20.
pressureFactoroptionalnumber
Pressure factor constant in Jacobi updates.
Default is 0.2.
radiusoptionalnumber
Gaussian splat radius in UV^2. Increase for larger splats.
Default is 0.1.
useBoundariesoptionalboolean
Mirror-velocity boundary conditions at screen edges.
Default is true.
pointerScaleoptionalnumber
Multiplier applied to pointer delta when generating splats.
Default is 45.
neighborStrideoptionalnumber
Multiplier for curl/divergence/pressure neighbor texel offsets.
Default is 1.
speedFactoroptionalnumber
Scales sub-stepping relative to frame time (lower = more substeps).
Default is 1.
Returns
Node — Color node sampling the current dye texture of the fluid simulation.
Example
import * as THREE from 'three/webgpu';
import { smoke } from '@three-blocks/core';

const renderer = new THREE.WebGPURenderer();
await renderer.init();

const postProcessing = new THREE.PostProcessing(renderer);
const pointer = new THREE.Vector2();

// smoke(pointer, simRes, dyeRes, iterations, densityDissipation, velocityDissipation,
//       pressureDissipation, curlStrength, pressureFactor, radius, useBoundaries, pointerScale)
const fluidNode = smoke(pointer, 128, 512, 3, 0.97, 0.98, 0.8, 20, 0.2, 0.1, true, 45);

postProcessing.outputNode = fluidNode;

renderer.setAnimationLoop(() => postProcessing.render());