Our first WebGL build was a slideshow. Here's the optimization journey that made it playable.
The Initial Performance Disaster
When we first compiled to WebGL, the game ran at 15fps on high-end desktop browsers and was completely unplayable on mobile. The culprits: unoptimized texture loading (200MB initial download), excessive draw calls (400+ per frame), uncompressed audio assets (50MB of music), and JavaScript garbage collection spikes every 2 seconds. Unity's default WebGL build settings are designed for feature completeness, not performance. We needed a complete optimization overhaul.
Texture Compression and Progressive Loading
We implemented ETC2 texture compression for Android browsers and DXT for desktop, reducing texture memory from 200MB to 35MB. Implemented progressive loading where essential UI textures load first (500KB), followed by current realm assets (5MB), with other realms loading in the background. Used Unity's Addressables system to unload unused assets aggressively—transitioning between realms now triggers immediate garbage collection of old realm textures. Result: initial load time dropped from 45 seconds to 8 seconds.
Draw Call Batching and Shader Optimization
Consolidated materials using texture atlases, reducing unique materials from 87 to 12. Implemented GPU instancing for repeated elements (particles, UI elements, magical effects). Wrote custom shaders that combine multiple effects (glow + color grading + distortion) into single passes instead of Unity's default multi-pass approach. Reduced draw calls from 400+ to 45 average, with peaks of 80 during intensive scenes. Frame rate jumped from 15fps to 45fps just from this change alone.
JavaScript Interop and GC Optimization
WebGL runs on JavaScript, so garbage collection is unavoidable—but we can minimize it. Implemented object pooling for all frequently instantiated objects (particles, UI elements, temporary game objects), eliminating 95% of allocations. Reduced string allocations by caching dialog text and using string builders. Moved audio playback to native Web Audio API instead of Unity's audio system, eliminating 200ms GC spikes. Final result: 60fps on desktop, 30fps on mid-range mobile browsers, with smooth frame pacing and no stutters.