smoke

@three-blocks/coreWebGPU
smoke(node : Node<Texture>, options : SmokeOptions) : 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(scenePass, { ... })

Example: Basic postprocessing setup

Example: Interactive pointer-driven splats

import { smoke } from '@three-blocks/core';
import { uniform } from 'three/tsl';
import { Vector2 } from 'three/webgpu';

// Create a uniform to track pointer position in NDC [-1, 1]
const pointer = uniform(new Vector2(0, 0));

const fluidNode = smoke(scenePass, {
  pointer: pointer.value,  // Pass the Vector2 directly
  pointerScale: 3,         // Stronger splat force
  radius: 0.3              // Larger splat radius
});

// Update pointer on mouse move
document.addEventListener('mousemove', (e) => {
  pointer.value.x = (e.clientX / window.innerWidth) * 2 - 1;
  pointer.value.y = -(e.clientY / window.innerHeight) * 2 + 1;
});
Parameters
nodeoptionalNode<Texture>
Scene/texture input to chain from (e.g. result of pass(scene, camera)).
optionsoptionalSmokeOptions
Configuration options.
Returns
Node — Color node sampling the current dye texture of the fluid simulation.
Example
import * as THREE from 'three/webgpu';
import { pass } from 'three/tsl';
import { smoke } from '@three-blocks/core';

// Create renderer, scene, camera
const renderer = new THREE.WebGPURenderer();
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight);

// Setup postprocessing with smoke effect
const postProcessing = new THREE.PostProcessing(renderer);
const scenePass = pass(scene, camera);

// Apply smoke simulation as post effect
const fluidNode = smoke(scenePass, {
  simRes: 128,
  dyeRes: 512,
  curlStrength: 30,
  densityDissipation: 0.98
});

postProcessing.outputNode = fluidNode;

// Render loop
function animate() {
  requestAnimationFrame(animate);
  postProcessing.render();
}