The creation screen is done — 302 client tests (up from the 250 baseline), content build green. Also flips the M3 Title screen from planned to done: it shipped in a77bf03/f071392 and the roadmap never caught up, which would have misled M4-c into thinking it must build one. Adds six new trap species to docs/traps.md from this milestone's review passes: substring-collision assertions, a BBCode wrapper masking an empty ContentDB, a test asserting the script's own loop bound, a trivially-true gating fixture, assertions already true before the action under test ran, an "iterates everything" guard that checked three hardcoded pairs, a node-type sweep that missed RichTextLabel, tests that called handlers instead of pressing nodes, GUT silently skipping an unparseable class_name test file at the old count, and a test that can hang instead of fail. Also documents the new client-docs convention: clickable cards are Buttons with mouse_filter = 2 on every child, and pressed on a toggle_mode Button is the chosen state. Human F6 confirmation of the rendered screen against the mock is still outstanding and is not claimed here.
83 lines
4.9 KiB
Markdown
83 lines
4.9 KiB
Markdown
# /client/docs
|
||
|
||
Client-specific documentation. Scoped to the Godot project.
|
||
|
||
Put here:
|
||
|
||
- Scene tree / autoload structure
|
||
- Input model — menu vs free-text boundary, which must be visible (§15)
|
||
- Combat wiring — deterministic damage, per-encounter seeding (§10)
|
||
- Canon log data structure and fact-harvesting (§11)
|
||
- HTTP client + fallback-degradation handling (§13)
|
||
|
||
Cross-cutting design (anything touching both client and api) goes in the root [`/docs`](../../docs), not here.
|
||
|
||
## UI scene conventions (shell + all screens)
|
||
|
||
Screens are **authored editor-first** — the layout lives in the `.tscn`, not in
|
||
code. See ADR [0001](../../docs/adr/0001-editor-first-ui-scenes.md) for the why;
|
||
this is the how. Reference: `scenes/shell/{MainWindowShell,SystemDock,NarrationBook}.tscn`
|
||
+ `scripts/ui/shell/*.gd`, and `scenes/creation/CharacterCreation.tscn` +
|
||
`scripts/ui/creation/{character_creation,creation_draft,creation_copy}.gd` (M4-b).
|
||
|
||
- **Clickable cards are Buttons with `mouse_filter = 2` on every child.** A card that
|
||
holds a name, a blurb and a trait line is a `Button` (Button-base variation, so
|
||
`normal`/`hover`/`pressed` actually skin it) with a `VBoxContainer` of Labels inside.
|
||
Every child needs `mouse_filter = 2` (IGNORE) or the Label swallows the click and the
|
||
card never toggles. `pressed` on a `toggle_mode` Button *is* the "chosen" state — no
|
||
script-side stylebox swapping.
|
||
|
||
- **The `.tscn` owns the tree.** Author every node in the editor: containers,
|
||
panels, labels, buttons, art-slot placeholders. Assign the shared theme on the
|
||
scene root (`theme = game_theme.tres`) and set each node's `theme_type_variation`
|
||
(from `ThemeKeys`) in the editor, so the scene previews themed. Instance
|
||
sub-screens (`PackedScene` ext_resource) rather than rebuilding them.
|
||
- **The script does on-load work only.** `@onready var x := $Path/To/Node` refs,
|
||
signal/service wiring, animations, and binding state into the authored nodes
|
||
(label text, colours from `Palette`). Do **not** create nodes in `_ready()`.
|
||
- **Data-driven repeats = fixed authored slots, bound at runtime.** Author enough
|
||
turn-order tokens / consumable slots / etc. in the editor; the script fills the
|
||
first N from state and hides the rest. Previewable now; systems write them later.
|
||
- **Scene-root sizing.** Give the root a fixed size via offsets (e.g. 1920×1080)
|
||
for editor preview, but **no full-rect anchors on the root** — a root Control run
|
||
via F6 collapses to (0,0) under full-rect anchors. Keep `size = get_viewport_rect().size`
|
||
on `_ready` + a `size_changed` connection (the M3-a collapse lesson).
|
||
- **Button styling → Button-base variations only.** Never put a PanelContainer
|
||
variation (`DarkPanel`, `ParchmentCard`) on a `Button`; it has no `normal/hover/
|
||
pressed` styleboxes so the button renders unskinned. Use the Button-base
|
||
variations (`PrimaryCTA`, `Tab`, `TabActive`, `Chip`, `DockButton`, `ParchmentButton`).
|
||
- **`RichTextLabel` prose** reads its dark serif ink from the theme's base
|
||
`RichTextLabel` style (it does *not* inherit `default_font`/`default_color`).
|
||
Just add the `RichTextLabel` — don't override its colour per-node.
|
||
- **Theme is generated.** All colours live in `palette.gd`; `game_theme.tres` is
|
||
built by `scripts/theme/build_game_theme.gd` (source of truth). To add/adjust a
|
||
variation, edit the builder + `theme_keys.gd`, then regenerate:
|
||
`godot --headless -s res://scripts/theme/build_game_theme.gd`. Never hand-edit
|
||
the `.tres` or put a hex literal in a script or `.tscn`.
|
||
- **Wiring the DM loop / injectable services.** Follow the shell: a `service`
|
||
var settable *between* `instantiate()` and `add_child()` lets tests inject a
|
||
`FakeTransport`-backed `DmService` so on-load calls stay hermetic; `_ready`
|
||
builds the real `HttpTransport`-backed one when none was injected.
|
||
- **Visual gate.** Headless GUT proves structure (nodes mount, sizes non-zero,
|
||
bindings run); it cannot prove rendering. Every screen needs a **human F6
|
||
eyeball** before it's done. Note shader surfaces (`DarkBay`, vignette) render
|
||
their texture only on an F6 run, not in the editor.
|
||
|
||
## Narrate live smoke (M2 client HTTP loop)
|
||
|
||
The `narrate_harness` scene is a throwaway proof of the client → `/dm/narrate`
|
||
loop. It is not the game UI.
|
||
|
||
**Prereqs:** the proxy running and Ollama reachable.
|
||
|
||
1. Start the proxy: from `api/`, `uvicorn app.main:app --port 8000` (with the
|
||
`.env` from `.env.example`; Ollama up at `OLLAMA_BASE_URL`).
|
||
2. In the Godot editor, open `res://scenes/narrate_harness.tscn` and run it (F6).
|
||
3. Click **Narrate this scene**. Expect grounded prose in the Narrator's voice
|
||
(referencing Greywater / Brannoc / the washed-out bridge), tags stripped, and
|
||
`facts harvested: N` with N ≥ 0.
|
||
4. **Degraded path:** stop the proxy and click again. Expect the authored
|
||
fallback line and `(degraded)` in the status — never an error.
|
||
|
||
Override the proxy URL with the `coc_rpg/proxy_base_url` project setting.
|