Standardized YAML frontmatter on all 40 docs/design/ files with title, description, type, status, ticket, decision_refs, and author fields. Covers specs, wireframes, voice cards, spatial layouts, and system designs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
13 KiB
title, description, type, status, ticket, decision_refs, author, created, updated
| title | description | type | status | ticket | decision_refs | author | created | updated | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Sound Indicator Visual Design | Fog-edge pulse specification for directional sound indicators with range differentiation and suppression rules | design | active | #317 |
|
Araminta | 2026-02-20 | 2026-02-20 |
Sound Indicator Visual Design — Fog-Edge Pulse Specification
Version: v0.1 (Sprint 14) Author: Araminta (Visual Designer) Date: 2026-02-20 Ticket: #317 Status: Active — constrains client sound_indicator_renderer.gd implementation Foundation: Visual Grammar v0.1, Decision D-018 (three-range sound model)
1. Purpose and Scope
Sound indicators are complementary to audio, not a replacement for it. They exist for players with audio off, in loud environments, or when audio is present but directionality is ambiguous. They should not be noticeable during routine exploration — only when something specific warrants attention.
The v0.1 implementation uses directional arrows at the viewport edge as the indicator shape (already implemented in sound_indicator_renderer.gd). This spec defines the full intended visual design including the pulse behavior described in the ticket, and notes where the current implementation differs from the spec.
D-018 scope: Sound indicators cover the medium-range tier (sounds outside LOS, within ~3–20 tiles). Close-range sounds (≤3 tiles, within LOS) are handled by positional 2D audio — no indicator needed. Within medium range, three sub-tiers (close-medium, standard, far-medium) differentiate visual intensity — see §7 for the full breakdown.
2. Colors
Per D-018 three-range sound model and D-033/D-048 color vocabulary:
| Sound category | Hex | Usage |
|---|---|---|
| Neutral | #c8d0e0 |
Footsteps, ambient movement, cargo handling, non-social activity |
| Voice | #e8c547 |
NPC conversation, speech, social activity |
| Danger | #d45d5d |
Alarms, alerts, gunshots, explosions, threats |
These are the same as the insert chrome color (#c8d0e0), the Person of Interest amber (#e8c547), and the Hostile red (#d45d5d). The alignment is intentional — the sound indicator system is part of the insert overlay, and its color vocabulary maps directly to the entity relationship system. A voice indicator uses the same amber as a Person of Interest entity because voices are people, and people are potentially interesting.
3. Position — Fog Edge, Not Screen Edge
3.1 Principle
Sound indicators live at the boundary of the player's visible cone — where clear vision meets fog. Not at the physical screen border, not as a minimap overlay.
The current implementation projects indicators to the viewport boundary (approximately correct — viewport edge ≈ fog edge at the camera's field of view). This is sufficient for v0.1. The spec's intent is that indicators should feel like they're at the perceptual boundary, not tacked to the UI chrome.
EDGE_INSET = 20.0px in the current implementation provides the correct "just inside the boundary" feel.
3.2 Z-Layer
Sound indicators render on z-layer 6 (insert overlay), not z-layer 5 (fog). They are insert data — the character's lattice is processing the sound, not the character's naked ears. They are unaffected by the fog shader.
The current implementation (sound_indicator_renderer.gd) renders as a Node2D draw call. This should be confirmed as rendering on z-layer 6 in the scene tree.
4. Shape — Arrow vs Pulse Arc
4.1 Current Implementation
The current sound_indicator_renderer.gd renders filled arrowhead triangles:
- Tip at the viewport boundary edge point
- Arrow points toward the sound source
- Size: 12px length, 7px half-width
- Filled polygon, not an outline
This is a valid v0.1 placeholder. It communicates direction clearly.
4.2 Target Design — Pulse Arc Segment
The intended final design is a thin arc segment at the fog boundary rather than a solid arrow. The arc reads as "sound reaching the edge of perception" rather than "here is an arrow pointing at something."
| Property | Value | Notes |
|---|---|---|
| Shape | Arc segment (partial ring) | Centered on source direction, 40° sweep |
| Arc radius | 6px — visually thin | Not a thick ring |
| Position | Fog boundary | Radiates outward from boundary inward by 3px |
| Animation | Pulse outward and fade | Single pulse per event, see §5 |
Arc sweep: 40° centered on the direction to the sound source. Narrow enough to clearly point, wide enough to be visible at a glance. A line would be too thin; a semicircle too vague.
For v0.1: Continue using the current arrow implementation. The arc design is the target for when sprite art replaces colored rectangles — the arc will feel more natural against full art than a solid arrowhead.
5. Animation — Pulse Behavior
5.1 Current Implementation
The current implementation renders a static indicator (no pulse animation) that lives for INDICATOR_LIFETIME = 3.5s and fades over the last FADE_DURATION = 0.6s. The fade is a linear alpha ramp from full opacity to 0.
This is functional but does not communicate the sound event as a moment — it reads as a persistent marker rather than an alert.
5.2 Target Pulse Specification
The intended animation is a single expanding pulse per sound event, not a persistent marker:
| Phase | Duration | Behavior |
|---|---|---|
| Onset | 0.0–0.2s | Indicator appears at full opacity, max brightness |
| Expand | 0.2–0.6s | Indicator expands outward by 3–4px (for arrow: scale 1.0 → 1.3) |
| Hold | 0.6–1.5s | Full opacity, static size |
| Fade | 1.5–2.5s | Linear alpha 100% → 0% |
Total duration: 2.5s (vs current 3.5s). The shorter duration prevents indicators from lingering as persistent clutter.
For v0.1: Implement the onset flash (full opacity on appear) and the fade. Skip the expand animation if performance is constrained — the expand is polish.
Easing: Onset is instant (no fade-in — sound events are sudden, their indicators should be too). Fade-out uses ease-in (slow start, accelerates to transparent). The sound indicator should feel like it vanishes rather than slowly becoming invisible.
5.3 Deduplication
Same-source deduplication is already implemented correctly: if an indicator exists at a tile position, new events reset its timer rather than stacking. This prevents a continuous conversation from spawning dozens of overlapping indicators.
6. Direction Encoding
6.1 Arrow Direction
The current implementation projects the indicator to the viewport boundary in the direction of the sound source from the player. The arrowhead tip points toward the sound source. This correctly encodes direction.
Rule: The indicator tip always points toward the source, not away from it. The player reads "the sound is in that direction."
6.2 Arc Direction (Target Design)
In the arc design, the arc is centered on the direction vector from player to sound source. The arc's midpoint lies on the line from player to source, at the fog boundary. The 40° sweep is centered on this midpoint. The arc opens toward the source (the open side of the arc faces the player, the midpoint faces the source).
7. Range Differentiation — Three Visual Levels
D-018 specifies three distance ranges. Sound indicators apply to medium range (outside LOS), but within medium there are visual levels based on proximity:
| Distance | Visual treatment | Alpha | Notes |
|---|---|---|---|
| Close-medium (3–5 tiles) | Full indicator, 90% alpha | 90% | Clear, noticeable |
| Standard medium (5–12 tiles) | Standard indicator, 70% alpha | 70% | Visible but not urgent |
| Far-medium (12–20 tiles) | Smaller indicator, 45% alpha | 45% | Subtle, ambient |
For the arrow implementation: Scale the arrow by distance proxy — close-medium at scale(1.0), far-medium at scale(0.7). The size reduction plus alpha reduction creates a clear near-vs-far reading.
Alpha cap at 90%: Sound indicators should never be fully opaque. They are insert data, not a HUD alert. The 10% transparency gap maintains their insert-layer quality.
8. Suppression Rules — When Indicators Do NOT Appear
Sound indicators are suppressed in the following conditions:
| Condition | Rule |
|---|---|
| Sound source within player's LOS | Suppressed. The player can see/hear the source directly. |
| Sound source at close range (≤3 tiles) | Suppressed. Close range is handled by positional 2D audio. |
| Sound source outside 20-tile radius | Suppressed. Long-range sounds are insert notification territory (future sprint). |
insert_active == false |
Suppressed. Sound indicators are insert overlay elements (z-layer 6). |
| Danger-category sound, player already in dialogue | Not suppressed. Danger indicators break through dialogue focus. (See note.) |
Dialogue suppression exception for Danger: Per D-070 (confrontation as cognitive vulnerability), ambient sounds are muffled during confrontation/dialogue — but this is audio suppression, not visual suppression. If an alarm fires while the player is in dialogue, the danger indicator should still appear. The player may not hear the alarm (audio is dipped) but the insert catches it. This is the insert doing its job: processing data the character's conscious attention missed.
Voice indicator suppression logic: event_type containing "voice"/"speech"/"convers"/"talk" → Voice category. This is already implemented in color_for_type() in the current renderer. No change needed.
9. Current Implementation vs Spec — Delta Summary
| Aspect | Current (v0.1) | Target (spec) |
|---|---|---|
| Shape | Filled arrowhead | Arc segment (40°, 6px radius) |
| Animation | Static + linear fade (3.5s total) | Pulse onset + fade (2.5s total) |
| Range differentiation | None — all indicators same size | Three levels: 3px scale + alpha |
| Z-layer | Needs confirmation | Z-layer 6 (insert overlay) |
| Direction | Correct — arrow points toward source | Same principle, different shape |
| Colors | Correct — uses Constants palette | Same |
| Deduplication | Correct — resets timer on re-trigger | Same |
| Insert-off suppression | Not yet implemented | Suppress when insert_active == false |
v0.1 implementation priority:
- Confirm z-layer 6 placement (quick fix if wrong)
- Add insert-off suppression
- Add basic range alpha differentiation (single alpha pass by distance)
- Keep arrow shape — replace with arc when sprite art arrives
10. Visual Design Rationale
Why at the fog edge, not screen edge or minimap?
Screen-edge indicators have no spatial relationship to the game world — they're purely navigational UI. The fog boundary is where the character's perception ends. A sound at the fog edge is a sound at the limit of what the character can process. Placing the indicator there is diegetically honest: the character's insert is flagging something at the edge of their awareness, not beyond it.
Minimap overlays require a minimap. We don't have one in v0.1. And minimap is meta-game — the indicator at the fog edge is in-world.
Why single pulse, not persistent marker?
Sound is a moment, not a state. A sound event happens at a point in time and then is over. A persistent marker would imply "there is still a sound here," which isn't necessarily true. The single pulse says "something happened in that direction." The player acts on it or doesn't.
Why amber for voice, not a neutral sound color?
Because voices are the most important medium-range sound in the game. NPCs talking to each other is signal. Footsteps are noise. Making voice indicators amber — the same as Person of Interest entity color — trains the player to associate amber with "social activity worth paying attention to." The color vocabulary reinforces the relationship system.
Appendix A — Decision Cross-References
| Decision | Relevance |
|---|---|
| D-018 | Three-range sound model — source for indicator tier assignment. |
| D-047 | Two-tier animation. Tier 2 NPC behaviors produce the sound events that trigger voice indicators. |
| D-048 | Insert overlay visual language — indicators are part of the insert, not the world. |
| D-049 | Z-level rendering stack — z-layer 6 for insert overlay. |
| D-059 | Fog shader. Sound pings in fog are separate from sound indicators (fog layer concentric rings vs insert edge arrows). |
| D-070 | Confrontation as cognitive vulnerability — danger indicators not suppressed during dialogue. |
Appendix B — Quick Reference for Stig
| Property | Value |
|---|---|
| Z-layer | 6 (insert overlay) |
| Neutral color | #c8d0e0 |
| Voice color | #e8c547 |
| Danger color | #d45d5d |
| Max alpha | 90% |
| Total visible duration (target) | 2.5s |
| Total visible duration (current) | 3.5s |
| Fade duration | 1.0s ease-in |
| Deduplication | Reset timer on same-tile re-trigger |
| Range alpha levels | Close-medium 90% / standard 70% / far-medium 45% |
| Suppression: within LOS | Yes |
| Suppression: insert off | Yes |
| Suppression: danger + dialogue | No — danger breaks through |