@nodetool-ai/game-renderer 0.8.1 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/README.md +46 -0
  2. package/dist/.nodetool-build-stamp +1 -1
  3. package/dist/audio/mixer.d.ts +75 -0
  4. package/dist/audio/mixer.d.ts.map +1 -0
  5. package/dist/audio/mixer.js +345 -0
  6. package/dist/audio/mixer.js.map +1 -0
  7. package/dist/audio/player.d.ts +67 -0
  8. package/dist/audio/player.d.ts.map +1 -0
  9. package/dist/audio/player.js +337 -0
  10. package/dist/audio/player.js.map +1 -0
  11. package/dist/audio/spatial.d.ts +50 -0
  12. package/dist/audio/spatial.d.ts.map +1 -0
  13. package/dist/audio/spatial.js +166 -0
  14. package/dist/audio/spatial.js.map +1 -0
  15. package/dist/audio/voices.d.ts +11 -0
  16. package/dist/audio/voices.d.ts.map +1 -0
  17. package/dist/audio/voices.js +22 -0
  18. package/dist/audio/voices.js.map +1 -0
  19. package/dist/audio.d.ts +6 -38
  20. package/dist/audio.d.ts.map +1 -1
  21. package/dist/audio.js +3 -226
  22. package/dist/audio.js.map +1 -1
  23. package/dist/browser.d.ts +2 -1
  24. package/dist/browser.d.ts.map +1 -1
  25. package/dist/browser.js +5 -5
  26. package/dist/browser.js.map +1 -1
  27. package/dist/browser3d.d.ts +2 -0
  28. package/dist/browser3d.d.ts.map +1 -0
  29. package/dist/browser3d.js +2 -0
  30. package/dist/browser3d.js.map +1 -0
  31. package/dist/build-tauri.d.ts +69 -0
  32. package/dist/build-tauri.d.ts.map +1 -0
  33. package/dist/build-tauri.js +406 -0
  34. package/dist/build-tauri.js.map +1 -0
  35. package/dist/build.d.ts.map +1 -1
  36. package/dist/build.js +29 -19
  37. package/dist/build.js.map +1 -1
  38. package/dist/build3d.d.ts +11 -0
  39. package/dist/build3d.d.ts.map +1 -0
  40. package/dist/build3d.js +126 -0
  41. package/dist/build3d.js.map +1 -0
  42. package/dist/canvas2d.d.ts +12 -3
  43. package/dist/canvas2d.d.ts.map +1 -1
  44. package/dist/canvas2d.js +59 -12
  45. package/dist/canvas2d.js.map +1 -1
  46. package/dist/fixed-tick-host.d.ts +10 -0
  47. package/dist/fixed-tick-host.d.ts.map +1 -0
  48. package/dist/fixed-tick-host.js +29 -0
  49. package/dist/fixed-tick-host.js.map +1 -0
  50. package/dist/frame-budget.d.ts +34 -0
  51. package/dist/frame-budget.d.ts.map +1 -0
  52. package/dist/frame-budget.js +52 -0
  53. package/dist/frame-budget.js.map +1 -0
  54. package/dist/frame.d.ts +20 -1
  55. package/dist/frame.d.ts.map +1 -1
  56. package/dist/frame.js +69 -1
  57. package/dist/frame.js.map +1 -1
  58. package/dist/game3d-capture-page.js +5834 -0
  59. package/dist/game3d-player.js +6001 -0
  60. package/dist/imageDiff.d.ts +9 -0
  61. package/dist/imageDiff.d.ts.map +1 -0
  62. package/dist/imageDiff.js +30 -0
  63. package/dist/imageDiff.js.map +1 -0
  64. package/dist/index.d.ts +12 -1
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +9 -0
  67. package/dist/index.js.map +1 -1
  68. package/dist/input-bindings.d.ts +76 -0
  69. package/dist/input-bindings.d.ts.map +1 -0
  70. package/dist/input-bindings.js +377 -0
  71. package/dist/input-bindings.js.map +1 -0
  72. package/dist/input.d.ts +1 -1
  73. package/dist/input.d.ts.map +1 -1
  74. package/dist/input.js +1 -14
  75. package/dist/input.js.map +1 -1
  76. package/dist/input3d.d.ts +3 -0
  77. package/dist/input3d.d.ts.map +1 -0
  78. package/dist/input3d.js +3 -0
  79. package/dist/input3d.js.map +1 -0
  80. package/dist/node.d.ts +5 -0
  81. package/dist/node.d.ts.map +1 -1
  82. package/dist/node.js +28 -11
  83. package/dist/node.js.map +1 -1
  84. package/dist/node3d.d.ts +29 -0
  85. package/dist/node3d.d.ts.map +1 -0
  86. package/dist/node3d.js +160 -0
  87. package/dist/node3d.js.map +1 -0
  88. package/dist/particles/curves.d.ts +16 -0
  89. package/dist/particles/curves.d.ts.map +1 -0
  90. package/dist/particles/curves.js +49 -0
  91. package/dist/particles/curves.js.map +1 -0
  92. package/dist/particles/index.d.ts +6 -0
  93. package/dist/particles/index.d.ts.map +1 -0
  94. package/dist/particles/index.js +6 -0
  95. package/dist/particles/index.js.map +1 -0
  96. package/dist/particles/random.d.ts +10 -0
  97. package/dist/particles/random.d.ts.map +1 -0
  98. package/dist/particles/random.js +26 -0
  99. package/dist/particles/random.js.map +1 -0
  100. package/dist/particles/render2d.d.ts +40 -0
  101. package/dist/particles/render2d.d.ts.map +1 -0
  102. package/dist/particles/render2d.js +70 -0
  103. package/dist/particles/render2d.js.map +1 -0
  104. package/dist/particles/shapes.d.ts +18 -0
  105. package/dist/particles/shapes.d.ts.map +1 -0
  106. package/dist/particles/shapes.js +92 -0
  107. package/dist/particles/shapes.js.map +1 -0
  108. package/dist/particles/simulator.d.ts +88 -0
  109. package/dist/particles/simulator.d.ts.map +1 -0
  110. package/dist/particles/simulator.js +371 -0
  111. package/dist/particles/simulator.js.map +1 -0
  112. package/dist/player-v1.js +2502 -0
  113. package/dist/preparation3d.d.ts +3 -0
  114. package/dist/preparation3d.d.ts.map +1 -0
  115. package/dist/preparation3d.js +3 -0
  116. package/dist/preparation3d.js.map +1 -0
  117. package/dist/renderPipeline.d.ts +12 -0
  118. package/dist/renderPipeline.d.ts.map +1 -0
  119. package/dist/renderPipeline.js +17 -0
  120. package/dist/renderPipeline.js.map +1 -0
  121. package/dist/renderer3d/animation/index.d.ts +11 -0
  122. package/dist/renderer3d/animation/index.d.ts.map +1 -0
  123. package/dist/renderer3d/animation/index.js +212 -0
  124. package/dist/renderer3d/animation/index.js.map +1 -0
  125. package/dist/renderer3d/assets/cache.d.ts +14 -0
  126. package/dist/renderer3d/assets/cache.d.ts.map +1 -0
  127. package/dist/renderer3d/assets/cache.js +74 -0
  128. package/dist/renderer3d/assets/cache.js.map +1 -0
  129. package/dist/renderer3d/assets/dispose.d.ts +4 -0
  130. package/dist/renderer3d/assets/dispose.d.ts.map +1 -0
  131. package/dist/renderer3d/assets/dispose.js +41 -0
  132. package/dist/renderer3d/assets/dispose.js.map +1 -0
  133. package/dist/renderer3d/assets/hdri-contract.d.ts +23 -0
  134. package/dist/renderer3d/assets/hdri-contract.d.ts.map +1 -0
  135. package/dist/renderer3d/assets/hdri-contract.js +2 -0
  136. package/dist/renderer3d/assets/hdri-contract.js.map +1 -0
  137. package/dist/renderer3d/assets/instances.d.ts +5 -0
  138. package/dist/renderer3d/assets/instances.d.ts.map +1 -0
  139. package/dist/renderer3d/assets/instances.js +86 -0
  140. package/dist/renderer3d/assets/instances.js.map +1 -0
  141. package/dist/renderer3d/capture-driver-types.d.ts +42 -0
  142. package/dist/renderer3d/capture-driver-types.d.ts.map +1 -0
  143. package/dist/renderer3d/capture-driver-types.js +2 -0
  144. package/dist/renderer3d/capture-driver-types.js.map +1 -0
  145. package/dist/renderer3d/capture-page.d.ts +36 -0
  146. package/dist/renderer3d/capture-page.d.ts.map +1 -0
  147. package/dist/renderer3d/capture-page.js +68 -0
  148. package/dist/renderer3d/capture-page.js.map +1 -0
  149. package/dist/renderer3d/culling.d.ts +10 -0
  150. package/dist/renderer3d/culling.d.ts.map +1 -0
  151. package/dist/renderer3d/culling.js +27 -0
  152. package/dist/renderer3d/culling.js.map +1 -0
  153. package/dist/renderer3d/environment/index.d.ts +4 -0
  154. package/dist/renderer3d/environment/index.d.ts.map +1 -0
  155. package/dist/renderer3d/environment/index.js +9 -0
  156. package/dist/renderer3d/environment/index.js.map +1 -0
  157. package/dist/renderer3d/environment/sky.d.ts +45 -0
  158. package/dist/renderer3d/environment/sky.d.ts.map +1 -0
  159. package/dist/renderer3d/environment/sky.js +221 -0
  160. package/dist/renderer3d/environment/sky.js.map +1 -0
  161. package/dist/renderer3d/hud/fonts.d.ts +13 -0
  162. package/dist/renderer3d/hud/fonts.d.ts.map +1 -0
  163. package/dist/renderer3d/hud/fonts.js +69 -0
  164. package/dist/renderer3d/hud/fonts.js.map +1 -0
  165. package/dist/renderer3d/hud/paint.d.ts +4 -0
  166. package/dist/renderer3d/hud/paint.d.ts.map +1 -0
  167. package/dist/renderer3d/hud/paint.js +22 -0
  168. package/dist/renderer3d/hud/paint.js.map +1 -0
  169. package/dist/renderer3d/import.d.ts +34 -0
  170. package/dist/renderer3d/import.d.ts.map +1 -0
  171. package/dist/renderer3d/import.js +408 -0
  172. package/dist/renderer3d/import.js.map +1 -0
  173. package/dist/renderer3d/index.d.ts +74 -0
  174. package/dist/renderer3d/index.d.ts.map +1 -0
  175. package/dist/renderer3d/index.js +338 -0
  176. package/dist/renderer3d/index.js.map +1 -0
  177. package/dist/renderer3d/lights/index.d.ts +7 -0
  178. package/dist/renderer3d/lights/index.d.ts.map +1 -0
  179. package/dist/renderer3d/lights/index.js +67 -0
  180. package/dist/renderer3d/lights/index.js.map +1 -0
  181. package/dist/renderer3d/materials/index.d.ts +4 -0
  182. package/dist/renderer3d/materials/index.d.ts.map +1 -0
  183. package/dist/renderer3d/materials/index.js +8 -0
  184. package/dist/renderer3d/materials/index.js.map +1 -0
  185. package/dist/renderer3d/passes/post-processing.d.ts +44 -0
  186. package/dist/renderer3d/passes/post-processing.d.ts.map +1 -0
  187. package/dist/renderer3d/passes/post-processing.js +213 -0
  188. package/dist/renderer3d/passes/post-processing.js.map +1 -0
  189. package/dist/renderer3d/pipeline.d.ts +15 -0
  190. package/dist/renderer3d/pipeline.d.ts.map +1 -0
  191. package/dist/renderer3d/pipeline.js +10 -0
  192. package/dist/renderer3d/pipeline.js.map +1 -0
  193. package/dist/renderer3d/playwright-contract.d.ts +3 -0
  194. package/dist/renderer3d/playwright-contract.d.ts.map +1 -0
  195. package/dist/renderer3d/playwright-contract.js +4 -0
  196. package/dist/renderer3d/playwright-contract.js.map +1 -0
  197. package/dist/renderer3d/preparation.d.ts +79 -0
  198. package/dist/renderer3d/preparation.d.ts.map +1 -0
  199. package/dist/renderer3d/preparation.js +458 -0
  200. package/dist/renderer3d/preparation.js.map +1 -0
  201. package/dist/renderer3d/scene-sync.d.ts +8 -0
  202. package/dist/renderer3d/scene-sync.d.ts.map +1 -0
  203. package/dist/renderer3d/scene-sync.js +96 -0
  204. package/dist/renderer3d/scene-sync.js.map +1 -0
  205. package/dist/renderer3d/shadows/cascades.d.ts +40 -0
  206. package/dist/renderer3d/shadows/cascades.d.ts.map +1 -0
  207. package/dist/renderer3d/shadows/cascades.js +244 -0
  208. package/dist/renderer3d/shadows/cascades.js.map +1 -0
  209. package/dist/renderer3d/shadows/index.d.ts +44 -0
  210. package/dist/renderer3d/shadows/index.d.ts.map +1 -0
  211. package/dist/renderer3d/shadows/index.js +129 -0
  212. package/dist/renderer3d/shadows/index.js.map +1 -0
  213. package/dist/renderer3d/types.d.ts +18 -0
  214. package/dist/renderer3d/types.d.ts.map +1 -0
  215. package/dist/renderer3d/types.js +2 -0
  216. package/dist/renderer3d/types.js.map +1 -0
  217. package/dist/smoke.d.ts +15 -0
  218. package/dist/smoke.d.ts.map +1 -0
  219. package/dist/smoke.js +138 -0
  220. package/dist/smoke.js.map +1 -0
  221. package/dist/standalone-player.d.ts +11 -1
  222. package/dist/standalone-player.d.ts.map +1 -1
  223. package/dist/standalone-player.js +67 -41
  224. package/dist/standalone-player.js.map +1 -1
  225. package/dist/standalone-player3d.d.ts +14 -0
  226. package/dist/standalone-player3d.d.ts.map +1 -0
  227. package/dist/standalone-player3d.js +255 -0
  228. package/dist/standalone-player3d.js.map +1 -0
  229. package/dist/touch-controls.d.ts +22 -8
  230. package/dist/touch-controls.d.ts.map +1 -1
  231. package/dist/touch-controls.js +88 -21
  232. package/dist/touch-controls.js.map +1 -1
  233. package/dist/ui/controller.d.ts +59 -0
  234. package/dist/ui/controller.d.ts.map +1 -0
  235. package/dist/ui/controller.js +201 -0
  236. package/dist/ui/controller.js.map +1 -0
  237. package/dist/ui/hud2d.d.ts +11 -0
  238. package/dist/ui/hud2d.d.ts.map +1 -0
  239. package/dist/ui/hud2d.js +25 -0
  240. package/dist/ui/hud2d.js.map +1 -0
  241. package/dist/ui/layout.d.ts +42 -0
  242. package/dist/ui/layout.d.ts.map +1 -0
  243. package/dist/ui/layout.js +182 -0
  244. package/dist/ui/layout.js.map +1 -0
  245. package/dist/ui/paint.d.ts +45 -0
  246. package/dist/ui/paint.d.ts.map +1 -0
  247. package/dist/ui/paint.js +121 -0
  248. package/dist/ui/paint.js.map +1 -0
  249. package/dist/webgpu/effects.d.ts +22 -0
  250. package/dist/webgpu/effects.d.ts.map +1 -0
  251. package/dist/webgpu/effects.js +69 -0
  252. package/dist/webgpu/effects.js.map +1 -0
  253. package/dist/webgpu/hud.d.ts +4 -0
  254. package/dist/webgpu/hud.d.ts.map +1 -0
  255. package/dist/webgpu/hud.js +27 -0
  256. package/dist/webgpu/hud.js.map +1 -0
  257. package/dist/webgpu/lighting.d.ts +4 -0
  258. package/dist/webgpu/lighting.d.ts.map +1 -0
  259. package/dist/webgpu/lighting.js +47 -0
  260. package/dist/webgpu/lighting.js.map +1 -0
  261. package/dist/webgpu/pipeline.d.ts +11 -0
  262. package/dist/webgpu/pipeline.d.ts.map +1 -0
  263. package/dist/webgpu/pipeline.js +11 -0
  264. package/dist/webgpu/pipeline.js.map +1 -0
  265. package/dist/webgpu/sprites.d.ts +6 -0
  266. package/dist/webgpu/sprites.d.ts.map +1 -0
  267. package/dist/webgpu/sprites.js +74 -0
  268. package/dist/webgpu/sprites.js.map +1 -0
  269. package/dist/webgpu/types.d.ts +14 -0
  270. package/dist/webgpu/types.d.ts.map +1 -0
  271. package/dist/webgpu/types.js +2 -0
  272. package/dist/webgpu/types.js.map +1 -0
  273. package/dist/webgpu.d.ts +4 -3
  274. package/dist/webgpu.d.ts.map +1 -1
  275. package/dist/webgpu.js +119 -279
  276. package/dist/webgpu.js.map +1 -1
  277. package/package.json +52 -10
package/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # Native game rendering and export
2
+
3
+ Legacy games keep their WebGPU and Canvas 2D renderers. Import the 3D browser
4
+ renderer from `@nodetool-ai/game-renderer/browser3d`, capture from `node3d`, and
5
+ static export from `build3d`. The package's default entry does not import Three.js
6
+ or Rapier. A 3D player requires WebGL2 and reports capability failures explicitly.
7
+
8
+ Model import normalizes owned GLB or glTF input and its declared dependencies
9
+ into self-contained GLB bytes. Preparation rejects remote runtime dependencies,
10
+ unsupported required extensions, malformed geometry and over-budget resources.
11
+ Bindings record a digest, stable node and clip selectors, bounds and import
12
+ settings. Use meters, Y up and forward `-Z` after preparation. Primitive or convex
13
+ colliders belong to gameplay definitions. A model hierarchy cannot add scripts
14
+ or physics components.
15
+
16
+ Each instance owns its skeleton and animation mixer. Cosmetic clip sampling
17
+ uses the committed tick, which permits pause, rewind, restore and capture without
18
+ wall-clock drift. Geometry and textures share immutable caches. Renderer disposal
19
+ releases model instances, GPU resources and outstanding loads. Context loss
20
+ pauses the host before rebuilding rendering resources.
21
+
22
+ Captures run the same Three.js renderer in Chromium with a closed set of staged
23
+ bytes, cancellation and bounded time. Reports include the committed state hash,
24
+ capabilities, render statistics and projected entity bounds. Capture needs a
25
+ Playwright runtime and installed Chromium. Desktop packaging stages Playwright
26
+ and the capture bundle. The server profile intentionally omits browser automation
27
+ and reports unavailable capture capability.
28
+
29
+ Static export validates every asset digest and stages files atomically before
30
+ returning the output directory. It includes the game document, pinned runtime
31
+ code, QuickJS WASM, models, colliders, audio and fonts. Serve it over static HTTP
32
+ for browser module and WASM loading. Use HTTPS or loopback HTTP because asset
33
+ verification requires Web Crypto. The export needs no provider credentials.
34
+
35
+ Run `npm run test --workspace=packages/game-renderer` for model preparation,
36
+ skinning, animation sampling, shadows, lifecycle, capture and offline replay.
37
+ Hardware frame-rate targets in the [3D design](../../docs/plans/native-game-3d-upgrade.md)
38
+ remain separate from software-rendered correctness fixtures.
39
+
40
+ Run `npm run verify:electron3d --workspace=packages/game-renderer` after building
41
+ packages to render the registered capture bundle in the installed Electron
42
+ binary. It writes a PNG and backend/load statistics under
43
+ `nodetool-game3d-electron` in the operating system's temporary directory. The
44
+ Chromium lifecycle test writes `game3d-renderer-spike.json` in that directory's
45
+ parent. Both commands honor `TMPDIR` and report the tested resolution and GPU.
46
+ Their software-rendered timings do not establish the hardware target.
@@ -1 +1 @@
1
- 2026-09-28T09:19:04.696Z
1
+ 2026-10-12T12:30:00.497Z
@@ -0,0 +1,75 @@
1
+ import { type GameAudioMixerInput, type GameEvent, type GameEvent3D } from "@nodetool-ai/protocol";
2
+ /** The values a bus is moving to: the base settings with the active mixer snapshot applied. */
3
+ export interface GameAudioBusState {
4
+ readonly parent: string | null;
5
+ readonly volume: number;
6
+ readonly muted: boolean;
7
+ readonly lowpassHz: number | null;
8
+ readonly reverbSend: number;
9
+ readonly userVolume: number;
10
+ readonly userMuted: boolean;
11
+ readonly duckGain: number;
12
+ readonly activeVoices: number;
13
+ }
14
+ export interface GameAudioMixerState {
15
+ readonly snapshot: string;
16
+ readonly buses: Readonly<Record<string, GameAudioBusState>>;
17
+ }
18
+ /**
19
+ * The game's bus graph: voices feed a bus input, buses feed their parent, and master feeds the limiter.
20
+ * Mixer state is presentation only. It reads simulation events and never writes back to a session.
21
+ */
22
+ export declare class GameAudioMixer {
23
+ private readonly context;
24
+ private readonly tickRate;
25
+ private settings;
26
+ private readonly buses;
27
+ private readonly activeVoices;
28
+ private readonly limiter;
29
+ private readonly makeup;
30
+ private readonly makeupParam;
31
+ private reverb;
32
+ private snapshotId;
33
+ private sceneId;
34
+ private readonly destination;
35
+ private readonly clock;
36
+ /**
37
+ * `options.clock` returns the context time at which mixer changes are scheduled. It defaults to the context's current time.
38
+ * Offline renders pass a clock to schedule changes at chosen render times.
39
+ */
40
+ constructor(context: BaseAudioContext, settings: GameAudioMixerInput | undefined, tickRate: number, options?: {
41
+ readonly destination?: AudioNode;
42
+ readonly clock?: () => number;
43
+ });
44
+ /** Replaces the mixer settings. Values jump to the new mix; the active snapshot stays when it still exists. */
45
+ update(settings: GameAudioMixerInput | undefined): void;
46
+ /** The node a voice on `busId` connects to. Unknown buses play on sfx. */
47
+ input(busId: string): AudioNode;
48
+ /** The bus for a voice of an asset slot: the author's assignment, else music for scene music and sfx for everything else. */
49
+ busFor(assetSlot: string, music: boolean): string;
50
+ voiceStarted(busId: string): void;
51
+ voiceEnded(busId: string): void;
52
+ /** Reads a simulation event and moves to the snapshot its transition rule names. */
53
+ observe(event: GameEvent | GameEvent3D): void;
54
+ /** Applies the scene's transition rule when the scene changes. */
55
+ enterScene(sceneId: string): void;
56
+ /** Returns to the base mix, or the scene's snapshot, without fading. Used when a session restarts or restores. */
57
+ reset(sceneId: string): void;
58
+ /** Moves to a mixer snapshot over `fadeTicks`. */
59
+ transition(snapshotId: string, fadeTicks: number): void;
60
+ /** Player-facing volume, for example from a settings screen. Multiplies the authored fader. */
61
+ setUserVolume(busId: string, volume: number): void;
62
+ setUserMuted(busId: string, muted: boolean): void;
63
+ state(): GameAudioMixerState;
64
+ dispose(): void;
65
+ private bus;
66
+ private openLowpass;
67
+ private values;
68
+ private needsReverb;
69
+ /** Builds missing buses, wires parents, and moves every parameter to the current mix over `seconds`. */
70
+ private apply;
71
+ private applyBus;
72
+ private voicesOnBranch;
73
+ private applyDucking;
74
+ }
75
+ //# sourceMappingURL=mixer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mixer.d.ts","sourceRoot":"","sources":["../../src/audio/mixer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,345 @@
1
+ import { GAME_AUDIO_BASE_SNAPSHOT, GAME_AUDIO_BUILTIN_BUSES, gameAudioMixer } from "@nodetool-ai/protocol";
2
+ const OPEN_LOWPASS_HZ = 20000;
3
+ const LIMITER_RATIO = 20;
4
+ const BUTTERWORTH_Q_DB = 20 * Math.log10(Math.SQRT1_2);
5
+ /** An AudioParam whose scheduled ramp is tracked so a new ramp can start from the exact current value. */
6
+ class TrackedParam {
7
+ param;
8
+ from;
9
+ to;
10
+ start = 0;
11
+ end = 0;
12
+ curve = "linear";
13
+ constructor(param, value, now) {
14
+ this.param = param;
15
+ this.from = value;
16
+ this.to = value;
17
+ param.setValueAtTime(value, now);
18
+ }
19
+ get target() { return this.to; }
20
+ valueAt(time) {
21
+ if (time >= this.end || this.end <= this.start) {
22
+ return this.to;
23
+ }
24
+ if (time <= this.start) {
25
+ return this.from;
26
+ }
27
+ const progress = (time - this.start) / (this.end - this.start);
28
+ return this.curve === "exponential" ? this.from * (this.to / this.from) ** progress : this.from + (this.to - this.from) * progress;
29
+ }
30
+ rampTo(value, now, seconds, curve = "linear") {
31
+ if (value === this.to && now >= this.end) {
32
+ return;
33
+ }
34
+ const current = this.valueAt(now);
35
+ this.param.cancelScheduledValues(now);
36
+ this.param.setValueAtTime(current, now);
37
+ if (seconds > 0 && current !== value) {
38
+ if (curve === "exponential") {
39
+ this.param.exponentialRampToValueAtTime(value, now + seconds);
40
+ }
41
+ else {
42
+ this.param.linearRampToValueAtTime(value, now + seconds);
43
+ }
44
+ }
45
+ else {
46
+ this.param.setValueAtTime(value, now);
47
+ }
48
+ this.from = current;
49
+ this.to = value;
50
+ this.start = now;
51
+ this.end = seconds > 0 ? now + seconds : now;
52
+ this.curve = curve;
53
+ }
54
+ }
55
+ /** Deterministic noise so every player builds the same impulse response. */
56
+ function impulseResponse(context, decaySeconds) {
57
+ const length = Math.max(1, Math.round(decaySeconds * context.sampleRate));
58
+ const buffer = context.createBuffer(2, length, context.sampleRate);
59
+ let seed = 0x9e3779b9;
60
+ for (let channel = 0; channel < buffer.numberOfChannels; channel++) {
61
+ const data = buffer.getChannelData(channel);
62
+ for (let index = 0; index < length; index++) {
63
+ seed = (seed + 0x6d2b79f5) >>> 0;
64
+ let mixed = Math.imul(seed ^ (seed >>> 15), seed | 1);
65
+ mixed ^= mixed + Math.imul(mixed ^ (mixed >>> 7), mixed | 61);
66
+ const noise = (((mixed ^ (mixed >>> 14)) >>> 0) / 0xffffffff) * 2 - 1;
67
+ data[index] = noise * Math.exp(-6.9 * index / length);
68
+ }
69
+ }
70
+ return buffer;
71
+ }
72
+ /**
73
+ * The game's bus graph: voices feed a bus input, buses feed their parent, and master feeds the limiter.
74
+ * Mixer state is presentation only. It reads simulation events and never writes back to a session.
75
+ */
76
+ export class GameAudioMixer {
77
+ context;
78
+ tickRate;
79
+ settings;
80
+ buses = new Map();
81
+ activeVoices = new Map();
82
+ limiter;
83
+ makeup;
84
+ makeupParam;
85
+ reverb = null;
86
+ snapshotId = GAME_AUDIO_BASE_SNAPSHOT;
87
+ sceneId = null;
88
+ destination;
89
+ clock;
90
+ /**
91
+ * `options.clock` returns the context time at which mixer changes are scheduled. It defaults to the context's current time.
92
+ * Offline renders pass a clock to schedule changes at chosen render times.
93
+ */
94
+ constructor(context, settings, tickRate, options = {}) {
95
+ this.context = context;
96
+ this.tickRate = tickRate;
97
+ this.destination = options.destination ?? context.destination;
98
+ this.clock = options.clock ?? (() => context.currentTime);
99
+ this.settings = gameAudioMixer.parse(settings ?? {});
100
+ const now = this.clock();
101
+ this.limiter = context.createDynamicsCompressor();
102
+ this.limiter.knee.value = 0;
103
+ this.limiter.ratio.value = LIMITER_RATIO;
104
+ this.limiter.attack.value = 0.003;
105
+ this.limiter.release.value = 0.1;
106
+ this.makeup = context.createGain();
107
+ this.makeupParam = new TrackedParam(this.makeup.gain, 1, now);
108
+ this.limiter.connect(this.makeup).connect(this.destination);
109
+ this.apply(0, true);
110
+ }
111
+ /** Replaces the mixer settings. Values jump to the new mix; the active snapshot stays when it still exists. */
112
+ update(settings) {
113
+ this.settings = gameAudioMixer.parse(settings ?? {});
114
+ if (this.snapshotId !== GAME_AUDIO_BASE_SNAPSHOT && !(this.snapshotId in this.settings.snapshots)) {
115
+ this.snapshotId = GAME_AUDIO_BASE_SNAPSHOT;
116
+ }
117
+ this.apply(0, true);
118
+ }
119
+ /** The node a voice on `busId` connects to. Unknown buses play on sfx. */
120
+ input(busId) {
121
+ return (this.buses.get(busId) ?? this.bus("sfx")).input;
122
+ }
123
+ /** The bus for a voice of an asset slot: the author's assignment, else music for scene music and sfx for everything else. */
124
+ busFor(assetSlot, music) {
125
+ const assigned = this.settings.assetBuses[assetSlot];
126
+ if (assigned !== undefined && this.buses.has(assigned)) {
127
+ return assigned;
128
+ }
129
+ return music ? "music" : "sfx";
130
+ }
131
+ voiceStarted(busId) {
132
+ const id = this.buses.has(busId) ? busId : "sfx";
133
+ this.activeVoices.set(id, (this.activeVoices.get(id) ?? 0) + 1);
134
+ this.applyDucking();
135
+ }
136
+ voiceEnded(busId) {
137
+ const id = this.buses.has(busId) ? busId : "sfx";
138
+ const count = (this.activeVoices.get(id) ?? 0) - 1;
139
+ if (count > 0) {
140
+ this.activeVoices.set(id, count);
141
+ }
142
+ else {
143
+ this.activeVoices.delete(id);
144
+ }
145
+ this.applyDucking();
146
+ }
147
+ /** Reads a simulation event and moves to the snapshot its transition rule names. */
148
+ observe(event) {
149
+ for (const transition of this.settings.transitions) {
150
+ const on = transition.on;
151
+ if ((on.kind === "trigger" && event.kind === "trigger" && event.event === on.event) ||
152
+ (on.kind === "win" && event.kind === "win")) {
153
+ this.transition(transition.snapshot, transition.fadeTicks);
154
+ }
155
+ }
156
+ }
157
+ /** Applies the scene's transition rule when the scene changes. */
158
+ enterScene(sceneId) {
159
+ if (this.sceneId === sceneId) {
160
+ return;
161
+ }
162
+ this.sceneId = sceneId;
163
+ const rule = this.settings.transitions.find((transition) => transition.on.kind === "scene" && transition.on.sceneId === sceneId);
164
+ if (rule) {
165
+ this.transition(rule.snapshot, rule.fadeTicks);
166
+ }
167
+ }
168
+ /** Returns to the base mix, or the scene's snapshot, without fading. Used when a session restarts or restores. */
169
+ reset(sceneId) {
170
+ const rule = this.settings.transitions.find((transition) => transition.on.kind === "scene" && transition.on.sceneId === sceneId);
171
+ this.sceneId = sceneId;
172
+ this.snapshotId = rule?.snapshot ?? GAME_AUDIO_BASE_SNAPSHOT;
173
+ this.apply(0, false);
174
+ }
175
+ /** Moves to a mixer snapshot over `fadeTicks`. */
176
+ transition(snapshotId, fadeTicks) {
177
+ if (snapshotId !== GAME_AUDIO_BASE_SNAPSHOT && !(snapshotId in this.settings.snapshots)) {
178
+ return;
179
+ }
180
+ if (snapshotId === this.snapshotId) {
181
+ return;
182
+ }
183
+ this.snapshotId = snapshotId;
184
+ this.apply(fadeTicks / this.tickRate, false);
185
+ }
186
+ /** Player-facing volume, for example from a settings screen. Multiplies the authored fader. */
187
+ setUserVolume(busId, volume) {
188
+ const bus = this.buses.get(busId);
189
+ if (!bus || !Number.isFinite(volume)) {
190
+ return;
191
+ }
192
+ bus.userVolume = Math.min(2, Math.max(0, volume));
193
+ this.applyBus(bus, 0);
194
+ }
195
+ setUserMuted(busId, muted) {
196
+ const bus = this.buses.get(busId);
197
+ if (!bus) {
198
+ return;
199
+ }
200
+ bus.userMuted = muted;
201
+ this.applyBus(bus, 0);
202
+ }
203
+ state() {
204
+ const buses = {};
205
+ for (const bus of this.buses.values()) {
206
+ const values = this.values(bus.id);
207
+ buses[bus.id] = { parent: bus.parent, volume: values.volume, muted: values.muted, lowpassHz: values.lowpassHz ?? null,
208
+ reverbSend: values.reverbSend, userVolume: bus.userVolume, userMuted: bus.userMuted, duckGain: bus.duckParam.target,
209
+ activeVoices: this.activeVoices.get(bus.id) ?? 0 };
210
+ }
211
+ return { snapshot: this.snapshotId, buses };
212
+ }
213
+ dispose() {
214
+ for (const bus of this.buses.values()) {
215
+ for (const node of [bus.input, bus.filter, bus.fader, bus.duck, bus.send]) {
216
+ node.disconnect();
217
+ }
218
+ }
219
+ this.buses.clear();
220
+ this.reverb?.convolver.disconnect();
221
+ this.reverb?.output.disconnect();
222
+ this.limiter.disconnect();
223
+ this.makeup.disconnect();
224
+ }
225
+ bus(id) {
226
+ const existing = this.buses.get(id);
227
+ if (existing) {
228
+ return existing;
229
+ }
230
+ const now = this.clock();
231
+ const input = this.context.createGain();
232
+ const filter = this.context.createBiquadFilter();
233
+ const fader = this.context.createGain();
234
+ const duck = this.context.createGain();
235
+ const send = this.context.createGain();
236
+ filter.type = "lowpass";
237
+ filter.Q.setValueAtTime(BUTTERWORTH_Q_DB, now);
238
+ input.connect(filter).connect(fader).connect(duck);
239
+ const bus = { id, input, filter, fader, duck, send, parent: null, userVolume: 1, userMuted: false,
240
+ faderParam: new TrackedParam(fader.gain, 1, now), filterParam: new TrackedParam(filter.frequency, this.openLowpass(), now),
241
+ duckParam: new TrackedParam(duck.gain, 1, now), sendParam: new TrackedParam(send.gain, 0, now) };
242
+ this.buses.set(id, bus);
243
+ return bus;
244
+ }
245
+ openLowpass() { return Math.min(OPEN_LOWPASS_HZ, this.context.sampleRate / 2); }
246
+ values(id) {
247
+ const base = this.settings.buses[id] ?? { volume: 1, muted: false, reverbSend: 0 };
248
+ const override = this.snapshotId === GAME_AUDIO_BASE_SNAPSHOT ? undefined : this.settings.snapshots[this.snapshotId]?.buses[id];
249
+ return { volume: override?.volume ?? base.volume, muted: override?.muted ?? base.muted,
250
+ lowpassHz: override?.lowpassHz ?? base.lowpassHz, reverbSend: override?.reverbSend ?? base.reverbSend };
251
+ }
252
+ needsReverb() {
253
+ return Object.values(this.settings.buses).some((bus) => bus.reverbSend > 0) ||
254
+ Object.values(this.settings.snapshots).some((snapshot) => Object.values(snapshot.buses).some((bus) => (bus.reverbSend ?? 0) > 0));
255
+ }
256
+ /** Builds missing buses, wires parents, and moves every parameter to the current mix over `seconds`. */
257
+ apply(seconds, rewire) {
258
+ const ids = [...GAME_AUDIO_BUILTIN_BUSES, ...Object.keys(this.settings.buses)];
259
+ for (const id of ids) {
260
+ this.bus(id);
261
+ }
262
+ if (rewire) {
263
+ const decaySeconds = this.settings.reverb.decaySeconds;
264
+ if (this.needsReverb() && (!this.reverb || this.reverb.decaySeconds !== decaySeconds)) {
265
+ this.reverb?.convolver.disconnect();
266
+ this.reverb?.output.disconnect();
267
+ const convolver = this.context.createConvolver();
268
+ convolver.buffer = impulseResponse(this.context, decaySeconds);
269
+ const output = this.context.createGain();
270
+ convolver.connect(output).connect(this.bus("master").input);
271
+ this.reverb = { convolver, output, decaySeconds };
272
+ }
273
+ for (const bus of this.buses.values()) {
274
+ const parent = bus.id === "master" ? null : this.settings.buses[bus.id]?.parent ?? "master";
275
+ bus.duck.disconnect();
276
+ bus.send.disconnect();
277
+ if (parent === null) {
278
+ bus.duck.connect(this.settings.limiter.enabled ? this.limiter : this.destination);
279
+ }
280
+ else {
281
+ bus.duck.connect(this.bus(parent).input);
282
+ bus.duck.connect(bus.send);
283
+ if (this.reverb) {
284
+ bus.send.connect(this.reverb.convolver);
285
+ }
286
+ }
287
+ bus.parent = parent;
288
+ }
289
+ const now = this.clock();
290
+ const thresholdDb = this.settings.limiter.thresholdDb;
291
+ this.limiter.threshold.value = thresholdDb;
292
+ // Web Audio adds automatic makeup gain of 0.6 times the full-range gain reduction. Undo it so the limiter is transparent below threshold.
293
+ this.makeupParam.rampTo(10 ** (0.6 * thresholdDb * (1 - 1 / LIMITER_RATIO) / 20), now, 0);
294
+ }
295
+ for (const bus of this.buses.values()) {
296
+ this.applyBus(bus, seconds);
297
+ }
298
+ this.applyDucking();
299
+ }
300
+ applyBus(bus, seconds) {
301
+ const now = this.clock();
302
+ const values = this.values(bus.id);
303
+ const silent = values.muted || bus.userMuted;
304
+ bus.faderParam.rampTo(silent ? 0 : values.volume * bus.userVolume, now, seconds);
305
+ bus.filterParam.rampTo(Math.min(values.lowpassHz ?? OPEN_LOWPASS_HZ, this.openLowpass()), now, seconds, "exponential");
306
+ bus.sendParam.rampTo(bus.parent === null ? 0 : values.reverbSend, now, seconds);
307
+ }
308
+ voicesOnBranch(id) {
309
+ let count = 0;
310
+ for (const [busId, voices] of this.activeVoices) {
311
+ let current = busId;
312
+ while (current !== null) {
313
+ if (current === id) {
314
+ count += voices;
315
+ break;
316
+ }
317
+ current = this.buses.get(current)?.parent ?? null;
318
+ }
319
+ }
320
+ return count;
321
+ }
322
+ applyDucking() {
323
+ const now = this.clock();
324
+ const targets = new Map();
325
+ for (const rule of this.settings.ducking) {
326
+ if (!this.buses.has(rule.bus)) {
327
+ continue;
328
+ }
329
+ const active = this.voicesOnBranch(rule.when) > 0;
330
+ const current = targets.get(rule.bus) ?? { gain: 1, attackTicks: rule.attackTicks, releaseTicks: rule.releaseTicks };
331
+ targets.set(rule.bus, active && rule.gain < current.gain ? { ...current, gain: rule.gain, attackTicks: rule.attackTicks } : current);
332
+ }
333
+ for (const bus of this.buses.values()) {
334
+ const target = targets.get(bus.id);
335
+ const gain = target?.gain ?? 1;
336
+ const previous = bus.duckParam.target;
337
+ if (gain === previous) {
338
+ continue;
339
+ }
340
+ const ticks = gain < previous ? target?.attackTicks ?? 0 : target?.releaseTicks ?? 0;
341
+ bus.duckParam.rampTo(gain, now, ticks / this.tickRate);
342
+ }
343
+ }
344
+ }
345
+ //# sourceMappingURL=mixer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mixer.js","sourceRoot":"","sources":["../../src/audio/mixer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import { type GameAssetBinding, type GameAssetBinding3D, type GameAudioMixerInput, type GameEvent, type GameEvent3D, type GameSnapshot } from "@nodetool-ai/protocol";
2
+ import { type GameAudioMixerState } from "./mixer.js";
3
+ import { type GameAudioSpatialQuality, type GameAudioSpatialView } from "./spatial.js";
4
+ export interface GameAudioOptions {
5
+ readonly assets: Readonly<Record<string, GameAssetBinding | GameAssetBinding3D>>;
6
+ readonly tickRate: number;
7
+ readonly resolveAsset: (binding: GameAssetBinding | GameAssetBinding3D) => Promise<string | null>;
8
+ readonly status: (message: string) => void;
9
+ readonly context?: AudioContext;
10
+ /** The document's `audio.mixer`. Omitted means the default bus graph. */
11
+ readonly mixer?: GameAudioMixerInput;
12
+ /** Panning quality for spatial voices. Default `high` (HRTF). */
13
+ readonly spatialQuality?: GameAudioSpatialQuality;
14
+ }
15
+ /** Shares Web Audio voice, decoding, and lifecycle behavior across browser players. */
16
+ export declare class GameAudioPlayer {
17
+ private options;
18
+ private readonly context;
19
+ private readonly mixer;
20
+ private readonly buffers;
21
+ private readonly voices;
22
+ private readonly fading;
23
+ private readonly pending;
24
+ private readonly voiceAssets;
25
+ private readonly spatialVoices;
26
+ private view;
27
+ private listenerSample;
28
+ private listenerVelocity;
29
+ private desiredMusic;
30
+ private sceneId;
31
+ private tick;
32
+ private generation;
33
+ private legacySequence;
34
+ private disposed;
35
+ private paused;
36
+ constructor(options: GameAudioOptions);
37
+ private mixerSettings;
38
+ /** Applies edited mixer settings. Playing voices keep playing on their buses. */
39
+ updateMixer(settings: GameAudioMixerInput | undefined): void;
40
+ /** Player-facing bus volume, for example from a settings screen. */
41
+ setBusVolume(busId: string, volume: number): void;
42
+ setBusMuted(busId: string, muted: boolean): void;
43
+ mixerState(): GameAudioMixerState;
44
+ private buffer;
45
+ /** Keeps decoded audio for unchanged bindings when the editor document changes. */
46
+ updateAssets(assets: GameAudioOptions["assets"]): void;
47
+ preload(): void;
48
+ unlock(): Promise<void>;
49
+ pause(): void;
50
+ resume(): void;
51
+ sync(snapshot: Pick<GameSnapshot, "tick" | "music" | "sceneId">): void;
52
+ private startDesiredMusic;
53
+ /**
54
+ * Moves the listener and every spatial voice to a rendered frame. Players call it once per rendered frame with the view
55
+ * built from the interpolated frame, so positions follow what is on screen. Emitters missing from the view keep their last position.
56
+ */
57
+ updateSpatial(view: GameAudioSpatialView): void;
58
+ /** Creates the panner for a voice and connects it to the bus. The voice connects to the returned node. */
59
+ private spatialOutput;
60
+ /** Plays audio events and lets other simulation events drive mixer snapshot transitions. */
61
+ handle(event: GameEvent | GameEvent3D): void;
62
+ private start;
63
+ private stop;
64
+ reset(snapshot: Pick<GameSnapshot, "tick" | "music" | "sceneId">): void;
65
+ dispose(): void;
66
+ }
67
+ //# sourceMappingURL=player.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"player.d.ts","sourceRoot":"","sources":["../../src/audio/player.ts"],"names":[],"mappings":"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"}