Skip to main content

ParticleManager API Reference

GPU-instanced particle system for efficient visual effects rendering.

Overview

The ParticleManager provides a unified interface for managing all particle effects in Hyperscape. It uses GPU instancing and TSL NodeMaterials to render thousands of particles with minimal CPU overhead. Location: packages/shared/src/entities/managers/particleManager/ Performance:
  • 4 draw calls total (vs. ~150 before refactor)
  • GPU-driven animation (zero CPU cost)
  • Supports 264+ concurrent particle instances

Architecture

ParticleManager

Central router that dispatches particle events to specialized sub-managers.

Constructor

Parameters:
  • scene - Three.js scene to add particle meshes to
Example:

Methods

register()

Register a new particle emitter.
Parameters:
  • id - Unique identifier for this emitter
  • config - Particle configuration (discriminated union)
Config Types: Water Particles (Fishing Spots):
Glow Particles (Fires, Altars, Torches):
Examples:

unregister()

Remove a particle emitter and free its instances.
Parameters:
  • id - Emitter identifier to remove
Example:
Behavior:
  • Automatically routes to correct sub-manager via ownership map
  • Frees all particle instances
  • No type hint required

move()

Move an existing emitter to a new position.
Parameters:
  • id - Emitter identifier to move
  • newPos - New world position
Example:
Behavior:
  • Updates all particle instances to new position
  • Automatically routes to correct sub-manager
  • No type hint required

update()

Update all particle managers (call once per frame).
Parameters:
  • dt - Delta time in seconds
  • camera - Active camera for billboard orientation
Example:
Behavior:
  • Updates camera right/up vectors for billboarding
  • Advances particle ages and respawns expired particles
  • Updates InstancedBufferAttributes (GPU upload)
  • Triggers burst effects for fishing spots

dispose()

Clean up all particle resources.
Example:
Behavior:
  • Removes all meshes from scene
  • Disposes geometries and materials
  • Disposes textures
  • Clears ownership map

WaterParticleManager

Manages fishing spot particle effects (splash, bubble, shimmer, ripple).

Particle Types

Splash:
  • Parabolic arc motion
  • 0.6-1.2s lifetime
  • 0.05-0.3 tile radius
  • 0.12-0.32 tile peak height
  • Burst effects every 3-10 seconds
Bubble:
  • Rising motion with wobble
  • 1.2-2.5s lifetime
  • 0.04-0.2 tile radius
  • 0.3-0.55 tile rise height
  • Drift with sine wave
Shimmer:
  • Surface wandering
  • 1.5-3.0s lifetime
  • 0.15-0.6 tile radius
  • Twinkle effect (sine wave)
  • Circular motion
Ripple:
  • Expanding ring
  • Continuous loop
  • 0.15-1.45 tile scale
  • Ring texture with fade

Fishing Spot Variants

Net Fishing:
Fly Fishing:
Default (Bait):

GlowParticleManager

Manages instanced glow billboard particles (fires, altars, torches).

Glow Presets

Fire Preset

Rising embers with heat distortion.
Behavior:
  • Particles rise from base position
  • Chaotic motion with turbulence
  • Orange/yellow color gradient
  • Suitable for campfires, furnaces

Altar Preset

Geometry-aware sparks rising from altar mesh.
Behavior:
  • Particles spawn on altar mesh surface
  • Rise upward with slight outward drift
  • Three-tone color gradient (core → mid → outer)
  • Requires meshRoot for bounds detection

Torch Preset

Tight flame cluster for wall-mounted torches.
Behavior:
  • 6 particles per torch
  • Tight spread (0.08 radius)
  • Concentrated flame effect
  • Minimal horizontal drift

Color Configuration

Single Color:
Three-Tone Gradient:

TSL NodeMaterials

Particles use Three.js Shading Language (TSL) for GPU-driven animation.

Vertex Shader

Billboard Orientation:
Particle Motion:

Fragment Shader

Opacity Envelopes:

Instance Attributes

Particle Layers (Splash, Bubble, Shimmer)

Vertex Buffer Layout (7 of 8 max):
  1. position (vec3) - Base geometry vertex position
  2. uv (vec2) - Texture coordinates
  3. instanceMatrix (mat4) - Instance transform (unused, identity)
  4. spotPos (vec3) - Emitter world position
  5. ageLifetime (vec2) - Current age (x), total lifetime (y)
  6. angleRadius (vec2) - Polar angle (x), radial distance (y)
  7. dynamics (vec4) - Peak height (x), size (y), speed (z), direction (w)

Ripple Layer

Vertex Buffer Layout (5 of 8 max):
  1. position (vec3) - Base geometry vertex position
  2. uv (vec2) - Texture coordinates
  3. instanceMatrix (mat4) - Instance transform (unused, identity)
  4. spotPos (vec3) - Emitter world position
  5. rippleParams (vec2) - Phase offset (x), ripple speed (y)

Integration with ResourceSystem

The ResourceSystem automatically manages particle lifecycle for resource entities.

Resource Spawning

Resource Despawning

Resource Movement

Event Routing

Integration with DuelArenaVisualsSystem

The DuelArenaVisualsSystem uses ParticleManager for torch fire effects.

Torch Placement

Torch Cleanup

Performance Considerations

Instance Limits

Hard Limits:
  • Splash: 96 instances
  • Bubble: 72 instances
  • Shimmer: 72 instances
  • Ripple: 24 instances
Exceeding Limits: When all instances are allocated, register() will use fewer particles than requested. The system gracefully degrades by allocating as many instances as available.

Memory Usage

Per Particle Layer:
  • Geometry: ~2KB (PlaneGeometry with 2 triangles)
  • Material: ~1KB (TSL NodeMaterial)
  • Instance Data: ~100 bytes per instance
  • Total: ~10KB per layer + (100 bytes × instance count)
Total Memory:
  • 4 particle layers × 10KB = 40KB base
  • 264 instances × 100 bytes = 26KB instance data
  • Textures: 64×64×4 × 2 = 32KB
  • Total: ~100KB

GPU Bandwidth

Per Frame Upload:
  • Only dirty attributes are uploaded
  • Typical: 2-3 attributes per frame
  • Splash: ~1KB (96 instances × 2 floats × 4 bytes)
  • Bubble: ~750 bytes
  • Shimmer: ~750 bytes
  • Total: ~2.5KB per frame

Draw Calls

Before Refactor:
  • 1 draw call per fishing spot
  • 30 fishing spots = 30 draw calls
  • 5 particles per spot = 150 draw calls total
After Refactor:
  • 4 draw calls total (4 InstancedMeshes)
  • 97% reduction in draw calls

Extending the System

Adding New Particle Types

To add a new particle type (e.g., snow, rain, magic effects):
  1. Create Specialized Manager:
  1. Add Config Type:
  1. Update ParticleManager:

Custom Glow Presets

To add a new glow preset:
  1. Define Preset Configuration:
  1. Update Preset Type:
  1. Use New Preset:

Best Practices

Registration

  • Unique IDs: Use entity ID or unique identifier
  • Cleanup: Always unregister when entity is destroyed
  • Position: Use world coordinates, not local
  • Type Safety: Use discriminated union for config

Performance

  • Batch Operations: Register multiple emitters before first update
  • Avoid Churn: Don’t register/unregister every frame
  • Reuse IDs: Unregister before re-registering same ID
  • Limit Instances: Stay within hard limits (96/72/72/24)

Visual Quality

  • Color Choice: Use hex colors matching game aesthetic
  • Preset Selection: Choose preset matching effect type
  • Position Height: Adjust Y position for visual alignment
  • Scale: Use modelScale for size adjustment

Debugging

Enable Particle Debug Logging

Visualize Instance Allocation

Inspect Particle Attributes

Migration Guide

From ResourceEntity Particles

Before (per-entity particles):
After (ParticleManager):
Benefits:
  • No per-entity particle code
  • Automatic GPU instancing
  • Centralized particle management
  • Consistent visual quality

From Manual Particle Meshes

Before (manual mesh creation):
After (ParticleManager):
Benefits:
  • No manual animation code
  • Automatic billboarding
  • GPU-driven updates
  • Shared geometry/material