oskiewar: the game module leaves with the first byte, and the mouse gets the camera master
Load. A cold visit ran five round trips before the game module even started downloading: the HTML, then the module script's eight imports (discovered only when the parser reached them), then their nested imports, then an awaited analytics-config fetch, and only then oskiewar.js. lith answers every one of these in under 35 ms, so the whole cost was the chain. Now an inline script on the first line of the head starts the oskiewar.js fetch and the relay's open-room probe together, modulepreload links pull the whole two-level module graph in one hop, the typeface is preloaded, the analytics config is fetched off the critical path with a short queue for early actions, and the title voice's three cross-origin range requests wait until after boot. Boot marks and a [boot] console line report source and compile+boot times. Pace. , and . step the pace mid-fight the way +/- do on the title — a quarter at a time, floor 25%, never past full speed — for reading a bot's tells. The keys go dead once a rival is real (a rollback session, a versus fight, or a watched room), and a host who was at quarter speed snaps back to full the moment the relay deals the fight. Camera. A drag on empty canvas orbits the same yaw and pitch the right stick does; the wheel and a trackpad pinch dolly; shift or sideways scroll turns. Presses on menu options, the title's start word or a grabbable wordmark letter stay the taps they were. A click in a fight is still the web's "use item", decided on release — a press that stays put holds Y so the rubber SMG keeps firing, and travel belongs to the camera. Also: the local dev server learns the auth0-otp and auth0-spa-js paths account.mjs now imports, so a working-tree boot no longer 404s on them. buildVersion 118, social preview reburned against these bytes. Claude-Session: https://claude.ai/code/session_01QohRAHSmeUzgFUSyYrMV28