Files
code_of_conquest_dnd/client/docs/README.md
Phillip Tarrant c933d12504 docs: record editor-first UI-scene convention (ADR 0001)
Capture the direction change from M3-b: UI screens are authored editor-first
as .tscn node trees (previewable/arrangeable in the Godot editor), scripts do
on-load work only — never build the tree in _ready(). Add ADR 0001, a
"UI scene conventions" how-to in client/docs, a §16 mandate in the charter,
and mark M3-a/M3-b done in the roadmap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 10:04:57 -05:00

75 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# /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`.
- **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.