Stumper
Stumper is the KATforge multiplayer trivia game. Players join a lobby, race to answer AI-generated questions across 20+ categories, and climb the leaderboard. Single-player endless mode and practice mode share the same question pipeline.
flowchart LR
Browser["Browser<br/>(stumper.gg)"]
API["API<br/>(api.katforge.com)"]
Mercure["Mercure<br/>SSE Hub"]
Anthropic["Anthropic<br/>Claude API"]
PG["Postgres<br/>(stumper schema)"]
Browser -->|REST| API
Browser -->|EventSource| Mercure
API -->|publish| Mercure
API -->|generate| Anthropic
API <--> PG
Pages in this section
| Page | What's in it |
|---|---|
| Gameplay | Player-facing rules: lobbies, endless, scoring, streaks |
| Architecture | Server + client components and how they compose |
| Lobby Lifecycle | State machine + Mercure publish points |
| Scoring & XP | Streak multipliers, speed bonus, level thresholds |
| Question Pipeline | AI generation, dedup, categorization, caching |
| Client | Pinia stores, composables, EventSource flow |
| Decisions | Architectural choices and the why behind them |
Where to start
- Building a new feature: skim Architecture → read the file for the component you'll touch (each page links to its source) → write the spec for the new fluent method first, then the implementation.
- Fixing a bug: jump to the relevant component page; the public surface is documented as a fluent API so you can find the right method by its name.
- Joining the project: read Gameplay → Architecture → Lobby Lifecycle in that order.
Repository layout
| Path | Contents |
|---|---|
api.katforge.com/src/Game/Stumper/ | Server: controllers, services, repositories, entities, shapes |
stumper.gg/src/ | Vue 3 client: stores, composables, components, pages |
packages/sdk/src/games/stumper.ts | TypeScript SDK module that wraps every Stumper API endpoint |
Documentation-driven contract
This section is the spec for Stumper, not just a description of the current code. When adding a feature:
- Write the new fluent method signature here first
- Update the architecture diagram if a new component is involved
- Implement against the spec
- The page becomes the contract — anything not documented here doesn't exist
That keeps the public surface coherent across the server, the SDK, and the client.