# Netcode

Multiplayer is not available to games yet; these notes are the rules scripts will run under once it is.

The networked-play notes that concern scripts and the engine host. Transport, rollback and sessions will be
documented here as they are built; this file starts with what the host side has settled.

## Mixed sessions

A match may have browser peers and desktop peers together.

1. **Physics agrees.** The browser build steps the same world bit for bit as the shipped desktop engine.
   - `crates/physics-digest` compares the two tick by tick, and both run Rapier's deterministic maths.
2. **Scripts agree** when every peer runs `HostConfig::networked().with_web_peers()`.
   - The preset counts calls, limits call depth to 256, refuses promise jobs, removes `SharedArrayBuffer` and gives
     scripts a `Math` that is the same bits on every engine and OS (`script_math.js`; `**` is refused, use `Math.pow`).
   - `with_web_peers()` gives desktop peers only the `ctx` members the browser serves.
   - Peers compare their identity in the handshake (`argus::PeerIdentity`): the engine and its version,
     `determinism_digest()`, the scene (the SHA-256 of its file's canonical JSON), the tick rate and the seed. The
     first that differs refuses the session with its `peer-*-mismatch` code (docs/RUNTIME-CODES.md, "Peers"). The
     digest alone is not enough: two peers on one build with different seeds pass it, then draw different
     `Math.random` numbers. Every peer loads the scene from its file: a world built from a struct is hashed by its
     parsed scene, which a file-loaded peer does not match.
   - A peer's first message is its hello (`argus::PeerHello`), the identity under a protocol number:
     `{"type":"hello","proto":1,"engine":"argus","version":"0.7.0","determinismDigest":"e176215280f181dc","scene":"Arena","sceneSha256":"…","tickRate":60,"seed":"12345"}`.
     The seed and the digest are strings (decimal, 16 hex digits): a u64 does not fit a JS number exactly. On join,
     `PeerHello::accept` reads `proto` first and refuses another protocol, or a message that is not a whole protocol-1
     hello, with `peer-protocol-mismatch` before it compares any field; then it compares the identity. Each side checks the hello it received, and both refuse with the same code. A hello's fields change only
     with a new protocol number, so an older peer meets a clean refusal naming the protocol (or, when `proto` is not a
     whole number, saying the message is no hello it can read), never a half-read hello. A hello is read only in the
     form a peer writes it: lower-case hex, and a seed with no sign or leading zero.
3. **The cost is the browser's gap.** A behaviour that calls a member the browser does not serve throws
   `WebUnsupportedError` on every peer.
   - The members a desktop peer loses, and when each comes to the browser, are the generated table in `docs/API.md`
     (the networked-session section); `crates/host/src/web/served.json` is its source.
   - Every member the web host serves shrinks it.
4. **Sound is presentation.** `ctx.audio.play` gives the same voice numbers everywhere, and the browser plays it through
   WebAudio (kira's cpal backend). A browser holds sound until the player's first click, key or touch on the page, so a
   browser peer is silent until then; the voices and their numbers run all the same.
5. **Where it stands (20 Oct 2026).** Every sample (hop-lane, kart-starter, lantern-hollow, pebblewind-heights,
   twin-trail) and `games/duel-yard` runs in the browser with no script errors, on the web host the merge queue holds.
   - The browser serves 186 of the 270 handle members. The 84 left are in groups no sample's own code calls: joints,
     navigation, tilemaps, most of the camera's screen maths, the environment's readers, the audio mixer's bus and
     music controls, part of the animator, players and views, the world's spawn and grab queries, labels, render
     parameters, input rebinding and `entity.setParent`.
   - A behaviour that calls one of them still throws `WebUnsupportedError` on every peer of a mixed session.

