@skewedaspect/sage 0.9.6 → 0.10.0-beta.2

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 (74) hide show
  1. package/dist/behaviors/sound.d.ts +12 -127
  2. package/dist/classes/debugConsole.d.ts +1 -0
  3. package/dist/classes/gameEngine.d.ts +31 -46
  4. package/dist/classes/gameLevel.d.ts +21 -12
  5. package/dist/classes/level.d.ts +24 -29
  6. package/dist/entities/constants.d.ts +1 -0
  7. package/dist/entities/defineEntity.d.ts +17 -0
  8. package/dist/entities/entityPicking.d.ts +15 -0
  9. package/dist/entities/meshConfig.d.ts +14 -0
  10. package/dist/entities/nodeEntity.d.ts +43 -0
  11. package/dist/entities/nodePool.d.ts +8 -0
  12. package/dist/entities/nodeSimulation.d.ts +30 -0
  13. package/dist/entities/nodeSimulationContext.d.ts +17 -0
  14. package/dist/entities/standardMeshSource.d.ts +8 -0
  15. package/dist/events/payloads.d.ts +0 -42
  16. package/dist/events/types.d.ts +2 -23
  17. package/dist/input/actionContext.d.ts +13 -0
  18. package/dist/input/actionRegistry.d.ts +7 -0
  19. package/dist/input/binding.d.ts +33 -0
  20. package/dist/input/bindings/delta.d.ts +23 -0
  21. package/dist/input/bindings/toggle.d.ts +25 -0
  22. package/dist/input/bindings/trigger.d.ts +23 -0
  23. package/dist/input/bindings/value.d.ts +26 -0
  24. package/dist/input/configuration.d.ts +15 -0
  25. package/dist/input/deliverAction.d.ts +4 -0
  26. package/dist/input/deviceReader.d.ts +5 -0
  27. package/dist/input/deviceReaders/gamepad.d.ts +9 -0
  28. package/dist/input/deviceReaders/keyboard.d.ts +8 -0
  29. package/dist/input/deviceReaders/mouse.d.ts +9 -0
  30. package/dist/input/deviceState.d.ts +24 -0
  31. package/dist/input/inputCapture.d.ts +21 -0
  32. package/dist/input/resolveBinding.d.ts +4 -0
  33. package/dist/interfaces/game.d.ts +21 -5
  34. package/dist/interfaces/level.d.ts +21 -3
  35. package/dist/managers/asset.d.ts +17 -3
  36. package/dist/managers/game.d.ts +15 -5
  37. package/dist/managers/input.d.ts +31 -51
  38. package/dist/managers/level.d.ts +20 -4
  39. package/dist/managers/outline.d.ts +4 -4
  40. package/dist/managers/simulationSave.d.ts +38 -0
  41. package/dist/{postProcessingFrameGraph-CaMgQzR-.js → postProcessingFrameGraph-C3Og4kaS.js} +34 -26
  42. package/dist/postProcessingFrameGraph-C3Og4kaS.js.map +1 -0
  43. package/dist/sage.d.ts +54 -16
  44. package/dist/sage.es.js +1868 -2424
  45. package/dist/sage.es.js.map +1 -1
  46. package/dist/sage.umd.js +1 -1
  47. package/dist/sage.umd.js.map +1 -1
  48. package/dist/utils/bounds.d.ts +11 -0
  49. package/dist/utils/physics.d.ts +4 -1
  50. package/package.json +29 -66
  51. package/LICENSE +0 -21
  52. package/Readme.md +0 -73
  53. package/dist/behaviors/index.d.ts +0 -2
  54. package/dist/behaviors/stateMachine.d.ts +0 -76
  55. package/dist/classes/bindings/toggle.d.ts +0 -116
  56. package/dist/classes/bindings/trigger.d.ts +0 -81
  57. package/dist/classes/bindings/value.d.ts +0 -104
  58. package/dist/classes/entity.d.ts +0 -332
  59. package/dist/classes/input/gamepad.d.ts +0 -94
  60. package/dist/classes/input/keyboard.d.ts +0 -66
  61. package/dist/classes/input/mouse.d.ts +0 -91
  62. package/dist/classes/input/readers/gamepad.d.ts +0 -73
  63. package/dist/classes/input/readers/keyboard.d.ts +0 -56
  64. package/dist/classes/input/readers/mouse.d.ts +0 -41
  65. package/dist/interfaces/action.d.ts +0 -22
  66. package/dist/interfaces/binding.d.ts +0 -123
  67. package/dist/interfaces/entity.d.ts +0 -97
  68. package/dist/interfaces/input.d.ts +0 -180
  69. package/dist/managers/binding.d.ts +0 -233
  70. package/dist/managers/entity.d.ts +0 -264
  71. package/dist/managers/save.d.ts +0 -75
  72. package/dist/postProcessingFrameGraph-CaMgQzR-.js.map +0 -1
  73. package/dist/utils/entityProxy.d.ts +0 -2
  74. package/dist/utils/raycast.d.ts +0 -26
@@ -1,24 +1,4 @@
1
1
  import { AbstractMesh } from '@babylonjs/core';
2
- import { DeviceType, InputDevice, InputState } from "../interfaces/input.d.ts";
3
- /** Payload for input:device:connected events */
4
- export interface DeviceConnectedPayload {
5
- device: InputDevice;
6
- }
7
- /** Payload for input:device:disconnected events */
8
- export interface DeviceDisconnectedPayload {
9
- device: InputDevice;
10
- }
11
- /** Payload for input:changed events */
12
- export interface InputChangedPayload {
13
- deviceId: string;
14
- device: InputDevice;
15
- state: InputState;
16
- }
17
- /** Payload for input:device-type:changed events */
18
- export interface DeviceTypeChangedPayload {
19
- deviceType: DeviceType;
20
- previousDeviceType: DeviceType | null;
21
- }
22
2
  /** Payload for level:progress events */
23
3
  export interface LevelProgressPayload {
24
4
  levelName: string;
@@ -58,12 +38,6 @@ export interface LevelTransitionErrorPayload {
58
38
  to: string;
59
39
  error: unknown;
60
40
  }
61
- /** Payload for action:* events */
62
- export interface ActionPayload {
63
- value: boolean | number;
64
- deviceId: string;
65
- context?: string;
66
- }
67
41
  /** Payload for trigger:enter events */
68
42
  export interface TriggerEnterPayload {
69
43
  trigger: string;
@@ -74,17 +48,6 @@ export interface TriggerExitPayload {
74
48
  trigger: string;
75
49
  other: AbstractMesh;
76
50
  }
77
- /** Payload for entity:state-changed events */
78
- export interface EntityStateChangedPayload {
79
- /** The ID of the entity whose state changed */
80
- entityId: string;
81
- /** The type of the entity */
82
- entityType: string;
83
- /** The current state (optional - may include full state or just changed parts) */
84
- state?: object;
85
- /** Specific changes made (optional - alternative to full state) */
86
- changes?: Record<string, unknown>;
87
- }
88
51
  /** Payload for asset:progress events */
89
52
  export interface AssetProgressPayload {
90
53
  path: string;
@@ -113,10 +76,6 @@ export interface GameResumedPayload {
113
76
  * while still providing type safety for known event types.
114
77
  */
115
78
  export interface LibraryEventPayloadMap {
116
- 'input:device:connected': DeviceConnectedPayload;
117
- 'input:device:disconnected': DeviceDisconnectedPayload;
118
- 'input:changed': InputChangedPayload;
119
- 'input:device-type:changed': DeviceTypeChangedPayload;
120
79
  'level:progress': LevelProgressPayload;
121
80
  'level:complete': LevelCompletePayload;
122
81
  'level:error': LevelErrorPayload;
@@ -128,7 +87,6 @@ export interface LibraryEventPayloadMap {
128
87
  'asset:complete': AssetCompletePayload;
129
88
  'trigger:enter': TriggerEnterPayload;
130
89
  'trigger:exit': TriggerExitPayload;
131
- 'entity:state-changed': EntityStateChangedPayload;
132
90
  'game:paused': GamePausedPayload;
133
91
  'game:resumed': GameResumedPayload;
134
92
  [key: string]: unknown;
@@ -1,12 +1,3 @@
1
- /**
2
- * Template literal type for action events.
3
- * Actions are dynamically named based on user-defined action names.
4
- *
5
- * @example
6
- * type MyActions = ActionEvent<'jump' | 'attack' | 'dodge'>;
7
- * // Results in: "action:jump" | "action:attack" | "action:dodge"
8
- */
9
- export type ActionEvent<Name extends string = string> = `action:${Name}`;
10
1
  /**
11
2
  * Template literal type for level events.
12
3
  *
@@ -15,24 +6,12 @@ export type ActionEvent<Name extends string = string> = `action:${Name}`;
15
6
  * // Results in: "level:progress" | "level:complete"
16
7
  */
17
8
  export type LevelEvent<Name extends string = string> = `level:${Name}`;
18
- /**
19
- * Template literal type for input events.
20
- *
21
- * @example
22
- * type MyInputEvents = InputEvent<'changed' | 'device:connected'>;
23
- * // Results in: "input:changed" | "input:device:connected"
24
- */
25
- export type InputEvent<Name extends string = string> = `input:${Name}`;
26
9
  /** Library-defined level event types */
27
10
  export type LibraryLevelEvent = LevelEvent<'progress' | 'complete' | 'error'>;
28
- /** Library-defined input event types */
29
- export type LibraryInputEvent = InputEvent<'changed' | 'device:connected' | 'device:disconnected'>;
30
- /** Library-defined action event types (dynamic, based on action name) */
31
- export type LibraryActionEvent = ActionEvent<string>;
32
11
  /** All library-defined event types */
33
- export type LibraryEventType = LibraryLevelEvent | LibraryInputEvent | LibraryActionEvent;
12
+ export type LibraryEventType = LibraryLevelEvent;
34
13
  /**
35
14
  * Wildcard subscription patterns for subscribing to multiple events.
36
15
  * These are valid for subscribe() but NOT for publish().
37
16
  */
38
- export type WildcardPattern = 'action:*' | 'level:*' | 'input:*' | 'input:device:*' | `${string}:*`;
17
+ export type WildcardPattern = 'level:*' | `${string}:*`;
@@ -0,0 +1,13 @@
1
+ import { Binding } from "./binding.d.ts";
2
+ export declare class ActionContextRegistry {
3
+ #private;
4
+ registerContext(name: string, exclusive?: boolean): void;
5
+ activateContext(name: string, currentState: (binding: Binding<unknown>) => unknown): void;
6
+ deactivateContext(name: string): void;
7
+ isActive(name: string): boolean;
8
+ isRegistered(name: string): boolean;
9
+ addBinding(binding: Binding<unknown>): void;
10
+ removeBinding(binding: Binding<unknown>): void;
11
+ list(): readonly Binding<unknown>[];
12
+ isLive(binding: Binding<unknown>): boolean;
13
+ }
@@ -0,0 +1,7 @@
1
+ import { Action } from '@skewedaspect/sage-core';
2
+ export declare class ActionRegistry {
3
+ #private;
4
+ register(action: Action): void;
5
+ get(name: string): Action | undefined;
6
+ list(): readonly Action[];
7
+ }
@@ -0,0 +1,33 @@
1
+ import { Action } from '@skewedaspect/sage-core';
2
+ export type BindingKind = 'trigger' | 'toggle' | 'value' | 'delta';
3
+ export type DeviceType = 'keyboard' | 'mouse' | 'gamepad';
4
+ export interface DeviceID {
5
+ type: DeviceType;
6
+ index: number;
7
+ }
8
+ export interface BindingInput {
9
+ device: DeviceID;
10
+ sourceType: string;
11
+ sourceKey: string;
12
+ }
13
+ export interface BindingDefinition {
14
+ kind: BindingKind;
15
+ action: string;
16
+ input: BindingInput;
17
+ context?: string;
18
+ options?: Record<string, unknown>;
19
+ }
20
+ export interface BindingFire {
21
+ value: boolean | number;
22
+ }
23
+ export interface Binding<State> {
24
+ readonly kind: BindingKind;
25
+ readonly action: Action;
26
+ readonly device: DeviceID;
27
+ readonly context?: string;
28
+ readonly preventDefault: boolean;
29
+ readonly input: BindingInput;
30
+ process(state: State): BindingFire | undefined;
31
+ prime(state: State): void;
32
+ toDefinition(): BindingDefinition;
33
+ }
@@ -0,0 +1,23 @@
1
+ import { Action } from '@skewedaspect/sage-core';
2
+ import { Binding, BindingDefinition, BindingFire, BindingInput, DeviceID } from "../binding.d.ts";
3
+ import { DeviceReader } from "../deviceReader.d.ts";
4
+ export interface DeltaOptions {
5
+ scale?: number;
6
+ invert?: boolean;
7
+ deadzone?: number;
8
+ /** Takes this input from the browser while the binding is live (input.md#claiming-an-input-from-the-browser). */
9
+ preventDefault?: boolean;
10
+ }
11
+ export declare class DeltaBinding<State> implements Binding<State> {
12
+ #private;
13
+ readonly kind: "delta";
14
+ readonly action: Action;
15
+ readonly device: DeviceID;
16
+ readonly context?: string;
17
+ readonly preventDefault: boolean;
18
+ constructor(action: Action, device: DeviceID, reader: DeviceReader<State>, options?: DeltaOptions, context?: string);
19
+ get input(): BindingInput;
20
+ process(state: State): BindingFire | undefined;
21
+ prime(_state: State): void;
22
+ toDefinition(): BindingDefinition;
23
+ }
@@ -0,0 +1,25 @@
1
+ import { Action } from '@skewedaspect/sage-core';
2
+ import { Binding, BindingDefinition, BindingFire, BindingInput, DeviceID } from "../binding.d.ts";
3
+ import { DeviceReader } from "../deviceReader.d.ts";
4
+ export interface ToggleOptions {
5
+ onValue?: boolean | number;
6
+ offValue?: boolean | number;
7
+ initialState?: boolean;
8
+ threshold?: number;
9
+ invert?: boolean;
10
+ /** Takes this input from the browser while the binding is live (input.md#claiming-an-input-from-the-browser). */
11
+ preventDefault?: boolean;
12
+ }
13
+ export declare class ToggleBinding<State> implements Binding<State> {
14
+ #private;
15
+ readonly kind: "toggle";
16
+ readonly action: Action;
17
+ readonly device: DeviceID;
18
+ readonly context?: string;
19
+ readonly preventDefault: boolean;
20
+ constructor(action: Action, device: DeviceID, reader: DeviceReader<State>, options?: ToggleOptions, context?: string);
21
+ get input(): BindingInput;
22
+ process(state: State): BindingFire | undefined;
23
+ prime(state: State): void;
24
+ toDefinition(): BindingDefinition;
25
+ }
@@ -0,0 +1,23 @@
1
+ import { Action } from '@skewedaspect/sage-core';
2
+ import { Binding, BindingDefinition, BindingFire, BindingInput, DeviceID } from "../binding.d.ts";
3
+ import { DeviceReader } from "../deviceReader.d.ts";
4
+ export type EdgeMode = 'rising' | 'falling' | 'both';
5
+ export interface TriggerOptions {
6
+ edge?: EdgeMode;
7
+ threshold?: number;
8
+ /** Takes this input from the browser while the binding is live (input.md#claiming-an-input-from-the-browser). */
9
+ preventDefault?: boolean;
10
+ }
11
+ export declare class TriggerBinding<State> implements Binding<State> {
12
+ #private;
13
+ readonly kind: "trigger";
14
+ readonly action: Action;
15
+ readonly device: DeviceID;
16
+ readonly context?: string;
17
+ readonly preventDefault: boolean;
18
+ constructor(action: Action, device: DeviceID, reader: DeviceReader<State>, options?: TriggerOptions, context?: string);
19
+ get input(): BindingInput;
20
+ process(state: State): BindingFire | undefined;
21
+ prime(state: State): void;
22
+ toDefinition(): BindingDefinition;
23
+ }
@@ -0,0 +1,26 @@
1
+ import { Action } from '@skewedaspect/sage-core';
2
+ import { Binding, BindingDefinition, BindingFire, BindingInput, DeviceID } from "../binding.d.ts";
3
+ import { DeviceReader } from "../deviceReader.d.ts";
4
+ export interface ValueOptions {
5
+ scale?: number;
6
+ offset?: number;
7
+ invert?: boolean;
8
+ deadzone?: number;
9
+ min?: number;
10
+ max?: number;
11
+ /** Takes this input from the browser while the binding is live (input.md#claiming-an-input-from-the-browser). */
12
+ preventDefault?: boolean;
13
+ }
14
+ export declare class ValueBinding<State> implements Binding<State> {
15
+ #private;
16
+ readonly kind: "value";
17
+ readonly action: Action;
18
+ readonly device: DeviceID;
19
+ readonly context?: string;
20
+ readonly preventDefault: boolean;
21
+ constructor(action: Action, device: DeviceID, reader: DeviceReader<State>, options?: ValueOptions, context?: string);
22
+ get input(): BindingInput;
23
+ process(state: State): BindingFire;
24
+ prime(_state: State): void;
25
+ toDefinition(): BindingDefinition;
26
+ }
@@ -0,0 +1,15 @@
1
+ import { Action } from '@skewedaspect/sage-core';
2
+ import { ActionContextRegistry } from "./actionContext.d.ts";
3
+ import { ActionRegistry } from "./actionRegistry.d.ts";
4
+ import { Binding, BindingDefinition } from "./binding.d.ts";
5
+ export interface ContextDefinition {
6
+ name: string;
7
+ exclusive: boolean;
8
+ }
9
+ export interface Configuration {
10
+ actions: readonly Action[];
11
+ bindings: readonly BindingDefinition[];
12
+ contexts: readonly ContextDefinition[];
13
+ }
14
+ export declare function exportConfiguration(actions: readonly Action[], bindings: readonly Binding<unknown>[], contexts: readonly ContextDefinition[]): Configuration;
15
+ export declare function importConfiguration(config: Configuration, actions: ActionRegistry, contexts: ActionContextRegistry): readonly BindingDefinition[];
@@ -0,0 +1,4 @@
1
+ import { Action, GameSimulationContext } from '@skewedaspect/sage-core';
2
+ import { Binding } from "./binding.d.ts";
3
+ export declare function deliverAction<State>(binding: Binding<State>, state: State, context: GameSimulationContext, senderID: string): void;
4
+ export declare function deliverValueAction(action: Action, value: number, context: GameSimulationContext, senderID: string): void;
@@ -0,0 +1,5 @@
1
+ export interface DeviceReader<State> {
2
+ readonly sourceType: string;
3
+ readonly sourceKey: string;
4
+ getValue(state: State): boolean | number | undefined;
5
+ }
@@ -0,0 +1,9 @@
1
+ import { GamepadState } from "../deviceState.d.ts";
2
+ import { DeviceReader } from "../deviceReader.d.ts";
3
+ export type GamepadSourceType = 'button' | 'axis';
4
+ export declare class GamepadReader implements DeviceReader<GamepadState> {
5
+ readonly sourceType: GamepadSourceType;
6
+ readonly sourceKey: string;
7
+ constructor(sourceType: GamepadSourceType, sourceKey: string);
8
+ getValue(state: GamepadState): boolean | number | undefined;
9
+ }
@@ -0,0 +1,8 @@
1
+ import { KeyboardState } from "../deviceState.d.ts";
2
+ import { DeviceReader } from "../deviceReader.d.ts";
3
+ export declare class KeyboardReader implements DeviceReader<KeyboardState> {
4
+ readonly sourceType = "key";
5
+ readonly sourceKey: string;
6
+ constructor(sourceKey: string);
7
+ getValue(state: KeyboardState): boolean | undefined;
8
+ }
@@ -0,0 +1,9 @@
1
+ import { MouseState } from "../deviceState.d.ts";
2
+ import { DeviceReader } from "../deviceReader.d.ts";
3
+ export type MouseSourceType = 'button' | 'position' | 'wheel' | 'movement';
4
+ export declare class MouseReader implements DeviceReader<MouseState> {
5
+ readonly sourceType: MouseSourceType;
6
+ readonly sourceKey: string;
7
+ constructor(sourceType: MouseSourceType, sourceKey: string);
8
+ getValue(state: MouseState): boolean | number | undefined;
9
+ }
@@ -0,0 +1,24 @@
1
+ export interface KeyboardState {
2
+ readonly keys: Readonly<Record<string, boolean>>;
3
+ }
4
+ export interface MouseState {
5
+ readonly buttons: Readonly<Record<string, boolean>>;
6
+ readonly position: Readonly<{
7
+ x: number;
8
+ y: number;
9
+ }>;
10
+ readonly wheel: Readonly<{
11
+ deltaX: number;
12
+ deltaY: number;
13
+ deltaZ: number;
14
+ }>;
15
+ /** How far the pointer travelled since the last routing pass, which is what a delta binding reads. */
16
+ readonly movement: Readonly<{
17
+ x: number;
18
+ y: number;
19
+ }>;
20
+ }
21
+ export interface GamepadState {
22
+ readonly buttons: Readonly<Record<string, number>>;
23
+ readonly axes: Readonly<Record<string, number>>;
24
+ }
@@ -0,0 +1,21 @@
1
+ import { BindingInput, DeviceType } from "./binding.d.ts";
2
+ export interface CaptureOptions {
3
+ deviceTypes?: readonly DeviceType[];
4
+ sourceTypes?: readonly string[];
5
+ signal?: AbortSignal;
6
+ }
7
+ export interface CandidateInput {
8
+ device: {
9
+ type: DeviceType;
10
+ index: number;
11
+ };
12
+ sourceType: string;
13
+ sourceKey: string;
14
+ value: boolean | number;
15
+ }
16
+ export declare class InputCapture {
17
+ #private;
18
+ constructor(options?: CaptureOptions);
19
+ feed(candidate: CandidateInput): void;
20
+ wait(): Promise<BindingInput>;
21
+ }
@@ -0,0 +1,4 @@
1
+ import { Action } from '@skewedaspect/sage-core';
2
+ import { Binding, BindingDefinition } from "./binding.d.ts";
3
+ import { DeviceReader } from "./deviceReader.d.ts";
4
+ export declare function resolveBinding<State>(definition: BindingDefinition, action: Action, reader: DeviceReader<State>): Binding<State>;
@@ -1,6 +1,14 @@
1
- import { EngineOptions, NullEngineOptions, WebGPUEngineOptions } from '@babylonjs/core';
1
+ import { AbstractMesh, EngineOptions, NullEngineOptions, Scene, WebGPUEngineOptions } from '@babylonjs/core';
2
+ import { StateBag } from '@skewedaspect/sage-core';
2
3
  import { LogLevel } from "./logger.d.ts";
3
- import { BindingDefinition } from "./binding.d.ts";
4
+ /**
5
+ * Builds a NodeEntity class's mesh from its name and state, into the given scene.
6
+ *
7
+ * NodeSimulationContext's own MeshLoader carries no scene, because the same context that calls it also holds
8
+ * the scene -- but a game's own loader is authored once, before any scene exists, and reused across every
9
+ * level's simulation, so it needs the scene handed in.
10
+ */
11
+ export type EntityMeshLoader = (scene: Scene, name: string, state: Readonly<StateBag>) => Promise<AbstractMesh | undefined>;
4
12
  export type GameCanvas = HTMLCanvasElement | OffscreenCanvas | null;
5
13
  /** Specifies which rendering engine to force using */
6
14
  export type EngineType = 'webgl' | 'webgpu' | 'auto';
@@ -19,8 +27,6 @@ export type RenderEngineOptions = (BabylonEngineOptions | NullEngineOptions | We
19
27
  export interface SageOptions {
20
28
  /** Render engine options for BabylonJS */
21
29
  renderOptions?: RenderEngineOptions;
22
- /** Input bindings to be registered at startup */
23
- bindings?: BindingDefinition[];
24
30
  /** Logging level for the engine */
25
31
  logLevel?: LogLevel;
26
32
  /** Audio channel names. If provided, SAGE initializes AudioV2 with one bus per channel. */
@@ -37,7 +43,17 @@ export interface SageOptions {
37
43
  * - `{ namespace: 'myGame' }`: enabled with custom namespace
38
44
  * - `false`: disabled (production builds)
39
45
  */
40
- debug?: false | {
46
+ debug?: boolean | {
41
47
  namespace?: string;
42
48
  };
49
+ /**
50
+ * Pre-loaded Havok WASM binary, for booting outside a browser.
51
+ *
52
+ * Havok normally fetches its own WASM over HTTP; in node there is nothing to fetch from, so the
53
+ * bytes have to be handed in. Browsers should leave this unset -- it is not a performance knob,
54
+ * and setting it does not change how physics behaves.
55
+ */
56
+ havokBinary?: BufferSource;
57
+ /** The simulation's fixed step duration, in seconds. Default 1/60. */
58
+ fixedStepDuration?: number;
43
59
  }
@@ -1,7 +1,18 @@
1
1
  import { Scene, TransformNode } from '@babylonjs/core';
2
2
  import { GameEngine } from "../classes/gameEngine.d.ts";
3
+ import { EntityMeshLoader } from "./game.d.ts";
3
4
  import { ColliderDebugConfig } from "../managers/colliderDebug.d.ts";
4
5
  import { LoggingUtility } from "../utils/logger.d.ts";
6
+ /**
7
+ * Options controlling how a level loads.
8
+ */
9
+ export interface LevelLoadOptions {
10
+ /**
11
+ * If true, this load is restoring a save: the level runs no marker-driven spawning of its own, since the
12
+ * restored snapshot is the sole source of entities (design/simulation.md#saved-games).
13
+ */
14
+ forRestore?: boolean;
15
+ }
5
16
  /**
6
17
  * Minimal interface for Level that property handlers receive.
7
18
  * This avoids circular dependencies while still providing access to level functionality.
@@ -43,7 +54,7 @@ export interface SpawnDefinition {
43
54
  tags?: string[];
44
55
  /** Additional configuration passed to the entity's initial state */
45
56
  config?: Record<string, unknown>;
46
- /** Debug collider visualization config. Overrides the entity definition's debugCollider. */
57
+ /** Debug collider visualization config, written into the spawned entity's own debugCollider state field. */
47
58
  debugCollider?: ColliderDebugConfig;
48
59
  }
49
60
  /**
@@ -51,13 +62,15 @@ export interface SpawnDefinition {
51
62
  * Used to configure entities that are marked with the 'entity' property in scene files.
52
63
  */
53
64
  export interface EntityDefinition {
54
- /** Optional name override for the entity (overrides the scene node name). */
65
+ /** The entity type name to spawn, adopting the marked node. */
66
+ entity: string;
67
+ /** Optional human-readable name for the entity instance. */
55
68
  name?: string;
56
69
  /** Tags to apply to the entity (merged with definition tags). */
57
70
  tags?: string[];
58
71
  /** Additional configuration passed to the entity's initial state */
59
72
  config?: Record<string, unknown>;
60
- /** Debug collider visualization config. Overrides the entity definition's debugCollider. */
73
+ /** Debug collider visualization config, written into the spawned entity's own debugCollider state field. */
61
74
  debugCollider?: ColliderDebugConfig;
62
75
  }
63
76
  /**
@@ -81,6 +94,11 @@ export interface SceneConfig {
81
94
  export interface LevelConfig {
82
95
  /** The name of the level */
83
96
  name: string;
97
+ /**
98
+ * Builds a NodeEntity class's mesh from its name and state, into the level's scene. Left unset, every
99
+ * entity this level spawns gets a node with no mesh.
100
+ */
101
+ meshSource?: EntityMeshLoader;
84
102
  /** Scene file path, or configuration object with path and options */
85
103
  scene?: string | SceneConfig;
86
104
  /** Name of a registered custom Level class to use instead of GameLevel */
@@ -17,16 +17,23 @@ export declare class AssetManager implements Disposable {
17
17
  private _containers;
18
18
  /** Extracted fragment meshes (source meshes for instancing), keyed by full fragment path */
19
19
  private _sourceMeshes;
20
+ /** Container loads still in flight, keyed by base path, so concurrent callers share one load */
21
+ private _pendingContainers;
20
22
  constructor(eventBus: GameEventBus, sceneEngine: SceneEngine, logger?: LoggingUtility);
21
23
  /**
22
24
  * Split a path on `#` into base path and optional fragment name.
23
25
  */
24
26
  private _parsePath;
25
27
  /**
26
- * Load (or retrieve from cache) the AssetContainer for a base path.
27
- * Increments refCount.
28
+ * Load (or retrieve from cache) the AssetContainer for a base path, counting one reference for this
29
+ * caller. A caller arriving while the same base path is already loading shares that load instead of
30
+ * starting a second one, which would leave the first container cached over and uncounted.
28
31
  */
29
32
  private _loadContainer;
33
+ /**
34
+ * Read one container off disk and cache it, counting no references; `_loadContainer` does the counting.
35
+ */
36
+ private _fetchContainer;
30
37
  /**
31
38
  * Find a mesh by name inside a container. Throws if not found.
32
39
  */
@@ -49,7 +56,14 @@ export declare class AssetManager implements Disposable {
49
56
  */
50
57
  clone(path: string): Mesh;
51
58
  /**
52
- * Preload a batch of asset paths. Emits `asset:progress` after each and `asset:complete` when finished.
59
+ * Preload a batch of asset paths, up to `MAX_CONCURRENT_LOADS` at a time, so a batch costs about as
60
+ * long as its slowest asset rather than the sum of them all.
61
+ *
62
+ * Emits `asset:progress` as each asset finishes loading, naming the asset that finished and counting
63
+ * one to one up to the total. Loads finish out of request order, so the paths do too.
64
+ *
65
+ * Every asset is attempted, and every load has finished before this returns. If any failed, it throws
66
+ * an `AggregateError` naming all of them and emits no `asset:complete`.
53
67
  */
54
68
  preload(paths: string[]): Promise<void>;
55
69
  /**
@@ -1,19 +1,23 @@
1
1
  import { AbstractEngine, Scene } from '@babylonjs/core';
2
2
  import { Disposable } from "../interfaces/lifecycle.d.ts";
3
3
  import { GameEventBus } from "../classes/eventBus.d.ts";
4
- import { GameEntityManager } from "./entity.d.ts";
4
+ import { GameEngine } from "../classes/gameEngine.d.ts";
5
+ import { InputManager } from "./input.d.ts";
5
6
  import { LevelManager } from "./level.d.ts";
6
- import { UserInputManager } from "./input.d.ts";
7
7
  import { LoggingUtility } from "../utils/logger.d.ts";
8
8
  /**
9
9
  * Callback function for frame updates.
10
10
  * Called once per frame with the delta time in seconds.
11
11
  */
12
12
  export type FrameCallback = (deltaTime: number) => void;
13
+ /** How a frame callback answers to pause (design/ui.md#when-a-view-observes). */
14
+ export interface FrameCallbackOptions {
15
+ suspendedByPause?: boolean;
16
+ }
13
17
  export declare class GameManager implements Disposable {
14
18
  private _engine;
15
19
  private _eventBus;
16
- private _entityManager;
20
+ private _gameEngine;
17
21
  private _inputManager;
18
22
  private _levelManager;
19
23
  private _log;
@@ -26,8 +30,14 @@ export declare class GameManager implements Disposable {
26
30
  /** Whether the game is currently paused */
27
31
  private _paused;
28
32
  started: boolean;
29
- constructor(engine: AbstractEngine, eventBus: GameEventBus, entityManager: GameEntityManager, inputManager: UserInputManager, levelManager: LevelManager, logger?: LoggingUtility);
33
+ constructor(engine: AbstractEngine, eventBus: GameEventBus, levelManager: LevelManager, logger?: LoggingUtility);
30
34
  get currentScene(): Scene | null;
35
+ /**
36
+ * Late-bind the GameEngine after construction.
37
+ * Called by createGameEngine() after the GameEngine instance is created.
38
+ */
39
+ $setGameEngine(gameEngine: GameEngine): void;
40
+ setInputManager(inputManager: InputManager): void;
31
41
  /**
32
42
  * Whether the game is currently paused.
33
43
  * When paused, entity updates and frame callbacks are skipped, but rendering continues.
@@ -57,7 +67,7 @@ export declare class GameManager implements Disposable {
57
67
  * unsubscribe();
58
68
  * ```
59
69
  */
60
- registerFrameCallback(callback: FrameCallback): () => void;
70
+ registerFrameCallback(callback: FrameCallback, options?: FrameCallbackOptions): () => void;
61
71
  private _renderLoop;
62
72
  private _resizeHandler;
63
73
  start(): Promise<void>;