Expeditione: How I packed an Interactive 3D Encyclopedia into 1MB and 9 Draw Calls.

Greetings everyone,

I’m currently solo-building Expeditione ( https://expeditione.fun ), an Interactive 3D Encyclopedia on the web. The mission is simple : I want to make learning and the web entirely immersive and memorable again.

To do that, it has to run completely flawlessly on any device. While building the landing page, I managed to fit the entire experience—3D geometry, textures, custom GLSL shaders, audio, code, all of it—into ~1MB.

image

**
**
But initially, my draw calls were sitting at a CPU-melting 168.

I refused to accept that. I completely tore down the rendering pipeline and managed to vaporize the workload down to exactly 9 draw calls without losing a single polygon of visual quality.

Here is exactly how I bypassed the exporter and split the architecture to achieve single digits :

Phase 1: The Known (Dynamic Instancing)

Result: 168 → 35 Draw Calls

The scene features dynamic foliage (vines, leaves) that use custom vertex shaders to sway in the wind. Initially, exporting these directly was killing the renderer. Instead of fixing it in code, I used the gltf-transform CLI to structurally re-engineer the .glb locally before it ever touched Three.js :

gltf-transform instance raw.glb temp.glb && gltf-transform draco temp.glb opt.glb

This collapsed dozens of identical meshes into instanced meshes. It saved the CPU, but my static terrain (the land, ship, and environment) was still heavily unoptimized.

Phase 2: The Aureon Method (Material Purging)

Result: 35 → 9 Draw Calls

The deep engine trap that most devs fall into is that the glTF exporter slices your geometry based on Material Slots. 1 Baked Texture + 10 Old Blender Materials = 10 separate Primitives = 10 Draw Calls in Three.js. Even if you override the material in Three.js later, the geometry is already fractured.

To fix this, I developed what I call the Aureon Method—a ruthless workflow for the Static Base of the scene :

  1. Bake: Bake the final scene to a single texture atlas (1k or 2k).

  2. The Purge: In Blender, obliterate every single individual material slot from your static meshes.

  3. The Dummy: Create one single “Master Material” and link it to everything you want merged.

  4. Join & Export: Join all the static objects (Ctrl + J) and export the .glb. Because the exporter only sees one material slot, it glues all vertices into one solid block.

  5. Three.js: Load the model, traverse the children, and apply your baked MeshBasicMaterial.

The math: The exporter sees 1 material slot → 1 primitive → 1 Mesh → exactly 1 Draw Call.

The same can be verified using Spector.js

Note : Texture Atlasing alone does NOT fix this. Most devs bake a single atlas but leave the original material slots on their meshes. When that happens, the glTF exporter still slices the geometry, ruining your draw calls. The Aureon Method forces the exporter to actually respect the atlas by destroying the slots entirely.

The Numbers That Make Me Happy

  • Start: 168 draw calls

  • After instancing: 35 draw calls

  • After the Aureon Method: 9 draw calls (~95% reduction)

By strictly dividing the architecture into Instanced Details (via CLI) and a Purged Static Base (via the Aureon Method), the GPU is practically asleep.

You can explore the live 1MB world here: [ https://expeditione.fun/ ]**
**
Hopefully, the Aureon Method helps anyone else out there who is wondering why their baked scene is somehow generating 100+ draw calls.

3 Likes