Skip to main content

Arena Performance Optimizations

Overview

The duel arena rendering system underwent major performance optimizations in February 2026, reducing draw calls by ~97% and eliminating expensive per-pixel lighting calculations.

Performance Improvements

Before Optimization

  • ~846 individual mesh draw calls - Each fence post, rail, pillar component rendered separately
  • 28 dynamic PointLights - Per-pixel lighting calculations every frame
  • Severe FPS drops - Especially noticeable with multiple arenas visible

After Optimization

  • ~22 draw calls - InstancedMesh batching for repeated geometry
  • 0 dynamic lights - Replaced with GPU-driven TSL emissive materials
  • Smooth 60 FPS - Consistent performance across all arena views

Technical Changes

1. InstancedMesh Conversion

Converted ~846 individual meshes to InstancedMesh batches: Total: 846 meshes → ~22 draw calls (97% reduction)

2. Dynamic Lighting Removal

Replaced all 28 PointLights with GPU-driven TSL emissive materials: Old approach (CPU-intensive):
New approach (GPU-driven):
Benefits:
  • Zero CPU cost per frame
  • Per-instance phase offset for natural variation
  • Runs entirely on GPU via emissiveNode

3. Fire Particle Improvements

Unified fire rendering on enhanced “fire” preset: Removed:
  • "torch" particle preset (redundant)
  • Separate torch/fire particle systems
Enhanced fire preset features:
  • Smooth value noise fragment shader (bilinear interpolated hash lattice)
  • Soft radial falloff designed for additive blending
  • Per-particle turbulent vertex motion for natural flickering
  • Height-based color gradient (white-yellow core → orange-red tips)
  • Overlapping particles merge into cohesive flame body
Shader implementation:

4. Dead Code Removal

Removed unused functions:
  • createArenaMarker() - Arena number markers (unused)
  • createAmbientDust() - Dust particles (unused)
  • createLobbyBenches() - Lobby benches (unused)

Performance Metrics

Draw Call Reduction

  • Before: ~846 draw calls per frame
  • After: ~22 draw calls per frame
  • Improvement: 97% reduction

Lighting Performance

  • Before: 28 PointLights × per-pixel calculations
  • After: 0 dynamic lights (GPU emissive only)
  • Improvement: Eliminated per-pixel lighting overhead

Frame Rate

  • Before: Variable FPS, drops to 30-40 FPS in arena areas
  • After: Consistent 60 FPS across all arena views
  • Improvement: 50-100% FPS increase in arena areas

Implementation Details

InstancedMesh Pattern

TSL Emissive Animation

Migration Notes

Breaking Changes

  • GlowPreset type no longer includes "torch" - use "fire" instead
  • MAX_RISE_SPREAD particle pool increased from 256 to 896 (supports more fire particles)

API Changes

  • GlowParticleManager.registerTorch() removed - use registerFire() instead
  • Fire particles now use turbulent vertex motion (phase parameter in dynamics array)

Troubleshooting

Grey/White Materials After Update

If braziers or pillars appear grey after updating:
  1. Clear browser cache and IndexedDB
  2. Restart the client
  3. Materials should restore with proper colors

Missing Fire Effects

If fire particles don’t appear:
  1. Check that particle system is initialized
  2. Verify MAX_RISE_SPREAD pool has capacity (now 896)
  3. Ensure emitter IDs are unique

Performance Still Poor

If FPS is still low after update:
  1. Check GPU compatibility (WebGPU required for TSL)
  2. Verify InstancedMesh is being used (check draw calls in DevTools)
  3. Ensure old PointLights were removed (check scene graph)
  • packages/shared/src/systems/client/DuelArenaVisualsSystem.ts - Main arena rendering system
  • packages/shared/src/entities/managers/particleManager/GlowParticleManager.ts - Fire particle system
  • packages/server/src/systems/StreamingDuelScheduler/managers/DuelOrchestrator.ts - Victory emote timing

References