Building an open world in the browser, part 2: Worker physics and the input lag fear
By Oleg Sidorkin, CTO and Co-Founder of Cinevva
New here? Use the series guide. It explains what a spike is and links all parts.
If you build browser multiplayer long enough, you eventually get this argument.
"Physics in a worker is clean architecture. Physics on the main thread feels safer."
Both can be true. What matters is control feel and latency under real input.
Spike 2 was built to answer that with measurements, not opinions.
Open Spike 2 in a new tab ↗ · View source
We reused the Spike 1 terrain and integrated Rapier in a dedicated module worker. Input state was sent to the worker every frame, simulation stepped there, and authoritative position came back to the renderer.
The key metrics were input to visible movement latency and physics step timing. We also watched for jitter under normal movement, sprint bursts, and jump cadence.
The result was better than expected. With our message shape and cadence, the worker boundary did not dominate latency. Controls still felt immediate, which was the only thing players would care about.
One challenge from this phase was interpretation risk. After a successful result, teams often overgeneralize and assume the architecture question is closed forever. It is not. We only validated one concrete scenario and hardware profile. Later spikes still had to recheck assumptions when GPU and streaming pressure changed.
This spike also gave us a process upgrade. We started exposing timing telemetry in HUD by default for interactive spikes. That changed team conversations from "it feels off" to "this path added 1.2 ms."
In part 3 we cover the less glamorous experiments that prevented expensive surprises later. Broadcast load, mobile constraints, and behavior generation reliability.
Technology referenced in this chapter
Rapier. A physics engine written in Rust that compiles to WebAssembly for browser use. It handles rigid bodies, colliders, joints, character controllers, and raycasting at 2-3x native performance. For open worlds, Rapier provides player character controllers (walking on terrain, climbing steps, sliding on slopes), object collision, raycasting for interactions, and trigger volumes. See Rapier documentation and our browser 3D tech guide on physics.
Web Workers. Browser threads that run JavaScript (or Wasm) off the main thread. Physics simulation in a worker means a heavy world.step() call doesn't block rendering. The main thread sends input state to the worker each frame via postMessage and receives authoritative positions back. The latency penalty is the two message hops (~0.1-0.5 ms each on desktop). The benefit is that the render thread never stalls on collision detection. Transferable objects (ArrayBuffer transfer) eliminate copy overhead for large position arrays.
WebAssembly (Wasm). A binary instruction format that runs at near-native speed in browsers. Rapier, Havok, and Recast all compile to Wasm. The physics step in Rapier-Wasm is typically 0.5-2 ms for a few hundred bodies, compared to 5-15 ms for equivalent JavaScript. Wasm modules load as .wasm files fetched alongside the JavaScript glue code. See WebAssembly specification.
Input-to-visual latency. The time between a keypress and the resulting visual change on screen. For movement to feel "immediate," this needs to stay under ~80 ms. In a worker physics setup, the chain is: keydown event (main thread) -> postMessage to worker -> physics step -> postMessage back -> renderer applies position -> next vsync. Each hop adds latency, which is why measurement matters more than architecture diagrams.
Part 2 of 12.
Previous: Part 1 - We started by trying to break it
Next: Part 3 - The unflashy spikes that saved us
Series guide: /blog/2026-02-25-open-world-browser-series-guide