From 4fb1a25469aabe9ba354c1b0683f3d506eb39f93 Mon Sep 17 00:00:00 2001 From: thibaud-leclere Date: Mon, 30 Mar 2026 22:21:26 +0200 Subject: [PATCH] docs: add game hints system design spec Co-Authored-By: Claude Opus 4.6 (1M context) --- .../specs/2026-03-30-game-hints-design.md | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 docs/superpowers/specs/2026-03-30-game-hints-design.md diff --git a/docs/superpowers/specs/2026-03-30-game-hints-design.md b/docs/superpowers/specs/2026-03-30-game-hints-design.md new file mode 100644 index 0000000..a89439d --- /dev/null +++ b/docs/superpowers/specs/2026-03-30-game-hints-design.md @@ -0,0 +1,71 @@ +# Game Hints System — Design Spec + +## Summary + +Each row of the game grid provides a hint about the main actor to guess. Hints are pre-generated when the grid is created and stored on `GameRow`. Each hint has a type (film, character, award) represented by a distinct icon. Clicking the icon opens a popover showing the hint text. + +## Data Model + +Two new columns on `game_row`: + +| Column | Type | Description | +|--------|------|-------------| +| `hint_type` | `VARCHAR(20)`, NOT NULL | One of: `film`, `character`, `award` | +| `hint_data` | `VARCHAR(255)`, NOT NULL | film → `movie.id`, character → `movie_role.id`, award → text "Nom du prix (année)" | + +No foreign key constraints on `hint_data` — the column stores either an id (resolved at read time) or raw text depending on `hint_type`. + +## Hint Generation + +Happens in `GameGridGenerator::generate()`, for each `GameRow`: + +1. Pick a random type from `[film, character, award]` +2. Resolve based on type: + - **film**: pick a random `MovieRole` of the main actor → store `movie.id` in `hint_data` + - **character**: pick a random `MovieRole` of the main actor → store `movieRole.id` in `hint_data` + - **award**: call `WikidataAwardGateway` to fetch an award → store `"Nom du prix (année)"` in `hint_data` +3. If the chosen type yields no result (e.g., no awards found), fallback to another random type +4. Avoid duplicate hints across rows (don't show the same film/character/award twice) + +## Wikidata Award Gateway + +New service: `WikidataAwardGateway` + +- Input: actor (name or `tmdb_id`) +- Output: list of awards, each with name and year +- Uses Wikidata SPARQL API to query awards associated with the person +- Storage format in `hint_data`: `"Oscar du meilleur second rôle (2014)"` +- Results can be cached to avoid repeated Wikidata queries + +## Frontend + +### Icon Button + +The current "?" button in `ActorPopover` is replaced by an icon representing the hint type: + +| hint_type | Icon | Font Awesome class | +|-----------|------|--------------------| +| `film` | Film/clap | `fa-film` | +| `character` | Theater masks | `fa-masks-theater` | +| `award` | Trophy | `fa-trophy` | + +### Popover Content + +On click, the popover displays only the hint text: +- **film**: movie title (resolved from `movie.id`) +- **character**: character name (resolved from `movie_role.id`) +- **award**: the raw text from `hint_data` + +### Data Flow + +1. Backend resolves `hint_data` to display text in `GameGridGenerator::computeGridData()` +2. Hint type + resolved text are passed to the Twig template as part of the grid data +3. Twig passes them as props to the React `GameGrid` component +4. `ActorPopover` receives `hintType` and `hintText` props instead of `actorName` + +## Future Extensibility + +New hint types can be added by: +1. Adding a new value for `hint_type` +2. Adding resolution logic in `GameGridGenerator` +3. Adding a new icon mapping in the frontend