Skip to content
All projects

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
The friend group Declaration was built for, standing arm in arm on a driveway on a summer afternoon.

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.

Play the demodeclaration-tau.vercel.appTry one turn (opens in a new tab)