Guides
Emitters
An emitter injects fuel, heat and smoke into the grid. It can be a point, a sphere, a box or the surface of any mesh. Every one is a live handle you can move, retune, disable or remove.
mesh preset: a torus knot in the demo's shape slot. The demo rotates the mesh, and the emitter follows its world matrix every frame.#Add one
const burner = fire.addEmitter({
type: 'sphere',
position: [0, 0.6, 0], // world metres
radius: 0.3,
fuel: 60, // fuel per second
temperature: 1.3, // what it injects is ignited at this temperature
smoke: 0.6, // smoke per second (× params.smoke)
});
burner.position.x += 0.5; // move it: every field is live
burner.set({ fuel: 90, velocity: [0, 3, 0] });
burner.enabled = false; // pause it
burner.remove(); // or fire.removeEmitter(burner)loadPreset() replaces every emitter, including ones you added. Call addEmitter() after loading a preset, or build the fire from preset: null and add your own. fire.clearEmitters() removes them all.
#Emitter types
type | Shape | Notes |
|---|---|---|
'point' | Small sphere | radius defaults to 0.15 m |
'sphere' | Sphere of radius | The default type. radius defaults to 0.3 m |
'box' | Box of size | radius is the edge softness here and defaults to 0.12 m |
'mesh' | The surface of a mesh | Surface samples splatted into the grid every frame |
Up to 8 point, sphere and box emitters are simulated at once, and any number of mesh emitters. Extra analytic emitters are skipped.
#Source fields
All of these are fields on the handle, with the defaults from EMITTER_DEFAULTS.
| Field | Default | |
|---|---|---|
fuel | 60 | Fuel injected per second. More fuel means a bigger flame |
temperature | 1.3 | Ignition temperature of what it injects: about 0.8 smoulders, 1.4 is a torch and 1.6 a blast |
smoke | 0.6 | Smoke per second, multiplied by params.smoke |
flicker | 0.5 | 0 is a steady source. At 1 the injection is fully gated by noise, which breaks the flame into licks |
velocity | (0, 1.6, 0) | Jet velocity in m/s |
velocityBlend | 0.3 | How hard the gas is forced toward velocity. 0.95 is a hard jet |
inheritVelocity | 0 | Fraction of the emitter's measured motion added to velocity |
embers | 0.5 | Ember spawn rate, 0 for none |
emberOffset, emberRadius | (0, 0.2, 0), 0.3 | Where the embers spawn, relative to the emitter |
#Jets
A jet is an emitter with a strong velocity and a velocityBlend near 1. The jet preset fires a 7.5 m/s nozzle up and to the right into a sphere obstacle:
const dir = new THREE.Vector3(0.88, 0.47, 0).normalize();
fire.addEmitter({
type: 'sphere', position: [-1.45, 0.62, 0], radius: 0.2,
fuel: 60, temperature: 1.45, smoke: 0.8, flicker: 0.3,
velocity: dir.multiplyScalar(7.5), velocityBlend: 0.95,
embers: 2.5,
});jet: the forced velocity carries the flame sideways until it splashes over the obstacle.#Moving emitters
Each frame the emitter measures its own world velocity into emitter.motion, clamped to 8 m/s. inheritVelocity passes a fraction of that on to the gas, so a waved torch leaves a trail instead of a flame that stays upright.
const torch = fire.addEmitter({
type: 'sphere', position: [0, 1.6, 0], radius: 0.28,
fuel: 70, temperature: 1.4, velocity: [0, 1.4, 0], velocityBlend: 0.35,
inheritVelocity: 0.6,
});
renderer.setAnimationLoop(() => {
torch.position.copy(hand.getWorldPosition(tmp)); // follow anything
fire.update(dt);
fire.render();
});torch preset. The demo walks the anchor on a figure-eight, and inheritVelocity: 0.6 bends the flame back along the path.#Mesh emitters
A mesh emitter samples points on a mesh surface once (with normals) and splats them into the grid every frame, using the mesh's current world matrix. Move, rotate or scale the mesh and the fire follows.
const statue = scene.getObjectByName('statue');
fire.addEmitter({
type: 'mesh',
mesh: statue, // any THREE.Mesh with geometry
fuel: 9, temperature: 1.1, smoke: 0.15,
samples: 16000, // surface samples
weight: 0.6, // strength
push: 7, // outward + upward push along the normals
filter: (p, n) => n.y > -0.4, // optional: skip downward-facing samples
});Without a scene mesh, pass geometry. It's a BufferGeometry, or one of the built-ins 'teepee', 'torusKnot', 'torus' and 'icosahedron'. The geometry stays invisible and is placed at position.
fire.addEmitter({ type: 'mesh', geometry: 'torusKnot', position: [0, 1.65, 0], samples: 26000, weight: 0.45 });#Preset mesh slots
Presets refer to meshes by slot name, so the same preset file works with your mesh or with a built-in fallback. campfire uses the logs slot (fallback teepee), and mesh uses shape (fallback torusKnot).
const fire = await FireSystem.create({ renderer, scene, camera, meshes: { logs: myLogs } });
fire.setMesh('shape', myStatue); // register later
fire.loadPreset('mesh', { meshes: { shape: myStatue } }); // or per loadloadPreset() caches surface samples per geometry and sample count, so switching back and forth between presets doesn't resample.