Own product · Carrom
Real carrom, with physics we wrote ourselves.
Carrom is a phone-first board game on a wooden board with exact disc physics. It has five game types, including the 29 Game and Tal Gach played across Bangladesh, India and Pakistan, with online 1 v 1 and 2 v 2, bots and pass-and-play. One TypeScript codebase runs on the web, Android and iOS, and online play runs on our own realtime server.
How to play Use it with your AI assistant
Live on the web. Android and iOS apps in testing and review: coming soon to Google Play and the App Store.

- Web (PWA)
- Android
- iOS
- iPadOS
- game types, each with its own rules engine
- 5
- strokes, bit-identical across browser engines
- 4,320
- automated tests: 396 unit and 150 browser tests, each browser test run at three screen sizes
- 540+
- first load on throttled Fast 3G
- ≤ 3 s
Inside the app
Real screens from the shipping app, as they appear in the store listings.

Break the Tal Gach tower 
Aim like a slingshot 
Animated boards 
2 v 2 online 
Boards, strikers and coin sets 
A daily challenge 
Five game types, one tap
What players get
Five game types
Classic, the 29 Game (first to 29), Tal Gach (break a 19-piece tower, first to 170), Disc Pool and Freestyle, plus a daily challenge and a tutorial.
Online 1 v 1 and 2 v 2
Quick Match by rating, with bots filling empty seats, private rooms, challenge links that open the app, an open-rooms lobby, rematch, emotes, a 20-second turn clock and an Elo rating per game type.
Bots and pass-and-play
Bots in 4 difficulties (Easy to Expert) and 4 personalities (balanced, aggressive, defensive, trick-shot), each with its own name and flag, and pass-and-play for 2 or 4 players on one device.
Progress that follows you
Coins, a shop of animated boards, strikers and coin sets, achievements, stats and daily streaks. Sign in with Google or Apple to keep it on every device.
Operator tools
Our admin panel shows live games and players, handles moderation, adjusts any player’s coins with a message to them, and changes ads, required updates, review prompts, matchmaking switches and even styling without an app release.
Everywhere from one codebase
Web, Android, iPhone and iPad from one codebase, and installable as a web app. Room links open the app if it’s installed, or the web game if it isn’t.
Built from scratch
Every layer is ours, from the rules of the game to the server it runs on.
Game client
Strict TypeScript, Vite and Canvas 2D, with no game engine and no UI framework. The turning boards and the Tal Gach tower previews are pure CSS 3D.
- TypeScript
- Vite
- Canvas 2D
- CSS 3D
Our own physics
Event-driven disc physics on a fixed 1/120 s step, independent of frame rate: pocket jaws, a coin that drops only when enough of it is over the hole, rattle-outs and a breaking tower. It replaced a general-purpose physics library.
- Deterministic
- Seeded randomness
- Headless tests
Realtime backend
Our own Node server on MongoDB, speaking a small JSON-over-WebSocket protocol: get, set, compare-and-set, watch and presence. It evaluates the same security-rules file that Firebase Realtime Database would.
- Node.js
- MongoDB
- WebSocket
- esbuild
Apps and sign-in
Capacitor apps for Android and iOS. Google and Apple sign-in runs through Firebase Auth, and our server checks every token itself. Ads come from AdMob, with no real-money purchases.
- Capacitor
- Firebase Auth
- AdMob
- App Links
Operations
We run the servers ourselves
No game-backend service in between: our own server, our own deploys, our own monitoring.
- Our own Linux server: nginx serves the game with Let’s Encrypt TLS behind Cloudflare
- WebSocket, app config and health checks proxied to the Node service under systemd
- The admin panel runs as its own service and calls an operator API that answers only on the machine itself
- One-command deploys: build, upload a timestamped release, switch, restart, health-check; the last 5 releases kept for instant rollback
- About 210 ms median round trip from Bangladesh through Cloudflare (measured at launch)
- Scripted app builds for Google Play and App Store Connect
- Android App Links and iOS universal links for room invites
Hard problems we solved
The parts players never see, with the numbers we measured.
The same physics on every phone
- The problem
- In an online game each phone simulates the opponent’s stroke itself. If two devices ever computed one number differently, their boards would drift apart, so the physics had to be exact everywhere.
- What we did
- The simulation uses only operations that are exact on every JavaScript engine, with our own square-root-based hypot, log, acos, sin and cos. All randomness is seeded and the core never reads the clock.
Result 4,320 strokes checked in Chromium’s and WebKit’s engines: every board bit-identical.
A desync, found and fenced off
- The problem
- Players on different app versions, with slightly different physics, were being matched together, and their boards disagreed.
- What we did
- A protocol version now gates matchmaking and rooms, and a physics fingerprint test fails the build if the physics changes without the version going up.
Result Only players with identical physics ever share a board.
A tower that breaks fairly
- The problem
- In Tal Gach the opening shot hits a stacked tower of 19 pieces. It has to feel like the real thing and be fair to both players.
- What we did
- A hit at 70% speed or more knocks one or two bottom coins out and leaves the tower standing; softer hits topple it. The randomness is seeded, so every device sees the same break.
Result Strong hits clear the bottom coins 90% of the time, the same on every screen.
Sound on Macs
- The problem
- The iPad app running on Apple-silicon Macs could decode neither AAC nor Opus audio.
- What we did
- The app ships 16-bit WAV copies of the sounds and music, and the game decodes them itself.
Result The same sound on every device, Macs included.
Leaving a vendor without touching the game
- The problem
- Online play started on Firebase Realtime Database, and we wanted the game data on our own server without rewriting the game.
- What we did
- Every online feature talks to one database interface. Our server enforces the same rules file with the same semantics, and one check suite of whole matches and more than 180 allowed or refused writes runs against both backends.
Result The game data now lives on our own server, and switching backends is a two-setting build switch.
Fast to the first shot
- The problem
- A casual game has seconds to win a player over, often on a slow mobile connection.
- What we did
- No engine or framework to download, no audio before the first tap, and a performance test that runs the production build on a throttled connection.
Result First load in 3 s or less on throttled Fast 3G.
Tested like a product, not a demo
- 396 unit tests and 150 browser tests, each run at phone, tablet and desktop size with screenshot baselines (over 400 runs)
- Bot-against-bot balance runs and a monkey test
- An emulator suite that plays whole online matches against the database rules
- Strokes simulated headless in unit tests, thanks to deterministic physics
Technology
- TypeScript
- Vite
- Canvas 2D
- Node.js
- MongoDB
- WebSocket
- Capacitor
- Firebase Auth
- AdMob
- Vitest
- Playwright
- nginx
- Cloudflare
- systemd
Want a game or a realtime app built this way?
We design, build and run games and realtime platforms end to end: apps, servers, stores and operations.