Renderer · interface

ParticleBatchOptions

Explained in Hello world.

interface ParticleBatchOptions
import type { ParticleBatchOptions } from '@driftengine/core';

Properties

NameTypeDescription
materialParticleMaterialWhich particle this is, by name.
More

This replaced a GLSL source string on 2026-08-13, the same change and for the same reason as PlumeOptions.material: a caller-supplied shader is a capability that can only ever exist on WebGL2, and naming the material lets each backend resolve what it can compile. See particleMaterial.ts.

blendParticleBlend
stretchSecoptionalnumberSeconds of travel a particle is stretched along. 0 for smoke.
More

The velocity it stretches along is a direction to be drawn on, not a motion being simulated, and it must stay that way. Nothing here integrates it: a caller writes both position and velocity every frame, so a deterministic consumer that computes where a particle is from its own plan can still ask for the streak that a moving thing has. That is load-bearing outside this repository, where a corona's streamers are the spark material stretched radially and nothing about them moves. Advancing position from this would take the feature away from every caller that is not running a simulation.

erosionoptionalnumberHow hard the noise erodes a puff, 0 to 1. Ignored by the spark and mote materials.
coreGainoptionalnumberHow far past white a spark's core may go. Ignored by the smoke and mote materials.
fogoptionalbooleanWhether the medium's fog and underwater tint reach this pool. Ignored by the spark and smoke materials, which stay unconditionally fogged — a real ember and real grit belong in the same haze as the rest of the world, matching every particle drawn before this option existed. Defaults to false, because a caller reaching for 'mote' over 'spark'/'smoke' is usually asking for exactly what those two cannot draw: an unlit point exactly its own colour, untouched by distance. See PARTICLE_MOTE_FRAG's own comment on uFogEnabled.
facingoptionalParticleFacingWhether each particle is one camera-facing quad or a world-fixed cross of two.
More

Defaults to 'camera', and this default changed — every particle drawn before it was a cross. A cross has a blade edge-on down each of two world axes, and a sprite squeezed into a one-pixel column spends its whole brightness there: a bright straight line through the middle, worst on the additive materials, and a pair of them from directly above. Consider 'cross' when the camera stays near horizontal and the parallax of two blades is worth more than a stable brightness, which is the trade the shader's own comment on uCameraFacing lays out.

textureoptionalSurfaceTextureThe image a 'sprite' draws: a surface texture, its first layer. Required by the sprite and ignored by the procedural materials. Colour is the particle's times the image's, unlit.
cellsoptionalreadonly [number, number]A 'sprite''s flipbook: the image as [columns, rows] cells, numbered across then down from the top-left, a particle's frames naming one. [1, 1], the default, is the whole image.
blendCellsoptionalbooleanWhether a 'sprite' blends from a particle's cell toward the next by the fraction of its frame, so a slow flipbook moves rather than steps. Off by default: one cell, sampled once.
softDepthoptionalnumberMetres over which a 'sprite' fades where it meets the opaque scene: the hard line a flat card draws where it cuts a floor or a body, softened. 0, the default, is a hard edge. It reads a copy of the frame's depth, which needs screenEffects; without one the edge stays hard and the renderer says so once.
cameraFadeoptionalnumberMetres in front of the eye over which a 'sprite' fades in. 0, the default, is no fade.
cameraOffsetoptionalnumberMetres each particle is moved toward the eye before it is drawn, so a sprite born inside a surface is drawn in front of it. 0 by default. Every material reads it.
sortoptionalbooleanWhether the live particles are drawn farthest first, the order an alpha blend assumes. Off by default, because sorting costs a pass over the particles on the CPU each frame and an additive blend is a sum that does not care. See particleSort.ts.
reuseoptionalParticleBatchAnother batch whose compiled program this one should reuse.
More

Several pools legitimately share a material while needing their own buffers — a game may have four kinds of smoke, each with its own colours, lifetime and capacity, all drawn by one fragment shader. Without this each of them compiles the same source again, which is pure boot time on the device where boot time is scarcest. The per-material constants stay per batch, because they are the point of having several.

Only valid for the same material, and that is now checked — it was not, and could not be, while the material was an opaque source string a caller supplied. Naming it made the constraint expressible, so a spark batch reusing a smoke program fails at construction with both names rather than drawing sparks that look like smoke.