Files
code_of_conquest_dnd/client/docs/README.md
Phillip Tarrant 31759ef848 docs(roadmap): M4-b lands; the Title screen was already built
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.
2026-07-13 16:00:17 -05:00

4.9 KiB
Raw Blame History

/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, 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 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.