Real-time word imposter game for Discord Activities and the open web — React + Vite, PartyKit multiplayer, Discord Embedded App SDK, Cloudflare Pages + Worker, optional Supabase profiles and stats.
| Layer | Choice | Role |
|---|---|---|
| UI | React 19, Vite 8, Tailwind v4, shadcn/ui | Fast client; works in Discord iframe and browser |
| Realtime | PartyKit | Authoritative game room, WebSocket sync |
| Discord OAuth | Cloudflare Worker | Token exchange; never ship client secrets to the browser |
| Hosting | Cloudflare Pages | Static app + URL mappings for Activities |
| Accounts (web) | Supabase (optional) | Anonymous / email / Discord link, round history, saved word lists |
flowchart LR
subgraph players [Players]
A[Discord Activity]
B[Web browser]
end
subgraph cf [Cloudflare]
Pages[Pages static app]
W[Worker /api/token]
end
PK[PartyKit game server]
A --> Pages
B --> Pages
Pages --> W
Pages --> PK
Requirements: Node 20+, npm.
git clone <your-fork-or-repo-url>.git
cd imposter-game
npm install && cd server && npm install && cd ..
cp .env.example .env
# Edit .env — see table below and .env.example comments| Terminal | Command |
|---|---|
| 1 — game server | npm run dev:party |
| 2 — client | npm run dev |
Open the URL Vite prints (usually http://localhost:5173). Outside Discord you get a guest / web profile flow; for Discord auth in dev, configure DISCORD_CLIENT_ID + DISCORD_CLIENT_SECRET in .env so POST /api/token works locally.
Playwright / CI: VITE_DISCORD_MOCK=1 pins a mock user and hides the web profile bar — use only for automated tests, not normal play.
Full reference lives in .env.example. These are the ones you touch first:
| Variable | Scope | Purpose |
|---|---|---|
VITE_DISCORD_CLIENT_ID |
Client build | Discord application ID |
VITE_PARTYKIT_HOST |
Client build | PartyKit host, e.g. localhost:1999 or your-party.username.partykit.dev |
VITE_DISCORD_TOKEN_URL |
Client build | Worker URL for token exchange in browser/PWA; inside Discord the app uses mapped /api/token |
DISCORD_CLIENT_ID / DISCORD_CLIENT_SECRET |
Vite dev + Worker | Server-side OAuth (secret never VITE_*) |
VITE_SUPABASE_URL + anon/publishable key |
Optional web | Cloud profile, history, saved lists — see migrations in supabase/migrations/ |
Production deploy uses .env.deploy (from .env.deploy.example) and npm run deploy — exact order and portal steps are in docs/LAUNCH_PLAN.md.
| Command | Description |
|---|---|
npm run dev |
Vite dev server |
npm run dev:party |
PartyKit dev (server/) |
npm run build |
Production client build (tsc + Vite) |
npm run lint |
ESLint |
npm run test:e2e |
Playwright (start PartyKit on 127.0.0.1:1999 locally first) |
npm run deploy |
Worker secrets + Partykit + Pages (uses .env.deploy) |
npm run deploy:worker / deploy:partykit / deploy:pages |
Granular deploy steps |
npm run assets:brand |
Regenerate PNGs from SVGs (sharp) |
npm run gen:sfx |
Regenerate UI sound WAVs |
| Doc | Use when |
|---|---|
| docs/README.md | Index of all guides |
| docs/LAUNCH_PLAN.md | Shipping to production (phases, Discord portal, verify) |
| docs/STAGING.md | Staging env + DEPLOY_ENV_FILE |
| docs/DISCORD_ACTIVITY_URLS.md | URL mappings, legal URLs, checklist |
| docs/SECURITY.md | JOIN hardening, JWT mode, rate limits |
| docs/POST_LAUNCH.md | Post-deploy smoke checks |
imposter-game/
├── src/ # React app (screens, hooks, i18n, components)
├── server/ # PartyKit project (room logic, word packs)
├── workers/ # Cloudflare Worker source (token / JWT)
├── e2e/ # Playwright tests
├── scripts/ # deploy.mjs, release helpers, assets
├── supabase/migrations/ # Optional SQL for web profiles / stats / lists
├── docs/ # Runbooks and checklists
└── public/ # Static assets, sounds, legal pages
- Never commit
.env,.env.deploy, or Discord client secrets. - Prefer
JOIN_VERIFYand/or party JWT for production rooms exposed on the public internet — see docs/SECURITY.md. - Vulnerability reports: SECURITY.md (private disclosure).
See CONTRIBUTING.md for local setup, checks, and PR expectations.
MIT — see file for full text. If you fork for your own Discord app, update branding and legal pages under public/ to match your product.
Built with PartyKit, Discord Embedded App SDK, Cloudflare Workers & Pages, and Supabase (optional).