Skip to content
All articles

VibeChess: reliable real-time play in Flutter

Published

VibeChess is a Flutter app for daily chess practice and live puzzle duels on iOS and Android. I built it around a constraint that shaped both the product and the backend: a duel needs to work when connections are unreliable and there are too few players online to guarantee a human opponent.

My role: Founder & CTO, spanning the mobile experience, real-time game flow, subscriptions, and releases. Core stack: Flutter, Dart, and Socket.IO.

Two modes, one progression system

Practice mode gives players mate-in-one puzzles with difficulty that adapts to their performance. Duels put two players on the same position; the first correct move wins the point. Ratings, streaks, and match history connect individual sessions to longer-term progress.

The modes have different engineering requirements. Practice is primarily a single-player interaction. A duel requires two clients to agree on the match lifecycle, accepted moves, and final result. Treating both as ordinary screen state would leave the client responsible for decisions it cannot safely make.

VibeChess practice screen with a mate-in-one puzzleVibeChess Progress screen with rating, streak, puzzle history, and achievements

Practice and progress in the published app. App Store screenshots captured in October 2026.

Keep game decisions on the server

I kept authoritative game state on the backend and display state in the Flutter client. The client submits a move and presents the resulting state; it does not independently decide who won a contested point.

That boundary matters throughout the match lifecycle:

Queue entry → matchmaking → match found
Move submission → validation → game update
Result calculation → rating and match history

The two hardest failure modes were disconnects during an active match and near-simultaneous move submissions. A disconnect affects both what the server should do and what the player sees. Concurrent submissions must resolve to one consistent result, regardless of which client displays an update first.

An isolated move-validation test is useful, but it does not establish that two clients recover correctly from a timing or connection problem. Working through these cases required concurrent-client testing as well as checking individual operations. The important distinction is between a correct response to one request and a consistent match experienced by both players.

The tradeoff is that server availability and reconciliation become central to the experience. The client needs to represent uncertainty when a connection fails, rather than treating its last displayed state as the final result.

Design for a small player pool

At launch, a human match could not be assumed. After 15 seconds without an opponent, the queue falls back to a bot calibrated to the player's rating.

This keeps the duel flow usable at low traffic. It also changes what is being offered: the player can enter a duel without being guaranteed a human opponent. The fallback solves waiting time; it does not create a multiplayer community. That distinction matters when evaluating the product's progress.

Treat guest progress as a separate state boundary

Guest mode lets a player try the core experience before creating an account. It also creates a second identity lifecycle. Puzzle progress, streaks, and account-specific state need explicit boundaries so that signing in does not accidentally mix one identity's data with another's.

I treated that transition as part of the product's state model. It belongs in the same design discussion as persistence and recovery, because a player losing progress at sign-in experiences a product failure even if authentication itself succeeds.

The release includes the operational work

Shipping covered more than the game loop. The app needed subscription entitlements enforced across client and backend, reminders, analytics, crash reporting, support, and account deletion. Each introduces paths outside the happy-path game session that still have to behave coherently.

After launch, event funnels, session observations, and direct feedback helped identify friction in onboarding, difficulty, and queue waiting. Those inputs support hypotheses for iteration; they do not, on their own, establish a retention improvement.

What shipped, and what I would carry forward

VibeChess shipped on iOS and Android with practice, live duels, a bot fallback, progression, and subscriptions. The engineering result is a connected mobile product with explicit boundaries between game authority, presentation, and identity.

For another real-time product, I would bring concurrent-client failure scenarios into the delivery plan earlier. Disconnect recovery and simultaneous actions shaped the implementation enough that they deserved early development time, alongside the core interaction.

View VibeChess on the App Store or Google Play.

Discuss this project with me · Explore more projects