01 / 03 Real-time networking
WebTransport State Engine
A high-tick-rate state synchronization engine for multiplayer 3D on the web. World state rides unreliable QUIC datagrams, so a lost packet costs one tick instead of stalling every tick behind it.
01 Results
Achieved < 15 ms interpolation latency on 10,000 concurrent entities. 99.9% packet delivery via QUIC/WebTransport fallback.
- Interpolation latency
- < 15 ms
- Concurrent entities
- 10,000
- Packet delivery
- 99.9%
02 Problem
WebSockets run on TCP, and TCP delivers bytes strictly in order. When one segment is lost, every snapshot queued behind it waits for the retransmission — head-of-line blocking. At a high tick rate a single dropped packet becomes a stall across the whole world, and the state it was holding back is stale by the time it arrives. Real-time state never needed ordering. It needs the newest snapshot, now.
03 Architecture
Authority stays on the server, responsiveness moves to the client, and the hot path never waits on a retransmission.
-
01
Go authority
Fixed-step simulation, spatial interest management and a delta baseline per client.
-
02
QUIC transport
Snapshots as unreliable datagrams; inputs and events on independent reliable streams.
-
03
TypeScript client
Clock synchronization, an adaptive jitter buffer and input capture.
-
04
C++ core in WASM
Client-side prediction, reconciliation and interpolation in linear memory.
-
05
Renderer
Three.js reads interpolated transforms straight out of the WASM heap.
04 Engineering
- 01
Datagrams for state, streams for intent
A snapshot is superseded every tick, so it is sent unreliably and never retransmitted. Inputs, joins and RPCs must arrive, so each concern gets its own reliable stream — an ordered channel can only ever block itself.
- 02
Deltas against acknowledged baselines
Each snapshot is encoded against the last state the client acknowledged, not the last one sent. Loss can’t corrupt state; it only widens the next delta. Positions are quantized to fixed point, rotations packed with smallest-three.
- 03
Prediction without rubber-banding
Local input is applied immediately by the C++ step. When an authoritative snapshot disagrees, the client rewinds, replays its unacknowledged inputs and blends the correction over a few frames instead of snapping.
- 04
Zero-copy hand-off
Interpolated transforms live in one contiguous buffer in WASM linear memory. The renderer reads them through typed-array views: no serialization and no per-frame garbage between simulation and GPU upload.
05 Excerpt
// flush sends one snapshot to one client, delta-encoded against the// newest state that client has acknowledged. Datagrams are never// retransmitted: if this one is lost, the next tick supersedes it.func (c *Client) flush(w *World, tick uint32) error { base := c.baselines.Acked() // advances only on a client ack c.enc.Begin(tick, base.Tick) w.EncodeDelta(&c.enc, base, c.interest) // quantized, interest-filtered c.baselines.Record(tick, w.Capture(c.interest)) return c.session.SendDatagram(c.enc.Bytes())}
The baseline only advances when the client acknowledges a snapshot, so no amount of loss can break the delta chain.
06 Specification
- Simulation
- Server-authoritative, fixed 60 Hz step
- Snapshots
- Unreliable QUIC datagrams, delta-encoded and quantized
- Budget
- One datagram per client per tick, priority-accumulated
- Reliable traffic
- Independent streams, one per channel
- Client core
- C++20 compiled to WebAssembly with SIMD
- Interpolation
- Adaptive delay, sized to measured jitter