Inspiration

Most small PvP games either cut corners on fairness (client-trusted combat that's trivial to cheat) or need real infrastructure to run (a dedicated game server, a database that's always on). I wanted a PvP game with server-authoritative, cheat-resistant combat that could still run entirely on free-tier infrastructure — which meant the architecture had to be the interesting part, not just the gameplay.

What it does

FrameShift Arena is a full-stack PvP web game built around a deterministic, replay-safe battle engine: dependency-free TypeScript (currently v3.2.0) that's shared, unmodified, between the server's authoritative combat resolver and the client's battle playback, so the same code that decides a fight's outcome is the code that renders it — no separate client-side combat simulation to drift out of sync. Phase 3 of the project is complete: a 54-sector world with a 3,063-species catalogue, AI-controlled bots, both live and asynchronous PvP, matchmaking, spectating, trading, auctions, clans, seasons, and achievements. It's installable as a PWA with offline support. The source repository stays private, but the game itself is fully playable at https://frameshift-arena.vercel.app/.

How I built it

The entire backend is a single Hono serverless function (api/index.ts) — Vercel's Hobby tier caps a project at 12 serverless functions, so staying within that limit isn't just a preference, it's enforced structurally and checked by a CI guard rather than relied on as a convention. Data lives in Neon Postgres, and both Neon and Vercel pause when idle, which keeps the whole thing running at zero cost between sessions of actual play. Correctness is checked with 2,096 tests across 104 files, using golden-snapshot testing against the event log the battle engine produces and a real Postgres instance per test via PGlite, rather than mocking the database away.

Challenges I ran into

Keeping the battle engine truly deterministic — byte-for-byte identical outcomes from identical inputs — while still sharing it unmodified between a Node server and a browser client ruled out a lot of conveniences (anything touching wall-clock time, floating-point operations that aren't guaranteed to be bit-identical across environments, non-deterministic iteration order) that would normally be invisible in either environment alone. The golden-snapshot test suite exists specifically because a battle engine bug doesn't look like a crash — it looks like a fight that resolves differently depending on who's watching it.

Links

Built With

Share this project:

Updates