Add a Genre Pack
When to Use
- •Creating the initial
noirgenre content (the app's required default) - •Adding a second or later genre
- •Expanding an existing genre with more cards or characters
Prerequisites
src/data/gameContent.ts must exist. If it doesn't, create it first — this file is the critical blocker preventing the app from compiling.
Required Exported Shape
// src/data/gameContent.ts must export these:
export interface Character { id: string; name: string; description: string; }
export interface ThemeAgenda { id: string; title: string; description: string; }
export interface GameCard {
id: string;
type: 'move' | 'element' | 'event';
subtype?: string; // move subtypes: Complicate|Introduce|Reveal|Callback|Resolve|Confront; element: 'secret'
name: string;
description: string;
effect: string; // Event cards: "+2 Tension", "-1 Coherence", etc.
}
export interface ScenePrompt { id: string; text: string; act: 1 | 2 | 3; }
export interface GenrePack {
name: string;
characters: Character[];
themeAgendas: ThemeAgenda[];
gameCards: GameCard[];
scenePrompts: ScenePrompt[];
}
export function getGenrePack(genre: string): GenrePack { ... }
Procedure
1. Create or open src/data/gameContent.ts
Use assets/GenrePackTemplate.ts as your guide.
2. Design Characters (minimum 4)
One assigned to each player on setup. Rules:
- •Must support 4 simultaneous players → need ≥ 4 characters
- •IDs must be unique within the genre:
"<genre>-detective","<genre>-informant", etc. - •
descriptionis flavor text seen during the draft phase (1–2 sentences)
3. Design Theme Agendas (minimum 4)
One assigned per player. A theme agenda describes the type of narrative moments that earn the player bonus points during scoring. Rules:
- •Must be discoverable from reading 9
LogEntry.narrationstrings - •Not tied to winning/losing mechanics — scoring is manual, player-judged
- •Example:
"Betrayal — scenes where trust is broken or a secret is exposed"
4. Design Cards
Card balance (single-copy deck — engine doubles it):
| Type | Count | Notes |
|---|---|---|
| Move | 6–8 | Must cover all 6 subtypes |
| Element | 4–6 | Mix of open and secret (subtype: 'secret') |
| Event | 4–6 | Each must have parseable meter deltas in effect |
Move card subtypes — at least 1 card per subtype:
| Subtype | Effect |
|---|---|
Complicate | +1 Tension, adds complication string to targeted Fact |
Introduce | Creates new open Fact; +1 Coherence if references an existing Fact |
Reveal | Reveals a secret Fact; +1 Coherence |
Callback | References a Fact, increments fact.callbacks; +1 Coherence |
Resolve | Costs 2 Tension, resolves a Fact; 2 pts to resolver, 1 pt to fact creator |
Confront | +1 Tension, free narration |
Event card effect string format — the parser checks for these exact substrings:
- •
+2 Tension,+1 Tension,-1 Tension - •
+2 Coherence,+1 Coherence,-1 Coherence - •Multiple effects can be combined:
"+2 Tension -1 Coherence"
5. Design Scene Prompts (minimum 9, three per act)
Provide at least 3 prompts per act so the engine can vary scenes across playthroughs:
- •Act 1 (scenes 1–3): Establishing prompts — introduce people, places, problems
- •Act 2 (scenes 4–6): Escalation prompts — complications, reveals, alliances
- •Act 3 (scenes 7–9): Resolution prompts — confrontations, final choices, aftermath
Prompt text should be setting-specific and leave room for player interpretation (1–2 sentences).
6. Register in getGenrePack
const GENRE_PACKS: Record<string, GenrePack> = {
noir: noirPack,
western: westernPack, // add new genres here
};
export function getGenrePack(genre: string): GenrePack {
return GENRE_PACKS[genre] ?? GENRE_PACKS["noir"];
}
7. Verify
- •
npm run buildcompiles without errors - •
getGenrePack("noir")returns a pack with ≥ 4 characters, ≥ 4 agendas, the 6 move subtypes, and ≥ 9 scene prompts - •No duplicate IDs within a pack