A multiplayer horror murder mystery Discord Activity. Players investigate a procedurally generated murder case together, vote on actions, and try to solve the mystery before getting killed.
Horror Quest runs as an embedded Activity inside a Discord voice channel. Up to 10 players join the same room, read AI-generated horror story scenes, and vote on what to do next. Every game is unique — the story, suspects, clues, and setting are all generated fresh by Gemini AI.
Features:
- AI-generated story with persistent clues and red herrings (Gemini 2.5 Flash)
- AI-generated scene images that change each chapter (Imagen 3.0 Fast)
- Voice narration for every scene — click Listen to hear the story read aloud (Gemini TTS)
- Ken Burns animated backgrounds for atmosphere
- Multiplayer voting — the chapter only advances when everyone has voted
- 3-minute timer per chapter (visual only — waits for all votes)
- Host controls: player limit (2–10), start game, play again
- Crimson Noir UI designed for readability (dyslexia-friendly text contrast + narration)
| Layer | Technology |
|---|---|
| Hosting | Cloudflare Workers |
| Multiplayer state | Durable Objects (SQLite-backed) |
| Real-time comms | WebSockets with hibernation |
| Story generation | Gemini 2.5 Flash |
| Scene images | Imagen 3.0 Fast |
| TTS narration | Gemini 2.5 Flash Preview TTS ("Charon" voice) |
| Frontend | Vite + TypeScript |
| Discord integration | @discord/embedded-app-sdk |
├── client/ # Vite frontend (TypeScript)
│ ├── index.html
│ ├── public/
│ │ ├── background.png # Gothic manor background
│ │ └── logo.png # Skull rose logo / loader
│ └── src/
│ ├── main.ts # Game client, Discord SDK, WebSocket, UI logic
│ └── style.css # Crimson Noir visual novel styles
│
├── worker/ # Cloudflare Worker (TypeScript)
│ └── src/
│ ├── index.ts # Hono router: auth, TTS, WebSocket upgrade
│ ├── GameRoom.ts # Durable Object: game state, voting, timers
│ ├── claude.ts # Gemini story generation
│ ├── gemini.ts # Imagen scene image generation
│ └── types.ts # Shared TypeScript types
│
├── wrangler.toml # Cloudflare deployment config
├── vite.config.ts # Vite build config
└── package.json
- Node.js 18+
- Cloudflare account (free plan works)
- Google AI Studio API key (Gemini + Imagen access, pay-as-you-go recommended)
- Discord Developer account
git clone <your-repo>
cd horror-quest
npm install- Go to Discord Developer Portal and create a new application
- Under Activities, enable the Activity and set URL Mappings:
/→your-worker-name.your-account.workers.dev
- Under OAuth2, note your Client ID and Client Secret
- Under Activities → Supported Platforms, enable Web (covers desktop too)
# Set your Discord client ID in the frontend
echo "VITE_DISCORD_CLIENT_ID=your_client_id_here" > client/.env.localUpdate wrangler.toml:
[vars]
DISCORD_CLIENT_ID = "your_client_id_here"npx wrangler secret put GEMINI_API_KEY
npx wrangler secret put DISCORD_CLIENT_SECRETnpm run deployThis builds the Vite frontend and deploys everything to Cloudflare Workers in one step.
Run the worker and frontend locally in two terminals:
# Terminal 1 — Cloudflare Worker (port 8787)
npm run worker:dev
# Terminal 2 — Vite frontend (port 3000)
npm run devNote: The Discord SDK requires running inside Discord. For local UI testing, use a Cloudflare tunnel to expose your local server and set it as the Activity URL in the Developer Portal.
npx cloudflared tunnel --url http://localhost:3000Per full game session (~8 chapters, 4 players):
| Item | Cost |
|---|---|
| Imagen 3.0 Fast (8 images) | ~$0.08 |
| Gemini 2.5 Flash story | ~$0.002 |
| Gemini TTS (per Listen click) | ~$0.01 |
| Cloudflare Workers | Free tier |
| Total per game | ~$0.10 |
With a $10 Google AI budget cap you get roughly 100+ games.
- Start a voice channel in Discord
- Click the rocket icon → launch Horror Quest
- The host clicks Begin the Mystery
- Read the scene — click ▶ Listen to hear it narrated
- Vote on what to do next — the chapter advances when everyone has voted
- Collect clues, avoid dying, and accuse the right suspect to win
MIT
