← All articles

How we built Table Online — a multiplayer backgammon game in Flutter for web, iOS and Android

Engineering lessons from building a real-time game in Flutter, with the same code running in the browser and natively on mobile. State management, server sync, 60fps performance.

A few months ago we shipped Table Online — a classic multiplayer backgammon game you can play directly in your browser at table-online.ro, or as a native app on iPhone and Android. All of it is built in Flutter, with a single source codebase for all three platforms. This article is an engineering look behind the scenes.

Why Flutter for a multiplayer game

The choice wasn’t obvious. For games, many people reflexively recommend Unity or a custom engine. We picked Flutter for three concrete reasons:

  1. Animations are first-class in Flutter. AnimationController, AnimatedBuilder, Hero, TweenAnimationBuilder — all motion data for backgammon pieces and dice is already solved by the framework. We didn’t have to write a physics engine.
  2. The web lets you adopt without downloading. The biggest friction in mobile game adoption is installation. With Flutter web, the user lands, taps twice, plays a game. If they like it, they install the app later.
  3. One codebase, three platforms — and this isn’t just a marketing line. Game logic, move validation, server communication — they all live in the same file and behave identically everywhere.

Architecture

In short:

  • Flutter frontend — UI, animations, local input. State management with Riverpod.
  • Dart server on Cloud Run — the game authority. Every move is server-validated; the client only proposes.
  • WebSockets for sync — one persistent connection per match, protobuf-style messages to save bandwidth.
  • Firestore for persistent state — user profiles, match history, leaderboard.

The decision that mattered most: the server is source-of-truth. The client proposes a move, the server decides if it’s valid, then broadcasts the result to both players. This eliminates an entire class of cheating and makes debugging predictable.

Performance: holding 60fps in the browser

Flutter web is harder than native mobile on the performance front. A few things made the difference:

  • RepaintBoundary around the board — we isolate board repaints from the rest of the UI. Moving a piece doesn’t repaint the score.
  • HTML renderer for text-heavy pages, CanvasKit for the game page — Flutter web supports two renderers and you can pick per build. For the game page, CanvasKit wins clearly.
  • Lazy loading assets — piece textures, sounds, victory animations only load when needed.

The most useful lesson

If I were starting over, I’d start with the web variant before mobile. It’s harder (Flutter web has fewer tools and more edge cases), but it forces correct architectural decisions early — bundle size, lazy loading, image optimization. The same decisions make the mobile build better later.


Want to discuss a Flutter project? Get in touch — we reply within one business day. And if you want to see the result in action, hop on table-online.ro and play a round.