Co-op-Arcade. Eine URL. Kein Origin.
Browser-2D-Shooter mit Waves, Bossen, Campaign und globalem Leaderboard — komplett auf Cloudflare-Edge. Kein Download. Kein Account. Kein Ad-Roll.

Warum es das gibt.
Browser-Arcade-Shooter sind heute entweder werbefinanzierte Portal-Spiele (Poki, Crazy Games) mit 2-Sekunden-Ad-Rolls vor jedem Run — oder native Mobile-Apps, die einen Store-Umweg und Account-Registrierung voraussetzen.
DefOrbit liefert ein vollwertiges 2D-Arcade-Erlebnis — Waves, Bosse, Co-Op, Campaign-Progression, globales Leaderboard — direkt aus einer einzigen URL. Kein Download, keine Ads, kein Account-Zwang für den Solo-Run. Zielgruppe: Gelegenheitsspieler, die auf Desktop oder Mobile „in den Pausenmodus“ wollen.
Der Rahmen, in den es passen musste.
index.html + ESM aus CDN. Kein Webpack, kein Vite.Wie es läuft.
◦ Schematische Darstellung, Zahlen illustrativ.
Vier bewusste Entscheidungen.
Durable Object pro Room, statt Redis + Socket-Server.
GameRoom-DO-Instanz (Room-Code als stabile ID). WebSocket direkt am DO.wrangler deploy. DO-Hibernation hält Idle-Rooms bei ~0 Kosten. State (Spielerliste, Seed, Started-Flag, Disconnect-Timer) lebt im DO-Memory — kein externer KV. Auto-Expire nach 15 min idle.Lockstep mit Seeded-RNG, statt autoritativem Server.
SeededRNG.js) parallel.score / enemies / earthHp) und 30-s-Reconnect-Window.Statisches Frontend + Worker/D1, statt SPA + Backend.
index.html als Root von CF Pages. Worker hängt nur unter /api/* an derselben Domain.wrangler deploy + git push, alles ist live.Google-OAuth inline verifizieren, statt OAuth-Library.
auth.js verifiziert Google-JWTs manuell via crypto.subtle.verify + JWKS-Cache (1 h TTL).Was nicht offensichtlich war.
Reconnect-Logik mit Tick-Delay
_inputDelay = 3 Ticks — kein Client darf seinen eigenen Input instant anwenden. Er schickt ihn, beide Seiten applyen frühestens in 3 Ticks.Das glättet die Simulation und erlaubt dem DO, bei Disconnect den 30-s-Reconnect-Timer zu halten, ohne den Partner sofort rauszuwerfen. Erst wenn der Timer abläuft, triggert
partner-left.Anti-Cheat mit Mode-Scope
SHA-256(score:kills:time:...:mode + salt), Timestamp-Window 5 min.Für Campaign-Purchases:
WHERE currency >= cost-Guard im UPDATE gegen Double-Click / Multi-Tab-Races. earn_nonces verhindert Replay. Outlier-Detection (p99-basiert) ist per-Mode gescoped und für Co-Op komplett übersprungen — zwei Spieler sprengen den Solo-p99 natürlich, ohne dass das geflaggt werden darf.Ein einziger Draw-Call für 512 Bullets
InstancedBufferGeometry mit Line-Primitive gerendert. Per-Instance-Attribute (iOff, iRot, iOn) werden im Vertex-Shader zu rotierter Line-Segment-Position. Off-Bullets via z = -9999 aus dem Clip-Space geschoben statt echtem Culling.Ergebnis: ein Draw-Call, egal wie voll die Szene ist — erlaubt UnrealBloom + 4 Shader-Passes auch auf Mobile bei 60 fps (mit reduziertem Bloom-Radius).
Scaling auf null
Der DO entscheidet per Heartbeat, wann er hibernatet — State wird serialisiert, nächste Nachricht weckt ihn auf. Kein Cron-Job nötig, um leere Rooms zu killen. Auto-Expire nach 15 min idle ist eine reine Sicherheitsleine, kein Kostenmechanismus.
Was läuft.
Was ich gelernt habe.
Lockstep ist billiger, als man denkt.
Deterministische Simulation wirkt im ersten Moment nach hohem Implementierungs-Aufwand. In der Praxis war der Seeded-RNG + Checksum-Vergleich weniger Code, als ein autoritativer Server inklusive Interpolation gewesen wäre — und die Free-Tier-Kompatibilität war nebenbei ein Bonus. Für asymmetrische Gameplay-Modi wäre der Trade-off anders.
Draw-Call-Budget zuerst, Shader danach.
Der Instinkt bei Bullet-Hell ist, an Shader-Kosten zu sparen. Falsche Front. 512 Bullets × 512 Draw-Calls killt Mobile sofort; ein Draw-Call + teure Fragment-Shader läuft flüssig. Beim nächsten Game plane ich die Instanced-Pipeline als allererstes Architektur-Element, nicht als spätere Optimierung.