Undercover takes the classic party game and turns it into a zero-login, real-time web app that works from a phone, a laptop, or anything with a browser. There's nothing to install. I didn't want to turn it into another chat-based digital game. Instead, I built it so the app disappears into the background: it hands out secret words, keeps time, and tallies votes, while the real game (the talking, the bluffing, the accusations) happens out loud, whether everyone's sitting around the same table or dialed into a video call together.
The result is a fast, install-free game that scales from four friends in a living room to a party of twenty scattered across devices, running on a serverless real-time backend with sub-100ms state sync across every connected device.
The Problem
Most social deduction games ported to mobile fall into the same trap. They try to replace table talk with in-app chat or emoji reactions, and that kills the exact energy that makes these games fun in the first place. I wanted the opposite: a tool that referees the game without getting in its way, so people could keep making eye contact, reading each other's faces, and arguing back and forth, whether that's across a table or across a Zoom call.
That constraint shaped almost every product decision. No chat feed, no typing, no sounds or vibrations that could leak information to the person sitting next to you (or sharing your screen on a call), and a join flow fast enough that a group of fifteen can be in a game within a minute of someone saying "let's play." It also had to work equally well on any device, since half a group might be on phones and the other half on laptops.
Key Features
- Three asymmetric roles. Civilians share a secret word, Undercover players get a closely related decoy word, and Mr. White gets nothing at all. He has to bluff blind, then guess the real word if he's caught.
- Zero-login, instant rooms. A six-character room code (with visually ambiguous characters like
0/Oand1/Iexcluded) is all it takes to join from any device, no app store, no account. - Works in person or over a call. Nothing in the design assumes players are in the same physical space, so a group can play just as easily huddled around one phone or spread across a video call.
- Fully synchronized game state. Every phase transition, countdown, and vote tally is driven by the server and mirrored to every client in real time, so there's never a "wait, whose turn is it" moment.
- Privacy-first role cards. Secret word cards automatically hide themselves the instant a player switches tabs or locks their screen, and votes stay anonymous until the round resolves.
- Host controls that mirror a real referee. Pause, skip, kick, transfer host, or end the game early, all reflected instantly across every player's screen.
- 260 hand-curated word pairs across 12 categories and four difficulty tiers, so the game holds up whether it's a casual pair or a group of deduction veterans.
- Forgiving Mr. White guesses. A normalization pipeline handles plurals, typos, articles, and curated synonym lists, so a good guess is never rejected on a technicality.
Under the Hood
The game runs on a real-time architecture built around one idea: the client is never trusted, and the server is the only source of truth.
- Astro + React islands on the frontend keep the marketing and landing pages static and fast, while the actual game view hydrates as a single interactive island backed by a lightweight Zustand store. It's responsive by default, so the same build works on a phone screen or a widescreen monitor.
- Cloudflare Durable Objects host one isolated, stateful "room" per game, each with its own SQLite-backed storage. Every game session is fully isolated, and the infrastructure scales horizontally without any shared database bottleneck.
- A pure, deterministic reducer sits at the heart of the game logic. Given a state, an action, and an injected context (time, randomness, word bank), it returns the next state and any side effects. No hidden I/O, no flaky timing bugs, just a function that's exhaustively unit tested (130+ specs) and trivially reproducible.
- Per-player view projection means the server never broadcasts the raw game state. Instead, it computes a sanitized, individualized view for each connected socket, so no amount of poking at network traffic can reveal another player's word or role.
- Zod-validated protocol on every message in both directions, which kept the client and server contracts airtight as the game evolved.
Challenges & Decisions Worth Mentioning
Keeping 20 devices in lockstep. With a large, mixed group of phones, tablets, and laptops, devices drift in and out of sleep, wifi hiccups, and someone always joins late. I built the reconnection layer around absolute server timestamps instead of client-side countdowns, so a device that wakes up mid-timer just re-syncs instantly instead of resetting or drifting out of phase with everyone else.
Designing for a table or a call, not a fixed screen. The biggest UX challenge wasn't a game screen. It was making sure information never leaked sideways, whether someone was glancing at a neighbor's phone or accidentally sharing their tab on a call. That's why there's no sound, no vibration, and an aggressive auto-hide on the role card the moment focus is lost. The interrogation-room, case-file visual style grew out of that same instinct: bold, unambiguous, high-contrast, so a glance tells you nothing you shouldn't know.
Server-authoritative everything. Early on I was tempted to let the client handle simple things like countdown display logic locally to save round-trips. I ripped that out in favor of a strict server-authoritative model. It cost a little latency budget, but it closed off an entire category of cheating vectors before they could even exist.
Outcomes
- A production Cloudflare Workers deployment handling real-time game sessions with Durable Object-backed persistence and zero cold-start database setup.
- 173+ automated tests across the engine, protocol, and word-bank packages, plus a dedicated Playwright suite simulating multi-browser, multi-player sessions end to end.
- An architecture that cleanly separates game logic from infrastructure, so the core engine is portable enough to reuse for future party-game projects.
