Back to selected work

Case study · Multiplayer product

BuildBattle Live

One shared brief. Twenty minutes. Web apps built inside the game, revealed together and judged by peers. I designed both the rules and the real-time system that enforces them.

Real-time multiplayer gameLive MVP
Product preview
BuildBattle interface showing a shared brief, the battle countdown and the built-in HTML editor.

Context

Turning vibe coding into a social game

AI tools make it possible to produce a small web app quickly. Building alone, however, creates no tension, comparison or verdict.

BuildBattle borrows the mechanics of a creative battle: every player receives the same brief, builds against the clock, discovers the entries at the same time and votes.

Problem

There is no competition without shared state

A battle has to synchronise the lobby, brief, participants, timer, builds, reveal, votes and rankings. If each browser controls time or phase changes, the game is no longer fair.

The system also had to prevent players from seeing a rival build before the reveal, block self-voting and run generated HTML without exposing the player session.

My role

From concept to playable system

I framed the product loop, defined the game invariants and built the experience end to end: React interface, real-time protocol, battle engine, persistence and rating system.

Most of the work came down to trade-offs: what had to remain server-authoritative, what could stay local and what needed to leave the MVP so the complete loop could ship.

Solution

A server-driven battle

Each match runs through a Durable Object with a strict state machine: lobby, building, showcase, voting and results. The server owns every deadline; clients only render the countdown.

During the build phase, each player uses the built-in editor, previews their HTML in a sandbox and publishes. Entries remain hidden until the simultaneous reveal. Peers then vote, and ranked mode applies ELO.

Key decisions

Four decisions that hold the game together

  1. One server authority

    One Durable Object per battle controls phases, timing, submissions and votes. Reconnecting retrieves the real state instead of rebuilding a match from browser memory.

  2. The same playing field

    In ranked mode, the server selects the brief when the match starts. It also assigns one AI companion to the entire battle, so no player can choose or upgrade their own model.

  3. Cut scope to ship

    The automatic capture pipeline was deferred. The MVP produces one HTML file inside the app and falls back to a deterministic local generator when no AI key is available.

  4. Treat every build as untrusted code

    Published HTML is size-limited, stored in the Durable Object and served under a restrictive CSP. Previews run in a sandboxed iframe with no cookies, storage or outbound network access.

Outcome & learning

A complete loop that can be tested end to end

The MVP is live. The local demo can also run all five phases solo against two bots, while the smoke test drives three players and three builds over real WebSockets through to results.

The main lesson: in multiplayer products, fairness is not a technical constraint added later. The server timer, shared model, simultaneous reveal and hidden tallies are part of the experience.

There is no documented match volume, active-user count or retention figure yet. The publishable evidence is the shipped product and its behaviour, not unmeasured adoption.

Stack & methods

A layered, tested real-time system

  • React + Vite
  • Cloudflare Workers
  • Durable Objects + WebSockets
  • Supabase Postgres, Auth and RLS
  • Functional state machine
  • ELO
  • Vitest + WebSocket smoke test
  • CSP and sandboxed iframes

Verifiable product

Play the full game loop

The live MVP lets you join a battle, build in the app, reveal the entries, then vote.