docs(sprints): Sprint 6 Touch briefings — server, client, copy, joint
18 tickets across 3 teams. Movement stances, fog shader rebuild, multi-verb interactions, smuggler inventory. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
# 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: <verb>" 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):
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
@@ -0,0 +1,81 @@
|
||||
# Sprint 6: Touch — Copy Tasks
|
||||
|
||||
**Goal:** Movement stances, fog rebuild, multi-verb interactions, and smuggler inventory
|
||||
|
||||
**Branch:** `copy`
|
||||
**Agents:** Mellanie (narrative), Paula (systems), Gestalt (content architecture)
|
||||
|
||||
## New Tickets
|
||||
|
||||
| # | Title | Blocked by |
|
||||
|---|-------|------------|
|
||||
| #441 | Define 3 smuggler item specs — manifest copy, access token, comm log | — |
|
||||
|
||||
Use `db/connectors/ticket show <id>` for full details.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- `decisions/scope.md` — D-065 (Smuggler inventory — knowledge-primary with physical evidence)
|
||||
- `decisions/content.md` — D-034 (THE FRIEND — production-level NPC pattern)
|
||||
|
||||
## Notes
|
||||
|
||||
### #441: Define 3 smuggler item specs
|
||||
- **What exists:** Knowledge graph tracks what player knows (KG infrastructure from Sprint 3-4). Physical inventory is new for Sprint 6.
|
||||
- **Needs:** Author YAML item specs for 3 smuggler inventory items (per D-065):
|
||||
1. **Manifest copy** — Proves cargo discrepancy. Leverage proof (smuggler's word doesn't carry institutional weight).
|
||||
2. **Corridor access token** — Proves ring membership. Physical proof of social network position.
|
||||
3. **Personal comm log** — Bridge between KG knowledge and provable leverage. Recorded conversations.
|
||||
- **D-065 context:** Knowledge is the primary "inventory" for all characters (you SAW the manifest, not you HAVE it). Smuggler additionally gets minimal physical inventory (3 items in v0.1) because the smuggler's word doesn't carry institutional weight — they need tangible proof for leverage. Detective's word IS evidence (institutional authority), so detective is mostly KG-only (2 slots reserved for future use).
|
||||
- **Content requirements per item:**
|
||||
- **Name:** Short display name (e.g., "Manifest Copy", "Access Token")
|
||||
- **Description:** 1-2 sentence item description in character voice (smuggler perspective)
|
||||
- **Flavor text:** Optional 1-line contextual note (e.g., "Kael's handwriting on the margins")
|
||||
- **Knowledge link:** Which FactId(s) this item proves or corroborates (e.g., manifest copy proves `CargoDiscrepancySova17`)
|
||||
- **Contraband flag:** Boolean — is this item detectable by security scans? (future #425)
|
||||
- **File location:** `content/campaigns/main/systems/krenn/sova/sova-transit/items/smuggler-inventory.yaml` or similar
|
||||
- **Cross-reference:** Sprint 5 deliverables (#297 Kael FRIEND pack, #298 Sera FRIEND pack) provide context for smuggler's social network and cargo operations. Items should reference established content.
|
||||
- **Integration:** Server #424 implements CarriedBy component + Take/Place verbs. Client #438 renders inventory UI. Copy team defines the content (what the items are, why they matter).
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
#441 (Smuggler item specs) → standalone
|
||||
|
||||
Server #424 (CarriedBy implementation) reads item specs
|
||||
Client #438 (Inventory UI) displays items
|
||||
```
|
||||
|
||||
## 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(content): smuggler inventory item specs" \
|
||||
--description "Sprint 6 copy deliverables per D-065 — manifest copy, access token, comm log" \
|
||||
--base main \
|
||||
--head copy
|
||||
```
|
||||
|
||||
## Notes for Copy Team
|
||||
|
||||
Sprint 6 is light for copy — only 1 ticket (#441). This is intentional: Sprint 5 was heavy content authoring (FRIEND packs ~150-200 lines), Sprint 6 focuses on systems and UI (server/client carry the load).
|
||||
|
||||
Item specs are small but thematically important. These items differentiate the smuggler's gameplay loop from the detective's. The smuggler needs physical proof because their word doesn't carry authority. Each item should feel like a risk to carry and a weapon to wield.
|
||||
|
||||
**Voice and perspective:**
|
||||
- Items are viewed through the smuggler's eyes. Descriptions should reflect the smuggler's relationship to the object (e.g., "Kael slipped me this token three weeks ago. Access to the maintenance corridors. Hope it still works.").
|
||||
- Item descriptions are diegetic — the character is looking at the item in their inventory. Not neutral game text.
|
||||
|
||||
**Knowledge integration:**
|
||||
- Each item should tie to at least one FactId from the knowledge graph. For example, the manifest copy might prove `CargoDiscrepancySova17` (a fact the smuggler knows) and unlock leverage in confrontation with Kael or Sera.
|
||||
- Paula and Gestalt: cross-check item specs against existing KG FactIds in `content/global/knowledge/` to ensure consistency.
|
||||
|
||||
**Contraband implications:**
|
||||
- All 3 items are contraband (security would flag them). This is thematically consistent with the smuggler archetype. Detective doesn't carry contraband by default (institutional authority protects them).
|
||||
- Contraband detection is deferred to future sprint (#425), but flag items now so the data is ready.
|
||||
|
||||
Sprint 6 copy work is small, high-quality, thematically load-bearing. Treat these 3 items as miniature character studies — what the smuggler carries defines who they are.
|
||||
@@ -0,0 +1,253 @@
|
||||
# Sprint 6: Touch — Joint Integration
|
||||
|
||||
**Goal:** Movement stances, fog rebuild, multi-verb interactions, and smuggler inventory
|
||||
|
||||
**Teams:** Server, Client, Copy
|
||||
**Agents:** All implementation agents (Dudley, Stig, Tyre, Hoshe, Mellanie, Paula, Gestalt)
|
||||
|
||||
## Sprint Overview
|
||||
|
||||
Sprint 6 is the control and interaction sprint. Sprint 1-5 built the simulation, the bridge, the rendering pipeline, the content loading, and the FRIEND NPCs. Sprint 6 delivers the player's direct interface to the world: how they move (stances), how they see (fog shader), how they interact (multi-verb system), and what they carry (inventory).
|
||||
|
||||
This sprint emerged from the **Control & Interaction Workshop** (2026-02-13), which produced 11 decisions (D-053 through D-065) and 33 tickets under epic #416. Sprint 6 implements the critical-path subset: 18 tickets across server, client, and copy teams.
|
||||
|
||||
## Team Distribution
|
||||
|
||||
| Team | Ticket Count | Load |
|
||||
|------|--------------|------|
|
||||
| Server | 9 tickets | Heavy (stance system, tile occupancy, two-phase verb computation, smuggler inventory, bridge v6) |
|
||||
| Client | 6 tickets | Heavy (cursor states, fog shader rebuild, interaction list, world radial menu, inventory UI, stance UI) |
|
||||
| Copy | 1 ticket | Light (3 smuggler item specs) |
|
||||
|
||||
## Pre-Sprint Requirements
|
||||
|
||||
Two open questions were resolved during the workshop and ticket creation:
|
||||
|
||||
- **OQ-01: Tile size** — Resolved to 0.5m x 0.5m (ticket #444, done)
|
||||
- **OQ-24: Inventory capacity** — Resolved to 3x3 grid = 9 slots universal (ticket #445, done)
|
||||
|
||||
All blocking decisions are confirmed. No pre-sprint work required.
|
||||
|
||||
## Critical Path
|
||||
|
||||
Sprint 6 has three parallel tracks with one critical integration point:
|
||||
|
||||
```
|
||||
Server track (stance + movement):
|
||||
#449 (ObserverSnapshot v6) → client #438 (inventory UI), client #439 (stance UI)
|
||||
#417 (Stance system)
|
||||
├─→ #418 (MovementProfile)
|
||||
├─→ #419 (Sprint suppression)
|
||||
└─→ #420 (TilePresence, parallel)
|
||||
|
||||
Server track (interaction verbs):
|
||||
#421 (ObjectType) → #422 (Two-phase verb computation) → client #432 (interaction list)
|
||||
|
||||
Server track (inventory):
|
||||
#424 (Smuggler inventory) → client #438 (inventory UI)
|
||||
Copy #441 (item specs) → informs server #424 content
|
||||
|
||||
Client track (cursor + fog):
|
||||
#429 (Cursor states) → #432 (interaction list)
|
||||
#430 (Fog shader rebuild) → standalone, large rewrite
|
||||
#433 (World radial menu) → standalone
|
||||
|
||||
Client track (UI):
|
||||
#438 (Inventory UI) → blocked by server #449
|
||||
#439 (Stance UI) → blocked by server #449
|
||||
```
|
||||
|
||||
**Critical integration point:** Server #449 (ObserverSnapshot v6) unblocks client #438 and #439. Server #417 (stance system) and #424 (inventory) must land before client UI can integrate.
|
||||
|
||||
## Cross-Team Integration Points
|
||||
|
||||
### Server → Client: ObserverSnapshot v6 (#449)
|
||||
|
||||
**Server deliverable:** Add two new fields to ObserverSnapshot (bridge wire protocol):
|
||||
- `player_stance: MovementStance` (enum: Sprint/Walk/Careful/Crouch)
|
||||
- `player_inventory: Vec<VisibleItem>` (items carried by player)
|
||||
|
||||
**Client consumers:**
|
||||
- #438 (Inventory UI) reads `player_inventory` to render 3x3 grid
|
||||
- #439 (Stance UI) reads `player_stance` to show HUD indicator
|
||||
|
||||
**Timeline:** Server #449 should land early in sprint (day 1-2) to unblock client UI work. Client can scaffold UI in parallel, but cannot test until #449 lands.
|
||||
|
||||
**Coordination:** Dudley (server) and Stig (client) coordinate on wire format. Use existing ObserverSnapshot pattern (see `server/src/bridge/types.rs` line 29-48 for current v5).
|
||||
|
||||
### Server → Client: Two-phase verb computation (#422 → #432)
|
||||
|
||||
**Server deliverable:** Refactor interaction verb computation into Phase 1 (ObjectType → max verb set) and Phase 2 (observer KG filter → final verbs). Populate `nearby_interactions` in ObserverSnapshot with 2-4 filtered verbs per entity.
|
||||
|
||||
**Client consumer:** #432 (entity interaction list) reads `nearby_interactions` and renders vertical list. Clicking a verb sends PlayerAction::Interact with target + verb.
|
||||
|
||||
**Timeline:** Server #421 (ObjectType) + #422 (two-phase) must land before client #432 can integrate. Client can build UI skeleton in parallel (test with mock data).
|
||||
|
||||
**Coordination:** Dudley (server) defines verb wire format (verb name, display text, tooltip). Stig (client) consumes format and renders insert-styled list per Araminta's D-056/D-057 spec.
|
||||
|
||||
### Copy → Server: Smuggler item specs (#441 → #424)
|
||||
|
||||
**Copy deliverable:** YAML item specs for 3 smuggler items (manifest copy, access token, comm log). Each item includes name, description, flavor text, knowledge link (FactId), contraband flag.
|
||||
|
||||
**Server consumer:** #424 (smuggler inventory) reads item specs, spawns items as world entities with CarriedBy component, implements Take/Place verbs.
|
||||
|
||||
**Timeline:** Copy #441 can land anytime during sprint (small authoring task, ~2-3 hours). Server #424 can proceed without item specs (use placeholder data), then swap in real content once copy delivers.
|
||||
|
||||
**Coordination:** Paula (copy) and Dudley (server) agree on YAML schema format early in sprint. Server defines schema, copy authors content.
|
||||
|
||||
## Sprint Completion Proof
|
||||
|
||||
At the end of Sprint 6, the following must be observable in-game:
|
||||
|
||||
### Movement and Stances
|
||||
1. **Stance toggle works:** Press C (or Ctrl) to cycle through Sprint → Walk → Careful → Crouch. HUD indicator updates (#439).
|
||||
2. **Movement speed changes:** Sprint = 1 tile/1 tick (fast). Walk = 1 tile/2 ticks (default). Careful = 1 tile/3 ticks (slow). Observable by walking across 10 tiles and counting ticks.
|
||||
3. **Monologue rate changes:** Sprint suppresses monologue (fewer lines). Careful enhances monologue (more lines, enhanced observation). Observable by changing stances in monologue-rich area (bar, hub).
|
||||
4. **Sprint suppresses interactions:** While sprinting, interaction prompts disappear (no verb list shown, even when hovering over NPC). Walk/Careful/Crouch restore interactions.
|
||||
5. **Same-tile occupancy works:** Two NPCs can occupy the same tile if one is Standing and one is Seated/Prone. Collision detection prevents two Standing entities on same tile.
|
||||
|
||||
### Fog and Visibility
|
||||
6. **Fog shader renders:** Launch game, observe 5-layer fog system:
|
||||
- Clear cone with soft gradient edge (no hard line)
|
||||
- Light fog (peripheral) with animated Perlin noise, desaturated colors
|
||||
- Deep fog (previously explored) with zone temperature tint (bar=warm, corridor=neutral)
|
||||
- Unexplored (with maps app) shows wireframe outlines
|
||||
- Unexplored (no maps) shows solid near-black
|
||||
7. **Fog breathes:** Noise animation cycles over 8-10s (light fog) and 15-20s (deep fog). Fog feels alive, not static.
|
||||
|
||||
### Interaction and Verbs
|
||||
8. **Cursor states work:** Hover over empty tile = default ticks. Hover over NPC = entity hover (ticks expand, D-033 color). Hover over object = X-shape grey cursor. All transitions 150ms.
|
||||
9. **Entity interaction list renders:** Hover over NPC with multiple verbs → vertical list appears (2-4 options max), anchored to entity, insert-styled. Click verb → PlayerAction::Interact sent to server.
|
||||
10. **World radial menu works:** Right-click anywhere → radial menu opens with 2 spokes (Observe + Insert). Drag-release or click-click to select. Renders on z-layer 6.
|
||||
11. **Two-phase verb computation:** Same object shows different verbs per character. Smuggler hovers over crate → sees "Move/Stash". Detective hovers → sees "Scan/Flag". Character-archetype differentiation via KG filter.
|
||||
|
||||
### Inventory
|
||||
12. **Inventory UI renders:** Smuggler character → bottom-right 3x3 grid appears. Icons for 3 items (manifest copy, access token, comm log). Detective character → 2 items (or empty if no items carried). Press 1-9 keys → item selection feedback.
|
||||
13. **Take/Place verbs work:** Approach item on ground → interaction list shows "Take". Click Take → item disappears from world, appears in inventory UI. Inventory icon click + right-click world → "Place" verb appears. Click Place → item returns to world.
|
||||
14. **Info boundary respected:** Items in smuggler's inventory are NOT visible to NPCs (no "What are you carrying?" monologue unless confrontation/scan mechanic triggered, deferred to future sprint #425).
|
||||
|
||||
### Integration
|
||||
15. **ObserverSnapshot v6 wire works:** Client receives `player_stance` and `player_inventory` fields from server. HUD updates reflect server state (no desyncs).
|
||||
16. **All systems compose:** Stance + fog + verbs + inventory all work simultaneously. No system breaks another.
|
||||
|
||||
### Validation Tests
|
||||
|
||||
**Simulation:**
|
||||
```bash
|
||||
# Stance system tests
|
||||
cargo test simulation::movement::stance
|
||||
|
||||
# Tile occupancy tests
|
||||
cargo test simulation::movement::tile_presence
|
||||
|
||||
# Two-phase verb computation tests
|
||||
cargo test simulation::interaction::two_phase
|
||||
|
||||
# Inventory tests
|
||||
cargo test simulation::interaction::carried_by
|
||||
```
|
||||
|
||||
**Client rendering:**
|
||||
```bash
|
||||
# Godot client launches without errors
|
||||
cd client && godot --headless --quit
|
||||
|
||||
# Shader compilation (fog shader)
|
||||
# Manual test: launch game, observe fog rendering with no errors in console
|
||||
```
|
||||
|
||||
**Content validation:**
|
||||
```bash
|
||||
# Smuggler item specs validate
|
||||
make validate-content
|
||||
|
||||
# Item YAML loads in server
|
||||
cargo run --bin line-previewer -- content/campaigns/main/systems/krenn/sova/sova-transit/items/smuggler-inventory.yaml
|
||||
```
|
||||
|
||||
## Test Plan Alignment (D-030)
|
||||
|
||||
Sprint 6 is in **Phase 2** (integration tests) transitioning to **Phase 3** (simulation depth).
|
||||
|
||||
Key test requirements:
|
||||
|
||||
**Phase 2 (integration):**
|
||||
- Bridge protocol test: ObserverSnapshot v6 serializes/deserializes correctly with new fields
|
||||
- Interaction pipeline test: PlayerAction::Interact → verb computation → ObserverSnapshot update → client rendering
|
||||
- Movement integration: stance toggle → movement speed change → monologue rate change (full pipeline)
|
||||
|
||||
**Phase 3 (simulation depth):**
|
||||
- Stance system: all 4 stances (Sprint/Walk/Careful/Crouch) produce correct tick multipliers
|
||||
- Tile occupancy: collision detection respects posture layers
|
||||
- Two-phase verbs: Phase 1 (ObjectType) + Phase 2 (KG filter) produce correct verb sets
|
||||
- Inventory: Take/Place verbs respect info boundary (carried items private)
|
||||
|
||||
Hoshe's involvement: QA review on #449 (ObserverSnapshot v6 — critical bridge change), #422 (two-phase verbs — complex KG integration), #430 (fog shader — large rewrite, performance regression risk).
|
||||
|
||||
## Integration Risks
|
||||
|
||||
**Risk:** ObserverSnapshot v6 wire format changes break existing client rendering.
|
||||
|
||||
**Mitigation:** Server #449 lands early (day 1-2). Stig tests client with new wire format before implementing #438 and #439. If deserialization breaks, revert #449 and coordinate with Dudley on schema fix.
|
||||
|
||||
**Risk:** Fog shader rebuild (#430) is a complete rewrite. High risk of regressions (performance, visual artifacts, z-layer conflicts).
|
||||
|
||||
**Mitigation:** Stig implements #430 on feature branch, tests in isolation before merging. Performance target: <1ms/frame (monitor with Godot profiler). If performance regresses, scale back noise animation complexity (reduce cycle count or simplify Perlin shader).
|
||||
|
||||
**Risk:** Two-phase verb computation (#422) is architecturally complex. Risk of Phase 1/Phase 2 boundary mismatches or KG query bugs.
|
||||
|
||||
**Mitigation:** Dudley implements #421 (ObjectType) first to validate Phase 1 logic. Add integration tests for Phase 2 KG filter (verify correct verbs per character archetype). Tyre reviews architecture before merge.
|
||||
|
||||
**Risk:** Copy #441 (item specs) might not align with server #424 YAML schema expectations.
|
||||
|
||||
**Mitigation:** Dudley defines YAML schema early in sprint (day 1), shares with Paula. Paula authors item specs against known schema. Server #424 uses placeholder data until copy delivers, so no blocking dependency.
|
||||
|
||||
**Risk:** Sprint has 18 tickets across 3 teams. High ticket count = coordination overhead.
|
||||
|
||||
**Mitigation:** Parallel tracks reduce blocking. Server #449 unblocks client early. Fog shader (#430) and world radial menu (#433) are standalone (no cross-team dependencies). Copy #441 is small (2-3 hours). Most complexity is server-side (#417, #422, #424) where Dudley has focused scope.
|
||||
|
||||
## Definition of Done
|
||||
|
||||
Sprint 6 is complete when:
|
||||
|
||||
1. All 18 tickets marked `done` in database
|
||||
2. All server code committed to `server` branch and tested
|
||||
3. All client code committed to `client` branch and tested
|
||||
4. All copy content committed to `copy` branch and validated
|
||||
5. PRs created for all three teams
|
||||
6. Sprint completion proof checklist verified (all 16 observable criteria met)
|
||||
7. Team Leader reviews in-game playtest: stance toggle, fog shader, interaction verbs, inventory UI all working together without desyncs or visual regressions
|
||||
|
||||
## PR Coordination
|
||||
|
||||
Three team PRs will be created:
|
||||
|
||||
1. **Server team PR**:
|
||||
- Branch: `server`
|
||||
- Scope: ObserverSnapshot v6, stance system, tile occupancy, two-phase verb computation, smuggler inventory
|
||||
- Review focus: Bridge protocol compatibility, simulation correctness, KG integration
|
||||
|
||||
2. **Client team PR**:
|
||||
- Branch: `client`
|
||||
- Scope: Cursor states, fog shader rebuild, interaction list, world radial menu, inventory UI, stance UI
|
||||
- Review focus: Rendering performance, visual consistency with Araminta spec, z-layer correctness
|
||||
|
||||
3. **Copy team PR**:
|
||||
- Branch: `copy`
|
||||
- Scope: Smuggler item specs (3 items)
|
||||
- Review focus: Content quality, voice consistency, knowledge graph integration
|
||||
|
||||
All PRs target `main` branch. Server PR should merge first (provides wire format for client). Client and copy can merge in parallel after server lands.
|
||||
|
||||
## Notes for Team Leader
|
||||
|
||||
Sprint 6 is the tactile sprint. After 5 sprints of infrastructure, this is the first sprint where the player's hands touch the world:
|
||||
|
||||
- **Movement feels deliberate:** Stance toggle creates tactical choices (sprint ahead to position, careful to observe, walk when safe). Speed is not just convenience — it's intention.
|
||||
- **Fog feels alive:** The shader rebuild (D-059) replaces the current flat fog with breathing, animated, knowledge-graph-driven fog. This is the visual signature of asymmetric information.
|
||||
- **Interaction feels responsive:** Cursor states (D-056) and vertical lists (D-057) replace generic "E to interact" with character-aware, knowledge-gated verb menus. The world responds to who you are, not just where you are.
|
||||
- **Inventory feels risky:** Smuggler carries contraband (manifest, token, log). These items are leverage and liability. Detective carries authority, not objects. Character differentiation through what you hold.
|
||||
|
||||
Sprint 6 delivers D-027 criterion #4: "observe → notice → follow → discover sequence emerges from systems not scripts." The stance system (observe in Careful), the verb system (notice contradictions), the fog system (follow entities in fog), and the inventory system (discover evidence) compose into emergent detective gameplay.
|
||||
|
||||
Quality bar: All systems must compose without breaking each other. Stance + fog + verbs + inventory running simultaneously with no desyncs, no performance regressions, no visual artifacts. Integration is the success metric.
|
||||
@@ -0,0 +1,124 @@
|
||||
# Sprint 6: Touch — Server Tasks
|
||||
|
||||
**Goal:** Movement stances, fog rebuild, multi-verb interactions, and smuggler inventory
|
||||
|
||||
**Branch:** `server`
|
||||
**Agents:** Dudley (simulation), Tyre (architecture), Hoshe (QA)
|
||||
|
||||
## New Tickets
|
||||
|
||||
| # | Title | Blocked by |
|
||||
|---|-------|------------|
|
||||
| #449 | ObserverSnapshot v6 — add player_stance, player_inventory wire fields | — |
|
||||
| #417 | Stance system — Sprint/Walk/Careful/Crouch with tick-based movement | #444 (done) |
|
||||
| #418 | MovementProfile component per archetype | #417 |
|
||||
| #419 | Sprint interaction buffer suppression | #417 |
|
||||
| #420 | Same-tile occupancy — TilePresence with posture layers | #444 (done) |
|
||||
| #421 | ObjectType component + verb sets per type | — |
|
||||
| #422 | Two-phase verb computation — KG-gated Phase 2 observer filter | #421 |
|
||||
| #424 | Smuggler inventory — CarriedBy component, Take/Place verbs, info boundary | #445 (done) |
|
||||
| #428 | Sprint anomaly monologue — double-take survival | — |
|
||||
|
||||
Use `db/connectors/ticket show <id>` for full details.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- `decisions/scope.md` — D-053 (Movement as stance toggle system), D-065 (Smuggler inventory)
|
||||
- `decisions/architecture.md` — D-054 (Tile-based movement with same-tile occupancy), D-055 (Sprint explicitly suppresses interaction buffer)
|
||||
- `decisions/perception.md` — D-057 (Entity interaction — vertical list, two-phase verb computation)
|
||||
|
||||
## Open Questions Resolved
|
||||
|
||||
- **OQ-01: Tile size** — Resolved to 0.5m x 0.5m (ticket #444, done)
|
||||
- **OQ-24: Inventory capacity** — Resolved to 3x3 grid = 9 slots universal (ticket #445, done)
|
||||
|
||||
## Notes
|
||||
|
||||
### #449: ObserverSnapshot v6 — player_stance, player_inventory
|
||||
- **What exists:** `server/src/bridge/types.rs` defines ObserverSnapshot v5 (current version: 4, see line 30-48)
|
||||
- **Needs:** Add two new fields to ObserverSnapshot struct:
|
||||
- `player_stance: MovementStance` (enum: Sprint/Walk/Careful/Crouch)
|
||||
- `player_inventory: Vec<VisibleItem>` (items carried by player, visible to player only per D-010 info boundary)
|
||||
- **Integration:** #417 provides MovementStance enum, #424 provides CarriedBy component query
|
||||
- **Critical path:** This ticket unblocks client #439 (stance UI) and #438 (inventory UI)
|
||||
|
||||
### #417: Stance system — tick-based movement
|
||||
- **What exists:** `server/src/simulation/movement.rs` has basic movement at 1 tile/2 ticks (Walk default)
|
||||
- **Needs:** Add MovementStance component (enum: Sprint/Walk/Careful/Crouch/Prone), implement stance ladder toggling via PlayerAction::ToggleStance, apply tick multipliers per stance (Sprint=1/1, Walk=1/2, Careful=1/3, Crouch=TBD), wire monologue rate modifiers (Sprint=40%, Walk=100%, Careful=150%)
|
||||
- **D-053 spec:** Sprint suppresses monologue to 40%, Careful enhances it to 150%. Perception coupling is multiplicative. No vision cone changes (cognitive, not sensory).
|
||||
- **Gotcha:** Prone is toggle-out only in normal play (must stand up explicitly). Future combat allows "hit the deck" quick-entry. v0.1 scope: Sprint/Walk/Careful/Crouch only.
|
||||
- **Integration:** Blocks #418 (MovementProfile), #419 (sprint suppression), #426 (ListeningFocus deferred), #439 (client stance UI)
|
||||
|
||||
### #418: MovementProfile component per archetype
|
||||
- **Needs:** Add MovementProfile component storing default stance per archetype (smuggler=Walk, detective=Walk). Apply on spawn.
|
||||
- **Rationale:** Future archetypes may have different defaults (e.g., maintenance worker defaults to Careful). Smuggler and detective both start Walk for v0.1.
|
||||
- **Integration:** Blocked by #417 (stance system must exist first)
|
||||
|
||||
### #419: Sprint interaction buffer suppression
|
||||
- **What exists:** `server/src/simulation/interaction.rs` computes nearby_interactions for ObserverSnapshot
|
||||
- **Needs:** When player stance == Sprint, explicitly clear interaction buffer (nearby_interactions = empty vec). Anomaly monologue survives sprint (D-055: sprint suppresses interpretation, not sensory data).
|
||||
- **D-055 spec:** Interaction verbs not computed during sprint. Sprint double-take: if character passes anomaly while sprinting, delayed monologue fires retroactively ("Wait — was that Kael? At this hour?").
|
||||
- **Integration:** Blocked by #417 (stance system), works with #428 (anomaly monologue)
|
||||
|
||||
### #420: Same-tile occupancy — TilePresence layers
|
||||
- **What exists:** Movement system uses discrete tile positions (Position component)
|
||||
- **Needs:** Add TilePresence component (enum: Standing/Prone/Seated/Fixture), allow multiple entities per tile if different posture layers, update collision detection to check layer conflicts
|
||||
- **D-054 spec:** Tile-based movement enables determinism (D-010 principle 4). Occupancy adds positioning depth (doorway blocking, eavesdrop positioning, sitting at furniture) within tile constraints. ~150 lines.
|
||||
- **Integration:** Crouch stance (#417) uses Prone/Seated layer. Enables future eavesdrop mechanics (#426, deferred).
|
||||
|
||||
### #421: ObjectType component + verb sets per type
|
||||
- **Needs:** Add ObjectType component (enum: Readable, Container, Terminal, Door, Pickup, Furniture), define verb sets per type (e.g., Readable → {Read, Observe}, Container → {Open, Search, Observe}), spawn objects with ObjectType in map loader
|
||||
- **D-057 context:** ObjectType drives Phase 1 verb computation (max possible verb set, no KG). Phase 2 filters by observer's KG.
|
||||
- **Integration:** Blocks #422 (two-phase verb computation)
|
||||
|
||||
### #422: Two-phase verb computation — KG observer filter
|
||||
- **What exists:** `server/src/simulation/interaction.rs` computes verbs, `server/src/knowledge/` has KG query infrastructure
|
||||
- **Needs:** Refactor verb computation into two phases:
|
||||
- **Phase 1 (simulation, no KG):** Query ObjectType component → return max verb set for that type
|
||||
- **Phase 2 (observer, reads KG):** Filter Phase 1 verbs by player's knowledge (e.g., Confront requires KnowsDetails+ per D-041), apply POI priority flips, add contradiction markers, character-archetype verb variation (smuggler sees "Move/Stash", detective sees "Scan/Flag" for same crate)
|
||||
- **D-057 spec:** Vertical list handles 2-4 options max. New verbs unlocked by KG changes highlighted with glow (client-side). Character differentiation via Phase 2 observer filter, not separate verb systems.
|
||||
- **Integration:** Blocked by #421 (ObjectType). Enables rich interactions without hardcoding character logic into simulation.
|
||||
|
||||
### #424: Smuggler inventory — CarriedBy, Take/Place verbs
|
||||
- **What exists:** Entities are world entities in ECS, KG tracks knowledge (not items)
|
||||
- **Needs:** Add CarriedBy(StableId) component referencing carrier entity, implement Take/Place verbs (add/remove CarriedBy component), respect info boundary (carried items private, not visible to other entities unless revealed via search/scan/confrontation), query system: all items WHERE CarriedBy == player
|
||||
- **D-065 spec:** Knowledge is primary inventory (you SAW the manifest). Physical inventory is secondary (3 specific items for smuggler in v0.1: manifest copy, access token, comm log). Smuggler 9 slots, detective 2 slots (D-065 updated after OQ-24 resolution: 3x3 grid = 9 slots universal).
|
||||
- **Gotcha:** Contraband detection (#425, deferred) will scan carried items via KG + CarriedBy query. Items behind info boundary until revealed.
|
||||
- **Integration:** Blocks #425 (contraband, deferred), #438 (client inventory UI)
|
||||
|
||||
### #428: Sprint anomaly monologue — double-take
|
||||
- **Needs:** When player in Sprint stance passes an anomaly (e.g., THE FRIEND in wrong location/wrong time), suppress immediate monologue but fire delayed retroactive monologue after ~1-2s: "Wait — was that Kael? At this hour?"
|
||||
- **D-055 context:** Sprint suppresses interpretation (monologue at 40%), not sensory data. Anomaly survival creates the "sprint double-take" feel — character's brain catches up after the fact.
|
||||
- **Integration:** Works with #419 (sprint suppression), uses existing monologue pipeline (#414, done in Sprint 5)
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
Critical path:
|
||||
#449 (ObserverSnapshot v6) → standalone, unblocks client #438, #439
|
||||
|
||||
#417 (Stance system)
|
||||
├─→ #418 (MovementProfile)
|
||||
├─→ #419 (Sprint suppression)
|
||||
└─→ #420 (TilePresence, parallel but both use tick system)
|
||||
|
||||
#421 (ObjectType) → #422 (Two-phase verb computation)
|
||||
|
||||
#424 (Smuggler inventory) → standalone, unblocks client #438
|
||||
|
||||
#428 (Sprint anomaly monologue) → standalone, parallel work
|
||||
```
|
||||
|
||||
## 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(simulation): movement stances, tile occupancy, two-phase verbs, smuggler inventory" \
|
||||
--description "Sprint 6 server deliverables per D-053, D-054, D-055, D-057, D-065" \
|
||||
--base main \
|
||||
--head server
|
||||
```
|
||||
Reference in New Issue
Block a user