--- title: "Sprint 13 — Client Briefing" description: "AudioManager 5-bus implementation, zone crossfade, audio dip profiles, recognition chime" type: sprint status: archived sprint: 13 team: "client" --- # Sprint 13: Sound — Client Tasks **Goal:** Wire the full audio architecture end-to-end — AudioManager, zone crossfades, dip profiles, recognition chime, and conversation murmur — and complete v0.1 content authoring so opening hooks, tutorial monologue, and all content packs are done. **Branch:** `client` **Agents:** Stig (client dev), Tyre (architect), Hoshe (QA) ## Carry-over from Sprint 12 None. All Sprint 12 client tickets done. ## New Tickets | # | Title | Blocked by | |---|-------|------------| | #528 | AudioManager full implementation — 5-bus setup, directory registry, volume sliders | — | | #529 | Zone crossfade implementation — 1.5-2s tween on zone_id change | #528 | | #530 | Audio dip profiles — dialogue, confrontation, ListeningFocus boost | #528 | | #531 | Recognition chime — fires at cognitive delay onset (D-067) | #528 | | #533 | Wire NPC conversation murmur to World SFX bus — event-driven playback | #528, #532 (audio) | Use `db/connectors/ticket show ` for full details. ## Key Decisions - `decisions/architecture.md` — D-068 (5-bus audio architecture), D-073 (zone crossfade approach) - `decisions/perception.md` — D-067 (recognition chime timing), D-069 (audio dip profiles), D-070 (confrontation as cognitive vulnerability), D-071 (ListeningFocus boost), D-072 (NPC conversation murmur) ## Notes - **#528 — AudioManager full implementation:** `client/scripts/autoloads/audio_manager.gd` already exists and is substantially built. The 5-bus setup, directory-scan registry, `play()`, `play_at()`, `apply_dip()`, `clear_dip()`, and `set_volume()` methods are all implemented. What remains: (1) `set_zone()` is a stub (`pass`) — this becomes the zone crossfade implementation for #529; (2) volume slider persistence (save/load player preferences); (3) settings UI bindings for the 5 sliders; (4) ensure the Godot project's AudioServer bus layout matches the 5 bus names in code. Before starting, verify bus names in `Project > Audio` match `BUS_MUSIC`, `BUS_AMBIENT`, `BUS_WORLD_SFX`, `BUS_PLAYER_ACTIONS`, `BUS_UI_SOUNDS`. - **#529 — Zone crossfade:** Implement `set_zone(zone_id: String)` in `audio_manager.gd`. `SimBridge` already receives tile data from `ObserverSnapshot` — determine the player's current tile zone and call `AudioManager.set_zone()` on zone change. Crossfade logic: kill any active ambient tweens, start a 1.5-2s `create_tween()` that fades out the current `_ambient_players` entry and fades in the new zone asset. Zone-to-asset mapping for v0.1: hub/workplace → `amb_hub_layer`, bar → `amb_bar_layer`, smuggling corridor → `amb_corridor_layer` (names must match filenames in `res://audio/`). Crossfade is interruptible — walking back across a boundary starts the reverse tween. - **#530 — Audio dip profiles:** `DIP_SPECS` and `apply_dip()` / `clear_dip()` are already implemented in `audio_manager.gd`. What remains: wire call sites. Dialogue open/close → `apply_dip("dialogue")` / `clear_dip()`. Confrontation start/end → `apply_dip("confrontation")` / `clear_dip()`. ListeningFocus: the tick gate (30+ stationary ticks) is the caller's responsibility (per existing comment in `audio_manager.gd`); `sim_bridge.gd` or `game_state.gd` must track `stationary_ticks` from the server's `ListeningFocus` field in the snapshot and call `apply_dip("listening_focus")` / `clear_dip()` accordingly. D-070: no UI indicator — the muffling is felt, not announced. - **#531 — Recognition chime:** `CHIME_RECOGNITION = "sfx_monologue_chime"` is already defined in `audio_manager.gd`. Wire it: when `fog_entities.gd` or `entity_renderer.gd` begins a recognition sequence (detecting `RecognitionTrigger` in the snapshot), call `AudioManager.play(AudioManager.CHIME_RECOGNITION)` at the ONSET of the cognitive delay — not at completion. The chime routes to the `UISounds` bus automatically (default bus in `play()`). Full sequence per D-067: entity detected → chime plays (300-400ms) → 0.6s cognitive delay begins concurrently → monologue text appears during delay → blob transitions to D-033 color + silhouette → recognition complete. The chime is the "unresolved" signal — it precedes recognition, does not confirm it. - **#533 — NPC murmur wiring:** Blocked by #532 (audio team produces the asset). Once the murmur asset exists in `res://audio/`, wire event-driven playback: when `SimBridge` receives conversation/voice events from `ObserverSnapshot`, call `AudioManager.play_at(asset_key, world_pos, BUS_WORLD_SFX)` for proximity or `AudioManager.play(asset_key, BUS_WORLD_SFX)` for ambient murmur. Single universal asset — zone ambient provides natural conspicuousness (bar's `amb_bar_layer` buries it, corridor's low ambient exposes it). No zone-specific murmur variants. ## Dependency Chain ``` #528 (AudioManager — complete set_zone + settings UI + slider persistence) → #529 (zone crossfade — implement set_zone body) → #530 (dip profiles — wire call sites in sim_bridge / game_state) → #531 (recognition chime — wire ONSET trigger in fog_entities / entity_renderer) → #533 (murmur wiring) ← also blocked by #532 (audio team asset) ``` #528 can start immediately. #529, #530, #531 can proceed in parallel once #528 is done. #533 waits for both #528 and #532. ## 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(audio): description" --description "body" --base main --head client ```