@skewedaspect/sage 0.9.0-beta.0 → 0.9.0-beta.10

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 (45) hide show
  1. package/dist/behaviors/sound.d.ts +18 -21
  2. package/dist/classes/bindings/toggle.d.ts +7 -4
  3. package/dist/classes/bindings/trigger.d.ts +7 -4
  4. package/dist/classes/bindings/value.d.ts +4 -3
  5. package/dist/classes/entity.d.ts +80 -4
  6. package/dist/classes/gameEngine.d.ts +6 -2
  7. package/dist/classes/gameLevel.d.ts +57 -0
  8. package/dist/classes/level.d.ts +3 -10
  9. package/dist/engines/audio.d.ts +19 -0
  10. package/dist/engines/scene.d.ts +11 -14
  11. package/dist/events/payloads.d.ts +7 -1
  12. package/dist/handlers/collider.d.ts +3 -0
  13. package/dist/handlers/sound.d.ts +1 -0
  14. package/dist/interfaces/action.d.ts +2 -0
  15. package/dist/interfaces/binding.d.ts +19 -4
  16. package/dist/interfaces/game.d.ts +2 -0
  17. package/dist/interfaces/level.d.ts +113 -21
  18. package/dist/managers/audio.d.ts +31 -0
  19. package/dist/managers/binding.d.ts +45 -4
  20. package/dist/managers/entity.d.ts +29 -1
  21. package/dist/managers/level.d.ts +8 -7
  22. package/dist/sage.d.ts +4 -1
  23. package/dist/sage.es.js +1127 -458
  24. package/dist/sage.es.js.map +1 -1
  25. package/dist/sage.umd.js +1 -1
  26. package/dist/sage.umd.js.map +1 -1
  27. package/package.json +14 -5
  28. package/docs/architecture.md +0 -184
  29. package/docs/behaviors.md +0 -1120
  30. package/docs/binding_system.md +0 -792
  31. package/docs/design/input.md +0 -86
  32. package/docs/entity_system.md +0 -1325
  33. package/docs/eventbus.md +0 -406
  34. package/docs/getting_started.md +0 -283
  35. package/docs/images/sage_logo.png +0 -0
  36. package/docs/images/sage_logo_shape.png +0 -0
  37. package/docs/level_system.md +0 -572
  38. package/docs/levels-for-artists.md +0 -561
  39. package/docs/levels.md +0 -688
  40. package/docs/overview.md +0 -56
  41. package/docs/physics_system.md +0 -689
  42. package/docs/scene_system.md +0 -727
  43. package/docs/serialization.md +0 -179
  44. package/docs/timer.md +0 -113
  45. package/docs/vue_composables.md +0 -252
@@ -1,5 +1,6 @@
1
- import { Scene } from '@babylonjs/core';
1
+ import { TransformNode } from '@babylonjs/core';
2
2
  import { GameEntityBehavior } from "../classes/entity.d.ts";
3
+ import { GameEngine } from "../classes/gameEngine.d.ts";
3
4
  import { GameEvent } from "../classes/eventBus.d.ts";
4
5
  /**
5
6
  * Configuration for a single sound.
@@ -17,6 +18,8 @@ export interface SoundConfig {
17
18
  maxDistance?: number;
18
19
  /** Whether to autoplay when registered, default false */
19
20
  autoplay?: boolean;
21
+ /** Audio channel name (e.g., 'sfx', 'music'). Used with AudioManager. */
22
+ channel?: string;
20
23
  }
21
24
  /**
22
25
  * State interface for entities using SoundBehavior.
@@ -30,8 +33,10 @@ export interface SoundEntityState {
30
33
  * Behavior for managing sounds on an entity.
31
34
  *
32
35
  * Sounds are configured in the entity's state under the `sounds` property.
33
- * The behavior creates Sound instances based on the configuration and provides
34
- * runtime control methods.
36
+ * The behavior creates sounds via AudioManager (BabylonJS AudioV2).
37
+ *
38
+ * Requires AudioManager to be configured on the GameEngine. If no AudioManager is found,
39
+ * a warning is logged and no sounds are created.
35
40
  *
36
41
  * @example
37
42
  * ```typescript
@@ -41,8 +46,8 @@ export interface SoundEntityState {
41
46
  * behaviors: [SoundBehavior, ...],
42
47
  * defaultState: {
43
48
  * sounds: {
44
- * jump: { url: 'sounds/jump.mp3', volume: 0.8 },
45
- * footstep: { url: 'sounds/footstep.mp3', loop: true }
49
+ * jump: { url: 'sounds/jump.mp3', volume: 0.8, channel: 'sfx' },
50
+ * footstep: { url: 'sounds/footstep.mp3', loop: true, channel: 'sfx' }
46
51
  * }
47
52
  * }
48
53
  * }
@@ -55,26 +60,18 @@ export interface SoundEntityState {
55
60
  export declare class SoundBehavior extends GameEntityBehavior<SoundEntityState> {
56
61
  name: string;
57
62
  eventSubscriptions: string[];
58
- /** Map of sound name to Sound instance */
63
+ /** Map of sound name to StaticSound instance */
59
64
  private _sounds;
60
- /** Reference to the scene for creating sounds */
61
- private _scene;
62
65
  /** Whether sounds have been initialized */
63
66
  private _initialized;
64
- /**
65
- * Initialize the behavior with a scene reference.
66
- * This creates all Sound instances based on the entity's state.sounds configuration.
67
- *
68
- * @param scene
69
- */
70
- initialize(scene: Scene): void;
71
- /**
72
- * Process events. Override to handle action events that should trigger sounds.
73
- */
67
+ /** AudioManager reference */
68
+ private _audioManager;
69
+ /** Node reference for spatial detach on cleanup */
70
+ private _node;
71
+ private _log;
72
+ onNodeAttached(node: TransformNode, gameEngine: GameEngine): void;
74
73
  processEvent(_event: GameEvent, _state: SoundEntityState): boolean;
75
- /**
76
- * Called when the entity is destroyed.
77
- */
74
+ onReset(_state: SoundEntityState): void;
78
75
  destroy(): Promise<void>;
79
76
  private _createSound;
80
77
  private _disposeSounds;
@@ -1,7 +1,7 @@
1
1
  import { GameEventBus } from "../eventBus.d.ts";
2
2
  import { Action } from "../../interfaces/action.d.ts";
3
3
  import { Binding, ToggleBindingDefinition } from "../../interfaces/binding.d.ts";
4
- import { DeviceValueReader, InputState } from "../../interfaces/input.d.ts";
4
+ import { DeviceType, DeviceValueReader, InputState } from "../../interfaces/input.d.ts";
5
5
  /**
6
6
  * Options for configuring a toggle binding
7
7
  */
@@ -49,6 +49,7 @@ export declare class ToggleBinding implements Binding {
49
49
  readonly action: Action;
50
50
  readonly context?: string;
51
51
  readonly deviceID: string;
52
+ readonly deviceType: DeviceType;
52
53
  readonly reader: DeviceValueReader;
53
54
  private readonly _invert;
54
55
  private readonly _threshold;
@@ -87,10 +88,11 @@ export declare class ToggleBinding implements Binding {
87
88
  *
88
89
  * @param action
89
90
  * @param deviceID
91
+ * @param deviceType
90
92
  * @param reader
91
93
  * @param options
92
94
  */
93
- constructor(action: Action, deviceID: string, reader: DeviceValueReader, options?: ToggleBindingOptions);
95
+ constructor(action: Action, deviceID: string, deviceType: DeviceType, reader: DeviceValueReader, options?: ToggleBindingOptions);
94
96
  /**
95
97
  * Process input state and emit an action event if the toggle flipped.
96
98
  *
@@ -99,9 +101,10 @@ export declare class ToggleBinding implements Binding {
99
101
  */
100
102
  process(state: InputState, eventBus: GameEventBus): void;
101
103
  /**
102
- * Reset edge-detection state so the next input is evaluated from a clean baseline.
104
+ * Reset edge-detection state for a context activation. When a state is provided, primes from the current physical
105
+ * input so that already-held inputs don't produce phantom edges in the newly activated context.
103
106
  */
104
- resetEdgeState(): void;
107
+ resetEdgeState(state?: InputState): void;
105
108
  /**
106
109
  * Reset toggle to its initial state
107
110
  */
@@ -1,7 +1,7 @@
1
1
  import { GameEventBus } from "../eventBus.d.ts";
2
2
  import { Action } from "../../interfaces/action.d.ts";
3
3
  import { Binding, TriggerBindingDefinition } from "../../interfaces/binding.d.ts";
4
- import { DeviceValueReader, InputState } from "../../interfaces/input.d.ts";
4
+ import { DeviceType, DeviceValueReader, InputState } from "../../interfaces/input.d.ts";
5
5
  /**
6
6
  * All supported edge modes for validation
7
7
  */
@@ -43,6 +43,7 @@ export declare class TriggerBinding implements Binding {
43
43
  readonly action: Action;
44
44
  readonly context?: string;
45
45
  readonly deviceID: string;
46
+ readonly deviceType: DeviceType;
46
47
  readonly reader: DeviceValueReader;
47
48
  private readonly _edgeMode;
48
49
  private readonly _threshold;
@@ -56,10 +57,11 @@ export declare class TriggerBinding implements Binding {
56
57
  *
57
58
  * @param action
58
59
  * @param deviceID
60
+ * @param deviceType
59
61
  * @param reader
60
62
  * @param options
61
63
  */
62
- constructor(action: Action, deviceID: string, reader: DeviceValueReader, options?: TriggerBindingOptions);
64
+ constructor(action: Action, deviceID: string, deviceType: DeviceType, reader: DeviceValueReader, options?: TriggerBindingOptions);
63
65
  /**
64
66
  * Process input state and emit an action event on the configured edge transition(s).
65
67
  *
@@ -68,9 +70,10 @@ export declare class TriggerBinding implements Binding {
68
70
  */
69
71
  process(state: InputState, eventBus: GameEventBus): void;
70
72
  /**
71
- * Reset edge-detection state so the next input is evaluated from a clean baseline.
73
+ * Reset edge-detection state for a context activation. When a state is provided, primes from the current physical
74
+ * input so that already-held inputs don't produce phantom rising edges in the newly activated context.
72
75
  */
73
- resetEdgeState(): void;
76
+ resetEdgeState(state?: InputState): void;
74
77
  /**
75
78
  * Returns a JSON-serializable representation of this trigger binding.
76
79
  */
@@ -1,7 +1,7 @@
1
1
  import { GameEventBus } from "../eventBus.d.ts";
2
2
  import { Action } from "../../interfaces/action.d.ts";
3
3
  import { Binding, ValueBindingDefinition } from "../../interfaces/binding.d.ts";
4
- import { DeviceValueReader, InputState } from "../../interfaces/input.d.ts";
4
+ import { DeviceType, DeviceValueReader, InputState } from "../../interfaces/input.d.ts";
5
5
  /**
6
6
  * Options for configuring a value binding
7
7
  */
@@ -61,6 +61,7 @@ export declare class ValueBinding implements Binding {
61
61
  readonly action: Action;
62
62
  readonly context?: string;
63
63
  readonly deviceID: string;
64
+ readonly deviceType: DeviceType;
64
65
  readonly reader: DeviceValueReader;
65
66
  private readonly _scale;
66
67
  private readonly _offset;
@@ -84,7 +85,7 @@ export declare class ValueBinding implements Binding {
84
85
  * @param reader
85
86
  * @param options
86
87
  */
87
- constructor(action: Action, deviceID: string, reader: DeviceValueReader, options?: ValueBindingOptions);
88
+ constructor(action: Action, deviceID: string, deviceType: DeviceType, reader: DeviceValueReader, options?: ValueBindingOptions);
88
89
  /**
89
90
  * Process input state, apply scaling/deadzone/clamping, and emit an action event if the value changed.
90
91
  *
@@ -95,7 +96,7 @@ export declare class ValueBinding implements Binding {
95
96
  /**
96
97
  * No-op for value bindings — they have no edge-detection state to reset.
97
98
  */
98
- resetEdgeState(): void;
99
+ resetEdgeState(_state?: InputState): void;
99
100
  /**
100
101
  * Returns a JSON-serializable representation of this value binding.
101
102
  */
@@ -2,6 +2,27 @@ import { TransformNode } from '@babylonjs/core';
2
2
  import { GameEntityBehaviorConstructor } from "../interfaces/entity.d.ts";
3
3
  import { Destroyable } from "../interfaces/lifecycle.d.ts";
4
4
  import { GameEvent, GameEventBus } from "./eventBus.d.ts";
5
+ import { GameEngine } from "./gameEngine.d.ts";
6
+ /**
7
+ * Result of a request sent to an entity's behaviors.
8
+ * `success: true` means a behavior handled the request and returned a value.
9
+ * `success: false` means no behavior handled it, or a behavior threw an error.
10
+ */
11
+ export type RequestResult<T> = {
12
+ success: true;
13
+ value: T;
14
+ } | {
15
+ success: false;
16
+ error: string;
17
+ };
18
+ /**
19
+ * Narrow interface for entity-to-manager messaging delegation.
20
+ * Avoids a circular import between entity.ts and managers/entity.ts.
21
+ */
22
+ interface EntityMessenger {
23
+ send(target: string, type: string, payload?: unknown, senderID?: string): Promise<void>;
24
+ request<T>(target: string, type: string, payload?: unknown, senderID?: string): Promise<RequestResult<T>>;
25
+ }
5
26
  /**
6
27
  * Options for attaching a behavior at a specific position.
7
28
  * Only one positioning option should be specified.
@@ -26,6 +47,8 @@ interface SimpleGameEntity<EntityState extends object = object> {
26
47
  state: EntityState;
27
48
  eventBus: GameEventBus;
28
49
  tags: ReadonlySet<string>;
50
+ send(target: string, type: string, payload?: unknown): Promise<void>;
51
+ request<T>(target: string, type: string, payload?: unknown): Promise<RequestResult<T>>;
29
52
  }
30
53
  /**
31
54
  * Base class for game entity behaviors. Subclass this to define how an entity reacts to events
@@ -35,7 +58,7 @@ interface SimpleGameEntity<EntityState extends object = object> {
35
58
  export declare abstract class GameEntityBehavior<RequiredState extends object = object> {
36
59
  abstract name: string;
37
60
  abstract eventSubscriptions: string[];
38
- protected entity: SimpleGameEntity | null;
61
+ protected entity: SimpleGameEntity<RequiredState> | null;
39
62
  $emit(event: GameEvent): void;
40
63
  /**
41
64
  * Emits an entity:state-changed event to notify UI or other observers of state changes.
@@ -49,8 +72,16 @@ export declare abstract class GameEntityBehavior<RequiredState extends object =
49
72
  * Sets the entity for this behavior.
50
73
  * @param entity
51
74
  */
52
- $setEntity(entity: SimpleGameEntity | null): void;
75
+ $setEntity(entity: SimpleGameEntity<RequiredState> | null): void;
53
76
  abstract processEvent(event: GameEvent, state: RequiredState): Promise<boolean> | boolean;
77
+ /**
78
+ * Handles a direct request sent to this entity. Return a value to respond,
79
+ * or `undefined` to pass the request to the next behavior.
80
+ *
81
+ * @param event - The request event (type, payload, senderID, targetID)
82
+ * @param state - Current entity state
83
+ */
84
+ processRequest?(event: GameEvent, state: RequiredState): Promise<unknown> | unknown | undefined;
54
85
  update?(dt: number, state: RequiredState): void;
55
86
  destroy?(): Promise<void>;
56
87
  /**
@@ -60,8 +91,9 @@ export declare abstract class GameEntityBehavior<RequiredState extends object =
60
91
  * The scene is accessible via `node.getScene()`.
61
92
  *
62
93
  * @param node - The TransformNode (typically a Mesh) the entity is attached to.
94
+ * @param gameEngine - The game engine instance for accessing managers and engines.
63
95
  */
64
- onNodeAttached?(node: TransformNode): void;
96
+ onNodeAttached?(node: TransformNode, gameEngine: GameEngine): void;
65
97
  /**
66
98
  * Called when the entity is detached from its scene node.
67
99
  * Override to clean up node-dependent resources.
@@ -100,6 +132,8 @@ export declare class GameEntity<EntityState extends object = object> implements
100
132
  /** Array of behaviors attached to the entity. Order determines event processing priority. */
101
133
  behaviors: GameEntityBehavior[];
102
134
  eventBus: GameEventBus;
135
+ private _gameEngine;
136
+ private _entityManager;
103
137
  private _tags;
104
138
  private subscriptions;
105
139
  /**
@@ -144,9 +178,10 @@ export declare class GameEntity<EntityState extends object = object> implements
144
178
  * Internal method for EntityManager to attach entity to a node.
145
179
  * Do not call directly - use EntityManager.attachToNode() instead.
146
180
  * @param node
181
+ * @param gameEngine
147
182
  * @internal
148
183
  */
149
- $attachToNode(node: TransformNode): void;
184
+ $attachToNode(node: TransformNode, gameEngine: GameEngine): void;
150
185
  /**
151
186
  * Internal method for EntityManager to detach entity from its node.
152
187
  * Do not call directly - use EntityManager.detachFromNode() instead.
@@ -165,6 +200,47 @@ export declare class GameEntity<EntityState extends object = object> implements
165
200
  * @param child
166
201
  */
167
202
  $removeChild(child: GameEntity): void;
203
+ /**
204
+ * Sets the entity manager reference for cross-entity messaging.
205
+ * Called by the EntityManager after entity creation.
206
+ * @param manager
207
+ * @internal
208
+ */
209
+ $setEntityManager(manager: EntityMessenger): void;
210
+ /**
211
+ * Sends a fire-and-forget event directly to a specific entity's behaviors, bypassing the event bus.
212
+ * If the target matches this entity's own ID, dispatches locally.
213
+ *
214
+ * @param target - Entity ID or name
215
+ * @param type - Event type string
216
+ * @param payload - Optional event payload
217
+ */
218
+ send(target: string, type: string, payload?: unknown): Promise<void>;
219
+ /**
220
+ * Sends a request to a specific entity's behaviors and returns the first response.
221
+ * If the target matches this entity's own ID, dispatches locally.
222
+ *
223
+ * @param target - Entity ID or name
224
+ * @param type - Request type string
225
+ * @param payload - Optional request payload
226
+ */
227
+ request<T>(target: string, type: string, payload?: unknown): Promise<RequestResult<T>>;
228
+ /**
229
+ * Sends a fire-and-forget event directly to this entity's own behaviors.
230
+ *
231
+ * @param type - Event type string
232
+ * @param payload - Optional event payload
233
+ * @internal
234
+ */
235
+ $send(type: string, payload?: unknown, senderID?: string): Promise<void>;
236
+ /**
237
+ * Sends a request to this entity's own behaviors and returns the first response.
238
+ *
239
+ * @param type - Request type string
240
+ * @param payload - Optional request payload
241
+ * @internal
242
+ */
243
+ $request<T>(type: string, payload?: unknown, senderID?: string): Promise<RequestResult<T>>;
168
244
  /**
169
245
  * Resets the entity for object pool recycling.
170
246
  * Restores state and tags to defaults, detaches from node, notifies behaviors, and resets children.
@@ -2,6 +2,7 @@ import { AbstractEngine, HavokPlugin } from '@babylonjs/core';
2
2
  import { GameCanvas } from "../interfaces/game.d.ts";
3
3
  import { Disposable } from "../interfaces/lifecycle.d.ts";
4
4
  import { SceneEngine } from "../engines/scene.d.ts";
5
+ import { AudioEngine } from "../engines/audio.d.ts";
5
6
  import { AssetManager } from "../managers/asset.d.ts";
6
7
  import { BindingManager } from "../managers/binding.d.ts";
7
8
  import { GameManager } from "../managers/game.d.ts";
@@ -9,6 +10,7 @@ import { GameEntityManager } from "../managers/entity.d.ts";
9
10
  import { LevelManager } from "../managers/level.d.ts";
10
11
  import { SaveManager } from "../managers/save.d.ts";
11
12
  import { UserInputManager } from "../managers/input.d.ts";
13
+ import { AudioManager } from "../managers/audio.d.ts";
12
14
  import { GameEvent, GameEventBus, GameEventCallback, Unsubscribe } from "./eventBus.d.ts";
13
15
  import { ActionPayload, LibraryEventPayloadMap } from "../events/payloads.d.ts";
14
16
  import { WildcardPattern } from "../events/types.d.ts";
@@ -23,14 +25,15 @@ export type GameHook = (gameEngine: GameEngine) => Promise<void>;
23
25
  * Interface representing the engines used in the game.
24
26
  * All engines must implement Disposable for proper cleanup.
25
27
  */
26
- interface Engines extends Record<string, Disposable> {
28
+ interface Engines extends Record<string, Disposable | undefined> {
27
29
  sceneEngine: SceneEngine;
30
+ audioEngine?: AudioEngine;
28
31
  }
29
32
  /**
30
33
  * Interface representing the managers used in the game.
31
34
  * All managers must implement Disposable for proper cleanup.
32
35
  */
33
- interface Managers extends Record<string, Disposable> {
36
+ interface Managers extends Record<string, Disposable | undefined> {
34
37
  assetManager: AssetManager;
35
38
  bindingManager: BindingManager;
36
39
  gameManager: GameManager;
@@ -38,6 +41,7 @@ interface Managers extends Record<string, Disposable> {
38
41
  inputManager: UserInputManager;
39
42
  levelManager: LevelManager;
40
43
  saveManager: SaveManager;
44
+ audioManager?: AudioManager;
41
45
  }
42
46
  /**
43
47
  * Central hub that owns the render loop, physics, event bus, and all managers.
@@ -1,4 +1,5 @@
1
1
  import { Scene, TransformNode, Vector3 } from '@babylonjs/core';
2
+ import { StaticSound } from '@babylonjs/core/AudioV2/abstractAudio/staticSound';
2
3
  import { LevelConfig, LevelContext } from "../interfaces/level.d.ts";
3
4
  import { GameEntity } from "./entity.d.ts";
4
5
  import { Level } from "./level.d.ts";
@@ -32,6 +33,10 @@ export declare class GameLevel extends Level {
32
33
  protected _entityNodes: EntityNodeData[];
33
34
  /** Entities spawned by this level */
34
35
  protected _spawnedEntities: GameEntity[];
36
+ /** Level-scoped sounds created from config */
37
+ protected _levelSounds: Map<string, StaticSound>;
38
+ /** Sounds that were playing before deactivation (for resume on activate) */
39
+ private _playingSoundsBeforeDeactivate;
35
40
  /**
36
41
  * Create a GameLevel from a configuration object
37
42
  *
@@ -49,6 +54,43 @@ export declare class GameLevel extends Level {
49
54
  * Import all meshes from the configured scene file (GLB/GLTF/Babylon) into the scene.
50
55
  */
51
56
  private _loadSceneFile;
57
+ /**
58
+ * Set up the scene environment: IBL (image-based lighting) for PBR reflections and/or a visible skybox.
59
+ */
60
+ private _processEnvironment;
61
+ /**
62
+ * Create an environment texture from an HDR or env file.
63
+ */
64
+ private _createEnvironmentTexture;
65
+ private _getFileExtension;
66
+ /**
67
+ * Process cameras: apply YAML overrides to imported cameras, create new ones, and set the active camera.
68
+ * If no YAML cameras config exists, the first imported camera (if any) is activated.
69
+ */
70
+ private _processCameras;
71
+ /**
72
+ * Create a new camera from a YAML definition.
73
+ */
74
+ private _createCamera;
75
+ /**
76
+ * Apply shared camera properties from a config to an existing camera.
77
+ */
78
+ private _applyCameraConfig;
79
+ /**
80
+ * Process lights: apply YAML overrides to imported lights and create new ones.
81
+ * If no YAML lights config exists, imported lights are left unchanged.
82
+ */
83
+ private _processLights;
84
+ /**
85
+ * Create a new light from a YAML definition.
86
+ */
87
+ private _createLight;
88
+ /**
89
+ * Apply shared light properties from a config to an existing light.
90
+ */
91
+ private _applyLightConfig;
92
+ private _toVector3;
93
+ private _toColor3;
52
94
  /**
53
95
  * Configure and enable the Havok physics plugin with the level's gravity settings.
54
96
  */
@@ -97,6 +139,21 @@ export declare class GameLevel extends Level {
97
139
  * Create a game entity for an entity-tagged node, attaching the existing scene node to it.
98
140
  */
99
141
  private _processEntityNode;
142
+ /**
143
+ * Create level-scoped sounds from YAML config. Sounds are tracked for lifecycle management
144
+ * (pause on deactivate, resume on activate, dispose on unload).
145
+ */
146
+ private _processLevelSounds;
147
+ /**
148
+ * Pause all playing level sounds when the level is deactivated.
149
+ * Subclasses that override this must call `super.onDeactivate()`.
150
+ */
151
+ onDeactivate(): Promise<void>;
152
+ /**
153
+ * Resume previously playing level sounds when the level is reactivated.
154
+ * Subclasses that override this must call `super.onActivate()`.
155
+ */
156
+ onActivate(): Promise<void>;
100
157
  /**
101
158
  * Dispose of this level's resources
102
159
  */
@@ -1,10 +1,7 @@
1
1
  import { Scene } from '@babylonjs/core';
2
2
  import { LoggerInterface } from "../interfaces/logger.d.ts";
3
3
  import { LevelConfig, LevelContext, LevelInstance, PropertyHandler } from "../interfaces/level.d.ts";
4
- import { AssetManager } from "../managers/asset.d.ts";
5
- import { SceneEngine } from "../engines/scene.d.ts";
6
- import { GameEventBus } from "./eventBus.d.ts";
7
- import { GameEntityManager } from "../managers/entity.d.ts";
4
+ import { GameEngine } from "./gameEngine.d.ts";
8
5
  /**
9
6
  * Abstract base class for game levels.
10
7
  *
@@ -37,10 +34,7 @@ export declare abstract class Level implements LevelInstance {
37
34
  constructor(config: LevelConfig, context: LevelContext);
38
35
  get scene(): Scene | null;
39
36
  get isLoaded(): boolean;
40
- get eventBus(): GameEventBus;
41
- get assetManager(): AssetManager;
42
- get entityManager(): GameEntityManager;
43
- get sceneEngine(): SceneEngine;
37
+ get gameEngine(): GameEngine;
44
38
  get propertyHandlers(): Map<string, PropertyHandler>;
45
39
  /**
46
40
  * Emit a progress event during loading
@@ -58,8 +52,7 @@ export declare abstract class Level implements LevelInstance {
58
52
  * Abstract method for building the scene content.
59
53
  * Concrete levels must implement this to create their specific content.
60
54
  *
61
- * All dependencies (sceneEngine, entityManager, eventBus) are available via
62
- * `this.sceneEngine`, `this.entityManager`, etc.
55
+ * All dependencies are available via `this.gameEngine`.
63
56
  *
64
57
  */
65
58
  protected abstract buildScene(): Promise<Scene>;
@@ -0,0 +1,19 @@
1
+ import { AudioBus } from '@babylonjs/core/AudioV2/abstractAudio/audioBus';
2
+ import { IStaticSoundOptions, StaticSound } from '@babylonjs/core/AudioV2/abstractAudio/staticSound';
3
+ import { Disposable } from "../interfaces/lifecycle.d.ts";
4
+ import { LoggingUtility } from "../utils/logger.d.ts";
5
+ export declare class AudioEngine implements Disposable {
6
+ private _engine;
7
+ private _mainBus;
8
+ private _buses;
9
+ private _log;
10
+ constructor(logger: LoggingUtility);
11
+ initialize(): Promise<void>;
12
+ $teardown(): Promise<void>;
13
+ createBus(name: string): Promise<AudioBus>;
14
+ getBus(name: string): AudioBus | undefined;
15
+ createSound(name: string, url: string, bus?: AudioBus, options?: Partial<IStaticSoundOptions>): Promise<StaticSound>;
16
+ setMasterVolume(volume: number): void;
17
+ getMasterVolume(): number;
18
+ setBusVolume(bus: AudioBus, volume: number): void;
19
+ }
@@ -1,4 +1,4 @@
1
- import { AbstractEngine, AbstractMesh, AssetContainer, DirectionalLight, FreeCamera, HemisphericLight, Light, Mesh, PhysicsAggregate, PhysicsShapeType, PointLight, Scene, Sound, SpotLight, Vector3 } from '@babylonjs/core';
1
+ import { AbstractEngine, AbstractMesh, AssetContainer, DirectionalLight, FreeCamera, HemisphericLight, Light, Mesh, PhysicsAggregate, PhysicsShapeType, PointLight, RectAreaLight, Scene, SpotLight, Vector3 } from '@babylonjs/core';
2
2
  import { HavokPhysicsWithBindings } from '@babylonjs/havok';
3
3
  import { GameCanvas } from "../interfaces/game.d.ts";
4
4
  import { Disposable } from "../interfaces/lifecycle.d.ts";
@@ -58,6 +58,16 @@ export declare class SceneEngine implements Disposable {
58
58
  * @param intensity - Default: 1.0
59
59
  */
60
60
  createSpotLight(name: string, position: Vector3, direction: Vector3, angle: number, exponent: number, scene: Scene, intensity?: number): SpotLight;
61
+ /**
62
+ * Creates a rectangular area light (emits from a flat rectangle in the -Z direction)
63
+ * @param name
64
+ * @param position
65
+ * @param width
66
+ * @param height
67
+ * @param scene
68
+ * @param intensity - Default: 1.0
69
+ */
70
+ createRectAreaLight(name: string, position: Vector3, width: number, height: number, scene: Scene, intensity?: number): RectAreaLight;
61
71
  /**
62
72
  * Creates a sphere mesh. Defaults: diameter 1, 32 segments.
63
73
  * @param name
@@ -114,19 +124,6 @@ export declare class SceneEngine implements Disposable {
114
124
  restitution?: number;
115
125
  friction?: number;
116
126
  } | undefined, scene: Scene): PhysicsAggregate;
117
- /**
118
- * Creates and loads a sound. Defaults: no loop, no autoplay, volume 1.0, playbackRate 1.0.
119
- * @param name
120
- * @param url
121
- * @param scene
122
- * @param options
123
- */
124
- createSound(name: string, url: string, scene: Scene, options?: {
125
- loop?: boolean;
126
- autoplay?: boolean;
127
- volume?: number;
128
- playbackRate?: number;
129
- }): Sound;
130
127
  /**
131
128
  * Loads a 3D model/asset into an AssetContainer without adding it to the scene automatically.
132
129
  * @param sceneFilename
@@ -1,5 +1,5 @@
1
1
  import { AbstractMesh } from '@babylonjs/core';
2
- import { InputDevice, InputState } from "../interfaces/input.d.ts";
2
+ import { DeviceType, InputDevice, InputState } from "../interfaces/input.d.ts";
3
3
  /** Payload for input:device:connected events */
4
4
  export interface DeviceConnectedPayload {
5
5
  device: InputDevice;
@@ -14,6 +14,11 @@ export interface InputChangedPayload {
14
14
  device: InputDevice;
15
15
  state: InputState;
16
16
  }
17
+ /** Payload for input:device-type:changed events */
18
+ export interface DeviceTypeChangedPayload {
19
+ deviceType: DeviceType;
20
+ previousDeviceType: DeviceType | null;
21
+ }
17
22
  /** Payload for level:progress events */
18
23
  export interface LevelProgressPayload {
19
24
  levelName: string;
@@ -111,6 +116,7 @@ export interface LibraryEventPayloadMap {
111
116
  'input:device:connected': DeviceConnectedPayload;
112
117
  'input:device:disconnected': DeviceDisconnectedPayload;
113
118
  'input:changed': InputChangedPayload;
119
+ 'input:device-type:changed': DeviceTypeChangedPayload;
114
120
  'level:progress': LevelProgressPayload;
115
121
  'level:complete': LevelCompletePayload;
116
122
  'level:error': LevelErrorPayload;
@@ -5,6 +5,9 @@ import { LevelManager } from "../managers/level.d.ts";
5
5
  * Supports the following properties on scene nodes:
6
6
  * - `collider` (string): Collider type - "box", "sphere", "mesh", or "none"
7
7
  * - `collider_mesh` (boolean): On a child node, marks it as the collision source for parent's "mesh" collider
8
+ * - `collider_mass` (number): Mass for the physics body. Defaults to 0 (static). Set > 0 for dynamic bodies.
9
+ * - `collider_kinematic` (boolean): When true, sets `disablePreStep = false` so the physics body
10
+ * tracks mesh transform each frame. Required for animated colliders (doors, elevators, platforms).
8
11
  *
9
12
  * For "mesh" colliders, if a child node has `collider_mesh: true`, that child's geometry
10
13
  * is used for collision and the child is made invisible.
@@ -9,6 +9,7 @@ import { LevelManager } from "../managers/level.d.ts";
9
9
  * - `sound_spatial` (boolean): Whether to use 3D spatial audio, default true
10
10
  * - `sound_distance` (number): Maximum distance for spatial audio, default 100
11
11
  * - `sound_autoplay` (boolean): Whether to autoplay, default true
12
+ * - `sound_channel` (string): Audio channel name, default 'ambient'
12
13
  *
13
14
  * @param levelManager
14
15
  */
@@ -4,6 +4,7 @@
4
4
  export interface DigitalAction {
5
5
  type: 'digital';
6
6
  name: string;
7
+ label?: string;
7
8
  }
8
9
  /**
9
10
  * Analog action (numeric)
@@ -11,6 +12,7 @@ export interface DigitalAction {
11
12
  export interface AnalogAction {
12
13
  type: 'analog';
13
14
  name: string;
15
+ label?: string;
14
16
  minValue?: number;
15
17
  maxValue?: number;
16
18
  }