DEV Community

Cover image for I Built a Game Where 3 Strangers Judge Your Photo Live — Here's the Real-Time Architecture Behind It
Jacob Miller
Jacob Miller

Posted on

I Built a Game Where 3 Strangers Judge Your Photo Live — Here's the Real-Time Architecture Behind It

I've been building a small multiplayer gaming platform outside my day job, and one of the four games — iCourt — turned out to be the most interesting engineering problem of the bunch. Wanted to write up how it works, both the mechanic and the stack behind it.

The idea

Two players get matched into a themed photo round — best mirror selfie, best sunset shot, best family photo, whatever the prompt is. Each submits a real photo, taken in the moment, within a tight time window. Then three independent jurors — real people, not an algorithm — vote live on which photo wins. Majority wins the round.

No AI scoring, no engagement-optimized ranking system deciding for you. Just three strangers looking at two photos and voting on gut feeling. It's turned out to be way more unpredictable than I expected — a technically sharper photo regularly loses to a rougher one because the jury just liked it more. You can't really game it by trying to be "correct," only interesting.

Why this was a harder build than it sounds

The tricky part isn't the photo upload — it's making sure everyone (both players, all three jurors) is looking at a consistent, synchronized view of the game state as it moves through phases: submission → moderation → jury viewing → live voting → verdict. If one juror's client falls half a second behind, or a player's upload confirmation doesn't reach the server the same way it reaches the other players, the whole round breaks trust immediately — "wait, why does it say the verdict already happened?"

Stack
Socket.IO for real-time state sync across all five participants (2 players + 3 jurors) in a round
Firebase / Firestore for account state, guest sessions, and persistent profile stats
Google Cloud Vision SafeSearch — every uploaded photo gets scanned automatically before it ever reaches a juror's screen. Adult content, graphic content, anything flagged as likely-unsafe results in immediate round termination, no juror ever sees it. This runs inline in the upload pipeline, not as a manual review step, since the whole round happens in under a minute.
Images are deleted immediately after a session ends — the only exception is a 48-hour retention window if the opposing player files a complaint during post-match feedback, specifically so that complaint can actually be reviewed against the real image.
The moderation pipeline was the part I underestimated

Building the "three jurors vote live" mechanic was actually the easy part conceptually — Socket.IO handles broadcast-to-multiple-clients pretty cleanly once you get the room/phase logic right. The part that took real thought was making sure nothing inappropriate could reach a juror's screen in a live, timed, human-judged game — since unlike a static content feed, there's no time for a manual review queue. The SafeSearch scan has to happen synchronously in the upload path, fast enough that it doesn't blow the round's tight timing, but strict enough to catch what it needs to catch before three real people are looking at it.

What I'd do differently

If I rebuilt this today, I'd instrument the drop-off points more carefully from day one. Watching real early users play has already surfaced things I didn't expect — someone not realizing where the upload button was under time pressure, someone finishing a round and immediately leaving after a loss. Small UX signals that only show up once actual strangers, not just you testing your own product, touch it.

Try it

It's free to play — no deposits, nothing to buy, just genuine gameplay. If you're curious how the jury mechanic actually feels from the inside, or want to poke holes in the real-time sync, I'd genuinely appreciate it: cubeengines.com/icourt

Happy to go deeper on any part of this — the Socket.IO room/phase management, the SafeSearch integration, or the guest-auth flow — in the comments.

Top comments (0)