> For the complete documentation index, see [llms.txt](https://faction-os.gitbook.io/faction-os-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://faction-os.gitbook.io/faction-os-docs/.spec_system/archive/sessions/phase04-session05-browser-audio-runtime-and-controls/spec.md).

# Session Specification

**Session ID**: `phase04-session05-browser-audio-runtime-and-controls` **Phase**: 04 - Media Catalog and Audio/Visual Pipeline **Status**: Complete **Created**: 2026-05-29 **Package**: apps/web **Package Stack**: React 18, Vite, TypeScript, Zustand, Web Audio API, Vitest, Testing Library

***

## 1. Session Overview

This session implements the browser audio runtime and controls for the full web cockpit. The work focuses on the currently shipped synthetic Web Audio barks, because Phase 04 has not approved any file-backed full app voice, SFX, alert, celebration, or music assets for runtime use.

The session turns audio from an always-on preference into an explicit opt-in experience with availability, blocked, muted, failed, and unavailable states. It keeps audio nonessential by preserving visible battlefield state, captions, settings status, and toast feedback as the source of truth when audio is muted, blocked by browser policy, unsupported, or unavailable.

The implementation stays inside `apps/web`. It does not copy audio from `EXAMPLES/`, promote draft provider outputs, add public-demo media, or create a hosted audio path. File-backed audio remains blocked until later Phase 04 gates approve source, rights, attribution, metadata, loudness, duration, fallback, accessibility, privacy, and byte-budget evidence.

***

## 2. Objectives

1. Make full app audio opt-in by default and persist bounded audio settings with storage recovery for stale or malformed snapshots.
2. Add a browser audio runtime boundary that reports unsupported, locked, unlocked, playing, blocked, failed, muted, and unavailable states without exposing sensitive data.
3. Wire existing synthetic voice barks through duplicate-trigger guards, cleanup-safe Web Audio helpers, visible equivalents, and explicit failure handling.
4. Update settings, hero speak, command palette, tests, and docs so audio is understandable without sound and file-backed assets remain blocked.

***

## 3. Prerequisites

### Required Sessions

* [x] `phase04-session01-media-requirements-and-provenance-baseline` - provides media matrix rows M04-014 through M04-017 and the audio release blocker model.
* [x] `phase04-session02-typed-media-catalog-contracts` - provides app media catalog records and blocked draft audio records.
* [x] `phase04-session03-draft-asset-generation-and-source-capture` - provides deferred and planned audio draft manifest records without runtime outputs.
* [x] `phase04-session04-visual-promotion-tooling-and-budgets` - provides the promotion-gate precedent and confirms current full app file-backed audio is not approved for runtime promotion.

### Required Tools/Knowledge

* Node 20+ and npm workspaces.
* React 18 component patterns in `apps/web/src/components/`.
* Zustand persistence patterns in `apps/web/src/store/useSettingsStore.ts`.
* Existing synthetic Web Audio helpers in `apps/web/src/lib/voiceSynth.ts`.
* Media catalog records in `apps/web/src/data/mediaCatalog.ts`.

### Environment Requirements

* Run commands from the repository root.
* No provider credentials are required.
* No network, hosted service, public-demo, or `EXAMPLES/` media access is required.

***

## 4. Scope

### In Scope (MVP)

* Users can enable or disable web cockpit audio explicitly - default audio to off for new settings snapshots and preserve valid prior user choices.
* Users can understand audio availability and browser unlock status - expose muted, unsupported, locked, unlocked, playing, blocked, failed, and unavailable copy in settings and action feedback.
* Users can trigger current synthetic faction barks safely - route hero state transitions and the hero speak action through cleanup-safe helpers and duplicate-trigger prevention.
* Users can adjust scoped audio behavior - add a bounded volume or intensity control and persist it with validation.
* Maintainers can verify no file-backed audio was promoted - keep draft audio catalog records blocked and document that full app media files are deferred.
* Maintainers can test muted, opt-in, blocked, unsupported, duplicate, failed, and cleanup states with focused Vitest and component coverage.

### Out of Scope (Deferred)

* Copying, transforming, or playing quarantined `EXAMPLES/` audio - *Reason: direct promotion is prohibited by the Phase 04 matrix.*
* Adding full app file-backed voice lines, SFX, alerts, celebration clips, or music - *Reason: no approved runtime audio files, loudness pass, metadata evidence, or byte budget exists.*
* Public demo speech, music, service worker cache, or offline audio changes - *Reason: Session 06 owns public demo media parity and offline loading.*
* Provider generation, voice selection, cost approval, or rights review - *Reason: Session 03 deferred generation and this session is runtime control only.*
* Release-wide accessibility, privacy, and performance certification - *Reason: Session 07 owns final media gates.*

***

## 5. Technical Approach

### Architecture

Add a small browser audio runtime boundary in `apps/web/src/lib/` that wraps the existing Web Audio synth helpers and reports stable result objects instead of silent no-ops. The runtime should check support, unlock state, enabled settings, volume, duplicate triggers, and playback failures before attempting audio.

Persist durable user preferences in `useSettingsStore`: audio opt-in, bounded volume or intensity, and recovery from malformed snapshots. Keep transient runtime status outside durable storage so browser policy failures, in-flight test cues, and last-cue captions do not pollute persisted settings.

Update `useVoiceBarks`, `SettingsDrawer`, `HeroDetailDrawer`, and command palette labels so every audio path has a visible equivalent. The existing screen state remains authoritative; audio is only an optional cue layered on top of visible state, captions, button status, and toast feedback.

### Design Patterns

* Explicit runtime result union: callers handle muted, unsupported, locked, blocked, failed, and played states.
* Durable preference versus transient runtime state: persisted settings remain small and recoverable.
* Boundary-first browser APIs: Web Audio access is isolated in helpers that are easy to mock in tests.
* Duplicate-trigger prevention: state-transition and test-cue paths cannot stack rapid audio while a cue is in flight.
* Catalog-first deferral: file-backed audio stays blocked until later gates approve runtime media records.

### Technology Stack

* TypeScript and React 18 in `apps/web`.
* Zustand for persisted preferences and transient runtime state.
* Web Audio API for current synthetic barks.
* Existing `howler` dependency remains unused unless later approved file-backed assets require it.
* Vitest, happy-dom, and Testing Library for focused coverage.

***

## 6. Deliverables

### Files to Create

| File                                         | Purpose                                                                                                    | Est. Lines |
| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/lib/audioRuntime.ts`           | Audio runtime result types, support checks, caption copy, duplicate guard helpers, and safe play wrappers. | \~220      |
| `apps/web/src/store/useAudioRuntimeStore.ts` | Transient browser audio status, last cue, blocked/failed state, and action helpers.                        | \~140      |
| `apps/web/tests/audioRuntime.test.ts`        | Unit tests for runtime result mapping, support checks, duplicate guards, and redacted failure copy.        | \~170      |
| `apps/web/tests/SettingsAudio.test.tsx`      | Component tests for audio settings controls, volume, status, test cue, and reset behavior.                 | \~180      |

### Files to Modify

| File                                           | Changes                                                                                                         | Est. Lines |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/lib/voiceSynth.ts`               | Return structured play/unlock results, add cleanup-safe node handling, and expose testable support state.       | \~90       |
| `apps/web/src/store/useSettingsStore.ts`       | Default audio to opt-in, add bounded audio volume or intensity, normalize stale snapshots, and persist updates. | \~70       |
| `apps/web/src/store/useVoiceBarks.ts`          | Route hero transition barks through the runtime with duplicate-trigger prevention and cleanup on unsubscribe.   | \~80       |
| `apps/web/src/components/SettingsDrawer.tsx`   | Replace the simple audio toggle with status, volume, test cue, visible fallback, and disabled-state copy.       | \~120      |
| `apps/web/src/components/HeroDetailDrawer.tsx` | Route Speak through the runtime, expose visible result copy, and prevent duplicate clicks while pending.        | \~60       |
| `apps/web/src/components/CommandPalette.tsx`   | Pass updated audio setting state and labels into command catalog.                                               | \~20       |
| `apps/web/src/lib/commandPalette.ts`           | Rename audio commands around opt-in audio cues and keep settings deep links accurate.                           | \~40       |
| `apps/web/src/data/mediaCatalog.ts`            | Keep file-backed audio records blocked and document the synthetic runtime boundary for Session 05.              | \~60       |
| `apps/web/tests/useSettingsStore.test.ts`      | Update persistence and recovery coverage for default-off audio and bounded volume.                              | \~70       |
| `apps/web/tests/HeroDetailDrawer.test.tsx`     | Update Speak tests for runtime results, disabled reasons, and duplicate protection.                             | \~80       |
| `apps/web/tests/CommandPalette.test.tsx`       | Update audio command labels and action expectations.                                                            | \~40       |
| `apps/web/README_web.md`                       | Document opt-in audio controls, visible equivalents, and file-backed media deferral.                            | \~50       |
| `docs/media-assets.md`                         | Document Session 05 browser audio behavior and blocked file-backed asset policy.                                | \~70       |

***

## 7. Success Criteria

### Functional Requirements

* [ ] New settings snapshots default full app audio to off unless the user explicitly enables it.
* [ ] Valid previously persisted audio choices continue to hydrate, while malformed audio settings fall back to safe defaults.
* [ ] Settings exposes audio enabled state, bounded volume or intensity, current browser audio status, test cue behavior, and clear unsupported/blocked copy.
* [ ] Hero state-transition barks and hero Speak use duplicate-trigger prevention while in flight and never play when muted, unsupported, blocked, or unavailable.
* [ ] Visible UI state, captions, button copy, and toasts remain sufficient when audio is muted, blocked, failed, or unavailable.
* [ ] File-backed audio, music, SFX, alert, and celebration assets remain blocked in catalog and docs until later gates approve them.

### Testing Requirements

* [ ] Unit tests cover audio runtime result mapping and duplicate guards.
* [ ] Settings store tests cover default opt-in, persistence, malformed snapshots, reset, and bounded volume.
* [ ] Component tests cover settings audio controls and hero Speak behavior.
* [ ] Focused web tests and typecheck pass.

### Non-Functional Requirements

* [ ] Audio runtime never logs secrets, provider payloads, raw prompts, broad local paths, or stack traces.
* [ ] Browser audio code cleans up timers, subscriptions, and Web Audio nodes on scope exit or cue completion.
* [ ] Audio remains local-first and requires no network, provider credentials, hosted service, analytics, or public-demo dependency.

### Quality Gates

* [ ] All files ASCII-encoded.
* [ ] Unix LF line endings.
* [ ] Code follows project conventions.
* [ ] `npm --workspace apps/web run typecheck`, focused tests, and relevant media gates pass or have documented blockers.

***

## 8. Implementation Notes

### Key Considerations

* `audioEnabled` currently defaults to `true`; Session 05 should make new users explicitly opt in while preserving valid stored preferences.
* Current `playBark` silently no-ops on unsupported or suspended audio; callers need structured results to show visible fallback copy.
* No full app file-backed audio record is approved. Current Session 05 runtime should use the synthetic Web Audio bark path only.
* Existing media catalog draft audio records are planned or deferred and must not become runtime paths in this session.

### Potential Challenges

* Browser AudioContext behavior differs across environments: isolate support and unlock checks behind testable helpers.
* Component tests run in happy-dom without real Web Audio: provide injectable runtime seams or stable mocks instead of relying on browser APIs.
* Changing the default audio setting affects existing tests: update tests to assert explicit opt-in rather than accidental default playback.

### Relevant Considerations

* \[P00] **Asset provenance gate**: No file-backed audio can ship without source, rights, attribution, optimization, metadata, size, and fallback review.
* \[P03] **Redaction is boundary-specific**: Audio runtime errors and settings feedback must avoid raw provider data, local paths, prompts, and stack details.
* \[P02-apps/web] **Responsive and accessibility debt**: Settings controls, captions, status copy, and focus behavior must remain accessible on desktop and mobile.
* \[P03] **Local-first boundary is architectural**: Audio must work or degrade without hosted accounts, provider credentials, analytics, or network access.

### Behavioral Quality Focus

Checklist active: Yes Top behavioral risks for this session:

* Audio plays before explicit opt-in or before browser gesture unlock.
* Rapid hero transitions or test clicks stack overlapping cues.
* Muted, unsupported, blocked, or failed audio leaves the user without a visible equivalent.

***

## 9. Testing Strategy

### Unit Tests

* Test audio runtime support, locked/unlocked, muted, unsupported, failed, and played result mapping.
* Test duplicate-trigger guards and cleanup of in-flight cue state.
* Test settings normalization for invalid booleans, invalid volume, partial snapshots, and reset defaults.

### Integration Tests

* Test SettingsDrawer audio controls, status text, volume control, test cue, reset behavior, and toast feedback.
* Test HeroDetailDrawer Speak behavior for enabled, muted, failed, blocked, and duplicate-trigger states.
* Test command palette audio command labels and state changes.

### Manual Testing

* Open settings, enable audio, trigger the test cue after a user gesture, mute audio, and verify visible status and no playback.
* Select a hero and use Speak while enabled and muted.
* Trigger hero state changes and confirm visible state remains sufficient when audio is unavailable.

### Edge Cases

* Browser has no AudioContext.
* AudioContext remains suspended or resume rejects.
* LocalStorage contains stale audio fields.
* User toggles audio or volume while a cue is in flight.
* Component unmounts during an active cue.

***

## 10. Dependencies

### External Libraries

* React 18.3.1.
* Zustand 4.5.4.
* Existing `howler` dependency remains available but should not be used for file-backed playback until approved audio assets exist.
* Browser Web Audio API.

### Other Sessions

* **Depends on**: `phase04-session01-media-requirements-and-provenance-baseline`, `phase04-session02-typed-media-catalog-contracts`, `phase04-session03-draft-asset-generation-and-source-capture`, `phase04-session04-visual-promotion-tooling-and-budgets`.
* **Depended by**: `phase04-session06-public-demo-media-parity-and-offline-loading`, `phase04-session07-media-accessibility-privacy-and-performance-gates`, `phase04-session08-media-validation-and-documentation-closeout`.

***

## Next Steps

Run the implement workflow step to begin AI-led implementation.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://faction-os.gitbook.io/faction-os-docs/.spec_system/archive/sessions/phase04-session05-browser-audio-runtime-and-controls/spec.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
