Files
2026-05-27 23:29:53 +01:00

3.9 KiB

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.