← Return to the index
§ man24 April 2026

Nombero

A turn-based multiplayer math game for mobile, where 2–5 players race to zero out a 9-digit sequence against a Rust authoritative server.

Overview

Nombero is a casual, party-style math game built for 2–5 players. Each round begins with every player holding a unique 9-digit sequence, and the objective is simple: be the first to reduce that sequence to zero. Players take turns drawing from a repository of numbers, choosing either to pop, which strips every occurrence of a digit from both their own sequence and an opponent's, or to multiply, which folds the drawn number into the sequences and reshapes the arithmetic landscape of the round.

The game ships in two complementary modes. In online play, a Rust server stands as the single source of truth, validating each move and computing state on behalf of every connected client. In offline mode, the full rules engine runs locally on the device, supporting pass-and-play on a single screen when no network is available.

What it does

  • Supports turn-based play for two to five players, with room codes for private matches among friends and random matchmaking for quick pickup games.
  • Runs an authoritative online mode in which the server validates each move before broadcasting state, making it effectively impossible for a tampered client to fabricate a win.
  • Offers an offline pass-and-play mode that mirrors the same rules engine on-device, so a dropped connection never cuts the evening short.
  • Ships to iOS, Android, and Web from a single codebase, built and distributed through Expo.
Nombero: Race to Zero Tutorial

Stack choices

The client is written in React Native with Expo, chosen so that a single codebase can reach iOS, Android, and Web without the overhead of maintaining three parallel UI trees. Tamagui handles theming and responsive primitives, resolving design tokens at compile time and keeping the per-frame cost low on the kinds of phones this game is actually played on.

The server is written in Rust on top of Axum, and owns several responsibilities: matchmaking, decoding incoming moves, validating them against the authoritative game state, and broadcasting the result to the other players in the room.

I use WebSockets rather than HTTP polling during the game. This is because polling forces every client to issue a request on a fixed interval whether or not the state has changed, and each request drags along a full set of HTTP headers (cookies, User-Agent, TLS handshake amortization, etc.), easily a few hundred bytes of overhead per poll, multiplied by every idle client. A WebSocket pays that cost once at upgrade, then sends frames with only a handful of bytes of framing overhead, and only when there's actually something to send. That collapses both the steady-state byte count and the worst-case move-to-render latency from "half a poll interval" down to one network round trip. That matters here because the server runs on Railway, where egress is metered and not cheap; idle lobbies and spectators would otherwise burn bandwidth doing nothing.

Challenges

The connection lifecycle, rather than the rules themselves, turned out to be where most of the real bugs lived. Mid-turn disconnects, rematch flows in which a socket had quietly died while the session state lingered, and clients attempting to matchmake into a stale game-mode version each formed their own distinct class of edge case. The matchmaking path compounds this further, since both room codes and random matchmaking funnel into a pre-game sync phase in which every player must lock in a unique-digit 9-number sequence before the first round can begin, and any partial progress through that phase must survive a reconnect cleanly.

Authoritative networking presented its own kind of difficulty. The client submits intents and then reconciles against the state returned by the server. Sizable effort went into validating each move and acknowledging only legal ones, that it's the player's turn, and that the move follows the game rules. The server is the final arbiter of truth.

It's also important that the server doesn't leak extra data, such as the user ID. Since the app has no sign-ins, every user is ephemeral, and for a low-stakes casual game with no real privacy surface, the user ID is essentially the secret. So I've taken extra care to ensure the server only sends the necessary data to the relevant players.

Cross-platform support was less a surprise but an expected cost of the stack. Reaching iOS, Android, and Web from a single codebase is the whole point of the toolchain, but the web platform breaks enough of React Native's underlying assumptions, particularly around gestures, safe areas, and audio, that a build which merely compiles is still a long way from one that actually plays correctly.

The most interesting problem, and perhaps the most underestimated, is the user interface itself. A pop or multiply mutates both players' sequences simultaneously, and the shared number repository refreshes every ten turns. Animating those mutations across up to five simultaneous player views, in a way that communicates clearly who was affected, what changed, and what remains in play, is a visual-language problem in which a correct rules engine accounts for.

Nombero Main ScreenNombero Main Screen

Nombero MatchmakingNombero Matchmaking

Nombero GameplayNombero Gameplay