Building real-time multiplayer games for native consoles is hard. Building them in a web browser—restricted by TCP/WebSocket packet buffering and varying JavaScript thread schedules—is an art form. Here is how we engineered the Kaverno multiplayer engine.
The Browser Latency Dilemma
Standard multiplayer games use UDP (User Datagram Protocol) because dropped packets shouldn't block subsequent updates. Web browsers historically only supported TCP via WebSockets, meaning a single dropped TCP packet can trigger Head-of-Line blocking.
To overcome this without sacrificing universal browser support, our network pipeline implements aggressive packet coalescing and lightweight payload serialization using typed ArrayBuffers.
Client-Side Prediction & Rollback
When you press 'W' or click to fire, you cannot wait 50ms for the server roundtrip before rendering the action. The client runs a local physics simulation immediately:
// Pseudocode: Kaverno Local Prediction Loop
function onPlayerInput(input) {
stateHistory.push({ tick: currentTick, input, pos: player.position });
applyMovement(player, input);
sendInputToServer(currentTick, input);
}
When the authoritative server snapshot returns, we verify if the server position matches our predicted position. If there is a mismatch (due to collision with another player), we rewind local state to that tick and replay all subsequent unacknowledged inputs in a single frame.
Binary Delta Compression Over WebSockets
Sending full world state 60 times a second would choke player bandwidth. Instead, our server only transmits "dirty bits"—entities whose positions or health changed since the client's last acknowledged tick. This reduced bandwidth consumption by over 74% across all matches.
60Hz Server Tick Rate Architecture
By hosting edge nodes across North America, Europe, and Asia Pacific with automated Anycast routing, players enjoy ping times consistently below 25ms, delivering responsive, tournament-grade gameplay right in your browser tab.
