Case study · Product & technical
Declaration
A card table for six friends, wherever they happen to be.
Declaration is a purpose-built companion for a six-person friend group playing a familiar card game, remotely or together in person. A host creates a table and shares six private seat links, and each player gets a secure private hand on their phone. The system handles the rules, timed declarations, scoring, turn changes, reconnection, and hidden information, while the friends keep the conversation on FaceTime, Discord, Zoom, or whichever call they already use.
- Role
- Designed and built end to end
- Status
- In development
- Table
- Six players, two teams of three
- Stack
- Next.js · React · TypeScript · Postgres · Redis

Why it exists
A card game the same six people had played for years stopped being possible once everyone scattered. The game itself survives a phone call fine; what does not survive is the bookkeeping. Somebody has to remember whose turn it is, what has been asked for, which sets are still live, and what everyone is holding, and nobody can see anybody else’s hand without the table between them.
So the product is not a video call with cards bolted on. The friends already have a call they like. Declaration takes over only the part a group chat cannot do: dealing private hands, enforcing the rules, and keeping hidden information hidden.
How a table works
Add six players
Host
Three names for each team. No accounts, no signups, nothing for anyone to remember a password for.
Send the seat links
One per player
Each player gets a one-time private invitation. The secret lives only in the URL fragment and is exchanged once for a seat scoped to that device.
Stay on your usual call
Everyone
Ask for cards and make declarations on the phone. The conversation stays wherever the group already has it.
What the system owns
- A private hand on each phone, and one shared public state everyone sees.
- Server-authoritative rules, scoring, and hidden information, so a player’s own device never holds what it should not.
- Timed declarations, turn changes, card conservation, and winner determination in a rules engine independent of the interface.
- Reconnection, so a dropped phone rejoins the same seat rather than ending the game.
Decisions worth defending
No accounts
Six people who already know each other do not need a signup flow. A private seat link is the whole identity model, which removes both the friction and a database of credentials worth stealing.
The client is never trusted with hidden information
A card game is only fun if nobody can read the other hands. Hands are resolved server-side and a player’s view returns only what that seat is allowed to know, so cheating would require the server to be wrong rather than the interface.
No voice or video
Building a call would have meant competing with FaceTime and Discord at the one thing the group is already happy with. The product deliberately stops at the edge of the conversation.
How it is built
Next.js App Router and React in TypeScript, with Tailwind for the interface. Game state is durable in PostgreSQL on Supabase, actions are idempotent so a retry cannot double-play a card, and Upstash Redis handles rate limiting. Vitest covers the rules engine, which is written to stand on its own so the game logic can be tested without a browser or a database.