FTC
Realtime multiplayer card game with a server-authoritative rules engine.
- Services
- Product DesignEngineering
- Industries
- Realtime
- Tools
- Next.jsSupabaseTypeScript
- Highlight
- No client decides the outcome.
- Live
- ftc-game.vercel.app
Top trumps, and the oldest problem in multiplayer
The game is simple: pick a universe, pick a deck, and call the strongest stat on your top card. The problem underneath it is not simple at all, and it is the one every multiplayer game meets on day one — if the client knows what the other player is holding, the game is over.
A card game is the purest version of this. Every card is data, the whole deck has to reach the device somehow, and the moment it does, the outcome is decidable before anyone plays.
What a deck has to be before it can be played
Decks are content, and content that is wrong breaks a game rather than looking bad. The rule is explicit: a deck needs fifty-two cards, eight stats, complete stat values for every card, and a cover image before it can be made playable. The cover doubles as the card back in play, which is a small thing that makes an authored deck feel finished.
Rooms and turns run over Supabase Realtime — the same shape as the rest of these projects, because a Postgres that can broadcast removes the need for a game server.
Every card is data, and data on a client is data the client can read. Where the comparison happens is the whole design.
- Game
- Fantasy trump cardsUniverse then deckCall the strongest stat
- Decks
- 52 cards8 statsCover doubles as the back
- Realtime
- Supabase RealtimeRooms, create or joinSupabase Auth
- Stack
- Next.js 15React 19Framer Motion + GSAPVercel
What it cost
Two animation libraries is one more than a project should have. Framer Motion and GSAP are both here — Motion for component transitions where it is genuinely nicer, GSAP for anything scrubbed or sequenced. It works and it is a cost, and if this were rebuilt today it would pick one.
Deck authoring is where the real work is. Fifty-two complete cards across eight stats is a spreadsheet problem, and the validation rule exists because a deck that is 95% filled in is a deck that produces a broken round somewhere in the middle of a match.
Where it does not work yet
The rules engine is not documented, and this page will not pretend otherwise. The thesis of the project is that no client decides the outcome; what the repository actually shows is Supabase Realtime, Supabase Auth and a deck schema. Whether comparison is server-side today, and where it runs, is not written down anywhere a reader could check.
That gap is the next thing worth closing — not because the code is necessarily wrong, but because on a card game "trust us, the server decides" is a claim that has to be readable to be worth anything.