Files
settled-reach/decisions/perception.md
T
jpmschweitzerandClaude Opus 4.6 3f799ad8ba docs(decisions): update D-076 dialogue max-width from 640px to 1200px
Reflects the intentional override — 1200px chosen for readability
after playtest feedback. Updates decision text, derivation, and
amendment history.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 14:46:02 +01:00

56 KiB

Perception Decisions

How the player observes and interacts with the world: camera, fog, line-of-sight, sound, monologue, perception modes, audio dip profiles, cognitive delays.


D-011: Fog of perception is non-negotiable (Pillar 1 infrastructure)

  • Date: 2026-02-09
  • Decision: Fog of perception is not a feature - it's the minimum requirement for information asymmetry to work with a top-down camera. Without it, the player is omniscient within their viewport and the entire information pillar collapses at the local map level. First-person camera gets this for free; top-down must enforce it.
  • Implementation: Line-of-sight based (shadowcasting), not simple radius. Walls block vision, buildings are opaque, corners create blind spots, z-levels interact with sightlines.
  • Sound as secondary information channel: Events outside LOS can be heard - footsteps, conversations, gunfire, alarms. Sound gives partial/directional information, prompting decisions based on incomplete data.
  • Applies to ALL entities: NPCs use the same LOS/perception system as the player. An NPC who can't see you doesn't know you're there. NPCs have memory and inference (saw you enter a building → knows you're inside). Ties to D-010 principle 2: information boundaries are universal, the player's isn't special.
  • Fog returns when you leave: Previously explored areas revert to fog over time. Information about locations decays. What you saw at the docks yesterday may not be true today.
  • v0.1 scope: 2D shadowcast per z-level + sound propagation. Vertical LOS (looking between floors) deferred.
  • Rationale: Team Leader identified overnight that top-down without fog is a fundamental gap in the information asymmetry design.
  • Raised by: Team Leader (Jeroen), with technical framing by Tyre and Gestalt.

D-015: Camera locked to character, rotation as future option

  • Date: 2026-02-09
  • Decision: Camera is locked to the character at all times. No panning. Optionally rotates to character facing direction (player option, later version).
  • Rationale: Pannable camera breaks the information model - you become a surveillance drone, not a character. Locked camera reinforces "you ARE this person." Rotation with facing direction restores directional audio mapping (binaural becomes viable again) and creates a natural vision cone (front = detailed, peripheral = reduced, behind = blind).
  • Vision cone model:
    • Forward: full LOS, full detail
    • Peripheral: reduced range, dimmer
    • Behind: fog / blind spot. You can be snuck up on.
  • Reference: Hotline Miami's camera made that game terrifying with the same principle.
  • v0.1: Locked camera, no rotation. Vision cone still works on fixed-north map. Rotation deferred as player option.
  • Raised by: Team Leader (Jeroen).

D-016: Internal monologue as core perception/atmosphere system

  • Date: 2026-02-09
  • Decision: The player character has an internal monologue that narrates sensory information the camera can't show, creates atmosphere, provides diegetic hints, and can be an unreliable narrator.
  • Functions:
    • Perception bridge: Translates non-visual senses into character voice. "Footsteps behind me. Two people, unhurried."
    • Atmosphere: Character's running commentary on environment, mood, situation.
    • Diegetic tutorial: Character thinks about what they might do. "That terminal might have access logs." No "press X" popups.
    • Unreliable narrator: Monologue is character's INTERPRETATION, not ground truth. Can be wrong. "Seems quiet. Safe to move." (It wasn't safe.)
    • Character voice: Varies by character background, mood, knowledge. Paranoid Guardian vs confident Senator walking the same street = different monologue = different experience.
  • Production note (Nigel): Cheapest feature on the list - it's text. Thousands of contextual lines, AI-assistable generation, character-specific variants.
  • Raised by: Emerged from team discussion. Tyre proposed text/log as sound option, team recognized broader potential.

D-017: Perception modes as character-build system

  • Date: 2026-02-09
  • Decision: The fog/vision system supports multiple perception modes that vary by character build, equipment, and ascension level. Each mode reveals different information with different trust/quality tradeoffs.
  • Confirmed modes:
    • Natural vision - detail, color, identity. Blocked by walls. Everyone has it.
    • Thermal - heat signatures through walls. Body count but no identity. Higher biononic / military gear.
    • Camera feeds - remote visual from fixed positions. Only where cameras exist. Feed can be spoofed/looped. Hacker, institutional access, insert exploit.
    • Unisphere tracking - location pings of known individuals. Only active inserts, can be masked. Law enforcement / intelligence access.
    • Audio analysis - sound signatures, direction, classification. No visual. Insert processing, trainable skill.
  • Ascension scaling:
    • Baseline: natural vision + carried gear
    • Enhanced: insert-based modes, camera access, audio processing
    • Higher: biononic thermal, enhanced spectrum, passive scanning
    • ANA-touched: pattern recognition across all feeds, predictive awareness
  • Playstyle implications (Nigel): Low-tech Guardian playthrough = survival horror (blind, relying on contacts and paranoia). Senator playthrough = information overload (cameras and tracking but drowning in data). Perception modes are playstyle selectors.
  • v0.1: Natural vision cone + basic audio indicators + insert minimap only. Additional modes are milestone features, each self-contained and modular.
  • Engine implication: Each perception mode is an observer query against the information boundary system (D-010 principle 2). Engine doesn't distinguish between eyes/thermal/camera - all are "given this sensor, what state is visible?"
  • Raised by: Team Leader (Jeroen) proposed thermal and camera hacking. Full team developed into perception mode framework.

D-018: Three-range sound model

  • Date: 2026-02-09
  • Decision: Sound information reaches the player through three ranges with decreasing accuracy and trust:
Range Method Info quality Trust level
Close (near/in LOS) Stereo audio (maps to facing direction with camera rotation) High accuracy, identity possible Raw sensory, reliable
Medium (outside LOS, nearby) Visual indicators at fog edge + internal monologue Directional, imprecise, type classification Sensory impression, reliable but vague
Long (across map) Insert notifications, text alerts Specific but delayed, location data Network-dependent, spoofable, manipulable
  • Key insight: Each range is a different information QUALITY, not just distance. Close = trustworthy. Long = potentially compromised. The Starflyer's agents would absolutely spoof long-range feeds.
  • v0.1: Screen-space stereo for close + visual fog-edge indicators for medium. Long-range insert alerts as stretch goal.
  • Raised by: Full team discussion.

D-019: Top-down confirmed as primary camera, 3D cutscenes for key moments

  • Date: 2026-02-09
  • Decision: Top-down is the gameplay camera. Final. 3D cutscenes can be used for significant narrative moments (wormhole traversal, Dyson barrier opening, first contact, major reveals).
  • Rationale after full honest review:
    • What first-person would give us (visceral traversal, face-to-face conversations, natural asymmetry, spatial horror) is real but compensated by: vision cone + fog, internal monologue, perception mode overlays, sound model
    • What top-down gives us that first-person can't: multi-layer information observation, tactical combat clarity, system legibility, NPC simulation visibility, strategic UI coexistence, 5-10x faster prototype
    • Key insight (Gestalt): the fun is systems interacting - observation → insert check → thermal → monologue → mental note → exploitation. That sequence is BETTER top-down.
    • Key insight (Paula): monologue interpreting faces/conversations is arguably richer than player reading 3D faces, and more faithful to Hamilton's close-POV writing style
    • 3D cutscenes recapture the visceral moments without burdening gameplay engineering. They're decoupled, can be added as polish, game ships complete without them.
    • Camera change to 3D IS the dramatic signal - player knows something significant is happening (Gestalt)
  • Architecture note (Tyre): Client-server separation means the renderer is swappable. A full first-person client is architecturally possible in the future. Top-down now doesn't mean top-down forever.
  • v0.1: Top-down only. No cutscenes. Those are milestone features.
  • Amendment (2026-02-12, Art Direction Workshop): Camera angle specified as ~15-20° from vertical ("the angle"), rendered in sprite art via orthographic camera. Sprites are drawn as if viewed from a shallow tilt (south-facing front faces visible on objects, entities, and walls), but the Godot camera is purely orthographic — the perspective is an art convention, not a camera setting. Tile grid remains square/orthogonal (64x64). Vision cone math remains pure 2D. 3D render pipeline uses Camera3D at -72.5° from horizontal (midpoint of range) to produce sprites with mathematically correct perspective. Matches Rimworld's approach: orthographic camera, tilt faked entirely in art. Internally referred to as "the angle."
  • Raised by: Team Leader (Jeroen), after full team review of tradeoffs in Round 12. Angle amendment: Team Leader, endorsed unanimously in Art Direction Workshop Round 3.

D-033: Entity color = relationship to player

  • Date: 2026-02-11
  • Decision: Entity color in the top-down view represents the character's relationship to the player character, not an objective property. The same NPC can appear as different colors to different characters. Color is a client-side derivation from RelationshipState component + knowledge state — not an NPC property.
  • Color palette:
    • Unknown/Neutral: Cool teal #4a9ebb — default for unassessed NPCs
    • Known/Friendly: Soft green #6bc9a6 — people the character knows and trusts
    • Person of Interest: Warm amber #e8c547 — monologue or case file has flagged something
    • Hostile/Dangerous: Muted red #d45d5d — character KNOWS there's danger (subjective, not omniscient)
    • Static objects: Muted grey #8b8ba0 — furniture, equipment, environmental
    • Player character: #e0e8ff (detective, cool) / #e8e0d0 (smuggler, warm)
  • Key principle: Red means danger TO YOUR CHARACTER, not danger in the abstract. The detective might see amber (flagged in case file) where the smuggler sees green (trusted colleague). This IS asymmetric information rendered visually.
  • Transition behavior: Color shifts smoothly (0.5s fade) when relationship state changes. THE FRIEND's first color shift (green → amber) should be the first relationship color change in the session — maximum emotional impact.
  • Cross-reference: Internal monologue (D-016), THE FRIEND pattern (D-034)
  • Raised by: Araminta (Round 1 proposal, color palette design), project lead (approved, directive #2)
  • Dissent: None

D-035: Symmetric shadowcasting (Albert Ford) selected for LOS computation

  • Date: 2026-02-11
  • Decision: Albert Ford's symmetric shadowcasting algorithm is selected for all line-of-sight computation. The traditional recursive shadowcasting algorithm is rejected.
  • Resolves: Q-018
  • Benchmark results (debug build, 1000 iterations, range 20):
Map Density Symmetric Recursive Speedup
32x32 open 920µs/call 1118µs/call 1.2x
32x32 10% walls 845µs/call 4003µs/call 4.7x
32x32 30% walls 334µs/call 2099µs/call 6.3x
64x64 open 929µs/call 1114µs/call 1.2x
64x64 10% walls 745µs/call 4060µs/call 5.5x
64x64 30% walls 215µs/call 1716µs/call 8.0x
150x150 open 919µs/call 1102µs/call 1.2x
150x150 10% walls 615µs/call 3347µs/call 5.4x
150x150 30% walls 163µs/call 1709µs/call 10.5x
  • Key findings:
    • Symmetric is 1.2-10.5x faster across all configurations (debug build; release will be significantly faster)
    • Advantage increases with wall density — more occlusion means less work for the quadrant-based approach
    • Map size has minimal effect on relative performance at range 20 (both algorithms are bounded by vision range, not map size)
    • All values well within the 100ms tick budget (D-026), even in debug
    • Symmetry property verified: if A sees B, then B always sees A — critical for D-011's requirement that NPCs use the same perception system as the player
  • Implementation: Uses rational fraction slopes (num/den integer pairs) to avoid floating-point drift. Processes 4 cardinal quadrants with coordinate transforms. The production API is compute_fov(is_opaque, origin_x, origin_y, range, z_level) -> VisibilityMap.
  • Raised by: Dudley (implementation + benchmark), Tyre (technical direction)
  • Dissent: None

D-043: Art direction — visual style ("functional warmth")

  • Date: 2026-02-12
  • Decision: Clean 2D with bold silhouettes, tile-based world composition (64x64px visual tiles on dual-scale grid per D-066), lighting-driven atmosphere. Not pixel art, not painted, not 3D. Godot 4 Light2D pipeline (PointLight2D per fixture, LightOccluder2D on walls, CanvasModulate for global ambient). AI-generated assets via Nano Banana / Gemini 2.5 Flash, rendered through 3D pipeline for perspective consistency. Core production principle: "Sprites are shape templates that the lighting system completes" — no baked shadows, no baked lighting, no baked mood.
  • Label: "Functional warmth" (Gore).
  • Resolution chain: 1024x1024 source → 256x256 working (outlines applied at 4-8px) → 64x64 runtime. Bilinear interpolation both passes. Outline color: dark blue-grey #333340.
  • Canonical reference: docs/workshops/art-direction-mood-board/workshop-outcomes.md §1.1, §9.1-9.3
  • Raised by: Araminta (lead), unanimously endorsed. Art Direction & Mood Board Workshop (3 rounds + closing).
  • Dissent: None. All four agents independently converged on the same style.

D-044: Art direction — visual hierarchy (entity > object > structure)

  • Date: 2026-02-12
  • Decision: Three-layer visual hierarchy: entities (2px outline, D-033 relationship color, highest saturation) > objects (1px outline, era-appropriate palette, moderate saturation) > structure (minimal/no outline, muted zone palette, lowest saturation). Hard rendering rule: entity always wins visual ties — if an entity and object overlap, the entity's D-033 color must remain visible. This is a readability guarantee, not an aesthetic preference.
  • Entity spec: 24x32 pixel footprint within 64x64px visual tiles. Entities occupy 1x1 sim tiles (0.5m) but render across a 2x2 sim tile sprite footprint per D-066. D-033 color as primary information signal, silhouette as primary identity signal. One identifying silhouette feature per named NPC (Kael's vest, Lera's apron, Sera's uniform). 3-4 template silhouettes for generic NPCs.
  • Canonical reference: docs/workshops/art-direction-mood-board/workshop-outcomes.md §1.4, §1.5
  • Raised by: Araminta (outline spec), Ozzie (readability priority). Unanimously endorsed.
  • Dissent: None

D-045: Art direction — environmental neutrality (strict zero shift)

  • Date: 2026-02-12
  • Decision: The base world layer never shifts in response to conspiracy activation or investigation state. The rendering pipeline never modifies world-layer visuals in response to narrative state. Zone lighting is fixed. What CANNOT change: light color temperature, shadow depth/direction, tile colors, wall tones, floor patterns, any CanvasModulate shift correlated with narrative state. What CAN change: insert overlay density, entity colors (D-033), monologue frequency/urgency, player character sprite posture. Allowed diegetic changes (everyone experiences them): time-of-day cycle (D-031), weather (physical reality, storyteller can time it).
  • Key insight (Gore): "The player walks into the bar after discovering the conspiracy and it's STILL warm and inviting. That's the horror. The warm light isn't ironic — it's indifferent."
  • Canonical reference: docs/workshops/art-direction-mood-board/workshop-outcomes.md §1.10
  • Raised by: Gore and Miri (strict zero position). Araminta and Ozzie moved to this position in Round 2 — convergence through persuasion, not compromise.
  • Dissent: None

D-046: Art direction — lighting system (three-reference model)

  • Date: 2026-02-12
  • Decision: Three-reference lighting: (1) Darkwood — vision cone mechanics, light pooling, graduated fog boundary, darkness-as-weight. Retuned: darkness = uncertainty (not hostility), light = visibility (not safety), beyond the cone = life continuing without you (not monsters). (2) Blade Runner 2049 / Deakins — color temperature as emotional language: warm amber = social/inhabited, cool white = institutional/official, mixed = transitional. (3) Edward Hopper (Nighthawks) — warm interior surrounded by unknowable dark. The game's central image. Emotional register: uncertainty, not dread. Character temperature via spatial paths: smuggler's routine through warm-lit spaces (dock, bar), detective's routine through cool-lit spaces (Commission kiosk, corridors). Same fixtures, different daily routes — no rendering tricks.
  • Godot implementation: PointLight2D (per fixture, per zone) + LightOccluder2D (on walls/obstacles) + CanvasModulate (global ambient) + textured PointLight2D on player (vision cone shape). Stock Godot 4 pipeline.
  • Canonical reference: docs/workshops/art-direction-mood-board/workshop-outcomes.md §1.6, §1.11
  • Raised by: Ozzie (Darkwood), Araminta (BR2049 color), Gore (Hopper), Miri (character spatial paths). Unanimously endorsed.
  • Dissent: None

D-047: Art direction — two-tier animation system

  • Date: 2026-02-12
  • Decision: Tier 1 (clear): public daily activities — walking/running (4-6 directional frames), working at terminal/handling cargo (2-3 states), eating/drinking (2-3 states), talking (2-3 states, distinguishable from "standing near"), sleeping (1 state). Instantly readable. Tier 2 (ambiguous): privately motivated behaviors — pausing, looking around, lingering near a location, changing direction, proximity without clear interaction. Player sees the action but cannot determine the intention. The boundary between tiers is invisible to the player.
  • Key insight: "The clear/ambiguous division isn't an art decision — it's the investigation mechanic expressed through animation" (Ozzie). Routine must be readable so deviations are noticeable. Maps to NPC tell system (D-024).
  • Canonical reference: docs/workshops/art-direction-mood-board/workshop-outcomes.md §1.12
  • Raised by: Ozzie and Gore (two-tier proposal), Araminta (production spec). Unanimously endorsed.
  • Dissent: None

D-048: Neural insert overlay — visual design

  • Date: 2026-02-12
  • Decision: Geometric data layer (precise positioning, clean lines, structured information) rendered with soft bloom shader pass (~2-3px gaussian blur at ~40% blend on the insert CanvasLayer). D-033 colors gain soft halos rather than hard edges. Smuggler's overlay: thinner, sparser (baseline lattice hardware). Detective's overlay: denser, crisper (augmented lattice hardware). Passive state nearly invisible; active state clean and precise. Insert overlay is NOT affected by the fog shader — insert data is computational, not perceptual. Insert markers can appear in fogged areas if the lattice has that data.
  • Tests: "If switching the overlay OFF would feel like going deaf rather than closing a window, it's working" (Gore). "After 10 minutes, does the player forget the insert is there? If yes, we've succeeded" (Ozzie).
  • Cross-reference: Diegetic insert (D-013), perception modes (D-017)
  • Canonical reference: docs/workshops/art-direction-mood-board/workshop-outcomes.md §1.9
  • Raised by: Araminta (geometric spec), Gore (organic requirement). Resolves Round 1 divergence — both survive in synthesis.
  • Dissent: None

D-049: Z-level rendering stack (8 layers)

  • Date: 2026-02-12
  • Decision: 8-layer z-stack: (0) Floor tiles — zone identity, movement surface. (1) Floor objects — cosmetic detail, walked over. (2) Furniture/placed objects — y-sorted with entities, visual complexity center. (3) Entity sprites — y-sorted with Layer 2, D-033 colored. (4) Overhead/wall tops — pipes, ducts, lighting fixtures, signage; semi-transparent partial occlusion. (5) Fog of perception — vision cone mask, fog shader; affects layers 0-4. (6) Insert overlay — lattice HUD elements, bloom-rendered, NOT affected by fog. (7) Monologue/UI — top of stack, always visible. Wall rendering: Option B (visible top + face) for structural walls, Option A (boundary lines) for interior partitions. Sprite stacking out of scope.
  • Key insight (Gore): Overhead occlusion is thematically significant — entities passing behind shelving/under overhangs create local information gaps within otherwise known spaces.
  • Canonical reference: docs/workshops/art-direction-mood-board/workshop-outcomes.md §1.14
  • Raised by: Araminta (8-layer spec), Gore (overhead as thematic tool). Unanimously endorsed.
  • Dissent: None

D-052: Character favorite colors — object-layer identification

  • Date: 2026-02-12
  • Decision: Each NPC has a favorite color expressed through personal objects (bedding, cushions, mugs, personal items), NOT on entity sprites. Muted register: dusty blue, warm terracotta, faded olive — personal, not faction. Creates secondary identification system: D-033 = relationship to player (entity layer), favorite color = person's identity in space (object layer). Investigation mechanic: recognizing whose stuff is where. Saturation constraint: favorite color saturation must stay below D-033 entity color saturation to preserve visual hierarchy. Godot implementation: mask shader + material duplication per unique color (~0.5-1ms at 50-100 objects). Build for v0.1.2+.
  • Cross-reference: Visual hierarchy (D-044), design principle (D-051)
  • Canonical reference: docs/workshops/art-direction-mood-board/workshop-outcomes.md §7 (D-051 candidate)
  • Raised by: Team Leader (Jeroen), unanimously endorsed.
  • Dissent: None

D-056: Cursor states — insert-styled geometric

  • Date: 2026-02-13
  • Decision: Four cursor states using the neural insert's geometric visual language:
    • Default: Four thin inward-pointing ticks with bloom. White-blue #c8d0e0. Barely visible — the insert's own cursor.
    • 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 a friend (green tint) should feel wrong.
  • All transitions 150ms linear. z-layer 7. Never changes by zone or narrative state (D-045).
  • Cursor changes on LOS, not just proximity. Click interaction range: ~2 sim tiles (= 1m per D-066). Weapon-selected mode suppresses interaction prompts unless Shift held ("combat intent trumps social intent").
  • Diegetic test (Stig): Interaction labels render on z-layer 6 (insert overlay). If the insert is off, labels disappear. Passes the "is this information from the character's implant?" test.
  • Rationale: Diegetic — cursor is the insert's own interface element. Consistent with D-048. Entity in weapon sights tinting to D-033 creates moral friction.
  • Cross-reference: Insert overlay (D-048), entity color (D-033), z-stack (D-049)
  • Source: Control & Interaction Workshop (2026-02-13)
  • Raised by: Araminta (visual spec), Stig (UX rules + diegetic test), Ozzie (weapon suppression)
  • Dissent: None.
  • OQ-07 resolution (2026-02-19, #522): Insert-off behavior is option (a): cursor shape still changes, verb labels suppressed.
    • Cursor state machine fires normally (entity hover → bracket shape, object hover → X-shape) — the character's body physically orients toward targets as a subconscious/spatial response.
    • Insert does not process targets into actionable data: should_show_interactions() returns false when insert_active == false, and interaction labels (z-layer 6) are hidden via set_insert_active(false) on InteractionList and InteractionPrompt.
    • GameState.insert_active is the source of truth (defaults true in v0.1; wired from snapshot field insert_active).
    • Rationale: diegetically consistent — the body reacts to proximity; the insert reacts to commands.

D-057: Entity interaction — vertical list, insert-styled

  • Date: 2026-02-13
  • Decision: Entity interactions use a compact vertical list (not radial). 2-4 options max, anchored to entity position. Insert-styled with Araminta's geometric aesthetic. New options unlocked by knowledge changes are highlighted with a gradient glow background. Radial menu reserved for world menu only (D-058). Max 3 visible response options in dialogue context.
  • Server architecture: Two-phase verb computation. Phase 1 (simulation, no KG): compute maximum possible verb set from ObjectType component (Readable, Container, Terminal, Door, Pickup, Furniture — each with specific verb sets). Phase 2 (observer, reads KG): filter by character's knowledge (Confront requires KnowsDetails+ per D-041), apply POI priority flips, add contradiction markers. Character-archetype verb variation implemented as Phase 2 observer filter rules (same crate: smuggler sees "Move/Stash", detective sees "Scan/Flag").
  • Diegetic test: Labels render on z-layer 6. If insert is off, labels disappear.
  • Rationale: Variable-length text options (e.g., confrontation lines in character voice) break radial spatial memory. List handles 1-4 options cleanly. New-item glow signals "something changed" without UX hazard of geometry transforming under cursor. Two-phase computation enables character differentiation without separate verb systems.
  • References: Disco Elysium (world-embedded indicators), Darkwood (minimal cursor), Rimworld (right-click context list).
  • Cross-reference: Cursor states (D-056), knowledge graph (D-041), z-stack (D-049)
  • Source: Control & Interaction Workshop (2026-02-13)
  • Raised by: Stig (vertical list structure + diegetic test), Araminta (insert aesthetic), Dudley (two-phase verb computation), Nigel (character-archetype verb sets). Lead resolved: Stig's structure, Araminta's styling.
  • Dissent: Araminta argued for spoke radial (geometry transformation signals qualitative knowledge change — new spoke growing). Lead rejected: items moving under cursor when knowledge changes is a moving goalpost (bad UX while aiming at an option).
  • OQ-07 resolution (2026-02-19, #522):
    • When insert_active == false, the interaction list hides completely (set_insert_active(false)_hide()).
    • Cursor shape changes still occur per D-056 OQ-07 — list suppression is independent of cursor state.
    • GameState.insert_active drives this at runtime, wired via main.gd on each snapshot.

D-058: World menu — radial, 4 spokes

  • Date: 2026-02-13
  • Decision: Right-click opens a radial world menu. Four spokes: Observe (eye icon), Insert (phone icon), Comms (signal icon), Wait (clock icon). Insert-styled: geometric lines, thin spokes with icons, nearly transparent. Renders on z-layer 6. Drag-release for power users (high-speed drag-to-select), click-click for newcomers. v0.1: 2 spokes only (Observe + Insert), scale to 5-6 later.
  • Rationale: Radial works for world menu because items are fixed categories that don't vary by knowledge state (unlike entity verbs). Spatial memory builds quickly (~10 minutes). Drag-to-select makes the radial feel fast and fluid for experienced players.
  • Cross-reference: Entity interaction (D-057), insert overlay (D-048), z-stack (D-049)
  • Source: Control & Interaction Workshop (2026-02-13)
  • Raised by: Stig (structure + implementation), Araminta (insert aesthetic)
  • Dissent: None.

D-059: Fog — shader-based, five layers, knowledge-graph-driven

  • Date: 2026-02-13
  • Decision: Fog is a shader-driven system (not particles) with five distinct layers:
    1. Clear (vision cone): Soft gradient edge over 6-8 sim tiles (= 3-4 visual tiles per D-066), no hard line. Darkwood approach.
    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:
    • 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).
    • Unrecognized entity: neutral grey #555566 blob. No silhouette. No identifying features.
    • Recognition transition governed by cognitive delay (D-060).
  • 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."
  • Soft perception degradation: At high overlay load, diegetic scan-line interference (insert under strain). No hard cap on simultaneous perception modes — soft visual warning instead.
  • Performance: <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.
  • Cross-reference: Fog of perception (D-011), sound model (D-018), perception modes (D-017), entity color (D-033), z-stack (D-049), knowledge graph (D-041)
  • Source: Control & Interaction Workshop (2026-02-13)
  • Raised by: Araminta (full visual spec + "fog is not darkness"), Tyre (performance validation), Nigel (replayability case — fog as primary divergence mechanism), Gestalt (signal/answer framework + soft cap rejection), Ozzie (false-positive shapes proposal)
  • Dissent: Gestalt proposed hard cap of 2 active perception modes. Lead rejected — replaced with Araminta's diegetic soft degradation.

D-060: Cognitive delay for fog recognition

  • Date: 2026-02-13
  • Decision: When the player recognizes a heard/sensed entity in fog, recognition is NOT instant. Single cognitive delay system: 0.6s base, 0.3s when observe_anomaly triggers (urgent context). Values are tunable via playtesting. Monologue fires DURING the delay ("Those footsteps... that's Kael's walk"), not after — the monologue IS the recognition. Visual transition: grey blob → D-033 color + silhouette feature over ~0.3s within the cognitive delay window. Natural recognition (organic resolve) feels different from sensor recognition (digital snap with biometric ID — different monologue voice too).
  • Rationale: Recognition should feel like a cognitive event, not a UI update. The delay creates a moment where the player's brain and the character's brain are working together. Context-sensitive urgency (0.3s for anomalies) prevents the delay from feeling sluggish in tense situations.
  • Cross-reference: Fog layers (D-059), monologue (D-016), sound model (D-018)
  • Source: Control & Interaction Workshop (2026-02-13)
  • Raised by: Ozzie (timing values + urgency split, adopted), Araminta (visual transition spec), Gestalt (longer values not adopted, but playtesting may adjust)
  • Dissent: Gestalt proposed 0.8-1.2s (longer, more contemplative). Lead chose Ozzie's shorter values as starting point.

D-061: Dialogue box — unified conversation log, bottom screen, max 20% height, no portraits

  • Date: 2026-02-13
  • Decision: Dialogue occupies the bottom of the screen, max 20% height, max-width 640px (D-076). NO portraits — the NPC is on screen, a portrait is redundant. Monologue floats ABOVE the dialogue box on z-layer 7 — spatial separation allows monologue to contradict dialogue visually (character thinks one thing while NPC says another). Walk-away via WASD, dialogue fades over 300ms, no close button (D-064). Auto-pause in single-player when implant UI is open; overlay design for multiplayer readiness.
  • Unified conversation log (Sprint 14, #535): The dialogue box is a single chronological log — not separate panels for active vs passive dialogue. Player-NPC conversations and overheard NPC-NPC conversations (D-078) flow into the same scrolling log. Each entry shows Speaker → Target: text with per-character name colours (hash-indexed from configurable palette in data/dialogue-theme.yaml). Player response options render below the log; max 3 visible. Locked options invisible (D-062).
  • Entry lifecycle: All entries share the same timeout (15s + 3s fade, configurable via theme YAML). Walk-away clears response options but preserves log entries — earned information is fair game. Panel auto-hides when all entries expire and no active conversation is in progress.
  • Passive overheard lines: Rendered at reduced opacity (0.9) per D-078. No response options for overheard content. Walk-away does not fire for passive-only display — the panel dismisses naturally when entries expire or the player walks out of earshot.
  • Rationale: Game world stays live above the dialogue box — player sees NPC body language while talking. Monologue above + dialogue below = the character can think one thing while saying another. Max 3 options + invisible locks = player never knows what they're missing. No portrait because the NPC IS on screen. A single unified log avoids a separate UI element for overheard content and makes the flow of conversation feel natural — active and passive dialogue interleave chronologically.
  • Cross-reference: Invisible locks (D-062), confrontation (D-063), walk-away (D-064), z-stack (D-049), max-width (D-076), overheard NPC conversation (D-078)
  • Source: Control & Interaction Workshop (2026-02-13). Amended Sprint 14 (#535): unified log architecture.
  • Raised by: Stig (UI spec + no portraits), Lead (20% height constraint + max-width directive). Sprint 14 unified log: Stig (implementation).
  • Dissent: Stig initially proposed 25% height and 50% width centered. Lead constrained to 20% height and max-width.

D-067: Recognition chime fires at onset of cognitive delay

  • Date: 2026-02-16
  • Decision: The monologue recognition chime (D-038 assets 7-8) fires at the ONSET of the cognitive delay (D-060), not at its completion. Chime duration 300-400ms, overlapping with the start of the delay. The chime is "unresolved" — it opens a question, doesn't answer one. Full sequence when recognizing an entity in fog: (1) hear/sense something → (2) chime plays → (3) 0.6s cognitive delay begins (concurrent with chime tail) → (4) monologue text appears during delay ("Those footsteps... that's Kael's walk") → (5) blob transitions to D-033 color + silhouette feature → (6) recognition complete.
  • Rationale: The chime marks the character's attention shifting, not the recognition completing. It creates an "unresolved" sensation — something is happening in the character's mind. Monologue text provides the resolution. This prevents the chime from feeling like a UI notification and instead makes it part of the character's cognitive process.
  • Resolves: Q-014
  • Cross-reference: Audio assets (D-038), cognitive delay (D-060), fog recognition (D-059), monologue (D-016)
  • Raised by: Gestalt (proposal), confirmed by Team Leader (Jeroen)
  • Dissent: None

D-069: Audio dip profiles for dialogue and confrontation

  • Date: 2026-02-16
  • Decision: Three audio dip profiles modify bus volumes during player focus states, all relative to player slider settings (proportional, not absolute):
    • Dialogue dip: Ambient -6 to -8dB, World SFX 0dB, Player Actions 0dB, UI 0dB. 300ms ease-in, 500ms ease-out. Reduces environmental noise to foreground conversation without muting world events.
    • Confrontation dip: Ambient -10 to -12dB + low-pass filter (20kHz → 800Hz), World SFX -4 to -6dB (graduated — loud events like sprinting footsteps break through, quiet sneaking doesn't), Player Actions 0dB, UI 0dB. 500ms ease-in, 1000ms ease-out with filter sweep. Creates emotional/cognitive muffling per D-070.
    • ListeningFocus boost: World SFX +2 to +3dB when player is stationary for 30+ ticks (eavesdrop bonus, per D-071). Expresses heightened attention as audio gain.
  • Key behaviors:
    • All dB values are proportional to player slider setting, not absolute. If player sets World SFX to 50%, the -6dB dip applies to that 50% base.
    • Dips are interruptible — walk-away or stance change kills current tween, starts new tween to neutral.
    • Graduated World SFX dip during confrontation: loud, urgent events (sprinting, doors slamming, alarms) break through at reduced volume. Quiet, careful movement may not be noticed.
  • Rationale: Dips model finite attention. Dialogue suppresses ambient noise (focus on conversation). Confrontation suppresses both ambient and peripheral sounds (emotional tunnel vision per D-070). ListeningFocus boost rewards deliberate eavesdropping. All effects proportional to user volume settings respects player accessibility choices.
  • Cross-reference: Audio architecture (D-068), confrontation vulnerability (D-070), eavesdropping (D-071), audio aesthetic (D-074)
  • Raised by: Inigo (initial spec), Gestalt (graduated approach + ListeningFocus boost), Tyre (implementation details), Ozzie (proportional dip to respect player settings)
  • Dissent: None

D-070: Confrontation as cognitive vulnerability

  • Date: 2026-02-16
  • Decision: Confrontation creates perceptual vulnerability through reduced ambient awareness. Design principle: "Emotional focus creates perceptual vulnerability." Player actions requiring cognitive focus (confrontation dialogue, future: deep terminal reading, complex insert queries) mechanically reduce ambient perception via audio dip (D-069) and may suppress peripheral monologue triggers. This is NOT a punishment — it's a realistic consequence of finite attention. The player mitigates risk by choosing WHERE and WHEN to confront (safe location vs exposed corridor, early shift vs busy period).
  • Mechanical expression:
    • During confrontation: ambient sounds muffled, quiet NPC movement may go undetected (graduated World SFX dip means careful footsteps suppressed, sprinting footsteps still audible).
    • Post-confrontation: delayed monologue may fire for missed events ("Wait — did someone just pass by?").
    • World continues per D-045 environmental indifference — no scripted ambushes, but NPCs on routine may coincidentally pass while player is focused.
    • Vulnerability is probabilistic and emergent, not scripted.
  • Consistency principle: Connects to D-053 sprint suppressing monologue (physical focus limits interpretation). Confrontation suppresses ambient perception (emotional focus limits peripheral awareness). High-focus activities suppress peripheral cognition — this is the shared rule.
  • Must feel "felt, not computed" (Paula): Muffling is psychological tunnel vision, not a debuff tooltip. No UI indicator. Player realizes in retrospect: "I was so focused on Sera I didn't hear Kael walk past."
  • Rationale: Makes WHERE and WHEN to confront meaningful decisions. Confronting in a private corner = safer. Confronting in a busy corridor during shift change = riskier. Player agency through spatial and temporal choice, not RNG.
  • Cross-reference: Audio dip (D-069), confrontation UI (D-063), environmental indifference (D-045), stance system (D-053), monologue (D-016)
  • Raised by: Gestalt (vulnerability principle), Ozzie (graduated dip approach), Paula ("felt not computed" framing)
  • Dissent: None

D-071: No ambient dip for eavesdropping — ListeningFocus boost

  • Date: 2026-02-16
  • Decision: Overheard conversation (eavesdropping) does NOT apply dialogue dip (D-069). Cognitive state is opposite of direct conversation: extracting signal from noise requires MORE ambient awareness, not less. Instead, eavesdrop quality improves via ListeningFocus boost (+2 to +3dB World SFX when stationary 30+ ticks). Eavesdrop information quality is: distance-dependent, stance-modified (D-053 Careful stance grants "tell notice bonus"), ListeningFocus-boosted, and ambient-noise-penalized.
  • Ambient zone affects eavesdrop difficulty:
    • Bar (high ambient) = conversations hidden in murmur, requires proximity + ListeningFocus.
    • Workplace (moderate ambient) = conversations semi-conspicuous, distance-dependent.
    • Corridor (low ambient) = conversations conspicuous, easy to overhear from distance.
  • Information confidence: Overheard information enters knowledge graph at lower confidence (KnowsOf, not KnowsDetails per D-041) unless ListeningFocus + proximity allows high-quality capture.
  • Rationale: Direct conversation = character focuses, ambient dips. Overheard conversation = character strains to hear, ambient stays or boosts. Opposite cognitive states produce opposite audio profiles. Creates meaningful difference between talking TO someone vs listening IN on someone.
  • Cross-reference: Audio dip (D-069), stance system (D-053), knowledge graph (D-041), zone audio (D-072)
  • Raised by: Gestalt (cognitive state framing), Paula (zone-conspicuousness model), unanimously endorsed
  • Dissent: None

D-072: Universal event-driven conversation murmur

  • Date: 2026-02-16
  • Decision: NPC-to-NPC conversations use a single universal murmur sound asset, not zone-specific variants. Zone ambient determines conspicuousness: bar ambient (high murmur density) hides conversations, corridor ambient (low background) makes conversations conspicuous. Maps to D-047 two-tier behavior visibility: bar conversations are Tier 1 (clearly happening, content obscured), corridor conversations are Tier 2 (ambiguous — are they talking or just standing near each other?).
  • Asset split:
    • Bar ambient murmur: baked into amb_bar_layer.ogg (continuous background per D-038).
    • NPC proximity murmur: separate event-driven asset, deferred to future sprint (not in Sprint 7 scope). When implemented, same asset plays everywhere; zone ambient determines audibility.
  • Rationale: One murmur asset + zone-dependent conspicuousness creates the signal/noise dynamic naturally. Bar = high noise floor, conversations blend in. Corridor = low noise floor, conversations stand out. Simpler content production, richer emergent behavior.
  • Cross-reference: Audio assets (D-038), two-tier animation (D-047), eavesdropping (D-071)
  • Raised by: Paula (zone-conspicuousness model), Inigo (scoping to future sprint)
  • Dissent: None

D-076: Dialogue box max-width — 1200px (OQ-29 resolution)

  • Date: 2026-02-19
  • Decision: DIALOGUE_MAX_WIDTH = 1200px. Dialogue box is max 1200px wide, centered on screen. Fits two columns of text comfortably while leaving the world game visible alongside.
  • Derivation: ~62% of target 1920px viewport width. Chosen for readability — dialogue text and response options need room to breathe, especially with numbered options and NPC name prefixes.
  • Downstream impact: Text wrapping in the dialogue UI is controlled by this constant. Box is centered; the game world remains visible left and right.
  • Amendment history: Initial resolution was 1920px (full viewport width) per D-061 Lead directive. Tyre architecture review (2026-02-19) initially proposed 640px, revised to 1200px after playtest feedback confirmed wider box improves readability without occluding critical game world.
  • Implementation: Constants.DIALOGUE_MAX_WIDTH in client/scripts/constants.gd.
  • Cross-reference: Dialogue box (D-061), dual-scale grid (D-066)
  • Amends: D-061 (adds pixel value for max-width)
  • Raised by: Stig (OQ-29), revised per Tyre architecture review and playtest feedback

D-077: Zone temperature memory — server-tracked zone_id (OQ-09 resolution)

  • Date: 2026-02-19
  • Decision: Zone temperature memory is server-tracked via zone_id: Option<u16> on VisibleTile in ObserverSnapshot. The server assigns a zone ID to each tile based on the ZoneMap resource (spatial zone assignment). The client maps zone_id to temperature tint from a local lookup table for deep fog rendering (D-059 layer 3: ~10% zone temperature tint — bar=warm dark, hub=cool dark, corridor=neutral dark).
  • Resolves: OQ-09
  • Rationale: D-073 already mandates zone_id per tile in ObserverSnapshot for audio zone crossfade. With zone_id already on the wire for crossfade, zone temperature memory is essentially free — no additional protocol field needed, no additional server computation beyond the zone lookup. Client-only tracking was rejected because: (1) the server is the authoritative source of zone geometry, (2) client heuristics (remembering last-visited zone) would diverge from server truth at zone boundaries, and (3) the data is already crossing the wire for D-073.
  • Implementation:
    • VisibleTile.zone_id: Option<u16>None for tiles outside any defined zone (corridors, transition spaces). Uses #[serde(default, skip_serializing_if)] for backwards compatibility with v10 clients.
    • ZoneMap resource (simulation/zone.rs): BTreeMap<(i32, i32, i32), u16> mapping tile coordinates to zone IDs. BTreeMap per D-010 principle 4 (deterministic iteration). Populated by map builders at setup time.
    • Zone enrichment runs in compute_observer_snapshot — the observer pipeline's final assembly stage. PerceptionQuery trait remains zone-unaware (zone assignment is map data, not perception geometry).
    • Protocol version bumped to 11.
  • Client contract: Client maintains a zone_id → { name, temperature_tint, ambient_layer } lookup table. Deep fog shader (layer 3) reads zone_id from the last-seen VisibleTile data to apply the ~10% temperature tint. AudioManager reads zone_id to trigger crossfade between ambient layers (D-073).
  • Cross-reference: Fog layers (D-059), zone crossfade (D-073), ObserverSnapshot (D-020), deterministic simulation (D-010)
  • Raised by: Tyre (architecture review, #523)
  • Dissent: None

D-078: Overheard NPC conversation — passive dialogue panel with occlusion filter

  • Date: 2026-02-19
  • Decision: NPC-to-NPC conversations overheard by the player are displayed in the dialogue panel in passive mode (read-only, no response options). An occlusion filter degrades displayed text based on distance, ambient noise, and player effort (ListeningFocus stance). Monologue remains a separate channel — it reacts to overheard content via the witness_interaction trigger but does not carry conversation text itself.
  • Passive panel behavior:
    • Same D-061 dialogue box, but read-only — no response options rendered.
    • Shows speaker name and intended target (e.g. "Kael → Mira").
    • Visually distinguished from interactive dialogue (dimmed border or header treatment — exact style TBD by Araminta).
    • Walking out of earshot dismisses the panel naturally.
  • Occlusion filter — server-authoritative:
    • Occlusion is computed on the server. The server rolls per-word visibility based on distance, ambient noise, and ListeningFocus stance, then sends pre-occluded text to the client with ... replacing dropped words. The client renders exactly what it receives — no client-side probability logic.
    • Per-word visibility is a probability, not a deterministic cutoff. Each word is independently rolled — same distance, same conversation can yield different fragments across playthroughs.
    • Close / clear: High probability per word — most or all text arrives intact, speaker names shown.
    • Moderate distance / some noise: Medium probability — words arrive as ..., speaker names visible. The player may or may not catch the crucial word.
    • Far / noisy zone: Low probability — speaker indicators only, few or no readable words. Audio murmur still plays per D-072.
    • ListeningFocus stance: Shifts probability curve upward — improves word visibility at current distance.
    • Multiplayer-readiness: Each observer gets their own occluded version computed from their specific distance/noise/stance. Seedable RNG per tick ensures deterministic replay (D-010).
    • Design intent: Stochastic word-drop means the player can never be certain they got the full picture from eavesdropping alone. This pushes them toward direct conversation to confirm — where they must reveal something about what they know. The information asymmetry loop closes on itself.
  • Dual-channel principle: Dialogue panel = what you hear. Monologue = what you think about it. The witness_interaction monologue trigger fires after overheard content is displayed, producing the character's internal reaction ("She's lying to him", "So they do know about the cargo"). These are separate UI elements with separate content pipelines.
  • Content pipeline: Copy team authors NPC-to-NPC dialogue lines once at full fidelity. The server applies occlusion degradation before sending to the client. No need to author multiple fidelity versions.
  • Rationale: Keeps monologue as a clean internal response system — thoughts only, never quoted speech. The dialogue panel already exists for player-NPC interaction; reusing it in passive mode for overheard conversation avoids a new UI element. The occlusion filter makes proximity and attention mechanically meaningful without gating content behind binary thresholds.
  • Cross-reference: Dialogue box (D-061), eavesdropping (D-071), conversation murmur (D-072), monologue system (D-016), knowledge confidence (D-041)
  • Raised by: Lead (passive panel directive, occlusion filter, monologue separation)
  • Dissent: None

32 decisions. Last updated: 2026-02-20 (D-061: amended with unified conversation log architecture from Sprint 14 #535)