9 pointsby astlouis443 hours ago2 comments
  • koolala16 minutes ago
    Man I wish Xonotic made this official and added a WebSocket prototol to official multiplayer server program so it could connect to public servers too. It's awesome you got P2P for it.
  • astlouis443 hours ago
    Hey HN! I've been using Claude Code a lot lately and got curious whether it could port a full open-source game to run in the browser. Xonotic (a fast open-source arena FPS, think Quake III / Unreal Tournament) seemed like a good candidate: it's built on the DarkPlaces engine (real C + OpenGL), ships gigabytes of assets, and has actual multiplayer.

    It's fully playable in the browser, no install or plugins. Pick a map like g-23 to drop into a match against bots.

    Some of the technical work I wanted to highlight that I/Claude focused on that went into making it actually fast:

    - The engine runs off the main thread. DarkPlaces is compiled to WASM/WebGL2, but the whole engine runs on a worker via Emscripten's PROXY_TO_PTHREAD, with the WebGL context owned directly by the worker through an OffscreenCanvas (zero cross-thread GL dispatch). That let me remove Asyncify entirely — the payoff is a steady frame loop (~4 ms/frame, 99.8% of frames under 16 ms in a profiled match).

    - GPU texture transcoding. Every texture is Basis Universal / KTX2, transcoded at load time to whatever compressed format your GPU supports (BC7 on desktop, etc). That took the texture set from ~5.3 GB of TGAs down to a few hundred MB on disk and cut GPU memory ~4×. Audio is re-encoded to Ogg Vorbis.

    - Streamed on-demand filesystem. Nothing is bundled. The engine reads through a virtual filesystem backed by Cloudflare R2; only a tiny boot set loads upfront, then each map prefetches its working set in parallel and streams the rest as surfaces actually draw. A full map's assets dropped from ~2.3 GB to ~320 MB per session.

    - SIMD. Built with -msimd128, so the math and skeletal-animation paths vectorize to wasm128.

    - Hosting. Cloudflare R2 (zero egress) behind a Worker, with COOP/COEP headers for SharedArrayBuffer/threads. Assets are immutable-cached and the engine binary revalidates, so reloads are cheap.

    Multiplayer is peer-to-peer. Click Host Game and you get a 6-character invite code; a friend enters it and you connect directly browser-to-browser over a WebRTC DataChannel (configured unreliable/unordered to match the engine's UDP netcode).

    A tiny Cloudflare Worker only relays the one-time WebRTC handshake — once you're connected, no game traffic touches any server. I tested a real 1v1 between Edmonton and Bangkok and it held up across the Pacific.

    Would love feedback, so please report any bugs or glitches here and I'll patch asap.