Romain Cournol

← Home BuildBattle

Twenty minutes, one brief, a server that trusts no one.

Role
Design and development
Year
2026
Stack
Durable Objects · WebSocket · React 18
Status
Deployed MVP · not joinable online yet
BuildBattle in the build phase: the phase bar reading lobby, build, showcase, vote, results; the brief drawn for the match, "Magic 8-Ball"; the server-held clock 26 seconds from lock-in; and the constraints imposed on every player.

Video games are a long-standing passion. The Beat Battle format appealed to me, so I transposed it to building: vibe-coding usually happens alone, with no clock and no judge. I wanted to see what survives with an imposed brief, a shared timer and a vote.

01 The problem

A real-time competitive game breaks at its client: if the browser owns the clock or the choice of brief, the first curious player opens devtools and wins.

02 What I built

Every match lives inside one Cloudflare Durable Object, with its server-side alarm timer. The React SPA renders state, it never produces it.

The decision I am most pleased with is invisible on screen. In ranked mode the server draws the brief from a private seed and explicitly refuses to seed it from the battle id: that id is returned to the host, and the brief-picking function ships inside the SPA bundle. Seeding from the id would let the host recompute the brief before the start, then pre-build.

Three scopes were cut to stay on a free plan: the paid auto-clip pipeline, publishing to an external URL, the async gallery. Email auth was dropped in favour of guest-only.

03 What I take from it

MVP deployed on Cloudflare Pages and Workers on 25 July 2026. The full loop runs locally, as a solo demo against two bots. The hosted auth service is paused: the landing screen answers online, but a battle cannot yet be created or joined.

The brief-seeding hole was closed before a single player played.

01

Arbitrate

The server holds the clock and the five phases. The browser renders, it does not decide.

02

Pin

Published bytes are pinned at submit: a late edit cannot change what was voted on.

03

Seal

Vote tallies are never broadcast before the results phase.

Result

321unit tests, plus a smoke test over real WebSockets

  • Published bytes pinned at submit: a late edit cannot change what was voted on
  • Vote tallies never broadcast before the results phase
  • In ranked mode the brief is drawn from a private seed, never from the battle id