Spaces:
Sleeping
Sleeping
Commit Β·
b24ad7d
1
Parent(s): 17a2f53
docs: Update architecture/UI docs and add new game mode template
Browse files- ARCHITECTURE.md: Updated deployment section with dual remotes,
added audio caching and preference persistence to perf table
- CONTEXT_UI.md: Added Discovered Context with actual file structure,
JS audio caching architecture, asset naming conventions, auto-hold
pattern, and sidebar rules documentation
- NEW_GAME_MODE_TEMPLATE.md: Comprehensive template for defining new
game modes β covers rules, scoring, tiers, audio, UI patterns, and
integration checklist with a worked Peasant's Gamble example
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- docs/ARCHITECTURE.md +31 -23
- docs/CONTEXT_UI.md +57 -2
- docs/NEW_GAME_MODE_TEMPLATE.md +278 -0
docs/ARCHITECTURE.md
CHANGED
|
@@ -250,34 +250,40 @@ To reduce perceived latency:
|
|
| 250 |
## 7. Deployment Architecture
|
| 251 |
|
| 252 |
```
|
| 253 |
-
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 254 |
-
β
|
| 255 |
-
β
|
| 256 |
-
|
| 257 |
-
β
|
| 258 |
-
|
| 259 |
-
β
|
| 260 |
-
|
| 261 |
-
β
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
β
|
| 269 |
-
β - PostgreSQL database
|
| 270 |
-
β - Realtime WebSocket channels
|
| 271 |
-
β - Row Level Security
|
| 272 |
-
|
| 273 |
-
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 274 |
```
|
| 275 |
|
| 276 |
-
###
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 277 |
|
| 278 |
```
|
| 279 |
SUPABASE_URL=https://xxx.supabase.co
|
| 280 |
-
SUPABASE_ANON_KEY=
|
| 281 |
```
|
| 282 |
|
| 283 |
---
|
|
@@ -292,6 +298,8 @@ SUPABASE_ANON_KEY=eyJxxx...
|
|
| 292 |
| Database round-trips | Batch updates where possible |
|
| 293 |
| Realtime subscription limits | One channel per lobby |
|
| 294 |
| Animation performance | CSS animations over JS |
|
|
|
|
|
|
|
| 295 |
|
| 296 |
### Scaling Limits (Free Tier)
|
| 297 |
|
|
|
|
| 250 |
## 7. Deployment Architecture
|
| 251 |
|
| 252 |
```
|
| 253 |
+
ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
|
| 254 |
+
β GitHub (source) β β Hugging Face Spaces β
|
| 255 |
+
β origin/master β β hf/main (live app) β
|
| 256 |
+
ββββββββββββ¬ββββββββββββββββ ββββββββββββ¬ββββββββββββββββ
|
| 257 |
+
β git push origin master β git push hf master:main
|
| 258 |
+
βββββββββββββββββ¬ββββββββββββββββββββ
|
| 259 |
+
β
|
| 260 |
+
ββββββββββββββΌβββββββββββββββββββββ
|
| 261 |
+
β Streamlit Application β
|
| 262 |
+
β - Serves UI + game engine β
|
| 263 |
+
β - JS-cached audio system β
|
| 264 |
+
β - Connects to Supabase (HTTPS) β
|
| 265 |
+
ββββββββββββββ¬βββββββββββββββββββββ
|
| 266 |
+
β
|
| 267 |
+
ββββββββββββββΌβββββββββββββββββββββ
|
| 268 |
+
β Supabase β
|
| 269 |
+
β - PostgreSQL database β
|
| 270 |
+
β - Realtime WebSocket channels β
|
| 271 |
+
β - Row Level Security β
|
| 272 |
+
βββββββββββββββββββββββββββββββββββ
|
|
|
|
| 273 |
```
|
| 274 |
|
| 275 |
+
### Remotes
|
| 276 |
+
|
| 277 |
+
| Remote | URL | Branch |
|
| 278 |
+
|--------|-----|--------|
|
| 279 |
+
| `origin` | `https://github.com/legomaheggoz-source/DevilsDozen.git` | `master` |
|
| 280 |
+
| `hf` | `https://huggingface.co/spaces/legomaheggo/DevilsDozen` | push `master:main` |
|
| 281 |
+
|
| 282 |
+
### Environment Variables (HF Spaces Secrets / `.env` locally)
|
| 283 |
|
| 284 |
```
|
| 285 |
SUPABASE_URL=https://xxx.supabase.co
|
| 286 |
+
SUPABASE_ANON_KEY=sb_publishable_xxx...
|
| 287 |
```
|
| 288 |
|
| 289 |
---
|
|
|
|
| 298 |
| Database round-trips | Batch updates where possible |
|
| 299 |
| Realtime subscription limits | One channel per lobby |
|
| 300 |
| Animation performance | CSS animations over JS |
|
| 301 |
+
| Audio data re-send on rerun | JS Audio caching in `window.parent` β base64 sent once, then tiny control commands |
|
| 302 |
+
| Widget prefs lost on `st.rerun()` | Non-widget session state keys (`_sfx_pref`, `_music_pref`, etc.) |
|
| 303 |
|
| 304 |
### Scaling Limits (Free Tier)
|
| 305 |
|
docs/CONTEXT_UI.md
CHANGED
|
@@ -328,6 +328,61 @@ streamlit run src/ui/app.py
|
|
| 328 |
|
| 329 |
## Discovered Context
|
| 330 |
|
| 331 |
-
>
|
| 332 |
|
| 333 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 328 |
|
| 329 |
## Discovered Context
|
| 330 |
|
| 331 |
+
> Updated Feb 2026 after full implementation and playtesting.
|
| 332 |
|
| 333 |
+
### Actual File Structure
|
| 334 |
+
|
| 335 |
+
Pages live under `src/ui/views/` (not `src/ui/pages/`). Sound system is in `src/ui/themes/sounds.py`.
|
| 336 |
+
|
| 337 |
+
| File | Purpose |
|
| 338 |
+
|------|---------|
|
| 339 |
+
| `src/ui/app.py` | Entrypoint β routing, sidebar rules, sound system init |
|
| 340 |
+
| `src/ui/themes/sounds.py` | JS-cached audio system (SFX + music) |
|
| 341 |
+
| `src/ui/themes/animations.py` | CSS/HTML animation helpers |
|
| 342 |
+
| `src/ui/themes/medieval.css` | Full medieval theme CSS |
|
| 343 |
+
| `src/ui/components/dice_tray.py` | Dice display with hold/reroll buttons |
|
| 344 |
+
| `src/ui/components/scoreboard.py` | Player scores panel |
|
| 345 |
+
| `src/ui/components/turn_controls.py` | Roll / Bank / End Turn buttons |
|
| 346 |
+
| `src/ui/components/lobby.py` | Create / Join / Waiting room |
|
| 347 |
+
| `src/ui/views/home.py` | Home + lobby waiting page |
|
| 348 |
+
| `src/ui/views/game.py` | Main game loop with polling |
|
| 349 |
+
| `src/ui/views/results.py` | Victory screen + standings |
|
| 350 |
+
|
| 351 |
+
### Audio System Architecture
|
| 352 |
+
|
| 353 |
+
The original approach injected base64 `<audio>` elements via `st.markdown` on every rerun, sending 5-8 MB per cycle. This was replaced with a JS-caching strategy:
|
| 354 |
+
|
| 355 |
+
1. **First load per track**: base64 data sent via `st.components.v1.html(height=0)`, cached as `window.parent._dd_audio` JS Audio objects using **parent window's Audio constructor** (`new p.Audio(...)`) so objects survive iframe replacement.
|
| 356 |
+
2. **Subsequent reruns**: Only tiny control commands (<1 KB) β play, pause, volume.
|
| 357 |
+
3. **SFX**: Lazy-loaded on first trigger, cached as data URI strings in `window.parent._dd_audio.sfx`.
|
| 358 |
+
4. **Preferences**: Stored in non-widget session state keys (`_sfx_pref`, `_music_pref`, `_sfx_volume`, `_music_volume`) that survive Streamlit's widget lifecycle cleanup during `st.rerun()`.
|
| 359 |
+
|
| 360 |
+
### Audio Asset Naming Convention
|
| 361 |
+
|
| 362 |
+
| Type | Key | Filename | Size |
|
| 363 |
+
|------|-----|----------|------|
|
| 364 |
+
| SFX | `dice_roll` | `dice_roll.mp3` | 45 KB |
|
| 365 |
+
| SFX | `bust` | `bust.mp3` | 64 KB |
|
| 366 |
+
| SFX | `bank` | `bank.mp3` | 46 KB |
|
| 367 |
+
| SFX | `hot_dice` | `hot_dice.mp3` | 58 KB |
|
| 368 |
+
| SFX | `victory` | `victory.mp3` | 327 KB |
|
| 369 |
+
| SFX | `tier_advance` | `tier_advance.mp3` | 59 KB |
|
| 370 |
+
| Music | `menu` | `menu_theme.mp3` | 4.3 MB |
|
| 371 |
+
| Music | `peasants_gamble` | `d6_theme.mp3` | 6.5 MB |
|
| 372 |
+
| Music | `alchemists_ascent` | `d20_theme.mp3` | 4.9 MB |
|
| 373 |
+
|
| 374 |
+
To add new audio: add the file to `assets/sounds/`, add to `_SFX_FILES` or `_MUSIC_FILES` dict in `sounds.py`, and update `.gitattributes` LFS tracking if needed.
|
| 375 |
+
|
| 376 |
+
### Auto-Hold Scoring Dice
|
| 377 |
+
|
| 378 |
+
After rolling (D6 and D20 Tier 1), all scoring dice default to "Held". Players uncheck to release. This inverts the original opt-in pattern to opt-out. D20 Tier 2 reroll and Tier 3 auto-apply are unchanged. Implementation is in `_handle_roll()` in `game.py`.
|
| 379 |
+
|
| 380 |
+
### Sidebar Game Rules
|
| 381 |
+
|
| 382 |
+
When `page == "game"`, rules for the active game mode are rendered below audio controls in the sidebar. Rules text is defined as module-level constants `_D6_RULES` and `_D20_RULES` in `app.py`.
|
| 383 |
+
|
| 384 |
+
### Run Command
|
| 385 |
+
|
| 386 |
+
```bash
|
| 387 |
+
python -m streamlit run src/ui/app.py
|
| 388 |
+
```
|
docs/NEW_GAME_MODE_TEMPLATE.md
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# New Game Mode Template
|
| 2 |
+
|
| 3 |
+
Use this template to define a new game mode for Devil's Dozen. Fill out each section, then open Claude Code and say:
|
| 4 |
+
|
| 5 |
+
> "I want to add a new game mode to Devil's Dozen. Here is the completed template: [paste or reference this file]."
|
| 6 |
+
|
| 7 |
+
Claude will use this template along with the existing `CONTEXT_*.md` docs to build the engine, wire up the UI, and add audio support.
|
| 8 |
+
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
## 1. Mode Identity
|
| 12 |
+
|
| 13 |
+
| Field | Value |
|
| 14 |
+
|-------|-------|
|
| 15 |
+
| **Display Name** | _(e.g., "Pirate's Plunder")_ |
|
| 16 |
+
| **Internal Key** | _(e.g., `pirates_plunder` β lowercase, underscores, used in code + DB)_ |
|
| 17 |
+
| **Dice Type** | _(e.g., D6 / D10 / D12 / D20 / mixed)_ |
|
| 18 |
+
| **Number of Dice** | _(e.g., 5)_ |
|
| 19 |
+
| **Min Players** | _(e.g., 2)_ |
|
| 20 |
+
| **Max Players** | _(e.g., 4)_ |
|
| 21 |
+
| **Target Score / Win Condition** | _(e.g., "First to 5,000 points" or "Survive 10 rounds")_ |
|
| 22 |
+
| **Configurable Win Conditions?** | _(e.g., "Yes β 3000 / 5000 / 10000" or "No β fixed at 250")_ |
|
| 23 |
+
|
| 24 |
+
---
|
| 25 |
+
|
| 26 |
+
## 2. Turn Structure
|
| 27 |
+
|
| 28 |
+
Describe what happens on a single player's turn from start to finish.
|
| 29 |
+
|
| 30 |
+
```
|
| 31 |
+
Example (Peasant's Gamble):
|
| 32 |
+
1. Player rolls all 6 D6 dice
|
| 33 |
+
2. Must hold at least one scoring die
|
| 34 |
+
3. Can choose to roll remaining dice or bank
|
| 35 |
+
4. If no scoring dice on a roll β BUST (lose all unbanked turn points)
|
| 36 |
+
5. If all dice score β HOT DICE (roll all 6 fresh, keep accumulated points)
|
| 37 |
+
6. Bank ends the turn and adds turn score to total
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
**Your turn structure:**
|
| 41 |
+
```
|
| 42 |
+
1. ...
|
| 43 |
+
2. ...
|
| 44 |
+
3. ...
|
| 45 |
+
```
|
| 46 |
+
|
| 47 |
+
---
|
| 48 |
+
|
| 49 |
+
## 3. Scoring Rules
|
| 50 |
+
|
| 51 |
+
### 3.1 Basic Scoring
|
| 52 |
+
|
| 53 |
+
List every scoring combination, its point value, and which dice participate.
|
| 54 |
+
|
| 55 |
+
| Combo | Points | Example |
|
| 56 |
+
|-------|--------|---------|
|
| 57 |
+
| _(e.g., Single 1)_ | _(e.g., 100)_ | _(e.g., rolling a 1 among other dice)_ |
|
| 58 |
+
| _(e.g., Three of a kind)_ | _(e.g., face value x 100)_ | _(e.g., three 4s = 400)_ |
|
| 59 |
+
|
| 60 |
+
### 3.2 Special Combos (if any)
|
| 61 |
+
|
| 62 |
+
| Combo | Points | Notes |
|
| 63 |
+
|-------|--------|-------|
|
| 64 |
+
| _(e.g., Straight 1-6)_ | _(e.g., 1500)_ | _(e.g., must be all 6 dice)_ |
|
| 65 |
+
|
| 66 |
+
### 3.3 Bust Condition
|
| 67 |
+
|
| 68 |
+
When does the player bust? _(e.g., "No scoring dice on a roll" / "Rolling a 1" / "Never busts")_
|
| 69 |
+
|
| 70 |
+
### 3.4 Hot Dice / Re-roll Condition (if any)
|
| 71 |
+
|
| 72 |
+
When does the player get to re-roll all dice fresh? _(e.g., "All dice are scoring" / "Not applicable")_
|
| 73 |
+
|
| 74 |
+
---
|
| 75 |
+
|
| 76 |
+
## 4. Tiers / Phases (if applicable)
|
| 77 |
+
|
| 78 |
+
Does the game have tiers, phases, or stages that change the rules as the player progresses?
|
| 79 |
+
|
| 80 |
+
If **no tiers**: Write "Single phase β rules are constant throughout."
|
| 81 |
+
|
| 82 |
+
If **yes**:
|
| 83 |
+
|
| 84 |
+
| Tier | Name | Score Range | Dice Count | Rule Changes |
|
| 85 |
+
|------|------|-------------|------------|-------------|
|
| 86 |
+
| 1 | _(e.g., Red)_ | _(e.g., 0-100)_ | _(e.g., 8)_ | _(e.g., Standard scoring)_ |
|
| 87 |
+
| 2 | _(e.g., Green)_ | _(e.g., 101-200)_ | _(e.g., 3)_ | _(e.g., Score x5, per-die reroll)_ |
|
| 88 |
+
|
| 89 |
+
---
|
| 90 |
+
|
| 91 |
+
## 5. Special Mechanics
|
| 92 |
+
|
| 93 |
+
Describe any unique mechanics not covered above:
|
| 94 |
+
|
| 95 |
+
- _(e.g., "Kingmaker: Rolling a 20 in Tier 3 gives 20 points to last-place player")_
|
| 96 |
+
- _(e.g., "Steal: Rolling triples lets you steal 50 points from another player")_
|
| 97 |
+
- _(e.g., "Curse: Rolling snake eyes resets your score to zero")_
|
| 98 |
+
|
| 99 |
+
If none: Write "No special mechanics."
|
| 100 |
+
|
| 101 |
+
---
|
| 102 |
+
|
| 103 |
+
## 6. Player-Facing Rules Summary
|
| 104 |
+
|
| 105 |
+
Write a concise version of the rules as you'd want players to see it in the sidebar during gameplay. Use markdown. Aim for <=20 lines. This will be displayed directly in the app.
|
| 106 |
+
|
| 107 |
+
```markdown
|
| 108 |
+
**Goal:** ...
|
| 109 |
+
|
| 110 |
+
**Rolling:**
|
| 111 |
+
- ...
|
| 112 |
+
- ...
|
| 113 |
+
|
| 114 |
+
**Scoring:**
|
| 115 |
+
| Combo | Points |
|
| 116 |
+
|---|---|
|
| 117 |
+
| ... | ... |
|
| 118 |
+
```
|
| 119 |
+
|
| 120 |
+
---
|
| 121 |
+
|
| 122 |
+
## 7. Audio
|
| 123 |
+
|
| 124 |
+
### 7.1 Background Music
|
| 125 |
+
|
| 126 |
+
Provide or describe the background music track for this mode.
|
| 127 |
+
|
| 128 |
+
| Field | Value |
|
| 129 |
+
|-------|-------|
|
| 130 |
+
| **Filename** | _(e.g., `pirates_theme.mp3` β place in `assets/sounds/`)_ |
|
| 131 |
+
| **Music dict key** | _(must match the internal key from Section 1, e.g., `pirates_plunder`)_ |
|
| 132 |
+
| **Vibe / Description** | _(e.g., "Upbeat tavern shanty with fiddle and accordion")_ |
|
| 133 |
+
| **Provided?** | _(Yes β file attached / No β generate or find one)_ |
|
| 134 |
+
|
| 135 |
+
### 7.2 New Sound Effects (if any)
|
| 136 |
+
|
| 137 |
+
List any NEW SFX this mode needs beyond the existing set. Existing SFX that can be reused:
|
| 138 |
+
|
| 139 |
+
| Existing SFX | Trigger |
|
| 140 |
+
|---|---|
|
| 141 |
+
| `dice_roll` | On any dice roll |
|
| 142 |
+
| `bust` | On bust |
|
| 143 |
+
| `bank` | On banking score |
|
| 144 |
+
| `hot_dice` | On hot dice / re-roll all |
|
| 145 |
+
| `victory` | On game win |
|
| 146 |
+
| `tier_advance` | On tier/phase change |
|
| 147 |
+
|
| 148 |
+
**New SFX needed:**
|
| 149 |
+
|
| 150 |
+
| SFX Name | Filename | Trigger | Description |
|
| 151 |
+
|----------|----------|---------|-------------|
|
| 152 |
+
| _(e.g., `steal`)_ | _(e.g., `steal.mp3`)_ | _(e.g., "When player steals points")_ | _(e.g., "Coin clinking sound")_ |
|
| 153 |
+
|
| 154 |
+
If none: Write "No new SFX β reusing existing set."
|
| 155 |
+
|
| 156 |
+
---
|
| 157 |
+
|
| 158 |
+
## 8. UI Considerations
|
| 159 |
+
|
| 160 |
+
### 8.1 Dice Display
|
| 161 |
+
|
| 162 |
+
How should the dice look? _(e.g., "Same as D6 but with pirate skull on 1" / "Standard D20 with tier colors" / "Custom D10 faces")_
|
| 163 |
+
|
| 164 |
+
### 8.2 Hold / Interaction Pattern
|
| 165 |
+
|
| 166 |
+
Which pattern should this mode use?
|
| 167 |
+
|
| 168 |
+
- [ ] **Auto-hold scoring** (like current D6/D20 Tier 1) β scoring dice default to held, player unchecks to release
|
| 169 |
+
- [ ] **Per-die reroll** (like D20 Tier 2) β each die has a Reroll button
|
| 170 |
+
- [ ] **Auto-apply** (like D20 Tier 3) β roll result is applied automatically, no player choice
|
| 171 |
+
- [ ] **Other** β describe: _____________
|
| 172 |
+
|
| 173 |
+
### 8.3 Special UI Elements
|
| 174 |
+
|
| 175 |
+
Any special animations, indicators, or displays needed?
|
| 176 |
+
|
| 177 |
+
- _(e.g., "Show a 'steal target' selector when triples are rolled")_
|
| 178 |
+
- _(e.g., "Tier indicator like Alchemist's Ascent")_
|
| 179 |
+
- _(e.g., "Round counter at the top")_
|
| 180 |
+
|
| 181 |
+
If none: Write "Standard UI β no special elements."
|
| 182 |
+
|
| 183 |
+
---
|
| 184 |
+
|
| 185 |
+
## 9. Integration Checklist
|
| 186 |
+
|
| 187 |
+
_Claude will handle these, but this is the work involved for reference:_
|
| 188 |
+
|
| 189 |
+
### Engine (`src/engine/`)
|
| 190 |
+
- [ ] New engine class (e.g., `pirates_plunder.py`) with `roll_dice()`, `calculate_score()`, bust/hot-dice logic
|
| 191 |
+
- [ ] Scoring result dataclass with `points`, `is_bust`, `scoring_dice_indices`, `breakdown`
|
| 192 |
+
- [ ] Unit tests covering all scoring combos, edge cases, bust, and hot dice
|
| 193 |
+
|
| 194 |
+
### Database
|
| 195 |
+
- [ ] Add mode key to `game_mode` column allowed values
|
| 196 |
+
- [ ] Any new `game_state` columns? _(e.g., "round_number" / "steal_target")_
|
| 197 |
+
|
| 198 |
+
### UI
|
| 199 |
+
- [ ] Add to home page mode selector
|
| 200 |
+
- [ ] Wire into `game.py` roll/hold/bank handlers
|
| 201 |
+
- [ ] Add scoring indices helper in `game.py`
|
| 202 |
+
- [ ] Add rules text to `app.py` (`_XX_RULES` constant + sidebar render)
|
| 203 |
+
- [ ] Add background music entry to `_MUSIC_FILES` in `sounds.py`
|
| 204 |
+
- [ ] Add any new SFX entries to `_SFX_FILES` in `sounds.py`
|
| 205 |
+
- [ ] Add win condition options if configurable
|
| 206 |
+
|
| 207 |
+
### Assets
|
| 208 |
+
- [ ] Background music file in `assets/sounds/`
|
| 209 |
+
- [ ] Any new SFX files in `assets/sounds/`
|
| 210 |
+
- [ ] Update `.gitattributes` for LFS tracking if new MP3s added
|
| 211 |
+
|
| 212 |
+
---
|
| 213 |
+
|
| 214 |
+
## 10. Example: Filling This Out for Peasant's Gamble
|
| 215 |
+
|
| 216 |
+
<details>
|
| 217 |
+
<summary>Click to expand worked example</summary>
|
| 218 |
+
|
| 219 |
+
### 1. Mode Identity
|
| 220 |
+
|
| 221 |
+
| Field | Value |
|
| 222 |
+
|-------|-------|
|
| 223 |
+
| **Display Name** | Peasant's Gamble |
|
| 224 |
+
| **Internal Key** | `peasants_gamble` |
|
| 225 |
+
| **Dice Type** | D6 |
|
| 226 |
+
| **Number of Dice** | 6 |
|
| 227 |
+
| **Min/Max Players** | 2β4 |
|
| 228 |
+
| **Target Score** | First to target score |
|
| 229 |
+
| **Configurable?** | Yes β 3,000 / 5,000 / 10,000 |
|
| 230 |
+
|
| 231 |
+
### 2. Turn Structure
|
| 232 |
+
|
| 233 |
+
```
|
| 234 |
+
1. Roll all 6 dice
|
| 235 |
+
2. Must hold at least one scoring die
|
| 236 |
+
3. Roll remaining dice or bank turn score
|
| 237 |
+
4. No scoring dice = BUST (lose turn score)
|
| 238 |
+
5. All dice score = HOT DICE (roll all 6 fresh)
|
| 239 |
+
6. Bank adds turn score to total, ends turn
|
| 240 |
+
```
|
| 241 |
+
|
| 242 |
+
### 3. Scoring Rules
|
| 243 |
+
|
| 244 |
+
| Combo | Points |
|
| 245 |
+
|---|---|
|
| 246 |
+
| Single 1 | 100 |
|
| 247 |
+
| Single 5 | 50 |
|
| 248 |
+
| Three 1s | 1,000 |
|
| 249 |
+
| Three 2sβ6s | Face x 100 |
|
| 250 |
+
| Four+ of a kind | Previous tier x 2 |
|
| 251 |
+
| 1-2-3-4-5 | 500 |
|
| 252 |
+
| 2-3-4-5-6 | 750 |
|
| 253 |
+
| 1-2-3-4-5-6 | 1,500 |
|
| 254 |
+
|
| 255 |
+
**Bust:** No scoring dice on a roll.
|
| 256 |
+
**Hot Dice:** All 6 dice are scoring.
|
| 257 |
+
|
| 258 |
+
### 4. Tiers
|
| 259 |
+
|
| 260 |
+
Single phase β rules are constant throughout.
|
| 261 |
+
|
| 262 |
+
### 7. Audio
|
| 263 |
+
|
| 264 |
+
| Field | Value |
|
| 265 |
+
|-------|-------|
|
| 266 |
+
| **Filename** | `d6_theme.mp3` |
|
| 267 |
+
| **Music key** | `peasants_gamble` |
|
| 268 |
+
| **Vibe** | Medieval tavern with lute and drums |
|
| 269 |
+
| **Provided?** | Yes |
|
| 270 |
+
|
| 271 |
+
No new SFX β reusing existing set.
|
| 272 |
+
|
| 273 |
+
### 8. UI
|
| 274 |
+
|
| 275 |
+
- Auto-hold scoring dice
|
| 276 |
+
- No special elements beyond standard dice tray + scoreboard
|
| 277 |
+
|
| 278 |
+
</details>
|