Web Engine Docs
Preparing documentation
Use the search bar to quickly find any topic
Preparing documentation
Use the search bar to quickly find any topic
GPU-accelerated particle systems with ParticleEmitter for fire, smoke, explosions, and visual effects.
Particle components enable high-performance visual effects like fire, smoke, explosions, sparks, and weather. Web Engine uses GPU-accelerated particle systems for rendering thousands of particles with minimal CPU overhead.
The ParticleEmitter component configures particle emission, lifetime, appearance, and behavior. Supports various emitter shapes, particle animations, and physics-based motion.
| Property | Type | Default | Description |
|---|---|---|---|
| maxParticles | ui16 | 1000 | Maximum particle count |
| emissionRate | f32 | 10.0 | Particles emitted per second |
| lifetime | f32 | 2.0 | Particle lifetime in seconds |
| speed | f32 | 5.0 | Initial particle speed (m/s) |
| size | f32 | 1.0 | Initial particle size |
| sizeEnd | f32 | 0.5 | Final particle size (interpolated) |
| color | [f32, 3] | [1, 1, 1] | Initial particle color [r, g, b] |
| colorEnd | [f32, 3] | [1, 1, 1] | Final particle color [r, g, b] |
| gravity | [f32, 3] | [0, -9.81, 0] | Gravity acceleration [x, y, z] |
| textureAssetId | ui32 | 0 | Particle texture asset ID |
| playing | ui8 | 1 | Emission active (0=paused, 1=playing) |
| rotationSpeed | f32 | 0.0 | Particle rotation angular velocity (rad/s) |
| shape | ui8 | 0 | Emitter shape: 0=Sphere, 1=Cone, 2=Box |
| angle | f32 | 0.5 | Cone angle in radians (for shape=1) |
| Property | Type | Default | Description |
|---|---|---|---|
| noiseStrength | f32 | 0.0 | Turbulence/noise strength |
| noiseFrequency | f32 | 1.0 | Turbulence/noise frequency |
| tilesX | ui8 | 1 | Texture sheet columns (sprite animation) |
| tilesY | ui8 | 1 | Texture sheet rows (sprite animation) |
| animationSpeed | f32 | 0.0 | Texture animation frames per second |
| opacity | f32 | 1.0 | Initial particle opacity (0-1) |
| opacityEnd | f32 | 0.0 | Final particle opacity (0-1) |
| velocityVariation | f32 | 0.0 | Speed randomness (0-1) |
| sizeVariation | f32 | 0.0 | Size randomness (0-1) |
| rotationVariation | f32 | 0.0 | Rotation randomness (0-1) |
| colorVariation | f32 | 0.0 | Color randomness (0-1) |
| emissionBursts | ui16 | 0 | Number of emission bursts |
| emissionBurstSize | ui16 | 0 | Particles per burst |
| emissionBurstInterval | f32 | 0.0 | Time between bursts (seconds) |
| Property | Type | Default | Description |
|---|---|---|---|
| audioAssetId | ui32 | 0 | Audio clip to play with particles |
| audioVolume | f32 | 1.0 | Audio volume (0-1) |
| audioPitch | f32 | 1.0 | Audio pitch multiplier |
| audioSpatial | ui8 | 1 | Spatial audio (0=2D, 1=3D) |
| audioRefDistance | f32 | 1.0 | Audio reference distance (meters) |
| audioMaxDistance | f32 | 100.0 | Audio max distance (meters) |
| audioRolloff | f32 | 1.0 | Audio distance rolloff factor |
import { addComponent, ParticleEmitter } from '@web-engine/core';// Create smoke emitterconst smoke = world.addEntity();addComponent(world, Transform, smoke);addComponent(world, ParticleEmitter, smoke);// Position above fireTransform.position[smoke] = [0, 2, 0];// Configure smoke particlesParticleEmitter.maxParticles[smoke] = 500;ParticleEmitter.emissionRate[smoke] = 20.0; // 20 particles/secParticleEmitter.lifetime[smoke] = 3.0; // 3 second lifetimeParticleEmitter.speed[smoke] = 2.0; // Slow upward driftParticleEmitter.size[smoke] = 2.0; // Large particlesParticleEmitter.sizeEnd[smoke] = 4.0; // Grow over time// Gray smoke colorParticleEmitter.color[smoke][0] = 0.3; // Dark grayParticleEmitter.color[smoke][1] = 0.3;ParticleEmitter.color[smoke][2] = 0.3;// Fade outParticleEmitter.opacity[smoke] = 0.8;ParticleEmitter.opacityEnd[smoke] = 0.0;// Slow upward drift with slight gravityParticleEmitter.gravity[smoke][1] = -1.0; // Weak gravityParticleEmitter.playing[smoke] = 1; // Start emitting
Particle emitters support three shapes for controlling emission direction:
Emits particles in all directions from a spherical volume.
ParticleEmitter.shape[entity] = 0; // Sphere// Particles emit in all directions (explosion, magic orb)
Emits particles in a cone shape, useful for fountains, jets, and directional effects.
ParticleEmitter.shape[entity] = 1; // ConeParticleEmitter.angle[entity] = Math.PI / 6; // 30 degree cone// Particles emit in a cone (fire hose, rocket exhaust, fountain)
Emits particles from a box volume, useful for rain, snow, and area effects.
ParticleEmitter.shape[entity] = 2; // Box// Particles emit from a box volume (rain, dust cloud)
const fire = world.addEntity();addComponent(world, Transform, fire);addComponent(world, ParticleEmitter, fire);ParticleEmitter.maxParticles[fire] = 300;ParticleEmitter.emissionRate[fire] = 50.0;ParticleEmitter.lifetime[fire] = 1.5;ParticleEmitter.speed[fire] = 3.0;ParticleEmitter.size[fire] = 1.5;ParticleEmitter.sizeEnd[fire] = 0.5; // Shrink// Orange to red to blackParticleEmitter.color[fire][0] = 1.0; // OrangeParticleEmitter.color[fire][1] = 0.5;ParticleEmitter.color[fire][2] = 0.0;ParticleEmitter.colorEnd[fire][0] = 0.2; // Dark redParticleEmitter.colorEnd[fire][1] = 0.0;ParticleEmitter.colorEnd[fire][2] = 0.0;// Fade outParticleEmitter.opacity[fire] = 1.0;ParticleEmitter.opacityEnd[fire] = 0.0;// Cone shape pointing upParticleEmitter.shape[fire] = 1;ParticleEmitter.angle[fire] = Math.PI / 8; // 22.5 degree cone// Slight gravity upward (buoyancy)ParticleEmitter.gravity[fire][1] = 2.0;// Add turbulenceParticleEmitter.noiseStrength[fire] = 2.0;ParticleEmitter.noiseFrequency[fire] = 1.5;ParticleEmitter.playing[fire] = 1;
const explosion = world.addEntity();addComponent(world, Transform, explosion);addComponent(world, ParticleEmitter, explosion);ParticleEmitter.maxParticles[explosion] = 200;ParticleEmitter.emissionRate[explosion] = 0.0; // Use burst insteadParticleEmitter.lifetime[explosion] = 2.0;ParticleEmitter.speed[explosion] = 15.0; // Fast initial speedParticleEmitter.size[explosion] = 2.0;ParticleEmitter.sizeEnd[explosion] = 0.0; // Shrink to nothing// Yellow-orange flashParticleEmitter.color[explosion][0] = 1.0;ParticleEmitter.color[explosion][1] = 0.8;ParticleEmitter.color[explosion][2] = 0.2;ParticleEmitter.colorEnd[explosion][0] = 0.3; // Dark smokeParticleEmitter.colorEnd[explosion][1] = 0.3;ParticleEmitter.colorEnd[explosion][2] = 0.3;// Sphere emission (all directions)ParticleEmitter.shape[explosion] = 0;// Downward gravityParticleEmitter.gravity[explosion][1] = -9.81;// Single burst of 200 particlesParticleEmitter.emissionBursts[explosion] = 1;ParticleEmitter.emissionBurstSize[explosion] = 200;// Add audioParticleEmitter.audioAssetId[explosion] = explosionSoundId;ParticleEmitter.audioVolume[explosion] = 1.0;ParticleEmitter.audioSpatial[explosion] = 1;ParticleEmitter.audioRefDistance[explosion] = 10.0;ParticleEmitter.audioMaxDistance[explosion] = 200.0;ParticleEmitter.playing[explosion] = 1;// Auto-cleanup after effect finishessetTimeout(() => {removeEntity(world, explosion);}, 2500);
const rain = world.addEntity();addComponent(world, Transform, rain);addComponent(world, ParticleEmitter, rain);// High above playerTransform.position[rain][1] = 20.0;ParticleEmitter.maxParticles[rain] = 2000;ParticleEmitter.emissionRate[rain] = 200.0; // Heavy rainParticleEmitter.lifetime[rain] = 2.0;ParticleEmitter.speed[rain] = 0.0; // Gravity onlyParticleEmitter.size[rain] = 0.2; // Small dropletsParticleEmitter.sizeEnd[rain] = 0.1;// Blue-white colorParticleEmitter.color[rain][0] = 0.7;ParticleEmitter.color[rain][1] = 0.8;ParticleEmitter.color[rain][2] = 1.0;// Box emitter (area coverage)ParticleEmitter.shape[rain] = 2;// Strong downward gravityParticleEmitter.gravity[rain][1] = -20.0;// Slight randomnessParticleEmitter.velocityVariation[rain] = 0.2;ParticleEmitter.playing[rain] = 1;
const sparks = world.addEntity();addComponent(world, Transform, sparks);addComponent(world, ParticleEmitter, sparks);ParticleEmitter.maxParticles[sparks] = 100;ParticleEmitter.emissionRate[sparks] = 30.0;ParticleEmitter.lifetime[sparks] = 0.8;ParticleEmitter.speed[sparks] = 8.0;ParticleEmitter.size[sparks] = 0.3;ParticleEmitter.sizeEnd[sparks] = 0.1;// Bright yellow-orangeParticleEmitter.color[sparks][0] = 1.0;ParticleEmitter.color[sparks][1] = 0.9;ParticleEmitter.color[sparks][2] = 0.3;ParticleEmitter.colorEnd[sparks][0] = 0.8;ParticleEmitter.colorEnd[sparks][1] = 0.2;ParticleEmitter.colorEnd[sparks][2] = 0.0;// Fade out quicklyParticleEmitter.opacity[sparks] = 1.0;ParticleEmitter.opacityEnd[sparks] = 0.0;// Sphere emissionParticleEmitter.shape[sparks] = 0;// GravityParticleEmitter.gravity[sparks][1] = -15.0;// High variationParticleEmitter.velocityVariation[sparks] = 0.5;ParticleEmitter.sizeVariation[sparks] = 0.3;ParticleEmitter.playing[sparks] = 1;
For animated particle effects (like fire, smoke, or magic), use texture sheet animation with tilesX, tilesY, and animationSpeed:
// Texture is 4x4 grid of animation frames (16 frames total)ParticleEmitter.tilesX[entity] = 4;ParticleEmitter.tilesY[entity] = 4;ParticleEmitter.animationSpeed[entity] = 12.0; // 12 FPSParticleEmitter.textureAssetId[entity] = animatedTextureId;// Particles will animate through all 16 frames during their lifetime