@sadhaka/loom-engine 0.13.0 → 0.15.0

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 (89) hide show
  1. package/dist/audio/audio-asset-cache.d.ts +12 -0
  2. package/dist/audio/audio-asset-cache.d.ts.map +1 -0
  3. package/dist/audio/audio-asset-cache.js +53 -0
  4. package/dist/audio/audio-asset-cache.js.map +1 -0
  5. package/dist/audio/audio-asset-loader.d.ts +16 -0
  6. package/dist/audio/audio-asset-loader.d.ts.map +1 -0
  7. package/dist/audio/audio-asset-loader.js +100 -0
  8. package/dist/audio/audio-asset-loader.js.map +1 -0
  9. package/dist/audio/audio-listener-resource.d.ts +19 -0
  10. package/dist/audio/audio-listener-resource.d.ts.map +1 -0
  11. package/dist/audio/audio-listener-resource.js +57 -0
  12. package/dist/audio/audio-listener-resource.js.map +1 -0
  13. package/dist/audio/cue-catalog.d.ts +39 -0
  14. package/dist/audio/cue-catalog.d.ts.map +1 -0
  15. package/dist/audio/cue-catalog.js +186 -0
  16. package/dist/audio/cue-catalog.js.map +1 -0
  17. package/dist/audio/music-director.d.ts +18 -0
  18. package/dist/audio/music-director.d.ts.map +1 -0
  19. package/dist/audio/music-director.js +177 -0
  20. package/dist/audio/music-director.js.map +1 -0
  21. package/dist/audio/spatial-audio-bus.d.ts +66 -0
  22. package/dist/audio/spatial-audio-bus.d.ts.map +1 -0
  23. package/dist/audio/spatial-audio-bus.js +341 -0
  24. package/dist/audio/spatial-audio-bus.js.map +1 -0
  25. package/dist/audio/spatial-audio-system.d.ts +17 -0
  26. package/dist/audio/spatial-audio-system.d.ts.map +1 -0
  27. package/dist/audio/spatial-audio-system.js +98 -0
  28. package/dist/audio/spatial-audio-system.js.map +1 -0
  29. package/dist/audio/zone-audio-system.d.ts +78 -0
  30. package/dist/audio/zone-audio-system.d.ts.map +1 -0
  31. package/dist/audio/zone-audio-system.js +206 -0
  32. package/dist/audio/zone-audio-system.js.map +1 -0
  33. package/dist/director/ai/ai-plugin-registry.d.ts +20 -0
  34. package/dist/director/ai/ai-plugin-registry.d.ts.map +1 -0
  35. package/dist/director/ai/ai-plugin-registry.js +232 -0
  36. package/dist/director/ai/ai-plugin-registry.js.map +1 -0
  37. package/dist/director/ai/mock-ai-plugin.d.ts +24 -0
  38. package/dist/director/ai/mock-ai-plugin.d.ts.map +1 -0
  39. package/dist/director/ai/mock-ai-plugin.js +83 -0
  40. package/dist/director/ai/mock-ai-plugin.js.map +1 -0
  41. package/dist/director/ai/plugin-context.d.ts +27 -0
  42. package/dist/director/ai/plugin-context.d.ts.map +1 -0
  43. package/dist/director/ai/plugin-context.js +152 -0
  44. package/dist/director/ai/plugin-context.js.map +1 -0
  45. package/dist/director/ai/plugin.d.ts +57 -0
  46. package/dist/director/ai/plugin.d.ts.map +1 -0
  47. package/dist/director/ai/plugin.js +32 -0
  48. package/dist/director/ai/plugin.js.map +1 -0
  49. package/dist/director/index.d.ts +27 -0
  50. package/dist/director/index.d.ts.map +1 -0
  51. package/dist/director/index.js +26 -0
  52. package/dist/director/index.js.map +1 -0
  53. package/dist/director/zone/mock-zone-bridge.d.ts +22 -0
  54. package/dist/director/zone/mock-zone-bridge.d.ts.map +1 -0
  55. package/dist/director/zone/mock-zone-bridge.js +107 -0
  56. package/dist/director/zone/mock-zone-bridge.js.map +1 -0
  57. package/dist/director/zone/sse-zone-bridge.d.ts +40 -0
  58. package/dist/director/zone/sse-zone-bridge.d.ts.map +1 -0
  59. package/dist/director/zone/sse-zone-bridge.js +164 -0
  60. package/dist/director/zone/sse-zone-bridge.js.map +1 -0
  61. package/dist/director/zone/zone-event-bridge.d.ts +21 -0
  62. package/dist/director/zone/zone-event-bridge.d.ts.map +1 -0
  63. package/dist/director/zone/zone-event-bridge.js +24 -0
  64. package/dist/director/zone/zone-event-bridge.js.map +1 -0
  65. package/dist/director/zone/zone-event-envelope.d.ts +90 -0
  66. package/dist/director/zone/zone-event-envelope.d.ts.map +1 -0
  67. package/dist/director/zone/zone-event-envelope.js +104 -0
  68. package/dist/director/zone/zone-event-envelope.js.map +1 -0
  69. package/dist/director/zone/zone-event-log.d.ts +17 -0
  70. package/dist/director/zone/zone-event-log.d.ts.map +1 -0
  71. package/dist/director/zone/zone-event-log.js +46 -0
  72. package/dist/director/zone/zone-event-log.js.map +1 -0
  73. package/dist/director/zone/zone-event-system.d.ts +14 -0
  74. package/dist/director/zone/zone-event-system.d.ts.map +1 -0
  75. package/dist/director/zone/zone-event-system.js +179 -0
  76. package/dist/director/zone/zone-event-system.js.map +1 -0
  77. package/dist/director/zone/zone-state-resource.d.ts +15 -0
  78. package/dist/director/zone/zone-state-resource.d.ts.map +1 -0
  79. package/dist/director/zone/zone-state-resource.js +60 -0
  80. package/dist/director/zone/zone-state-resource.js.map +1 -0
  81. package/dist/index.d.ts +27 -1
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +23 -1
  84. package/dist/index.js.map +1 -1
  85. package/dist/server/index.d.ts +7 -0
  86. package/dist/server/index.d.ts.map +1 -0
  87. package/dist/server/index.js +33 -0
  88. package/dist/server/index.js.map +1 -0
  89. package/package.json +6 -2
@@ -0,0 +1,12 @@
1
+ export declare class AudioAssetCache {
2
+ private buffers;
3
+ get(name: string): AudioBuffer | null;
4
+ has(name: string): boolean;
5
+ set(name: string, buffer: AudioBuffer): void;
6
+ drop(name: string): void;
7
+ clear(): void;
8
+ list(): ReadonlyArray<string>;
9
+ }
10
+ export declare const RESOURCE_AUDIO_ASSET_CACHE = "audio_asset_cache";
11
+ export declare function createAudioAssetCache(): AudioAssetCache;
12
+ //# sourceMappingURL=audio-asset-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-asset-cache.d.ts","sourceRoot":"","sources":["../../src/audio/audio-asset-cache.ts"],"names":[],"mappings":"AAYA,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAuC;IAGtD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAMrC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAO1B,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI;IAO5C,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,aAAa,CAAC,MAAM,CAAC;CAG9B;AAKD,eAAO,MAAM,0BAA0B,sBAAsB,CAAC;AAI9D,wBAAgB,qBAAqB,IAAI,eAAe,CAEvD"}
@@ -0,0 +1,53 @@
1
+ // AudioAssetCache - in-memory store of decoded AudioBuffers keyed by name.
2
+ //
3
+ // Per LOOM-AUDIO-SPEC §4.1. The cache is a thin Map<string, AudioBuffer>
4
+ // wrapper. AudioAssetLoader writes into it; CueCatalog and MusicDirector
5
+ // read from it. Lifetime is the AudioContext's lifetime; clear() is the
6
+ // hard reset for tests / scene transitions.
7
+ //
8
+ // Naming: callers choose name on load(). Defaults to URL basename without
9
+ // extension when omitted (the loader handles that derivation; the cache
10
+ // just stores whatever name it's handed). Re-loading the same name
11
+ // overwrites silently.
12
+ export class AudioAssetCache {
13
+ buffers = new Map();
14
+ // Get a previously-loaded buffer. Returns null if not in the cache.
15
+ get(name) {
16
+ return this.buffers.get(name) ?? null;
17
+ }
18
+ // True once a buffer has been placed under name (via the loader's
19
+ // store path; tests can also call set directly through factory init).
20
+ has(name) {
21
+ return this.buffers.has(name);
22
+ }
23
+ // Internal entry point used by AudioAssetLoader after decode resolves.
24
+ // Exposed publicly so consumers can pre-seed buffers from another
25
+ // source (synthesized OfflineAudioContext output, for instance).
26
+ set(name, buffer) {
27
+ this.buffers.set(name, buffer);
28
+ }
29
+ // Remove a single asset. Future get() returns null. The buffer object
30
+ // is GC'd if no live source still references it (any AudioBufferSource
31
+ // already started keeps a reference until it ends).
32
+ drop(name) {
33
+ this.buffers.delete(name);
34
+ }
35
+ // Clear the whole cache. Useful for tests + scene-boundary teardown.
36
+ clear() {
37
+ this.buffers.clear();
38
+ }
39
+ // Active entry names (for debug + tests).
40
+ list() {
41
+ return Array.from(this.buffers.keys());
42
+ }
43
+ }
44
+ // Resource key for the world's resource registry. Engine consumers
45
+ // register an AudioAssetCache instance under this key alongside
46
+ // RESOURCE_AUDIO_BUS so cues + music can resolve named assets.
47
+ export const RESOURCE_AUDIO_ASSET_CACHE = 'audio_asset_cache';
48
+ // Factory mirrors createTimeResource / createVeilBudgetResource so
49
+ // engine.create wiring is uniform.
50
+ export function createAudioAssetCache() {
51
+ return new AudioAssetCache();
52
+ }
53
+ //# sourceMappingURL=audio-asset-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-asset-cache.js","sourceRoot":"","sources":["../../src/audio/audio-asset-cache.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,EAAE;AACF,yEAAyE;AACzE,yEAAyE;AACzE,wEAAwE;AACxE,4CAA4C;AAC5C,EAAE;AACF,0EAA0E;AAC1E,wEAAwE;AACxE,mEAAmE;AACnE,uBAAuB;AAEvB,MAAM,OAAO,eAAe;IAClB,OAAO,GAA6B,IAAI,GAAG,EAAE,CAAC;IAEtD,oEAAoE;IACpE,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;IACxC,CAAC;IAED,kEAAkE;IAClE,sEAAsE;IACtE,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,uEAAuE;IACvE,kEAAkE;IAClE,iEAAiE;IACjE,GAAG,CAAC,IAAY,EAAE,MAAmB;QACnC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACjC,CAAC;IAED,sEAAsE;IACtE,uEAAuE;IACvE,oDAAoD;IACpD,IAAI,CAAC,IAAY;QACf,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,qEAAqE;IACrE,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,0CAA0C;IAC1C,IAAI;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;CACF;AAED,mEAAmE;AACnE,gEAAgE;AAChE,+DAA+D;AAC/D,MAAM,CAAC,MAAM,0BAA0B,GAAG,mBAAmB,CAAC;AAE9D,mEAAmE;AACnE,mCAAmC;AACnC,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAI,eAAe,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { AudioBus } from './audio-bus.js';
2
+ import type { AudioAssetCache } from './audio-asset-cache.js';
3
+ export interface AudioAssetManifest {
4
+ [name: string]: string;
5
+ }
6
+ export declare class AudioAssetLoader {
7
+ private audioBus;
8
+ private cache;
9
+ private inflight;
10
+ private constructor();
11
+ static create(audioBus: AudioBus, cache: AudioAssetCache): AudioAssetLoader;
12
+ load(url: string, name?: string): Promise<AudioBuffer>;
13
+ preload(manifest: AudioAssetManifest): Promise<void>;
14
+ inflightCount(): number;
15
+ }
16
+ //# sourceMappingURL=audio-asset-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-asset-loader.d.ts","sourceRoot":"","sources":["../../src/audio/audio-asset-loader.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,WAAW,kBAAkB;IAEjC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB;AAyBD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,QAAQ,CAAa;IAE7B,OAAO;IAKP,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,GAAG,gBAAgB;IAQrE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IA6BtD,OAAO,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAe1D,aAAa,IAAI,MAAM;CAGxB"}
@@ -0,0 +1,100 @@
1
+ // AudioAssetLoader - URL fetch + decode pipeline for audio assets.
2
+ //
3
+ // Per LOOM-AUDIO-SPEC §4.1. Two responsibilities:
4
+ // 1. fetch a URL via the Fetch API, decode the response into an
5
+ // AudioBuffer through audioBus.ctx.decodeAudioData, and store it
6
+ // in the AudioAssetCache under a caller-chosen name (or the URL
7
+ // basename without extension if name omitted).
8
+ // 2. preload a manifest of {name -> URL} entries, resolving once all
9
+ // load. Reject on the first load failure (consumer can wrap in
10
+ // Promise.allSettled if they want partial success).
11
+ //
12
+ // Failure semantics: if fetch or decode rejects, the cache is NOT
13
+ // touched - prior values under the same name survive a failed reload.
14
+ // Inflight counter increments on fetch start and decrements after the
15
+ // decode resolves OR rejects (regardless of cache write outcome) so a
16
+ // "still loading" UI can drive off it without sticking on errors.
17
+ // Derive a fallback asset name from a URL. Strips the query string and
18
+ // fragment, keeps the last path segment, then drops a trailing
19
+ // extension (.mp3, .ogg, .wav, .aac, .opus, etc.). Returns the URL as-is
20
+ // if no segments or no recognizable extension boundary - the cache will
21
+ // still accept any string as a key.
22
+ function basenameFromUrl(url) {
23
+ // Strip query + hash.
24
+ var clean = url.split('?')[0].split('#')[0];
25
+ // Take the last path segment.
26
+ var segments = clean.split('/');
27
+ var last = segments[segments.length - 1] ?? clean;
28
+ if (last.length === 0) {
29
+ // Trailing slash; fall back to the whole stripped URL.
30
+ return clean;
31
+ }
32
+ // Drop trailing extension (last dot, if any).
33
+ var dot = last.lastIndexOf('.');
34
+ if (dot > 0) {
35
+ return last.substring(0, dot);
36
+ }
37
+ return last;
38
+ }
39
+ export class AudioAssetLoader {
40
+ audioBus;
41
+ cache;
42
+ inflight = 0;
43
+ constructor(audioBus, cache) {
44
+ this.audioBus = audioBus;
45
+ this.cache = cache;
46
+ }
47
+ static create(audioBus, cache) {
48
+ return new AudioAssetLoader(audioBus, cache);
49
+ }
50
+ // Fetch + decode one URL. On success, stores the decoded AudioBuffer
51
+ // in the cache under `name` (or basename of URL when name is omitted)
52
+ // and returns the buffer. On failure (fetch reject, non-OK status, or
53
+ // decode reject), the promise rejects and the cache is left untouched.
54
+ async load(url, name) {
55
+ var assetName = name !== undefined ? name : basenameFromUrl(url);
56
+ this.inflight++;
57
+ try {
58
+ var response = await fetch(url);
59
+ if (!response.ok) {
60
+ throw new Error('AudioAssetLoader.load: fetch failed for "' + url + '": HTTP ' +
61
+ String(response.status));
62
+ }
63
+ var arrayBuf = await response.arrayBuffer();
64
+ // decodeAudioData returns a Promise in modern browsers (deprecated
65
+ // callback signature still works but Promise is canonical).
66
+ var buffer = await this.audioBus.ctx.decodeAudioData(arrayBuf);
67
+ this.cache.set(assetName, buffer);
68
+ return buffer;
69
+ }
70
+ finally {
71
+ // Always decrement, even on failure - the inflight counter tracks
72
+ // pending operations, not successful outcomes.
73
+ this.inflight--;
74
+ }
75
+ }
76
+ // Bulk preload. Resolves when ALL loads complete; rejects with the
77
+ // first underlying error if any single load rejects. Manifest entries
78
+ // run concurrently (Promise.all). Successfully-loaded entries land in
79
+ // the cache regardless of whether siblings later failed - this matches
80
+ // the "partial success allowed downstream" semantics of fetch+decode.
81
+ async preload(manifest) {
82
+ var entries = Object.keys(manifest);
83
+ if (entries.length === 0)
84
+ return;
85
+ var loads = [];
86
+ for (var i = 0; i < entries.length; i++) {
87
+ var n = entries[i];
88
+ var u = manifest[n];
89
+ loads.push(this.load(u, n));
90
+ }
91
+ await Promise.all(loads);
92
+ }
93
+ // Number of load() calls in flight. Useful for "X assets still
94
+ // loading" UI; not a throttle. Increments on fetch start, decrements
95
+ // when the inner pipeline resolves or rejects.
96
+ inflightCount() {
97
+ return this.inflight;
98
+ }
99
+ }
100
+ //# sourceMappingURL=audio-asset-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-asset-loader.js","sourceRoot":"","sources":["../../src/audio/audio-asset-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { AudioListenerPose } from './spatial-audio-bus.js';
2
+ export type { AudioListenerPose } from './spatial-audio-bus.js';
3
+ export interface AudioListenerResource {
4
+ pose: AudioListenerPose;
5
+ lastUpdateFrame: number;
6
+ }
7
+ export declare const DEFAULT_LISTENER_FORWARD: {
8
+ x: number;
9
+ y: number;
10
+ z: number;
11
+ };
12
+ export declare const DEFAULT_LISTENER_UP: {
13
+ x: number;
14
+ y: number;
15
+ z: number;
16
+ };
17
+ export declare function createAudioListenerResource(): AudioListenerResource;
18
+ export declare const RESOURCE_AUDIO_LISTENER = "audio_listener";
19
+ //# sourceMappingURL=audio-listener-resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-listener-resource.d.ts","sourceRoot":"","sources":["../../src/audio/audio-listener-resource.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAMhE,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,iBAAiB,CAAC;IAGxB,eAAe,EAAE,MAAM,CAAC;CACzB;AAID,eAAO,MAAM,wBAAwB,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAEvE,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAElE,CAAC;AAWF,wBAAgB,2BAA2B,IAAI,qBAAqB,CAWnE;AAKD,eAAO,MAAM,uBAAuB,mBAAmB,CAAC"}
@@ -0,0 +1,57 @@
1
+ // AudioListenerResource - the world's snapshot of where the player is
2
+ // hearing from.
3
+ //
4
+ // SpatialAudioBus.setListener writes the AudioContext.listener
5
+ // directly, but engine consumers also want a queryable resource so a
6
+ // secondary system (minimap, debug HUD, deterministic recording) can
7
+ // read the same pose without round-tripping through the AudioContext
8
+ // (which is synchronous in Web Audio but opaque in Node tests).
9
+ //
10
+ // SpatialAudioSystem (PHASE_RENDER) updates this each tick from the
11
+ // local character's transform and pushes the same pose into
12
+ // SpatialAudioBus.setListener. Renderer code that needs to gate work
13
+ // on "did the listener move this frame?" can compare lastUpdateFrame
14
+ // against the TimeResource frame counter.
15
+ //
16
+ // Default orientation per LOOM-AUDIO-SPEC.md §8.4:
17
+ // forward = (0, 0, -1) - camera looks down -Z (top-down 2D)
18
+ // up = (0, 1, 0)
19
+ // These are fixed in v1; only position changes per frame.
20
+ //
21
+ // Re-exports the AudioListenerPose type from spatial-audio-bus.ts for
22
+ // import convenience so consumers wiring just the resource don't need
23
+ // to pull in the bus module too.
24
+ // Default forward / up vectors per spec §8.4. Exported for tests and
25
+ // for consumers that want to compare against the canonical defaults.
26
+ export const DEFAULT_LISTENER_FORWARD = {
27
+ x: 0, y: 0, z: -1,
28
+ };
29
+ export const DEFAULT_LISTENER_UP = {
30
+ x: 0, y: 1, z: 0,
31
+ };
32
+ // Factory: returns a fresh AudioListenerResource at the world origin
33
+ // with the canonical default orientation. The resource is the same
34
+ // shape used by SpatialAudioBus.setListener, so engine consumers can
35
+ // pipe it straight through:
36
+ // var listener = createAudioListenerResource();
37
+ // spatialBus.setListener(listener.pose);
38
+ //
39
+ // lastUpdateFrame starts at 0 (never updated yet); SpatialAudioSystem
40
+ // stamps it on the first tick.
41
+ export function createAudioListenerResource() {
42
+ return {
43
+ pose: {
44
+ x: 0,
45
+ y: 0,
46
+ z: 0,
47
+ forward: { x: DEFAULT_LISTENER_FORWARD.x, y: DEFAULT_LISTENER_FORWARD.y, z: DEFAULT_LISTENER_FORWARD.z },
48
+ up: { x: DEFAULT_LISTENER_UP.x, y: DEFAULT_LISTENER_UP.y, z: DEFAULT_LISTENER_UP.z },
49
+ },
50
+ lastUpdateFrame: 0,
51
+ };
52
+ }
53
+ // Resource key for the world's resource registry. Engine consumers
54
+ // register an AudioListenerResource under this key; SpatialAudioSystem
55
+ // reads + writes it.
56
+ export const RESOURCE_AUDIO_LISTENER = 'audio_listener';
57
+ //# sourceMappingURL=audio-listener-resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-listener-resource.js","sourceRoot":"","sources":["../../src/audio/audio-listener-resource.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,gBAAgB;AAChB,EAAE;AACF,+DAA+D;AAC/D,qEAAqE;AACrE,qEAAqE;AACrE,qEAAqE;AACrE,gEAAgE;AAChE,EAAE;AACF,oEAAoE;AACpE,4DAA4D;AAC5D,qEAAqE;AACrE,qEAAqE;AACrE,0CAA0C;AAC1C,EAAE;AACF,mDAAmD;AACnD,+DAA+D;AAC/D,wBAAwB;AACxB,0DAA0D;AAC1D,EAAE;AACF,sEAAsE;AACtE,sEAAsE;AACtE,iCAAiC;AAiBjC,qEAAqE;AACrE,qEAAqE;AACrE,MAAM,CAAC,MAAM,wBAAwB,GAAwC;IAC3E,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;CAClB,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAwC;IACtE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;CACjB,CAAC;AAEF,qEAAqE;AACrE,mEAAmE;AACnE,qEAAqE;AACrE,4BAA4B;AAC5B,kDAAkD;AAClD,2CAA2C;AAC3C,EAAE;AACF,sEAAsE;AACtE,+BAA+B;AAC/B,MAAM,UAAU,2BAA2B;IACzC,OAAO;QACL,IAAI,EAAE;YACJ,CAAC,EAAE,CAAC;YACJ,CAAC,EAAE,CAAC;YACJ,CAAC,EAAE,CAAC;YACJ,OAAO,EAAE,EAAE,CAAC,EAAE,wBAAwB,CAAC,CAAC,EAAE,CAAC,EAAE,wBAAwB,CAAC,CAAC,EAAE,CAAC,EAAE,wBAAwB,CAAC,CAAC,EAAE;YACxG,EAAE,EAAE,EAAE,CAAC,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,mBAAmB,CAAC,CAAC,EAAE;SACrF;QACD,eAAe,EAAE,CAAC;KACnB,CAAC;AACJ,CAAC;AAED,mEAAmE;AACnE,uEAAuE;AACvE,qBAAqB;AACrB,MAAM,CAAC,MAAM,uBAAuB,GAAG,gBAAgB,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { AudioBus } from './audio-bus.js';
2
+ import type { AudioAssetCache } from './audio-asset-cache.js';
3
+ import type { PositionalPlayOptions, SpatialAudioBus, SpatialSourceHandle } from './spatial-audio-bus.js';
4
+ export type { PositionalPlayOptions, SpatialAudioBus, SpatialSourceHandle, };
5
+ export interface CueDefinition {
6
+ asset: string;
7
+ bus?: 'sfx' | 'music' | 'voice' | 'ui' | string;
8
+ spatial?: boolean;
9
+ defaults?: Partial<PositionalPlayOptions> & {
10
+ gain?: number;
11
+ rate?: number;
12
+ };
13
+ cooldownMs?: number;
14
+ }
15
+ export type CuePlayOptions = Partial<PositionalPlayOptions> & {
16
+ gain?: number;
17
+ rate?: number;
18
+ x?: number;
19
+ y?: number;
20
+ };
21
+ export declare class CueCatalog {
22
+ private audioBus;
23
+ private spatialBus;
24
+ private cache;
25
+ private cues;
26
+ private cooldowns;
27
+ private liveHandles;
28
+ private constructor();
29
+ static create(audioBus: AudioBus, spatialBus: SpatialAudioBus, cache: AudioAssetCache): CueCatalog;
30
+ register(name: string, def: CueDefinition): void;
31
+ unregister(name: string): void;
32
+ has(name: string): boolean;
33
+ list(): ReadonlyArray<string>;
34
+ play(name: string, options?: CuePlayOptions): SpatialSourceHandle | null;
35
+ stopAll(name: string): void;
36
+ private markPlayed;
37
+ }
38
+ export declare const RESOURCE_CUE_CATALOG = "cue_catalog";
39
+ //# sourceMappingURL=cue-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cue-catalog.d.ts","sourceRoot":"","sources":["../../src/audio/cue-catalog.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EACV,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AAMhC,YAAY,EACV,qBAAqB,EACrB,eAAe,EACf,mBAAmB,GACpB,CAAC;AAEF,MAAM,WAAW,aAAa;IAE5B,KAAK,EAAE,MAAM,CAAC;IAEd,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC;IAIhD,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,QAAQ,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAE7E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,cAAc,GACxB,OAAO,CAAC,qBAAqB,CAAC,GAC5B;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAiB7D,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,IAAI,CAAyC;IACrD,OAAO,CAAC,SAAS,CAAyC;IAG1D,OAAO,CAAC,WAAW,CAAoD;IAEvE,OAAO;IAMP,MAAM,CAAC,MAAM,CACX,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,eAAe,EAC3B,KAAK,EAAE,eAAe,GACrB,UAAU;IAIb,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI;IAOhD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAS9B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,IAAI,IAAI,aAAa,CAAC,MAAM,CAAC;IAQ7B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,mBAAmB,GAAG,IAAI;IA2FxE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAc3B,OAAO,CAAC,UAAU;CAGnB;AAKD,eAAO,MAAM,oBAAoB,gBAAgB,CAAC"}
@@ -0,0 +1,186 @@
1
+ // CueCatalog - named sound events with predefined wiring.
2
+ //
3
+ // Per LOOM-AUDIO-SPEC §4.2. Gameplay code calls cues.play('boss_spawn',
4
+ // {x, y}) and the catalog handles AudioBus / SpatialAudioBus routing,
5
+ // asset lookup, gain/rate defaults, and per-cue cooldowns. Spatial cues
6
+ // route through SpatialAudioBus.playPositional and require x + y in
7
+ // the play options; non-spatial cues route through AudioBus.playOneShot
8
+ // on the named bus (default 'sfx').
9
+ //
10
+ // Cooldown enforcement: each cue tracks its last-play timestamp; play()
11
+ // invocations within cooldownMs of the prior play return null without
12
+ // touching the audio graph. Useful for "boss_hit" so rapid-fire hits
13
+ // don't stack into clipping.
14
+ //
15
+ // stopAll(name): for spatial cues that loop (boss combat ambience), the
16
+ // catalog tracks live SpatialSourceHandles per cue name and exposes
17
+ // stopAll to kill them on a single command (e.g. "boss died, stop the
18
+ // loop"). Non-spatial one-shots are not tracked - they end on their own.
19
+ // Time source. Real implementation uses performance.now(); tests can
20
+ // inject a deterministic clock by overriding this through the public
21
+ // constructor seam later. v1 uses the global clock for simplicity.
22
+ function nowMs() {
23
+ if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
24
+ return performance.now();
25
+ }
26
+ return Date.now();
27
+ }
28
+ export class CueCatalog {
29
+ audioBus;
30
+ spatialBus;
31
+ cache;
32
+ cues = new Map();
33
+ cooldowns = new Map();
34
+ // Live spatial source handles per cue name. Cleared on stopAll(name).
35
+ // Non-spatial one-shots are NOT tracked - they end naturally.
36
+ liveHandles = new Map();
37
+ constructor(audioBus, spatialBus, cache) {
38
+ this.audioBus = audioBus;
39
+ this.spatialBus = spatialBus;
40
+ this.cache = cache;
41
+ }
42
+ static create(audioBus, spatialBus, cache) {
43
+ return new CueCatalog(audioBus, spatialBus, cache);
44
+ }
45
+ register(name, def) {
46
+ this.cues.set(name, def);
47
+ // Re-registering resets cooldown state so a fresh definition starts
48
+ // from a clean slate (avoids stale lastPlay timestamps on overwrite).
49
+ this.cooldowns.set(name, { lastPlayMs: -Infinity });
50
+ }
51
+ unregister(name) {
52
+ this.cues.delete(name);
53
+ this.cooldowns.delete(name);
54
+ // Stop any live handles for this cue so they don't outlive the
55
+ // definition.
56
+ this.stopAll(name);
57
+ this.liveHandles.delete(name);
58
+ }
59
+ has(name) {
60
+ return this.cues.has(name);
61
+ }
62
+ list() {
63
+ return Array.from(this.cues.keys());
64
+ }
65
+ // Play a registered cue. Spatial cues require x + y in options.
66
+ // Returns a handle for spatial cues; null for non-spatial cues, for
67
+ // unknown cues, for cues whose asset is not in the cache, or when
68
+ // cooldown is active.
69
+ play(name, options) {
70
+ var def = this.cues.get(name);
71
+ if (!def)
72
+ return null;
73
+ // Cooldown gate. Suppress play and leave lastPlay untouched if too
74
+ // soon after the prior successful play.
75
+ if (def.cooldownMs !== undefined && def.cooldownMs > 0) {
76
+ var entry = this.cooldowns.get(name) ?? { lastPlayMs: -Infinity };
77
+ var t = nowMs();
78
+ if (t - entry.lastPlayMs < def.cooldownMs) {
79
+ return null;
80
+ }
81
+ }
82
+ // Asset must be in cache.
83
+ var buffer = this.cache.get(def.asset);
84
+ if (!buffer)
85
+ return null;
86
+ // Merge defaults under the explicit options. The intent is "options
87
+ // override defaults"; we copy each key path explicitly for the
88
+ // strict-mode-friendly subset the spec uses.
89
+ var merged = {};
90
+ if (def.defaults) {
91
+ for (var k in def.defaults) {
92
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
93
+ merged[k] = def.defaults[k];
94
+ }
95
+ }
96
+ if (options) {
97
+ for (var k2 in options) {
98
+ var v = options[k2];
99
+ if (v !== undefined) {
100
+ merged[k2] = v;
101
+ }
102
+ }
103
+ }
104
+ var spatial = def.spatial === true;
105
+ if (spatial) {
106
+ if (typeof merged.x !== 'number' || typeof merged.y !== 'number') {
107
+ // Spatial cue requires position. Drop silently rather than throwing -
108
+ // matches "Returns null for ... failure" contract.
109
+ return null;
110
+ }
111
+ // Build a complete PositionalPlayOptions. We carry all merged
112
+ // fields into the spatial bus call.
113
+ var posOpts = {
114
+ x: merged.x,
115
+ y: merged.y,
116
+ };
117
+ if (typeof merged.z === 'number')
118
+ posOpts.z = merged.z;
119
+ if (merged.distanceModel !== undefined)
120
+ posOpts.distanceModel = merged.distanceModel;
121
+ if (typeof merged.refDistance === 'number')
122
+ posOpts.refDistance = merged.refDistance;
123
+ if (typeof merged.maxDistance === 'number')
124
+ posOpts.maxDistance = merged.maxDistance;
125
+ if (typeof merged.rolloffFactor === 'number')
126
+ posOpts.rolloffFactor = merged.rolloffFactor;
127
+ if (typeof merged.gain === 'number')
128
+ posOpts.gain = merged.gain;
129
+ if (typeof merged.rate === 'number')
130
+ posOpts.rate = merged.rate;
131
+ if (typeof merged.loop === 'boolean')
132
+ posOpts.loop = merged.loop;
133
+ var handle = this.spatialBus.playPositional(buffer, posOpts);
134
+ if (!handle)
135
+ return null;
136
+ // Track for stopAll. We DO NOT auto-cleanup non-loop one-shots
137
+ // here - the SpatialAudioBus is the source of truth on lifetime.
138
+ // stopAll is the primary cleanup path; if a cue is a one-shot the
139
+ // tracked handle just becomes a no-op stop later.
140
+ var setForName = this.liveHandles.get(name);
141
+ if (!setForName) {
142
+ setForName = new Set();
143
+ this.liveHandles.set(name, setForName);
144
+ }
145
+ setForName.add(handle);
146
+ this.markPlayed(name);
147
+ return handle;
148
+ }
149
+ // Non-spatial: route through AudioBus.playOneShot on the named bus.
150
+ var busName = def.bus ?? 'sfx';
151
+ var oneShotOpts = {};
152
+ if (typeof merged.rate === 'number')
153
+ oneShotOpts.rate = merged.rate;
154
+ if (typeof merged.gain === 'number')
155
+ oneShotOpts.gain = merged.gain;
156
+ this.audioBus.playOneShot(busName, buffer, oneShotOpts);
157
+ this.markPlayed(name);
158
+ return null;
159
+ }
160
+ // Stop all live spatial sources for this cue. Non-spatial one-shots
161
+ // are not tracked; this is a no-op for cues that have never produced
162
+ // a spatial handle.
163
+ stopAll(name) {
164
+ var setForName = this.liveHandles.get(name);
165
+ if (!setForName)
166
+ return;
167
+ setForName.forEach(function (h) {
168
+ try {
169
+ h.stop();
170
+ }
171
+ catch {
172
+ // Best-effort cleanup; never let a misbehaving handle take down
173
+ // sibling cues.
174
+ }
175
+ });
176
+ setForName.clear();
177
+ }
178
+ markPlayed(name) {
179
+ this.cooldowns.set(name, { lastPlayMs: nowMs() });
180
+ }
181
+ }
182
+ // Resource key for the world's resource registry. Engine consumers
183
+ // register a CueCatalog instance under this key alongside the audio
184
+ // bus + spatial bus + cache.
185
+ export const RESOURCE_CUE_CATALOG = 'cue_catalog';
186
+ //# sourceMappingURL=cue-catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cue-catalog.js","sourceRoot":"","sources":["../../src/audio/cue-catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { AudioBus } from './audio-bus.js';
2
+ import type { AudioAssetCache } from './audio-asset-cache.js';
3
+ export declare class MusicDirector {
4
+ private audioBus;
5
+ private cache;
6
+ private current;
7
+ private constructor();
8
+ static create(audioBus: AudioBus, cache: AudioAssetCache): MusicDirector;
9
+ playMusic(name: string, fadeInMs?: number): void;
10
+ stopMusic(fadeOutMs?: number): Promise<void>;
11
+ crossfadeMusic(name: string, fadeMs?: number): void;
12
+ currentMusic(): string | null;
13
+ private startTrack;
14
+ private fadeOutAndStop;
15
+ private hardStop;
16
+ }
17
+ export declare const RESOURCE_MUSIC_DIRECTOR = "music_director";
18
+ //# sourceMappingURL=music-director.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"music-director.d.ts","sourceRoot":"","sources":["../../src/audio/music-director.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAY9D,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,OAAO,CAA4B;IAE3C,OAAO;IAKP,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,GAAG,aAAa;IAOxE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAgBhD,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa5C,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAwBnD,YAAY,IAAI,MAAM,GAAG,IAAI;IAM7B,OAAO,CAAC,UAAU;IAwBlB,OAAO,CAAC,cAAc;IAoCtB,OAAO,CAAC,QAAQ;CAmBjB;AAKD,eAAO,MAAM,uBAAuB,mBAAmB,CAAC"}