Welcome to the pack 🐺

Everything you need to understand, run, and ship Werewolf AI Arena — a browser game where humans and AI bots play Ma Sói (Werewolf) together, live. This is the single source of truth. Read top to bottom on day one.

Next.js 16 + TypeScript Hosted on Vercel Upstash Redis DB Clerk auth Bots: Claude · Gemini · DeepSeek · Qwen Repo: private

1Overview — what are we building?

A live, watchable Werewolf arena. Humans coach or play alongside AI bots that argue, lie, and vote in Vietnamese (or English) with real personalities — including VN celebrity voices. Spectators can bet on who the wolf is.

🎭 The hook

AI bots with distinct voices (Đà Nẵng GenZ, Sơn Tùng, Trấn Thành…) debate and deceive each other. It's funny to watch and unpredictable.

👥 Who plays

Host creates a room → humans + spectators join by link → host fills empty seats with bots → match streams live to everyone.

🎯 The vision

Watch-first AI arena (Twitch-style): bet on outcomes, pay to inject chaos. Side-project, not a Wildcats product.

⚙️ Mental model: The browser is just a viewer. The real match runs server-side on Vercel, writes every event to Redis, and every player/spectator subscribes to a filtered stream of those events. That's why anyone can reload mid-game without breaking it.

2Quick Start — run it in 5 minutes

Goal: get the game on localhost:3000 and play one match in your terminal. You need Node 18+.

1 · Clone
Get the private repo (ask Lucas for GitHub access first).
git clone git@github.com:imnumber1234/werewolf-ai-arena.git
cd werewolf-ai-arena
2 · Install
npm install
3 · Add your keys
Copy .env.example to .env.local and fill it. See section ⑧ for every key + where to get it. Teammates DM each other the shared keys.
# Windows PowerShell
copy .env.example .env.local
4 · Run the web app
npm run dev # → http://localhost:3000
5 · (Fastest) play a match in the terminal — no web, no keys needed
Watch 6 dumb bots play a full match in ~5 min. Great for understanding the game loop.
npm run match # mock bots, $0 cost
npm run match:claude # force real Claude bots
🔎 Before every push: run npx tsc --noEmit to typecheck. A failing typecheck = a broken Vercel deploy.

3Repo & Git

ThingValue
Git remotegit@github.com:imnumber1234/werewolf-ai-arena.git
VisibilityPRIVATE — keep it that way. Never make public.
Main branchmain — pushing here auto-deploys to production. Be careful.
Access over SSHUse SSH (git@github.com), not HTTPS, to avoid login popups.
Local folderGitHub/Werewolf AI Arena/ in Lucas's workspace
⚠️ Workflow rule: main is live. For anything risky, branch first (git checkout -b feature/x), open a PR, merge when green. Don't push half-broken code straight to main — Vercel ships it instantly.

4Tech Stack

Frontend

  • Next.js 16 (React 19) — pages + API in one
  • TypeScript — everything is typed
  • PixiJS — 2D pixel-art village
  • three.js — optional 3D VRM avatars
  • Custom CSS (globals.css + landing.css)

Backend / Engine

  • Next.js API routes (serverless on Vercel)
  • Pure-TS game engine (src/engine/) — no game library
  • Vercel AI SDK — talks to all LLM vendors
  • Upstash Redis — room + event state
  • Clerk — user auth
  • msedge-tts — free voice (text-to-speech)

Folder map (where things live)

FolderWhat's inside
app/Pages (landing, lobby, room, join, train) + all API routes + React components
src/engine/The game brain — match loop, roles, win logic, cast, dialects, phrasebank
src/agent/The players — real LLM bots, mock bots, human input, webhook bots, prompt assembly
src/server/Storage + services — rooms, event log, permissions, betting, cost meter
src/cli/Terminal match runner (npm run match)
worker/Optional Cloudflare real-time layer (Phase 1, separate package)
public/Faces, 3D models, audio, memes, demo videos, mockups
db/Postgres schema for future Supabase archival
docs/Design + research docs (see section ⑬)

5Architecture — the reload-safe design

This is the most important concept. Understand it before touching match code.

/start — the driver
Host-only. Runs the entire match server-side, turn by turn, and writes every event to Redis. The host's browser does NOT run the match.
/stream — the watcher
Every viewer (player or spectator) subscribes here. They long-poll for new events and get only what their role is allowed to see.
matchMeta — the bouncer
Redis store of who-is-what. Server-side it filters events: a villager never receives the wolves' night chat.
Event log — the replay
Every message is one event. Reload? You just re-subscribe and replay the log. No freeze, no lost state.
💡 Why it matters: the old version streamed the match only to the host's browser — so if the host reloaded, the game froze for everyone. The current split (/start drives, /stream watches) fixed that. Don't reintroduce browser-driven match logic.

Vendor fallback chain

When a bot needs to speak, it tries vendors in order and degrades gracefully — so one slow/down provider never kills a match.

auto → DeepSeekQwenClaudeGoogle → random vote
// 60s timeout + 1 retry per bot. Hard match deadline: 270s (Vercel cap 300s).

6Database

Today it's all Upstash Redis (serverless key-value, no SQL). A Postgres schema exists for future match archival but isn't live yet.

StoreWhatLifetime
Room statePlayers, settings, current phase (Redis)4-hour TTL
Event logEvery match message, per room (Redis list)2-hour TTL, max 5000
matchMetaRoles + permissions per match (Redis)Per match
FUTURE matches / match_playersFinished-match archive — defined in db/schema.sqlPermanent (Supabase Postgres, not wired yet)
🔌 Connection: Upstash host is cute-termite-84944.upstash.io. Auth tokens live in .env.local under KV_REST_API_*. There's a read-only token too. Never commit these.
🗄️ Heads up: because Redis state has a TTL, rooms and logs auto-expire. That's by design (it's a live arena, not a record-keeper). Permanent history is the Supabase Phase-2 job — see docs/PLATFORM-MIGRATION.md.

7Hosting & Deployment

Primary — Vercel LIVE

URLwerewolf-ai-arena.vercel.app
DeployAuto on push to main
RegionSingapore (sin1)
Fn timeout300s (match deadline 270s)

Optional — Cloudflare Worker PHASE 1

Real-time WebSocket layer using Durable Objects, in worker/ (its own package). Mock matches work; not yet pointed at production. Config in worker/wrangler.jsonc.

Deploy checklist

1  npx tsc --noEmit — must pass
2  git commit with a scoped message
3  git push origin main → Vercel builds & ships automatically
4  Watch the Vercel dashboard for green build, then smoke-test the live URL

8Keys & Environment Variables

🔐 Security: This handbook lists key names + where to get them only — never the actual secret values. Teammates DM each other the shared keys. .env.local is gitignored; never commit it or paste keys in chat/Notion.
KeyPurposeWhere to get it
CLERK_SECRET_KEY
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
User auth (login)clerk.com — free tier
KV_REST_API_URL
KV_REST_API_TOKEN
KV_REST_API_READ_ONLY_TOKEN
REDIS_URL
Redis databaseupstash.com — free tier
ANTHROPIC_API_KEYClaude bots (default)console.anthropic.com
GOOGLE_GENERATIVE_AI_API_KEYGemini bots (optional)aistudio.google.com — free
DEEPSEEK_API_KEY + DEEPSEEK_BASE_URLDeepSeek bots (optional)platform.deepseek.com — funded by Anh
QWEN_API_KEY + QWEN_BASE_URLQwen bots (optional)dashscope.aliyun.com — funded by Anh
QSTASH_TOKENUpstash Workflow (host-reload fix, future)Upstash console
KLIPY_API_KEYReal GIFs (dormant feature)Optional, off by default
🧪 The terminal match (npm run match) needs no keys at all — it uses mock bots. Add keys only when you want real LLM bots or the full web app with login.

9How a Match Runs

1 · Create — Host makes a room: name, language (EN/VI), AI provider.
2 · Join — Humans & spectators open the link, pick a persona, choose play-or-watch.
3 · Fill — Host adds bots to empty seats (generic templates or VN celebrities). Default fill = 4 (keeps API rate limits happy).
4 · Start — Host hits start → engine runs the whole match server-side, broadcasting to all.
5 · Day — Public table-talk → everyone votes → one player is eliminated.
6 · Night — Roles act secretly: wolves kill, seer checks, doctor saves, witch heals/poisons → back to Day.
7 · End — Village wins (all wolves out) or wolves win (they equal/outnumber town). Results + XP awarded.

Pacing (tunable in src/config.ts)

PhaseTime
Night (roles act)30s
Day talk60s
Day vote30s
Human turn timeout45s
Bubble gap (one speaker at a time)5s
Max turns (hard ceiling)12

10Roles

Assigned by src/engine/roles.ts based on player count. More players unlock more special roles.

🐺
Werewolf
Kills one player each night. Wins when wolves equal or outnumber the town.
🧑‍🌾
Villager
No power. Wins by voting out every wolf during the day.
🔮
Seer
Each night, checks one player to learn if they're a wolf.
💉
Doctor
Saves one player from the wolves each night. Unlocks at 5 players.
🔫
Hunter
When killed, takes one player down with them. Unlocks at 7 players.
🧪
Witch
One heal + one poison for the whole game. Unlocks at 9 players.

11Content & Cast — the voices

The personality is the product. Each bot stacks: identity → regional dialect (giọng vùng miền) → job/role flavor → strategy → voice samples. Built in src/agent/persona.ts, fed by engine files below.

Generic personas (src/shared/personaTemplates.ts)

NOVA
Gái Đà Nẵng · GenZ

Central VN dialect, anxious nervous energy.

ATLAS
Trai Hà Nội · GenZ

Northern dialect, cà khịa (roast) humor.

LUNA
Gái Sài Gòn · GenZ

Southern dialect, dramatic, loves the drama.

ORION
Theatrical liar

Loud debate-club captain, English filler words.

IRIS
Skeptical librarian

Quote-collector, hunts contradictions.

ECHO
Quiet surgeon

Silent until ~90% certain, then strikes.

ZEPHYR
Startup founder

Confident, loud, often wrong.

RAVEN
Paranoid grandma

Trusts cat lovers, suspects fast talkers.

VN celebrity cast (src/engine/cast.ts)

Sơn Tùng M-TP
Superstar

Reserved, soft-spoken, cool detachment.

Trấn Thành
Famous MC

Ultra-talkative, emotional, empathetic, Southern accent.

Huấn Hoa Hồng
Fake life-coach

Grave, preaches morality, cocky.

Độ Mixi, Jack, Khả Bằng…
In development

Faces in public/faces/, personas TBD.

📚 Voice rule: named celebrities skip the random dialect and use an authored tic + samples (so Sơn Tùng always sounds like Sơn Tùng). Generic bots get a random region + job + 3–6 samples. The "why" is documented in docs/CHARACTER-VOICE-RESEARCH.md and docs/DIALECT-ENHANCEMENT-PLAN.md.

Content source files

FileHolds
src/engine/cast.tsNamed VN celebrities + their authored voice tics
src/engine/regions.tsVN regional dialects (Bắc / Trung / Nam / Tây)
src/engine/phrasebank.tsJob-based slang (bully, therapist, prophet, dealer…)
src/engine/strategies.tsPlay-styles (aggressive, defensive, deceptive)
src/agent/persona.tsAssembles the final ~400-token prompt per turn
🇻🇳 House rule: all Vietnamese must keep its diacritics (dấu) — "Sơn Tùng", never "Son Tung". Wrong dấu = wrong meaning.

12Assets — images, audio, video

AssetLocationNotes
Character facespublic/faces/[NAME]/5 emotion states each (normal/happy/sad/angry/scared) PNG
Portrait fallbackportraitFor() in portrait.tsDiceBear API when no custom face (free); Puter.js AI portraits = Phase 1b
Pixel villageapp/components/PixelStage.tsxSVG-drawn ring of avatars
3D avatars (VRM)public/3d/*.vrmOptional three.js models
Win musicpublic/audio/celebration.mp3Plays on win + dance button
Voice (TTS)msedge-ttsMicrosoft Edge TTS — free, no key
Memes / GIFspublic/memes/ + /api/gifCurated fallback pack; Klipy proxy dormant
Demo videospublic/demo.mp4, trailer.mp4For landing + promo

13Docs Index — read these next

Already in the repo. Start with HANDOFF.md, then the build plan.

DocWhat it covers
HANDOFF.mdFull handoff for the next person — read first
WEREWOLF_BUILD_PLAN.mdPhased roadmap + shipping log
AUDIT.mdSecurity & game-balance audit
BUGS.mdKnown issues + fixes
FLOW-DESIGN.md / FLOW-RESEARCH.mdUI/UX flow mockups + game-design research
docs/CHARACTER-VOICE-RESEARCH.mdHow/why the persona voice system works
docs/DIALECT-ENHANCEMENT-PLAN.mdVoice layering deep-dive
docs/PLATFORM-MIGRATION.mdPhase 2: Workflow + WebSocket + Supabase
docs/PLAYER-MODES-PLAN.mdHuman / spectator / bot modes spec
worker/README.mdCloudflare Durable Object setup

14Status & Known Bugs

FeatureStatus
Game loop (turn-based, role logic)SHIPPED
Role-filtered chat streamingSHIPPED
AI bots (Claude/Gemini/OpenAI/DeepSeek/Qwen)SHIPPED
Human players (turn-gated)SHIPPED
Spectator betting (two markets)SHIPPED
Training / XP ladderSHIPPED
AI portraits (DiceBear fallback)SHIPPED
Real GIFs (Klipy)ENV-GATED — needs key
Cloudflare real-time workerPHASE 1 — mock only
Supabase match archivalPLANNED — schema ready
Host-reload fix (Upstash Workflow)DESIGNED — needs QSTASH_TOKEN
🐞 Known bug: the smoke test (npm run test:smoke) is broken as of 2026-06-23 — see BUGS.md. Don't trust it as a gate yet; verify manually.

15Team & Workflow

🧑‍💻 Engineering (most of you)

  • Branch off main, PR, merge when typecheck passes
  • Run npx tsc --noEmit before every push
  • Test with npm run match (free) before spending API tokens
  • Never commit .env.local or any key
  • Keep VN diacritics intact in all content

📣 Marketing & Business (few of you)

  • You don't need to code — focus on the live URL + demo videos
  • Cast voices & personas are the marketing hook
  • Assets to use: public/demo.mp4, trailer.mp4, landing page
  • Vision: watch-first arena, betting, pay-to-inject (Twitch-style)
🔑 Onboarding step 0: ask Lucas for (1) GitHub repo access, (2) the shared keys via DM, (3) Vercel + Upstash + Clerk dashboard invites if you'll deploy.