Files
settled-reach/docs/sprints/sprint-6/client.md
T
jpmschweitzerandClaude Opus 4.6 bccdcfcdcb docs(docs): add frontmatter to all sprint briefings
Standardized YAML frontmatter on all 115 sprint briefing files across
sprints 1-26 with title, description, type, status, sprint number, and
team fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 00:15:45 +01:00

9.1 KiB

title, description, type, status, sprint, team
title description type status sprint team
Sprint 6 — Client Briefing Cursor state machine, fog shader rebuild, entity interaction list, inventory UI sprint archived 6 client

Sprint 6: Touch — Client Tasks

Goal: Movement stances, fog rebuild, multi-verb interactions, and smuggler inventory

Branch: client Agents: Stig (UI/rendering), Tyre (architecture), Hoshe (QA)

New Tickets

# Title Blocked by
#429 Cursor state machine — 4 states, Araminta spec, 150ms transitions
#430 Fog shader rebuild — 5-layer, CanvasGroup Layer 5, animated noise
#432 Entity interaction vertical list — insert-styled, z-layer 6 #429
#433 World radial menu — 2 spokes v0.1 (Observe + Insert)
#438 Inventory UI — 3x3 grid, 1-9 hotkeys #449 (server)
#439 Stance toggle UI — keybind + HUD indicator #449 (server)

Use db/connectors/ticket show <id> for full details.

Key Decisions

  • decisions/perception.md — D-056 (Cursor states), D-057 (Entity interaction vertical list), D-058 (World radial menu), D-059 (Fog shader rebuild), D-061 (Dialogue box)
  • decisions/scope.md — D-053 (Movement stances), D-065 (Smuggler inventory)
  • decisions/architecture.md — D-049 (Z-level rendering stack)

Open Questions Resolved

  • OQ-24: Inventory capacity — Resolved to 3x3 grid = 9 slots (ticket #445, done)

Notes

#429: Cursor state machine — 4 states

  • What exists: Basic cursor rendering in Godot (default arrow)
  • Needs: Implement 4-state cursor using D-048 insert geometric aesthetic (thin ticks, bloom shader):
    • Default: Four thin inward-pointing ticks with bloom. White-blue #c8d0e0. Barely visible.
    • Entity hover: Ticks expand outward (150ms), corner brackets frame entity, color shifts to D-033 relationship color, verb tooltip in insert styling, bloom pulse ~10% brighter on entity outline
    • Object hover: Ticks rotate 45° to X-shape, muted grey #8b8ba0 (amber #e8c547 if flagged), simpler frame than entity
    • Weapon aim: Hard transition. Ticks extend, center gap widens, lines thicken 1→2px, warm white #f0e8d8, NO bloom. Entity in sights tints to D-033 color (aiming at friend = green tint should feel wrong).
  • D-056 spec: All transitions 150ms linear. z-layer 7. Never changes by zone/narrative state (D-045). Cursor changes on LOS, not just proximity. Click interaction range: ~2 tiles. Weapon-selected mode suppresses interaction prompts unless Shift held.
  • Diegetic test (Stig): Interaction labels render on z-layer 6 (insert overlay). If insert is off, labels disappear.
  • Integration: Blocks #432 (entity interaction list — cursor states trigger list display)

#430: Fog shader rebuild — 5-layer from scratch

  • What exists: client/scripts/rendering/fog_renderer.gd extends TileMapLayer with 2-state fog (opaque black, semi-transparent edge). Lines 1-50 show current implementation.
  • Needs: REBUILD from scratch. Replace TileMapLayer-based fog with CanvasGroup + fragment shader. Five distinct layers:
    1. Clear (vision cone): Soft gradient edge 3-4 tiles (Darkwood approach), no hard line
    2. Light fog (peripheral): Desaturated 40-50%, brightness -30%, animated Perlin noise overlay (8-10s cycle), entity D-033 colors visible but reduced
    3. Deep fog (previously explored): Near-monochrome with ~10% "zone temperature" tint (bar=warm dark, hub=cool dark, corridor=neutral dark), more pronounced noise (15-20s cycle), fog breathes
    4. Unexplored + maps app: Geometric wireframe outlines #333340 (insert data aesthetic)
    5. Unexplored, no maps: Solid near-black #12141a (information zero)
  • Fog entities (sprites on Layer 5):
    • Sound pings: 2-3 thin concentric expanding rings (sonar-style) from source direction, insert white-blue. Loud = 3 rings bright fast. Quiet = 1 ring faint slow. Fade over 1.5s.
    • Recognized entity: D-033 color glow + faint identifying silhouette feature (e.g., "Kael's vest") + 0.8s breathing pulse + ±0.5 tile position drift (approximate, not exact). Recognition transition governed by D-060 cognitive delay.
    • Unrecognized entity: Neutral grey #555566 blob. No silhouette, no identifying features.
  • D-059 spec: Knowledge-graph-driven — same fog shows different information per character based on their KG. Smuggler recognizes dock workers = green icons. Detective sees same entities = grey blobs. "Fog is not darkness — it's the absence of your attention."
  • Performance target: <1ms/frame total. Vision cone = PointLight2D. Fog = natural darkness + noise shader on CanvasGroup (Layer 5). Sound pings = 0-5 sprites. Entity ghosts = 0-10 sprites typical.
  • Gotcha: This is a complete rewrite, not an enhancement. Delete fog_renderer.gd and start fresh with shader-based approach. Araminta's spec in D-059 is the source of truth.
  • Integration: Blocks #431 (fog entity visualization, deferred to Sprint 7+)

#432: Entity interaction vertical list — insert-styled

  • What exists: Interaction prompt system (#405, done in Sprint 5) shows "E: " on nearest entity
  • Needs: Replace single-verb prompt with compact vertical list (2-4 options max), anchored to entity position, insert-styled with Araminta's geometric aesthetic (thin lines, bloom, z-layer 6). New options unlocked by KG changes highlighted with gradient glow background. Max 3 visible response options in dialogue context.
  • D-057 spec: Variable-length text options (confrontation lines in character voice) break radial spatial memory. List handles 1-4 options cleanly. Radial reserved for world menu only (#433).
  • Server integration: Reads nearby_interactions from ObserverSnapshot (Phase 2 filtered verbs per D-057). Server provides 2-4 verbs, client renders list. Clicking a verb sends PlayerAction::Interact with target + verb.
  • Diegetic test: Labels render on z-layer 6. If insert is off, labels disappear (passes "is this information from character's implant?" test).
  • Integration: Blocked by #429 (cursor states — entity hover triggers list display). Works with server #422 (two-phase verb computation).

#433: World radial menu — 2 spokes v0.1

  • Needs: Right-click opens radial world menu. v0.1: 2 spokes only (Observe + Insert). Insert-styled: geometric lines, thin spokes with icons (eye icon for Observe, phone icon for Insert), nearly transparent. Renders on z-layer 6. Drag-release for power users (high-speed drag-to-select), click-click for newcomers. Future: scale to 4 spokes (add Comms, Wait).
  • D-058 spec: Radial works for world menu because items are fixed categories that don't vary by knowledge state (unlike entity verbs which use vertical list #432). Spatial memory builds quickly (~10 minutes).
  • Integration: Standalone. Complements #432 (entity list vs world radial — different UX for different contexts).

#438: Inventory UI — 3x3 grid, 1-9 hotkeys

  • Needs: Bottom-right HUD area, 3x3 grid (40x40px icons), mapped to 1-9 keys. No empty slots displayed — icons appear only when items are carried. Reads player_inventory from ObserverSnapshot v6 (server #449).
  • D-065 spec: OQ-24 resolved to 9 slots universal (3x3 grid). Smuggler gets 3 items in v0.1 (manifest copy, access token, comm log). Detective gets 2 slots used. Items are world entities with CarriedBy component (server-side).
  • UI positioning: Bottom-right, does not overlap dialogue box (max 20% height per D-061). Icons render at z-layer 7 (HUD elements).
  • Integration: Blocked by server #449 (ObserverSnapshot v6 adds player_inventory field). Works with server #424 (CarriedBy component + Take/Place verbs).

#439: Stance toggle UI — keybind + HUD indicator

  • Needs: Keybind for stance toggle (suggest C key, or Ctrl as ladder climb), HUD indicator showing current stance (icon + text: "Sprint" / "Walk" / "Careful" / "Crouch"). Reads player_stance from ObserverSnapshot v6 (server #449). Visual feedback on stance change (brief highlight or fade).
  • D-053 spec: Toggle-based ladder: Sprint → Walk → Careful → Crouch → (Prone future). Each stance affects movement speed and monologue rate. v0.1: 4 stances (Sprint/Walk/Careful/Crouch).
  • UI positioning: Top-left or top-right HUD area (not overlapping dialogue box or inventory). z-layer 7.
  • Integration: Blocked by server #449 (ObserverSnapshot v6 adds player_stance field). Works with server #417 (stance system).

Dependency Chain

Critical path:
#429 (Cursor states) → #432 (Entity interaction list)

Parallel tracks:
#430 (Fog shader rebuild) → standalone, large rewrite
#433 (World radial menu) → standalone
#438 (Inventory UI) → blocked by server #449
#439 (Stance UI) → blocked by server #449

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):

tea pr create \
  --repo jpmschweitzer/settled-reach \
  --login schweitz \
  --title "feat(client): cursor states, fog shader rebuild, interaction list, inventory + stance UI" \
  --description "Sprint 6 client deliverables per D-056, D-057, D-058, D-059, D-061, D-065" \
  --base main \
  --head client