(formerly Party Pack)
Nine social-deduction and party games in one server. Everyone plays from their phone; one player hosts a room and shares a 4-letter code.
| Game | Players | One-liner |
|---|---|---|
| 🐺 One Night Werewolf | 3–10 | Secret roles, one night of chaos, vote out the wolf |
| 🕵️ Spyfall | 3–10 | Everyone knows the location — except the spy |
| 🃏 Coup | 2–6 | Bluff your way to the last influence standing |
| 🔤 Codenames | 4–10 | Spymasters give one-word clues to their team |
| ⚔️ Avalon | 5–10 | Good vs. evil, missions and hidden traitors |
| 🐟 Fishbowl | 4–12 | Taboo → one word → charades, same phrases |
| 🎲 Liar's Dice | 2–8 | Bid on everyone's hidden dice, call the liar |
| 💰 Wits & Wagers | 3–10 | Guess the number, then bet on the best guess |
| 🏦 QE | 3–5 | Blind-bid auctions with unlimited money — spend the most and lose |
One player taps Host a new room and reads out the 4-letter room code; everyone else joins with it. The host picks the game in the lobby. Rooms are independent — any number of parties can play at once.
Disconnects are forgiving: a dropped phone has 15 seconds to reconnect (it happens automatically when the page regains network) and rejoins mid-game right where it left off.
npm install
npm start # http://localhost:3000, or PORT=xxxxrender.yaml is a ready Render blueprint: New + → Blueprint → point at this repo. The server reads PORT from the environment. Free-tier note: the instance sleeps when idle (first visit takes ~50s) and a sleep drops all active rooms.
The server also runs happily on a laptop or Mac mini at a party with no internet — everyone joins the machine's LAN address. Two macOS-only extras for that mode:
SPEAK_IP=1makes the machine speak its IP address through its speaker every 5 minutes until the first player joins (for when.localmDNS won't resolve on guests' phones).- Any unmatched URL serves the game page, so captive-portal probes auto-open the lobby when the box runs as its own access point.
| File | Role |
|---|---|
server.js |
Express + Socket.IO. Room registry + a createRoom() factory — each room owns its players, phase, game state, and timers. Sessions are token-based (survive reconnects); empty rooms self-destruct after 5 minutes. |
games/*.js |
One module per game: meta, validateSetup, initGame, per-player state projection (getStateFor), action handlers, computeGameResult. Modules are pure-ish — they operate on a passed game-state object and never touch sockets. |
public/index.html |
The whole client: one page, one screen per phase. |
sim.js |
Headless Monte-Carlo harness (Werewolf): drives full games via socket.io-client and verifies win-conditions. ROOM_CODE=XXXX joins an existing room to play alongside humans; optional Ollama-backed LLM players. |
Write games/yourgame.js exporting the module contract above, register it in the GAMES map and GAME_LIST in server.js, and add a screen + socket handlers in public/index.html. Grep for one of the smaller existing games (qe, liarsdice) as a template.