Case study
MovieTQ
A real-time multiplayer browser game where players race to name films first. Create or join rooms, play across multiple game modes, compete on leaderboards, and keep your progression through accounts, achievements, in-game currency, and cosmetics.
Two live modes
Bomb-It
Players take turns naming a film that fits the prompt before the bomb’s timer runs out. Miss, and you lose a life — last one standing wins.
Trailer Quiz
A trailer plays and everyone races to name the film before the round timer ends. The answer and the points land together at the buzzer.
Two modes are live today; more are on the way.
Inside the game
Real-time multiplayer
Server-authoritative rooms keep every player on the same frame, synced within a second. The server decides; clients just render.
Persistent progression
Accounts, levels, and XP that track your match scores — plus global leaderboards and achievements granted automatically from how you play.
An in-game economy
Earn Popcorn by playing and spend it in a cosmetics store — avatars, titles, backgrounds — with optional packs and subscription tiers through Stripe.
Moderation built in
An admin console with audited system logs, player and trailer reports, and the usual ban, mute, and block tools keeps lobbies civil.
Under the hood
Plain English by default — switch to the engineering detail.
A server-authoritative game loop
The server runs the whole match as a state machine on a one-second heartbeat, so scoring and timing can’t be faked by a client.
A LOBBY → STARTING → IN_ROUND → BETWEEN_ROUNDS → FINISHED machine ticks on a setInterval heartbeat; every request first walks one ordered Express middleware chain — CORS, CSRF, rate-limit, validation, auth.
Real-time sync
Everyone in a room sees the same trailer at the same moment; the server is the single source of truth.
Room presence is tracked server-side and every player action is validated through a Supabase service-role client that sits above row-level security — client state is discarded.
Trailers without the bandwidth bill
Trailers stream straight from YouTube’s CDN, and the player is cropped to hide its controls without breaking YouTube’s rules.
The embed renders inside a scaled, overflow-clipped wrapper — a bounding crop — so it stays technically visible; broken videos are caught by embed error codes (100/101/150) and instantly swapped for a backup.
Accounts, economy, and payments
Profiles persist levels, currency, and cosmetics, and Stripe handles packs and subscriptions.
Deleting or banning a user cascades across matches, inventory, and achievements; subscription tiers live in a shared package as the single source of truth, and an admin stats API reports live running costs.
One TypeScript codebase
Frontend, backend, and shared types live in one repository, typed end to end.
React + Vite on the front, Node 22 + Express on the back, Supabase (PostgreSQL) for data; server TypeScript compiles to JavaScript siblings at build time.
The social layer
Built with
- TypeScript
- React
- Vite
- Node.js
- Express
- Supabase
- PostgreSQL
- Stripe
The whole stack, built in-house
Frontend, backend, database, real-time multiplayer, accounts, and payments — designed, built, and operated end to end.