← devlog

2026-05-14

Three workers, one main thread

The streaming pipeline is the engineering proof of concept. Why three workers, and why not one or seven.

The PoC has to render at 30 FPS on an integrated GPU while streaming and decoding splat chunks the user has never seen before. The main thread can't do all of that. Workers are how we keep the canvas free.

The split is: fetch worker (HTTP, byte ranges, abort, backoff), decode worker (gunzip + parse + transferable buffers), persist worker (OPFS sync-access-handle, LRU cache, eviction). The main thread orchestrates and renders. That's it.

Why not one worker? Decoding + persistence both block on disk. If they share a thread, an aggressive write batch stalls a decode that the next frame needs. Tested early; saw the stalls; split them.

Why not seven? Each worker adds a postMessage hop and a wire format. The wire format is the API the workers expose; every new wire format is a versioned contract. Three workers is two contracts (main↔fetch, main↔decode, fetch↔persist piggybacks on the existing decode contract). Adding a fourth means a new contract for one extra parallelism point — usually not worth it.

The streaming-host abstraction layers a priority queue on top so callers don't see the worker boundary. The camera-direction priority boost (F2) and the trajectory prefetch (F1) both live in the host, not the workers; the workers stay narrow and the orchestration stays in one place.