Files
settled-reach/docs/sprints/sprint-14/client.md
T
jpmschweitzerandClaude Opus 4.6 16bc87c590 docs(sprints): add Sprint 14 "Live" briefings — 22 tickets across 4 teams
NPC mood, trust, routine execution, NPC-to-NPC conversations with D-078
occlusion, monologue display, content line pools, and visual specs.
Teams: server (7), client (3), copy (6), visual (6).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 19:52:50 +01:00

71 lines
7.5 KiB
Markdown

# Sprint 14: Live — Client Tasks
**Goal:** Bring NPCs to life — mood, trust, routine execution, and NPC-to-NPC conversation drive the first emergent social observables; the simulation produces a world that breathes independently of the player.
**Branch:** `client`
**Agents:** Stig (UI/rendering dev), Tyre (architect), Hoshe (QA)
## Carry-over from Sprint 13
None. All Sprint 13 client tickets done.
## New Tickets
| # | Title | Blocked by |
|---|-------|------------|
| #122 | Monologue display — client | — |
| #535 | Passive dialogue panel — overheard NPC conversation display | #247 (server) |
| #511 | F3 debug overlay (deferred — WRONG button covers same data) | #495 done |
Use `db/connectors/ticket show <id>` for full details.
## Key Decisions
- `decisions/architecture.md` — D-020 (ObserverSnapshot — `current_monologue` field), D-042 (UI microcopy format — YAML autoload for HUD labels)
- `decisions/perception.md` — D-016 (internal monologue — text display, atmosphere function), D-018 (three-range sound model — NPC-to-NPC conversations are Voice events), D-055 (sprint suppresses monologue at 40% rate — client renders what server sends; no client-side suppression needed)
- `decisions/content.md` — D-032 (separate monologue pools per character — client only needs to render; no character branching in display layer), D-035 (tag taxonomy — monologue has `character`, `trigger`, `prerequisite` tags; client ignores, server filters)
- D-078 (overheard NPC conversation — passive dialogue panel, server-authoritative occlusion, pre-occluded text rendering, speaker attribution)
## Notes
- **#122 — Monologue display — client:** The server-side monologue trigger system is complete — `MonologueEvent` arrives in `ObserverSnapshot.current_monologue` (field added Sprint 5, `server/src/bridge/types.rs`). The visual spec for monologue display was authored in Sprint 13 (#315, `docs/design/monologue-display-spec.md`). Sprint 14 work: implement the client-side display using that spec. Key requirements from the spec:
- **Position:** Bottom-left of viewport, above the interaction verb list, below the minimap. Not in the dialogue box area (max 20% height, D-061).
- **Typography:** Italic, smaller than dialogue (spec has exact px/pt — read `docs/design/monologue-display-spec.md` §Typography).
- **Stacking:** Queue — if a new monologue arrives while one is displaying, queue it (max depth from spec). Do not overwrite mid-display. Sprint 13 note: "monologue not lost on overwrite" is a P0 test (#477, done).
- **Fade:** Auto-fade after display duration. Duration is embedded in `MonologueEvent.display_duration` (float, seconds). Standard Godot `Tween`.
- **Character differentiation:** Smuggler and detective lines use different text colours — hex values in spec. Client reads the active character from `game_state.gd` (autoload at `client/scripts/autoloads/game_state.gd`) or derives it from the snapshot. The server already partitions monologue pools per character (D-032) so the client receives only the correct character's lines — no client-side branching needed.
- Existing `world_renderer.gd` (`client/scripts/rendering/world_renderer.gd`) is the root scene; monologue display is a new `CanvasLayer` child node or a `Control` node in the HUD layer (z-layer 6 per D-049 rendering stack). Do not put it in the dialogue box scene.
- **Integration with audio:** Monologue display does NOT trigger audio (monologue chime fires at cognitive delay onset from the server's recognition pipeline, not from text display). No client-side audio calls needed here.
- Delivery: `client/scripts/rendering/monologue_display.gd` (or similar), integrated into the HUD scene, reading `ObserverSnapshot.current_monologue`. Tests via Hoshe's gdUnit4 harness: queue management, fade-out timing, character colour, no-overwrite on active display.
- **#535 — Passive dialogue panel — overheard NPC conversation display:** Consumes `ConversationEvent` from `ObserverSnapshot` (added by server #247). Render overheard NPC-to-NPC conversations in the existing dialogue box in passive (read-only) mode. Per D-078 amendment — occlusion is server-authoritative; this ticket is a pure renderer of pre-occluded text. Key requirements:
- **Speaker attribution:** Display header as "Speaker → Target" (e.g. "Kael → Mira") using `speaker_name` and `target_name` from the event. Use the same attribution label slot as player conversation NPC-name display — no new layout region needed.
- **Pre-occluded text renderer:** Render `occluded_line` as-is. The server has already performed per-word Bernoulli drops and replaced dropped words with `...`. The client performs no stochastic logic — no `clarity_score`, no `randf()`, no per-word processing. Display the received string directly in the passive panel.
- **Read-only mode:** The dialogue box must suppress response options and player input when displaying a passive conversation. No response list, no input capture. Player can still move freely.
- **Dismissal:** On `conversation_end` event (or if player moves far enough that no `ConversationEvent` arrives for the NPC pair), dismiss via the standard 300ms fade (same `Tween` as walk-away fade, #437 done).
- **Monologue isolation:** Monologue display (#122, z-layer 6) is unaffected. Do not route conversation text through the monologue display. The server triggers `witness_interaction` which may produce a monologue — that arrives separately via `current_monologue` and is rendered by #122 normally.
- **Blocked by #247** — `ConversationEvent` struct must exist on `ObserverSnapshot` before this can be wired. Start with a stub event type and placeholder renderer if #247 is not yet landed.
- Delivery: passive mode in `client/scripts/ui/dialogue_box.gd` (or a new `passive_dialogue.gd` sibling), verbatim `occluded_line` render, speaker attribution header, `conversation_end` dismissal. Tests via Hoshe's gdUnit4 harness: attribution renders correctly, `occluded_line` with `...` tokens renders verbatim, panel does not show response options in passive mode, dismisses on `conversation_end`.
- **#511 — F3 debug overlay (deferred):** This ticket is low priority. The WRONG button (F12, #507 done) already captures snapshot state, text render, and description on demand without per-frame cost. The F3 overlay would duplicate that information as a persistent overlay. Stig recommended deferral in Sprint 12. Only implement this sprint if server tickets finish early and QA explicitly needs real-time overlay data that WRONG button cannot provide. Default: skip.
## Dependency Chain
```
#122 (monologue display) — standalone, no server dependency this sprint
#535 (passive dialogue panel) — blocked by #247 (server, NPC-to-NPC conversation system)
#511 (F3 overlay) — standalone, low priority, implement only if capacity allows
```
#122 has no blockers — `current_monologue` in the snapshot has been live since Sprint 5. The spec (#315) is done. This is a pure client rendering task.
#535 is blocked on #247 landing the `ConversationEvent` struct with `occluded_line: String` on `ObserverSnapshot`. Stig can stub the event type locally and build the renderer against it in parallel; wire-up follows when #247 merges. No stochastic logic needed on the client — render `occluded_line` verbatim.
## PR Workflow
When ready to submit, create a PR with `tea` CLI. All flags are required to avoid TTY prompts (see CLAUDE.md "Gitea access" section):
```bash
tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(client): description" --description "body" --base main --head client
```