Following up on my last post about iCourt — this time I want to walk through Pyramid, the flagship game on the same platform, and the real-time synchronization problem that made it the hardest of the four to get right.
The mechanic
Players join a live round with a stake in a free, non-purchasable in-game currency. As more players join within a short recording window, a shared multiplier grows — every join pushes it up. Anyone currently in the round can exit at any time and lock in whatever the multiplier is at that moment. If the window closes and not enough new players joined, the round collapses — everyone still in loses their stake for that round.
No deposits, no real money anywhere in this loop. It's a pure tension mechanic: timing, trust that others will keep joining, and the temptation to hold out for a bigger multiplier versus the risk of the whole thing collapsing under you.
Why this was the hardest sync problem on the platform
Unlike iCourt (which has a clear phase-by-phase flow — submit, moderate, vote, verdict), Pyramid has to handle an unbounded number of concurrent actors all racing against a shared, ticking clock. At any moment, N players could be joining, M players could be exiting, and the server has to:
Accept or reject each JOIN/EXIT with a fresh, deduplicated nonce (prevents double-submission from a flaky connection retry)
Recalculate every remaining player's live multiplier as new joins land
Broadcast the authoritative state to every connected client — never let the client calculate its own multiplier locally, since even a few hundred milliseconds of drift between two players' views of "what the multiplier currently is" breaks trust instantly
Handle the recording-window countdown server-side only, with the client purely rendering whatever TICK event it receives — no client-side timers pretending to be authoritative
That last point took a real redesign partway through. My first instinct was to let the client run its own countdown and just sync occasionally — it felt performant. But any client-side timer drift, even small, means two players in the same round can see different time-remaining values, and if one of them exits believing they have 2 seconds left while the server has already closed the window, that's a real, trust-breaking bug. Server-authoritative TICK events every 100ms, client purely renders — no exceptions — was the fix.
Stack
Socket.IO, self-hosted (not the CDN build — ran into an issue early on where privacy-focused browsers like Brave were blocking the third-party CDN script entirely, which silently broke the game for a chunk of users before I traced it)
Firebase / Firestore for wallet balance, player identity, persistent stats
A dedicated REVEAL_ENTRY sequencing system — entries are revealed one at a time with a short stagger (~280ms) even though they all technically joined within the same window, purely for the visual/dramatic effect of watching the pyramid build in real time. This is entirely a presentation-layer choice on top of already-committed server state, not the actual game logic.
The collapse mechanic specifically
When a round collapses, every client gets a COLLAPSE event with the real numbers — how many joined, how many exited, the final multiplier. I made a deliberate choice here: show the actual collapse reason plainly ("3 people joined but 5 exited" vs. a vague "you lost"). Transparency about why a round collapsed, rather than hiding the mechanics behind a generic loss screen, turned out to matter a lot for how a loss feels — players seem to accept a collapse better when they can see exactly what happened numerically, rather than it feeling arbitrary.
What real users have already taught me
With only a handful of genuine outside players so far, I've already seen two distinct behaviors worth designing around: some players play one round and leave regardless of outcome, and at least one forfeited mid-round rather than riding it out or exiting cleanly. Both are useful signals I wouldn't have gotten from testing solo — the loss/collapse-screen experience is probably the next thing I refine, since a first-time collapse might currently feel more punishing than it needs to for someone still learning the mechanic.
Try it
Free to play, no deposits, no purchases — the currency exists purely to make the stakes feel real without any actual money involved: cubeengines.com/pyramid
Happy to go deeper on the server-authoritative timer design, the nonce-based dedup system, or anything else about the real-time architecture in the comments.
Top comments (0)