Files
suaveplan/openspec/changes/enterprise-gaming-r3f-audio/tasks.md
2026-05-27 23:29:53 +01:00

78 lines
3.9 KiB
Markdown

# Tasks: enterprise-gaming-r3f-audio
**Change ID**: enterprise-gaming-r3f-audio
**Package**: `@suaveplan/r3f-audio`
**Target path**: `packages/gaming/r3f-audio`
**Prerequisite packages on Verdaccio**: `@suaveplan/audio-plugins-fx`, `@suaveplan/react-audio`, `@suaveplan/audio-transport`, `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/opentelemetry`
---
## 0. Pre-flight (non-negotiable)
- [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each)
- [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
- [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest.
## 1. Scaffold
- [ ] 1.1 Create directory tree per `proposal.md` file layout.
- [ ] 1.2 Write `package.json` at `0.1.0`, `"sideEffects": false`, full `exports` map (`.`, `./components`, `./components/<name>`, `./hooks`, `./hooks/<name>`, `./util`). React + R3F + three as peer deps.
- [ ] 1.3 Write `tsconfig.json`, `vitest.config.ts` (`happy-dom`).
## 2. Error codes
- [ ] 2.1 `src/error-codes.ts` — `defineCodes("R3F_AUDIO", [...])`, `R3fAudioError extends AudioError`.
- [ ] 2.2 `error-codes.test.ts`.
## 3. Util
- [ ] 3.1 `src/util/pose-to-ambient/` — `Vec3`/`Quat` conversions, scratch-vector helpers; no allocation per call.
- [ ] 3.2 `src/util/raycaster-pool/` — shared raycaster instance + per-source scoreboard.
## 4. Hooks
- [ ] 4.1 `use-audio-listener` — binds an `Object3D` ref to `engine.updateAmbient({ listener })` per frame.
- [ ] 4.2 `use-positional-audio` — acquires `SpatialPositionalPlugin`, writes pose per frame, releases on unmount.
- [ ] 4.3 `use-music-layer-weights` — writes `gameState` into `AmbientState.extension.gameState`.
- [ ] 4.4 `use-proximity-voice` — acquires `ProximityVoicePlugin`, attaches stream, writes position per frame.
- [ ] 4.5 `use-occlusion` — runs the raycaster pool against occluders, writes smoothed `occlusionDb`.
## 5. Components (each: `.tsx`, `.md`, `.types.ts`, `.test.tsx`, `.stories.tsx`)
- [ ] 5.1 `audio-listener/` — default target = active camera.
- [ ] 5.2 `positional-audio/`.
- [ ] 5.3 `proximity-voice-chat/`.
- [ ] 5.4 `music-layer-mixer/`.
- [ ] 5.5 `voice-transform/`.
- [ ] 5.6 `occlusion-provider/`.
## 6. OTel
- [ ] 6.1 Register `r3f_audio_active_sources` gauge; wire mount/unmount to its `add`/`subtract`.
## 7. Benchmarks
- [ ] 7.1 `src/__benchmarks__/pose-sync.bench.ts` — 60 fps pose write loop over 1024 sources.
- [ ] 7.2 `src/__benchmarks__/occlusion.bench.ts` — raycast pool over 256 sources against a 5 k-tri scene.
## 8. Integration + purity + bundle-size
- [ ] 8.1 `tests/integration.test.tsx` — full R3F scene + AudioProvider + listener + 4 positional sources + occlusion + music layer mixer; verify ambient state writes land on chain.
- [ ] 8.2 `tests/purity.test.ts` — built `dist/` references no audio context.
- [ ] 8.3 `tests/exports.test.ts` — every surface has subpath export; no `export *` in feature barrels.
- [ ] 8.4 `tests/bundle-size/listener-only.size.test.ts`.
## 9. Docs + verify
- [ ] 9.1 All co-located `.md` files (≥200 words).
- [ ] 9.2 `README.md` at package root.
- [ ] 9.3 `bunx turbo lint typecheck test --filter=@suaveplan/r3f-audio` green.
- [ ] 9.4 `bunx turbo test:coverage --filter=@suaveplan/r3f-audio` 100/100/100/100.
- [ ] 9.5 Banned-pattern + runner-import + file-size + missing-`.md` sweeps empty.
## 10. Spec reconciliation + archive
- [ ] 10.1 Walk every `### Requirement` and `**Verified by:**`.
- [ ] 10.2 Fold spec delta into `openspec/specs/r3f-audio/spec.md`.
- [ ] 10.3 Move change folder to archive.