kayf.dev

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.

Glowing world lines of networked entities in space-time: snapshot beads along each path, dropped packets as hollow rings, a translucent render-time plane and dashed predictions beyond it
Domain
Distributed real-time state
Stack
Go · C++ → WASM · TypeScript
Transport
WebTransport over HTTP/3

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.

  1. 01

    Go authority

    Fixed-step simulation, spatial interest management and a delta baseline per client.

  2. 02

    QUIC transport

    Snapshots as unreliable datagrams; inputs and events on independent reliable streams.

  3. 03

    TypeScript client

    Clock synchronization, an adaptive jitter buffer and input capture.

  4. 04

    C++ core in WASM

    Client-side prediction, reconciliation and interpolation in linear memory.

  5. 05

    Renderer

    Three.js reads interpolated transforms straight out of the WASM heap.

04 Engineering

  1. 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.

  2. 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.

  3. 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.

  4. 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

server/client.goGo
// 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.

Four entity traces over time with snapshot beads, dropped-packet rings, a render-time line and a shaded jitter-buffer band
Four entities as scope traces. Beads are snapshots, rings are dropped datagrams bridged by interpolation; the bright line is render time, the band ahead of it the jitter buffer.

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