threejs-worldgen
    Preparing search index...

    Class ParticleSystem

    A fixed-capacity pool of GPU particles: emit, update and (optionally) depth-sort run as TSL compute passes; one instanced draw renders them as camera-facing or velocity-stretched billboards with soft depth fade. Nothing is read back to the CPU.

    Emission is a ring buffer: each update spawns rate × dt particles (fractions carry over) from a point, box, disc, sphere or a weighted list of sources the CPU refreshes cheaply. Every particle's random numbers come from its serial number and seed, so a run is reproducible. Forces: gravity, temperature-driven buoyancy with cooling, wind with shear and drag, curl-noise turbulence and, with a ParticleGrid, lift from the grid's heat. Size, colour and opacity follow lifetime curves.

    const smoke = new ParticleSystem({ capacity: 8000, rate: 300, render: { shading: 'smoke', sort: true } })
    scene.add(smoke.object)
    // each frame:
    smoke.lighting.fromScene(scene)
    smoke.update(renderer, dt, camera)
    Index

    GPU buffers.

    capacity: number

    Pool size.

    Spawn scheduling (serials and ring slots).

    curves: CurveUniforms = ...

    Lifetime curves.

    grid: ParticleGrid | null

    Grid read by the forces and lighting, if any.

    Sun and sky light.

    object: Mesh<InstancedBufferGeometry, MeshBasicNodeMaterial>

    Add this to your scene (one instanced mesh). Particle positions are in its local space.

    Resolved settings.

    sources: SourceTable

    Weighted spawn sources (for emitter.shape: 'sources').

    time: number = 0

    Seconds simulated (wraps every 1000 s for float precision).

    uniforms: {
        absorption: UniformNode<"float", number>;
        albedoClean: UniformNode<"color", Color>;
        albedoDirty: UniformNode<"color", Color>;
        ambientTemperature: UniformNode<"float", number>;
        anisotropy: UniformNode<"float", number>;
        aspect: UniformNode<"float", number>;
        blackbody: UniformNode<"float", number>;
        buoyancy: UniformNode<"float", number>;
        camera: UniformNode<"vec3", Vector3>;
        capHeight: UniformNode<"float", number>;
        cooling: UniformNode<"float", number>;
        detail: UniformNode<"float", number>;
        detailDistance: UniformNode<"float", number>;
        drag: UniformNode<"float", number>;
        dt: UniformNode<"float", number>;
        emitPosition: UniformNode<"vec3", Vector3>;
        emitSize: UniformNode<"vec3", Vector3>;
        emitVelocity: UniformNode<"vec3", Vector3>;
        glow: UniformNode<"color", Color>;
        glowStrength: UniformNode<"float", number>;
        gravity: UniformNode<"float", number>;
        gridLift: UniformNode<"float", number>;
        intensity: UniformNode<"float", number>;
        life: UniformNode<"vec3", Vector3>;
        opacity: UniformNode<"float", number>;
        pixelAngle: UniformNode<"float", number>;
        refraction: UniformNode<"float", number>;
        seed: UniformNode<"uint", number>;
        shape: UniformNode<"int", number>;
        silverLining: UniformNode<"float", number>;
        size: UniformNode<"float", number>;
        sizeRandom: UniformNode<"vec3", Vector3>;
        softness: UniformNode<"float", number>;
        sortRange: UniformNode<"float", number>;
        sourceCount: UniformNode<"int", number>;
        sourceTotal: UniformNode<"float", number>;
        spawnCount: UniformNode<"uint", number>;
        spawnFirst: UniformNode<"uint", number>;
        spawnSlot: UniformNode<"uint", number>;
        spread: UniformNode<"float", number>;
        stretch: UniformNode<"float", number>;
        temperature: UniformNode<"vec3", Vector3>;
        time: UniformNode<"float", number>;
        turbulence: UniformNode<"float", number>;
        turbulenceScale: UniformNode<"float", number>;
        turbulenceSpeed: UniformNode<"float", number>;
        wind: UniformNode<"vec3", Vector3>;
        windShear: UniformNode<"float", number>;
    } = ...

    Shader uniforms.

    Type Declaration

    • absorption: UniformNode<"float", number>

      Absorption.

    • albedoClean: UniformNode<"color", Color>

      Clean smoke albedo.

    • albedoDirty: UniformNode<"color", Color>

      Dirty smoke albedo.

    • ambientTemperature: UniformNode<"float", number>

      Ambient temperature.

    • anisotropy: UniformNode<"float", number>

      HG anisotropy.

    • aspect: UniformNode<"float", number>

      Aspect.

    • blackbody: UniformNode<"float", number>

      Blackbody on/off (0/1).

    • buoyancy: UniformNode<"float", number>

      Buoyancy.

    • camera: UniformNode<"vec3", Vector3>

      Camera position in this system's local space.

    • capHeight: UniformNode<"float", number>

      Smoke cap height (0 = off).

    • cooling: UniformNode<"float", number>

      Cooling rate.

    • detail: UniformNode<"float", number>

      Detail.

    • detailDistance: UniformNode<"float", number>

      Detail distance.

    • drag: UniformNode<"float", number>

      Drag.

    • dt: UniformNode<"float", number>

      Step, seconds.

    • emitPosition: UniformNode<"vec3", Vector3>

      Emitter centre.

    • emitSize: UniformNode<"vec3", Vector3>

      Emitter size.

    • emitVelocity: UniformNode<"vec3", Vector3>

      Initial velocity.

    • glow: UniformNode<"color", Color>

      Glow colour.

    • glowStrength: UniformNode<"float", number>

      Glow strength.

    • gravity: UniformNode<"float", number>

      Gravity.

    • gridLift: UniformNode<"float", number>

      Grid lift.

    • intensity: UniformNode<"float", number>

      Brightness.

    • life: UniformNode<"vec3", Vector3>

      Life range.

    • opacity: UniformNode<"float", number>

      Opacity.

    • pixelAngle: UniformNode<"float", number>

      Radians per pixel (for minimum on-screen width of sparks).

    • refraction: UniformNode<"float", number>

      Haze refraction.

    • seed: UniformNode<"uint", number>

      Seed.

    • shape: UniformNode<"int", number>

      Emitter shape id.

    • silverLining: UniformNode<"float", number>

      Silver lining.

    • size: UniformNode<"float", number>

      Base size.

    • sizeRandom: UniformNode<"vec3", Vector3>

      Size random range.

    • softness: UniformNode<"float", number>

      Soft fade distance.

    • sortRange: UniformNode<"float", number>

      Farthest sort distance.

    • sourceCount: UniformNode<"int", number>

      Sources in use.

    • sourceTotal: UniformNode<"float", number>

      Sum of source weights.

    • spawnCount: UniformNode<"uint", number>

      Particles in this frame's batch.

    • spawnFirst: UniformNode<"uint", number>

      First serial of this frame's batch.

    • spawnSlot: UniformNode<"uint", number>

      Ring slot of this frame's batch.

    • spread: UniformNode<"float", number>

      Random speed.

    • stretch: UniformNode<"float", number>

      Stretch.

    • temperature: UniformNode<"vec3", Vector3>

      Temperature range.

    • time: UniformNode<"float", number>

      Animation clock.

    • turbulence: UniformNode<"float", number>

      Turbulence strength.

    • turbulenceScale: UniformNode<"float", number>

      Turbulence scale.

    • turbulenceSpeed: UniformNode<"float", number>

      Turbulence speed.

    • wind: UniformNode<"vec3", Vector3>

      Wind.

    • windShear: UniformNode<"float", number>

      Wind shear per 100 m.

    • Kills every particle (next update starts empty) and restarts the serials.

      Parameters

      • renderer: Renderer

      Returns this

    • Advances the clock and uniforms by dt and returns this frame's compute passes (emit, update) without running them, so several systems (and grid passes) can go to the GPU in one renderer.compute([...]). Call ParticleSystem.sort after them if sorting.

      Parameters

      • renderer: Renderer
      • dt: number
      • Optionalcamera: Camera | null

      Returns ComputeNode[]

    • Replaces all settings (anything not given goes back to defaults); structural ones stay.

      Parameters

      • input: {
            capacity?: number;
            curves?: { color?: string[]; opacity?: number[]; size?: number[] };
            emitter?: {
                position?: [number, number, number];
                shape?: EmitterShape;
                size?: [number, number, number];
                spread?: number;
                temperature?: [number, number];
                velocity?: [number, number, number];
            };
            forces?: {
                ambientTemperature?: number;
                buoyancy?: number;
                cooling?: number;
                drag?: number;
                gravity?: number;
                gridLift?: number;
                turbulence?: number;
                turbulenceScale?: number;
                turbulenceSpeed?: number;
                wind?: [number, number, number];
                windShear?: number;
            };
            life?: [number, number];
            maxPerFrame?: number;
            rate?: number;
            render?: {
                absorption?: number;
                albedo?: [string, string];
                anisotropy?: number;
                aspect?: number;
                blackbody?: boolean;
                blending?: "additive" | "alpha" | "premultiplied";
                capHeight?: number;
                detail?: number;
                detailDistance?: number;
                glow?: string;
                glowStrength?: number;
                intensity?: number;
                lightSteps?: number;
                opacity?: number;
                refraction?: number;
                shading?: ParticleShading;
                shadowSteps?: number;
                silverLining?: number;
                size?: number;
                sizeRandom?: [number, number];
                softness?: number;
                sort?: boolean;
                stretch?: number;
            };
            seed?: string
            | number;
        } = {}
        • Optionalcapacity?: number

          Pool size: the most particles alive at once. Changing it rebuilds the GPU buffers.

        • Optionalcurves?: { color?: string[]; opacity?: number[]; size?: number[] }

          Shape over life (0 → 1), each an evenly spaced list of 1 to 8 keys.

          • Optionalcolor?: string[]

            Colour (#rrggbb); multiplied by the blackbody colour when render.blackbody.

          • Optionalopacity?: number[]

            Opacity multiplier.

          • Optionalsize?: number[]

            Size multiplier.

        • Optionalemitter?: {
              position?: [number, number, number];
              shape?: EmitterShape;
              size?: [number, number, number];
              spread?: number;
              temperature?: [number, number];
              velocity?: [number, number, number];
          }

          Spawn shape and initial state.

          • Optionalposition?: [number, number, number]

            Centre, local space, metres.

          • Optionalshape?: EmitterShape

            point, box (half extents size), disc (radius size[0], on XZ), sphere (radius size[0]) or sources (see threejs-particles!ParticleSystem.setSources).

          • Optionalsize?: [number, number, number]

            Box half extents / disc and sphere radius in [0]; for sources, the jitter half extents around each source.

          • Optionalspread?: number

            Random extra speed in a random direction, m/s.

          • Optionaltemperature?: [number, number]

            Initial temperature range, kelvin (drives buoyancy, cooling and blackbody colour).

          • Optionalvelocity?: [number, number, number]

            Initial velocity, m/s.

        • Optionalforces?: {
              ambientTemperature?: number;
              buoyancy?: number;
              cooling?: number;
              drag?: number;
              gravity?: number;
              gridLift?: number;
              turbulence?: number;
              turbulenceScale?: number;
              turbulenceSpeed?: number;
              wind?: [number, number, number];
              windShear?: number;
          }

          What moves particles.

          • OptionalambientTemperature?: number

            Ambient air temperature, kelvin.

          • Optionalbuoyancy?: number

            Buoyancy: up-acceleration = 9.81 × buoyancy × (T − ambient) / ambient (Boussinesq).

          • Optionalcooling?: number

            Exponential cooling towards ambient, 1/s.

          • Optionaldrag?: number

            Drag towards the air velocity, 1/s.

          • Optionalgravity?: number

            Gravity, m/s² (down).

          • OptionalgridLift?: number

            With a grid: up-acceleration from the grid's channel 0 (heat h), gridLift × h / (1 + h) m/s².

          • Optionalturbulence?: number

            Curl-noise turbulence, m/s².

          • OptionalturbulenceScale?: number

            Eddy size, metres.

          • OptionalturbulenceSpeed?: number

            How fast the eddies change, 1/s.

          • Optionalwind?: [number, number, number]

            Air velocity, m/s; drag pulls particles towards it.

          • OptionalwindShear?: number

            Wind grows by this share per 100 m above emitter.position.y (wind shear).

        • Optionallife?: [number, number]

          Life range, seconds.

        • OptionalmaxPerFrame?: number

          Most particles spawned in one update (caps catch-up after a long frame).

        • Optionalrate?: number

          Particles per second. With emitter.shape: 'sources' this is per unit of source weight, so a bigger fire front spawns more. Throttled so the pool never runs out (capacity / mean life).

        • Optionalrender?: {
              absorption?: number;
              albedo?: [string, string];
              anisotropy?: number;
              aspect?: number;
              blackbody?: boolean;
              blending?: "additive" | "alpha" | "premultiplied";
              capHeight?: number;
              detail?: number;
              detailDistance?: number;
              glow?: string;
              glowStrength?: number;
              intensity?: number;
              lightSteps?: number;
              opacity?: number;
              refraction?: number;
              shading?: ParticleShading;
              shadowSteps?: number;
              silverLining?: number;
              size?: number;
              sizeRandom?: [number, number];
              softness?: number;
              sort?: boolean;
              stretch?: number;
          }

          How particles are drawn.

          • Optionalabsorption?: number

            Smoke: light absorbed per unit of density.

          • Optionalalbedo?: [string, string]

            Smoke albedo for clean (white) smoke and dirty (dark) smoke; particles mix by their source tint.

          • Optionalanisotropy?: number

            Smoke: Henyey-Greenstein anisotropy (0 isotropic … 0.9 strongly forward).

          • Optionalaspect?: number

            Height / width of each quad.

          • Optionalblackbody?: boolean

            Colour from temperature (blackbody) instead of only the colour curve.

          • Optionalblending?: "additive" | "alpha" | "premultiplied"

            additive (sparks), alpha (smoke) or premultiplied (flames: emit light and partly hide what is behind).

          • OptionalcapHeight?: number

            Smoke: height above the emitter (metres) where the plume caps into bright, dense, sharply billowing pyrocumulus-like cloud. 0 = off.

          • Optionaldetail?: number

            Per-pixel noise detail 0…1 (0 = flat sprites, cheapest).

          • OptionaldetailDistance?: number

            Beyond this camera distance (metres) the per-pixel detail and self-shadow taps fade out.

          • Optionalglow?: string

            Smoke: warm light from below (#rrggbb), scaled by how hot the particle still is.

          • OptionalglowStrength?: number

            Smoke: glow strength.

          • Optionalintensity?: number

            Brightness multiplier (HDR; > 1 blooms).

          • OptionallightSteps?: number

            Smoke with a grid: per-particle density steps towards the sun through the grid (0…8). Rebuilds the compute pass.

          • Optionalopacity?: number

            Opacity multiplier.

          • Optionalrefraction?: number

            Haze: screen-space refraction strength (fraction of the screen).

          • Optionalshading?: ParticleShading

            Built-in shading: unlit sprites, noise-shaped flame tongues, lit volumetric smoke, thin spark streaks, refracting haze.

          • OptionalshadowSteps?: number

            Smoke: per-pixel density taps towards the sun (0…4). Rebuilds the material.

          • OptionalsilverLining?: number

            Smoke: extra forward-scattered light on thin edges when back-lit (silver lining).

          • Optionalsize?: number

            Base size (width), metres.

          • OptionalsizeRandom?: [number, number]

            Random size multiplier range.

          • Optionalsoftness?: number

            Soft depth fade against opaque geometry, metres (0 = hard).

          • Optionalsort?: boolean

            Back-to-front GPU sort (alpha blending).

          • Optionalstretch?: number

            Stretch along velocity: extra length = speed × stretch (seconds). 0 = camera-facing quads.

        • Optionalseed?: string | number

          Seed for every per-particle random number (spawn position, velocity, size, life).

      Returns this

    • Merges input into the settings. Structural settings (see the constructor) are ignored with a warning.

      Parameters

      • input: {
            capacity?: number;
            curves?: { color?: string[]; opacity?: number[]; size?: number[] };
            emitter?: {
                position?: [number, number, number];
                shape?: EmitterShape;
                size?: [number, number, number];
                spread?: number;
                temperature?: [number, number];
                velocity?: [number, number, number];
            };
            forces?: {
                ambientTemperature?: number;
                buoyancy?: number;
                cooling?: number;
                drag?: number;
                gravity?: number;
                gridLift?: number;
                turbulence?: number;
                turbulenceScale?: number;
                turbulenceSpeed?: number;
                wind?: [number, number, number];
                windShear?: number;
            };
            life?: [number, number];
            maxPerFrame?: number;
            rate?: number;
            render?: {
                absorption?: number;
                albedo?: [string, string];
                anisotropy?: number;
                aspect?: number;
                blackbody?: boolean;
                blending?: "additive" | "alpha" | "premultiplied";
                capHeight?: number;
                detail?: number;
                detailDistance?: number;
                glow?: string;
                glowStrength?: number;
                intensity?: number;
                lightSteps?: number;
                opacity?: number;
                refraction?: number;
                shading?: ParticleShading;
                shadowSteps?: number;
                silverLining?: number;
                size?: number;
                sizeRandom?: [number, number];
                softness?: number;
                sort?: boolean;
                stretch?: number;
            };
            seed?: string
            | number;
        }
        • Optionalcapacity?: number

          Pool size: the most particles alive at once. Changing it rebuilds the GPU buffers.

        • Optionalcurves?: { color?: string[]; opacity?: number[]; size?: number[] }

          Shape over life (0 → 1), each an evenly spaced list of 1 to 8 keys.

          • Optionalcolor?: string[]

            Colour (#rrggbb); multiplied by the blackbody colour when render.blackbody.

          • Optionalopacity?: number[]

            Opacity multiplier.

          • Optionalsize?: number[]

            Size multiplier.

        • Optionalemitter?: {
              position?: [number, number, number];
              shape?: EmitterShape;
              size?: [number, number, number];
              spread?: number;
              temperature?: [number, number];
              velocity?: [number, number, number];
          }

          Spawn shape and initial state.

          • Optionalposition?: [number, number, number]

            Centre, local space, metres.

          • Optionalshape?: EmitterShape

            point, box (half extents size), disc (radius size[0], on XZ), sphere (radius size[0]) or sources (see threejs-particles!ParticleSystem.setSources).

          • Optionalsize?: [number, number, number]

            Box half extents / disc and sphere radius in [0]; for sources, the jitter half extents around each source.

          • Optionalspread?: number

            Random extra speed in a random direction, m/s.

          • Optionaltemperature?: [number, number]

            Initial temperature range, kelvin (drives buoyancy, cooling and blackbody colour).

          • Optionalvelocity?: [number, number, number]

            Initial velocity, m/s.

        • Optionalforces?: {
              ambientTemperature?: number;
              buoyancy?: number;
              cooling?: number;
              drag?: number;
              gravity?: number;
              gridLift?: number;
              turbulence?: number;
              turbulenceScale?: number;
              turbulenceSpeed?: number;
              wind?: [number, number, number];
              windShear?: number;
          }

          What moves particles.

          • OptionalambientTemperature?: number

            Ambient air temperature, kelvin.

          • Optionalbuoyancy?: number

            Buoyancy: up-acceleration = 9.81 × buoyancy × (T − ambient) / ambient (Boussinesq).

          • Optionalcooling?: number

            Exponential cooling towards ambient, 1/s.

          • Optionaldrag?: number

            Drag towards the air velocity, 1/s.

          • Optionalgravity?: number

            Gravity, m/s² (down).

          • OptionalgridLift?: number

            With a grid: up-acceleration from the grid's channel 0 (heat h), gridLift × h / (1 + h) m/s².

          • Optionalturbulence?: number

            Curl-noise turbulence, m/s².

          • OptionalturbulenceScale?: number

            Eddy size, metres.

          • OptionalturbulenceSpeed?: number

            How fast the eddies change, 1/s.

          • Optionalwind?: [number, number, number]

            Air velocity, m/s; drag pulls particles towards it.

          • OptionalwindShear?: number

            Wind grows by this share per 100 m above emitter.position.y (wind shear).

        • Optionallife?: [number, number]

          Life range, seconds.

        • OptionalmaxPerFrame?: number

          Most particles spawned in one update (caps catch-up after a long frame).

        • Optionalrate?: number

          Particles per second. With emitter.shape: 'sources' this is per unit of source weight, so a bigger fire front spawns more. Throttled so the pool never runs out (capacity / mean life).

        • Optionalrender?: {
              absorption?: number;
              albedo?: [string, string];
              anisotropy?: number;
              aspect?: number;
              blackbody?: boolean;
              blending?: "additive" | "alpha" | "premultiplied";
              capHeight?: number;
              detail?: number;
              detailDistance?: number;
              glow?: string;
              glowStrength?: number;
              intensity?: number;
              lightSteps?: number;
              opacity?: number;
              refraction?: number;
              shading?: ParticleShading;
              shadowSteps?: number;
              silverLining?: number;
              size?: number;
              sizeRandom?: [number, number];
              softness?: number;
              sort?: boolean;
              stretch?: number;
          }

          How particles are drawn.

          • Optionalabsorption?: number

            Smoke: light absorbed per unit of density.

          • Optionalalbedo?: [string, string]

            Smoke albedo for clean (white) smoke and dirty (dark) smoke; particles mix by their source tint.

          • Optionalanisotropy?: number

            Smoke: Henyey-Greenstein anisotropy (0 isotropic … 0.9 strongly forward).

          • Optionalaspect?: number

            Height / width of each quad.

          • Optionalblackbody?: boolean

            Colour from temperature (blackbody) instead of only the colour curve.

          • Optionalblending?: "additive" | "alpha" | "premultiplied"

            additive (sparks), alpha (smoke) or premultiplied (flames: emit light and partly hide what is behind).

          • OptionalcapHeight?: number

            Smoke: height above the emitter (metres) where the plume caps into bright, dense, sharply billowing pyrocumulus-like cloud. 0 = off.

          • Optionaldetail?: number

            Per-pixel noise detail 0…1 (0 = flat sprites, cheapest).

          • OptionaldetailDistance?: number

            Beyond this camera distance (metres) the per-pixel detail and self-shadow taps fade out.

          • Optionalglow?: string

            Smoke: warm light from below (#rrggbb), scaled by how hot the particle still is.

          • OptionalglowStrength?: number

            Smoke: glow strength.

          • Optionalintensity?: number

            Brightness multiplier (HDR; > 1 blooms).

          • OptionallightSteps?: number

            Smoke with a grid: per-particle density steps towards the sun through the grid (0…8). Rebuilds the compute pass.

          • Optionalopacity?: number

            Opacity multiplier.

          • Optionalrefraction?: number

            Haze: screen-space refraction strength (fraction of the screen).

          • Optionalshading?: ParticleShading

            Built-in shading: unlit sprites, noise-shaped flame tongues, lit volumetric smoke, thin spark streaks, refracting haze.

          • OptionalshadowSteps?: number

            Smoke: per-pixel density taps towards the sun (0…4). Rebuilds the material.

          • OptionalsilverLining?: number

            Smoke: extra forward-scattered light on thin edges when back-lit (silver lining).

          • Optionalsize?: number

            Base size (width), metres.

          • OptionalsizeRandom?: [number, number]

            Random size multiplier range.

          • Optionalsoftness?: number

            Soft depth fade against opaque geometry, metres (0 = hard).

          • Optionalsort?: boolean

            Back-to-front GPU sort (alpha blending).

          • Optionalstretch?: number

            Stretch along velocity: extra length = speed × stretch (seconds). 0 = camera-facing quads.

        • Optionalseed?: string | number

          Seed for every per-particle random number (spawn position, velocity, size, life).

      Returns this

    • Replaces the weighted spawn sources: SOURCE_STRIDE (8) floats each, x, y, z (local), weight, then data: size scale, lift (spawn up to this many metres above the source), tint (0 clean … 1 dirty smoke), temperature scale. Optional motion, MOTION_STRIDE (4) floats per source: a velocity (m/s, added to the emitter's: particles inherit a moving source's speed) and an opacity multiplier. Zero-weight sources are skipped; past maxSources the heaviest are kept. Uploads only the used part.

      Parameters

      • sources: ArrayLike<number>
      • Optionalcount: number
      • Optionalmotion: ArrayLike<number> | null

      Returns this

    • Back-to-front depth sort (when render.sort and a camera was given to the last prepare/update).

      Parameters

      • renderer: Renderer

      Returns this

    • Advances the particles by dt seconds on the GPU: emits, integrates, and sorts if enabled. camera (default: none) is used for sorting and spark sizing. Needs a WebGPU renderer; on the WebGL backend the system hides itself.

      Parameters

      • renderer: Renderer
      • dt: number
      • Optionalcamera: Camera | null

      Returns this