@yagejs/core 0.3.0 → 0.5.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.
package/dist/index.d.ts CHANGED
@@ -47,152 +47,6 @@ declare class AssetManager {
47
47
  private key;
48
48
  }
49
49
 
50
- /** Options for creating a Process. */
51
- interface ProcessOptions {
52
- /** Called each frame with dt (ms) and elapsed (ms). Return true to complete early. */
53
- update?: (dt: number, elapsed: number) => boolean | void;
54
- /** Called when the process completes. */
55
- onComplete?: () => void;
56
- /** Auto-complete after this duration in ms. */
57
- duration?: number;
58
- /** Loop the process. */
59
- loop?: boolean;
60
- /** Tags for process filtering. */
61
- tags?: string[];
62
- }
63
- /**
64
- * A Process represents an ongoing action updated each frame.
65
- * Used internally by Tween and Sequence, and directly for custom coroutines.
66
- */
67
- declare class Process {
68
- private readonly updateFn;
69
- private readonly onCompleteFn;
70
- private readonly duration;
71
- private readonly loop;
72
- /** Tags for filtering/grouping. */
73
- readonly tags: readonly string[];
74
- private elapsed;
75
- private _completed;
76
- private _paused;
77
- private _cancelled;
78
- private resolvePromise?;
79
- /** Create a timer that fires `onComplete` after `duration` ms. */
80
- static delay(duration: number, onComplete?: () => void, tags?: string[]): Process;
81
- constructor(options: ProcessOptions);
82
- /** Whether the process has completed. */
83
- get completed(): boolean;
84
- /** Whether the process is paused. */
85
- get paused(): boolean;
86
- /** Pause the process. */
87
- pause(): void;
88
- /** Resume the process. */
89
- resume(): void;
90
- /** Cancel the process. */
91
- cancel(): void;
92
- /** Returns a promise that resolves when the process completes or is cancelled. */
93
- toPromise(): Promise<void>;
94
- /**
95
- * Advance the process by dt milliseconds.
96
- * @internal
97
- */
98
- _update(dt: number): void;
99
- /**
100
- * Reset the process to its initial state so it can be re-run.
101
- * @internal Used by Sequence for loop/repeat with direct instances.
102
- */
103
- _reset(): void;
104
- private complete;
105
- }
106
- /** Linear easing (no easing). */
107
- declare const easeLinear: EasingFunction;
108
- /** Ease in quadratic. */
109
- declare const easeInQuad: EasingFunction;
110
- /** Ease out quadratic. */
111
- declare const easeOutQuad: EasingFunction;
112
- /** Ease in-out quadratic. */
113
- declare const easeInOutQuad: EasingFunction;
114
- /** Ease out bounce. */
115
- declare const easeOutBounce: EasingFunction;
116
-
117
- /**
118
- * Built-in system that ticks all ProcessComponents on entities in non-paused
119
- * scenes, plus a scene-level set of global processes.
120
- *
121
- * Runs at Phase.Update with priority 500, ensuring tweened values are fresh
122
- * before ComponentUpdateSystem (priority 1000) reads them.
123
- */
124
- declare class ProcessSystem extends System {
125
- readonly phase = Phase.Update;
126
- readonly priority = 500;
127
- /** Global time scale multiplier. Stacks multiplicatively with per-scene timeScale. */
128
- timeScale: number;
129
- private sceneManager;
130
- private sceneProcesses;
131
- onRegister(context: EngineContext): void;
132
- /** Add a scene-level process (not tied to any entity). */
133
- add(process: Process): Process;
134
- /** Cancel scene-level processes, optionally by tag. */
135
- cancel(tag?: string): void;
136
- update(dt: number): void;
137
- }
138
-
139
- /** Callbacks invoked by the game loop each frame. */
140
- interface GameLoopCallbacks {
141
- earlyUpdate(dt: number): void;
142
- fixedUpdate(fixedDt: number): void;
143
- update(dt: number): void;
144
- lateUpdate(dt: number): void;
145
- render(dt: number): void;
146
- endOfFrame(dt: number): void;
147
- }
148
- /** Configuration for the game loop. */
149
- interface GameLoopConfig {
150
- /** Fixed timestep in ms. Default: 1000/60. */
151
- fixedTimestep?: number;
152
- /** Max fixed steps per frame to prevent spiral of death. Default: 5. */
153
- maxFixedStepsPerFrame?: number;
154
- }
155
- /**
156
- * Game loop with fixed timestep accumulator.
157
- *
158
- * Driven by an external ticker (e.g., PixiJS Ticker) or manual `tick()` calls
159
- * for testing. Implements deterministic fixed updates with variable rendering.
160
- */
161
- declare class GameLoop {
162
- /** Fixed timestep in ms. */
163
- readonly fixedTimestep: number;
164
- /** Max fixed steps per frame. */
165
- readonly maxFixedStepsPerFrame: number;
166
- private accumulator;
167
- private running;
168
- private callbacks;
169
- private tickerUnsubscribe;
170
- private rafId;
171
- private lastTime;
172
- private _frameCount;
173
- constructor(config?: GameLoopConfig);
174
- /** Current frame count. */
175
- get frameCount(): number;
176
- /** Whether the loop is running. */
177
- get isRunning(): boolean;
178
- /** Ratio of accumulated time to fixed timestep, for physics interpolation. */
179
- get interpolationAlpha(): number;
180
- /** Provide the callbacks that the loop invokes each frame. */
181
- setCallbacks(callbacks: GameLoopCallbacks): void;
182
- /**
183
- * Attach an external ticker (e.g., PixiJS Ticker).
184
- * The ticker calls `tick(dt)` every frame.
185
- * If no ticker is attached, the loop uses requestAnimationFrame.
186
- */
187
- attachTicker(subscribe: (callback: (dt: number) => void) => () => void): void;
188
- /** Start the loop. */
189
- start(): void;
190
- /** Stop the loop. */
191
- stop(): void;
192
- /** Process one frame with the given dt in milliseconds. */
193
- tick(dtMs: number): void;
194
- }
195
-
196
50
  /**
197
51
  * A phantom-typed token for entity events.
198
52
  * Similar to ServiceKey, but used for entity-level event pub/sub.
@@ -443,46 +297,6 @@ declare class Entity {
443
297
  _setScene(scene: Scene | null, callbacks: EntityCallbacks | null): void;
444
298
  }
445
299
 
446
- /** Which scene op triggered this transition. */
447
- type SceneTransitionKind = "push" | "pop" | "replace";
448
- /** Context passed to a transition each frame. */
449
- interface SceneTransitionContext {
450
- /** Wall-clock ms elapsed since begin(). */
451
- readonly elapsed: number;
452
- readonly kind: SceneTransitionKind;
453
- readonly engineContext: EngineContext;
454
- /** The scene being left or removed (undefined on first push). */
455
- readonly fromScene: Scene | undefined;
456
- /** The scene being entered or revealed (undefined on last pop). */
457
- readonly toScene: Scene | undefined;
458
- }
459
- /**
460
- * A scene transition animates the handoff between scene stack states.
461
- *
462
- * `SceneManager` keeps both the outgoing and incoming scenes on the stack
463
- * for the transition's duration, then removes the outgoing scene afterward.
464
- * Transitions use raw wall-clock dt and ignore engine + scene `timeScale`.
465
- */
466
- interface SceneTransition {
467
- /** Total duration in wall-clock ms. */
468
- readonly duration: number;
469
- /** Called once when the transition starts. Set up resources here. */
470
- begin?(ctx: SceneTransitionContext): void;
471
- /** Called each frame with frame dt in ms. `ctx.elapsed` is clamped to `duration`. */
472
- tick(dt: number, ctx: SceneTransitionContext): void;
473
- /** Called when the transition ends. Tear down resources here. */
474
- end?(ctx: SceneTransitionContext): void;
475
- }
476
- /** Options accepted by `SceneManager.push/pop/replace`. */
477
- interface SceneTransitionOptions {
478
- transition?: SceneTransition;
479
- }
480
- /**
481
- * Resolve the effective transition for a scene op.
482
- * Precedence: call-site option → destination's `defaultTransition` → undefined.
483
- */
484
- declare function resolveTransition(callSite: SceneTransition | undefined, destination: Scene | undefined): SceneTransition | undefined;
485
-
486
300
  /** Filter criteria for entity queries. All fields are AND'd together. */
487
301
  interface EntityFilter {
488
302
  /** Match entities whose class implements this trait. */
@@ -523,6 +337,7 @@ declare abstract class Scene {
523
337
  private queryCache;
524
338
  private bus;
525
339
  private _entityEventHandlers?;
340
+ private _entityEventObserver?;
526
341
  private _scopedServices?;
527
342
  /** Access the EngineContext. */
528
343
  get context(): EngineContext;
@@ -580,6 +395,12 @@ declare abstract class Scene {
580
395
  * @internal
581
396
  */
582
397
  _onEntityEvent(eventName: string, data: unknown, entity: Entity): void;
398
+ /**
399
+ * Observe entity-scoped event emissions after they dispatch locally and
400
+ * bubble to the scene. Tooling only; game code should keep using `on()`.
401
+ * @internal
402
+ */
403
+ _observeEntityEvent(eventName: string, data: unknown, entity: Entity): void;
583
404
  /** Called during asset preloading with progress ratio (0→1). */
584
405
  onProgress?(ratio: number): void;
585
406
  /** Called when the scene is entered (after preload completes). */
@@ -601,6 +422,11 @@ declare abstract class Scene {
601
422
  * @internal
602
423
  */
603
424
  _registerScoped<T>(key: ServiceKey<T>, value: T): void;
425
+ /**
426
+ * Install or clear a tooling-only observer for bubbled entity events.
427
+ * @internal
428
+ */
429
+ _setEntityEventObserver(observer?: (eventName: string, data: unknown, entity: Entity) => void): void;
604
430
  /**
605
431
  * Resolve a scene-scoped service, or `undefined` if none was registered.
606
432
  * @internal
@@ -630,85 +456,124 @@ declare abstract class Scene {
630
456
  _destroyAllEntities(): void;
631
457
  }
632
458
 
459
+ /** Which scene op triggered this transition. */
460
+ type SceneTransitionKind = "push" | "pop" | "replace";
461
+ /** Context passed to a transition each frame. */
462
+ interface SceneTransitionContext {
463
+ /** Wall-clock ms elapsed since begin(). */
464
+ readonly elapsed: number;
465
+ readonly kind: SceneTransitionKind;
466
+ readonly engineContext: EngineContext;
467
+ /** The scene being left or removed (undefined on first push). */
468
+ readonly fromScene: Scene | undefined;
469
+ /** The scene being entered or revealed (undefined on last pop). */
470
+ readonly toScene: Scene | undefined;
471
+ }
633
472
  /**
634
- * Base class for all components.
473
+ * A scene transition animates the handoff between scene stack states.
635
474
  *
636
- * Components are the primary authoring model. Game developers write behavior
637
- * in components using optional `update(dt)` and `fixedUpdate(dt)` methods.
638
- * The built-in ComponentUpdateSystem calls these methods automatically.
475
+ * `SceneManager` keeps both the outgoing and incoming scenes on the stack
476
+ * for the transition's duration, then removes the outgoing scene afterward.
477
+ * Transitions use raw wall-clock dt and ignore engine + scene `timeScale`.
639
478
  */
640
- declare abstract class Component {
641
- /**
642
- * Back-reference to the owning entity. Set by the engine when the component
643
- * is added to an entity. Do not set manually.
644
- */
645
- entity: Entity;
646
- /** Whether this component is active. Disabled components are skipped by ComponentUpdateSystem. */
647
- enabled: boolean;
648
- private _serviceCache;
649
- private _cleanups?;
650
- /**
651
- * Access the entity's scene. Throws if the entity is not in a scene.
652
- * Prefer this over threading through `this.entity.scene` in component
653
- * code.
654
- */
655
- get scene(): Scene;
656
- /**
657
- * Access the EngineContext from the entity's scene.
658
- * Throws if the entity is not in a scene.
659
- */
660
- get context(): EngineContext;
661
- /**
662
- * Resolve a service by key, cached after first lookup. Scene-scoped values
663
- * (registered via `scene._registerScoped`) take precedence over engine
664
- * scope. A key declared with `scope: "scene"` that falls back to engine
665
- * scope emits a one-shot dev warning — almost always signals a missed
666
- * `beforeEnter` hook.
667
- */
668
- protected use<T>(key: ServiceKey<T>): T;
669
- private _warnScopedFallback;
670
- /**
671
- * Lazy proxy-based service resolution. Can be used at field-declaration time:
672
- * ```ts
673
- * readonly input = this.service(InputManagerKey);
674
- * ```
675
- * The actual resolution is deferred until first property access.
676
- */
677
- protected service<T extends object>(key: ServiceKey<T>): T;
678
- /**
679
- * Lazy proxy-based sibling component resolution. Can be used at field-declaration time:
680
- * ```ts
681
- * readonly anim = this.sibling(AnimatedSpriteComponent);
682
- * ```
683
- * The actual resolution is deferred until first property access.
684
- */
685
- protected sibling<C extends Component>(cls: ComponentClass<C>): C;
686
- /** Subscribe to events on any entity, auto-unsubscribe on removal. */
687
- protected listen<T>(entity: Entity, token: EventToken<T>, handler: (data: T) => void): void;
688
- /** Subscribe to scene-level bubbled events, auto-unsubscribe on removal. */
689
- protected listenScene<T>(token: EventToken<T>, handler: (data: T, entity: Entity) => void): void;
690
- /** Register a cleanup function to run when this component is removed or destroyed. */
691
- protected addCleanup(fn: () => void): void;
479
+ interface SceneTransition {
480
+ /** Total duration in wall-clock ms. */
481
+ readonly duration: number;
482
+ /** Called once when the transition starts. Set up resources here. */
483
+ begin?(ctx: SceneTransitionContext): void;
484
+ /** Called each frame with frame dt in ms. `ctx.elapsed` is clamped to `duration`. */
485
+ tick(dt: number, ctx: SceneTransitionContext): void;
486
+ /** Called when the transition ends. Tear down resources here. */
487
+ end?(ctx: SceneTransitionContext): void;
488
+ }
489
+ /** Options accepted by `SceneManager.push/pop/replace`. */
490
+ interface SceneTransitionOptions {
491
+ transition?: SceneTransition;
492
+ }
493
+ /**
494
+ * Resolve the effective transition for a scene op.
495
+ * Precedence: call-site option → destination's `defaultTransition` → undefined.
496
+ */
497
+ declare function resolveTransition(callSite: SceneTransition | undefined, destination: Scene | undefined): SceneTransition | undefined;
498
+
499
+ type EntityRef = {
500
+ readonly id: number;
501
+ readonly name: string;
502
+ };
503
+ type SceneRef = {
504
+ readonly name: string;
505
+ };
506
+ /** Base type for event map definitions. */
507
+ type EventMap = Record<string, unknown>;
508
+ /** Well-known engine events. */
509
+ interface EngineEvents {
510
+ "entity:created": {
511
+ entity: EntityRef;
512
+ };
513
+ "entity:destroyed": {
514
+ entity: EntityRef;
515
+ };
516
+ "component:added": {
517
+ entity: EntityRef;
518
+ component: Component;
519
+ };
520
+ "component:removed": {
521
+ entity: EntityRef;
522
+ componentClass: ComponentClass;
523
+ };
524
+ "scene:pushed": {
525
+ scene: SceneRef;
526
+ };
527
+ "scene:popped": {
528
+ scene: SceneRef;
529
+ };
530
+ "scene:replaced": {
531
+ oldScene: SceneRef;
532
+ newScene: SceneRef;
533
+ };
534
+ "scene:transition:started": {
535
+ kind: SceneTransitionKind;
536
+ fromScene: SceneRef | undefined;
537
+ toScene: SceneRef | undefined;
538
+ };
539
+ "scene:transition:ended": {
540
+ kind: SceneTransitionKind;
541
+ fromScene: SceneRef | undefined;
542
+ toScene: SceneRef | undefined;
543
+ };
544
+ "scene:loading:progress": {
545
+ scene: Scene;
546
+ ratio: number;
547
+ };
548
+ "scene:loading:done": {
549
+ scene: Scene;
550
+ };
551
+ "engine:started": undefined;
552
+ "engine:stopped": undefined;
553
+ "screen:fullscreen": {
554
+ active: boolean;
555
+ };
556
+ "screen:orientation": {
557
+ type: OrientationType;
558
+ };
559
+ }
560
+ /** Typed publish/subscribe event bus. */
561
+ declare class EventBus<E = EventMap> {
562
+ private handlers;
563
+ private observers;
564
+ /** Subscribe to an event. Returns an unsubscribe function. */
565
+ on<K extends keyof E>(event: K, handler: (data: E[K]) => void): () => void;
566
+ /** Subscribe to an event, auto-unsubscribe after first emission. */
567
+ once<K extends keyof E>(event: K, handler: (data: E[K]) => void): () => void;
568
+ /** Emit an event. Handlers are called synchronously in registration order. */
569
+ emit<K extends keyof E>(event: K, data: E[K]): void;
692
570
  /**
693
- * Run and clear all registered cleanups.
694
- * Called by Entity.remove() and Entity._performDestroy() before onRemove/onDestroy.
695
- * @internal
571
+ * Observe every emitted event without affecting handler order or control
572
+ * flow. Used by tooling such as the Inspector event log.
696
573
  */
697
- _runCleanups(): void;
698
- /** Called when the component is added to an entity. */
699
- onAdd?(): void;
700
- /** Called when the component is removed from an entity. */
701
- onRemove?(): void;
702
- /** Called when the component is destroyed (entity destroyed or component removed). */
703
- onDestroy?(): void;
704
- /** Called every frame by the built-in ComponentUpdateSystem. */
705
- update?(dt: number): void;
706
- /** Called every fixed timestep by the built-in ComponentUpdateSystem. */
707
- fixedUpdate?(dt: number): void;
708
- /** Return a JSON-serializable snapshot of this component's state. Used by the save system. */
709
- serialize?(): unknown;
710
- /** Called after onAdd() during save/load restoration. Apply state that depends on onAdd() having run. */
711
- afterRestore?(data: unknown, resolve: SnapshotResolver): void;
574
+ tap(observer: (event: keyof E, data: E[keyof E]) => void): () => void;
575
+ /** Remove all handlers for an event, or all handlers if no event specified. */
576
+ clear(event?: keyof E): void;
712
577
  }
713
578
 
714
579
  /** Log severity levels. */
@@ -775,63 +640,61 @@ declare class Logger {
775
640
  private log;
776
641
  }
777
642
 
778
- /**
779
- * Wraps system and component execution. On error, disables the offending
780
- * system/component and logs the error. The game loop never crashes.
781
- */
782
- declare class ErrorBoundary {
783
- private logger;
784
- private disabledSystems;
785
- private disabledComponents;
786
- constructor(logger: Logger);
787
- /** Wrap a system update call. On throw, disables the system. */
788
- wrapSystem(system: System, fn: () => void): void;
789
- /** Wrap a component lifecycle or update call. On throw, disables the component. */
790
- wrapComponent(component: Component, fn: () => void): void;
791
- /** Get all disabled systems and components for inspection. */
792
- getDisabled(): {
793
- systems: ReadonlyArray<{
794
- system: System;
795
- error: string;
796
- }>;
797
- components: ReadonlyArray<{
798
- component: Component;
799
- error: string;
800
- }>;
801
- };
643
+ /** Callbacks invoked by the game loop each frame. */
644
+ interface GameLoopCallbacks {
645
+ earlyUpdate(dt: number): void;
646
+ fixedUpdate(fixedDt: number): void;
647
+ update(dt: number): void;
648
+ lateUpdate(dt: number): void;
649
+ render(dt: number): void;
650
+ endOfFrame(dt: number): void;
802
651
  }
803
-
804
- /** A filter used to register a query — an array of required component classes. */
805
- type QueryFilter = readonly ComponentClass[];
806
- /** A live, iterable set of entities matching a query filter. */
807
- declare class QueryResult {
808
- /** @internal */
809
- readonly _entities: Set<Entity>;
810
- /** @internal */
811
- readonly _filter: QueryFilter;
812
- /** @internal */
813
- constructor(filter: QueryFilter);
814
- /** Iterate matching entities. */
815
- [Symbol.iterator](): Iterator<Entity>;
816
- /** Number of matching entities. */
817
- get size(): number;
818
- /** Get the first match (useful for singleton queries). */
819
- get first(): Entity | undefined;
820
- /** Convert to array (allocates). */
821
- toArray(): Entity[];
652
+ /** Configuration for the game loop. */
653
+ interface GameLoopConfig {
654
+ /** Fixed timestep in ms. Default: 1000/60. */
655
+ fixedTimestep?: number;
656
+ /** Max fixed steps per frame to prevent spiral of death. Default: 5. */
657
+ maxFixedStepsPerFrame?: number;
822
658
  }
823
- /** Incrementally maintained entity sets based on component signatures. */
824
- declare class QueryCache {
825
- private queries;
826
- /** Register a query. Returns a stable reference to a live result set. */
827
- register(filter: QueryFilter): QueryResult;
828
- /** Called by Entity when a component is added. */
829
- onComponentAdded(entity: Entity): void;
830
- /** Called by Entity when a component is removed. */
831
- onComponentRemoved(entity: Entity): void;
832
- /** Called when an entity is destroyed. */
833
- onEntityDestroyed(entity: Entity): void;
834
- private matches;
659
+ /**
660
+ * Game loop with fixed timestep accumulator.
661
+ *
662
+ * Driven by an external ticker (e.g., PixiJS Ticker) or manual `tick()` calls
663
+ * for testing. Implements deterministic fixed updates with variable rendering.
664
+ */
665
+ declare class GameLoop {
666
+ /** Fixed timestep in ms. */
667
+ readonly fixedTimestep: number;
668
+ /** Max fixed steps per frame. */
669
+ readonly maxFixedStepsPerFrame: number;
670
+ private accumulator;
671
+ private running;
672
+ private callbacks;
673
+ private tickerUnsubscribe;
674
+ private rafId;
675
+ private lastTime;
676
+ private _frameCount;
677
+ constructor(config?: GameLoopConfig);
678
+ /** Current frame count. */
679
+ get frameCount(): number;
680
+ /** Whether the loop is running. */
681
+ get isRunning(): boolean;
682
+ /** Ratio of accumulated time to fixed timestep, for physics interpolation. */
683
+ get interpolationAlpha(): number;
684
+ /** Provide the callbacks that the loop invokes each frame. */
685
+ setCallbacks(callbacks: GameLoopCallbacks): void;
686
+ /**
687
+ * Attach an external ticker (e.g., PixiJS Ticker).
688
+ * The ticker calls `tick(dt)` every frame.
689
+ * If no ticker is attached, the loop uses requestAnimationFrame.
690
+ */
691
+ attachTicker(subscribe: (callback: (dt: number) => void) => () => void): void;
692
+ /** Start the loop. */
693
+ start(): void;
694
+ /** Stop the loop. */
695
+ stop(): void;
696
+ /** Process one frame with the given dt in milliseconds. */
697
+ tick(dtMs: number): void;
835
698
  }
836
699
 
837
700
  /** Stack-based scene manager with push/pop/replace semantics. */
@@ -954,15 +817,52 @@ declare class SceneManager {
954
817
  private _fireResumeTransitions;
955
818
  }
956
819
 
957
- /** Full engine state snapshot. */
958
- interface EngineSnapshot {
959
- frameCount: number;
960
- sceneStack: SceneSnapshot[];
961
- entityCount: number;
962
- systemCount: number;
963
- errors: ErrorSnapshot;
820
+ /** Seeded random service used by runtime systems that must be deterministic. */
821
+ interface RandomService {
822
+ /** Random float in the range [0, 1). */
823
+ float(): number;
824
+ /** Random float in the range [min, max). */
825
+ range(min: number, max: number): number;
826
+ /** Random integer in the range [min, max] (inclusive). */
827
+ int(min: number, max: number): number;
828
+ /** Pick a random element from a non-empty array. */
829
+ pick<T>(arr: readonly T[]): T;
830
+ /** Shuffle an array in place and return the same array. */
831
+ shuffle<T>(arr: T[]): T[];
832
+ /** Return the seed this generator was constructed (or last reseeded) with. */
833
+ getSeed(): number;
834
+ }
835
+ /** Scene-scoped key for the active scene's deterministic RNG. */
836
+ declare const RandomKey: ServiceKey<RandomService>;
837
+ /** Normalize arbitrary numbers into the uint32 seed space. */
838
+ declare function normalizeSeed(seed: number): number;
839
+ /** Default seed for explicitly non-deterministic paths. */
840
+ declare function createDefaultRandomSeed(): number;
841
+ /** Create a deterministic random service. */
842
+ declare function createRandomService(seed?: number): RandomService;
843
+ /**
844
+ * Explicitly non-deterministic global RNG for boot-time or cross-scene code.
845
+ * Inspector seed control never touches this instance.
846
+ */
847
+ declare const globalRandom: RandomService;
848
+
849
+ /**
850
+ * Mirrors `GamepadAxisKey` from `@yagejs/input` as a local union so the
851
+ * Inspector contract gets compile-time literal checking without taking a
852
+ * runtime dependency on the input package.
853
+ */
854
+ type InspectorGamepadAxisKey = "leftX" | "leftY" | "rightX" | "rightY" | "leftTrigger" | "rightTrigger";
855
+ /**
856
+ * Options for synthetic pointer injection. Pass `id` / `type` / `isPrimary`
857
+ * to drive a non-primary, touch, or pen pointer in deterministic tests. All
858
+ * fields are optional and default to a primary mouse pointer with `id: 1`.
859
+ */
860
+ interface InspectorPointerOpts {
861
+ id?: number;
862
+ type?: "mouse" | "pen" | "touch";
863
+ isPrimary?: boolean;
964
864
  }
965
- /** Snapshot of a single entity. */
865
+ /** Backward-compatible summary snapshot returned by query helpers. */
966
866
  interface EntitySnapshot {
967
867
  id: number;
968
868
  name: string;
@@ -973,7 +873,7 @@ interface EntitySnapshot {
973
873
  y: number;
974
874
  };
975
875
  }
976
- /** Snapshot of a scene in the stack. */
876
+ /** Backward-compatible scene stack summary. */
977
877
  interface SceneSnapshot {
978
878
  name: string;
979
879
  entityCount: number;
@@ -995,21 +895,250 @@ interface ErrorSnapshot {
995
895
  error: string;
996
896
  }>;
997
897
  }
898
+ interface ComponentStateSnapshot {
899
+ type: string;
900
+ state: unknown | null;
901
+ }
902
+ interface WorldEntitySnapshot {
903
+ id: string;
904
+ type: string;
905
+ parent: string | null;
906
+ transform: {
907
+ x: number;
908
+ y: number;
909
+ rotation: number;
910
+ scaleX: number;
911
+ scaleY: number;
912
+ };
913
+ components: ComponentStateSnapshot[];
914
+ }
915
+ interface UINodeSnapshot {
916
+ id: string;
917
+ type: string;
918
+ layout: {
919
+ x: number;
920
+ y: number;
921
+ width: number;
922
+ height: number;
923
+ };
924
+ children: UINodeSnapshot[];
925
+ state: unknown | null;
926
+ }
927
+ interface UITreeSnapshot {
928
+ root: UINodeSnapshot;
929
+ }
930
+ interface PhysicsSnapshot {
931
+ bodies: Array<{
932
+ entityId: string;
933
+ type: "dynamic" | "kinematic" | "static";
934
+ position: {
935
+ x: number;
936
+ y: number;
937
+ };
938
+ rotation: number;
939
+ linvel: {
940
+ x: number;
941
+ y: number;
942
+ };
943
+ angvel: number;
944
+ }>;
945
+ contacts: Array<{
946
+ a: string;
947
+ b: string;
948
+ }>;
949
+ }
950
+ interface EventLogEntry {
951
+ frame: number;
952
+ source: "bus" | "entity";
953
+ type: string;
954
+ targetId?: string;
955
+ payload: unknown | null;
956
+ }
957
+ interface WorldSceneSnapshot {
958
+ id: string;
959
+ name: string;
960
+ paused: boolean;
961
+ timeScale: number;
962
+ seed: number;
963
+ entities: WorldEntitySnapshot[];
964
+ ui: UITreeSnapshot | null;
965
+ physics: PhysicsSnapshot;
966
+ events: EventLogEntry[];
967
+ }
968
+ interface CameraSnapshot {
969
+ sceneId: string;
970
+ sceneName: string;
971
+ name: string | null;
972
+ priority: number;
973
+ position: {
974
+ x: number;
975
+ y: number;
976
+ };
977
+ zoom: number;
978
+ rotation: number;
979
+ }
980
+ /**
981
+ * Per-pointer entry in {@link InputStateSnapshot.pointers}. Mirrors the runtime
982
+ * `PointerInfo` shape from `@yagejs/input`. Touch pointers vanish from the
983
+ * array once their last button releases; mouse pointers persist.
984
+ */
985
+ interface PointerSnapshot {
986
+ /** `PointerEvent.pointerId`, or the synthetic id passed via `firePointer*`. */
987
+ id: number;
988
+ x: number;
989
+ y: number;
990
+ type: "mouse" | "pen" | "touch";
991
+ isPrimary: boolean;
992
+ buttons: number[];
993
+ down: boolean;
994
+ }
995
+ interface InputStateSnapshot {
996
+ keys: string[];
997
+ actions: string[];
998
+ /**
999
+ * Aggregate / primary-pointer view, retained for back-compat. `x` / `y` track
1000
+ * the primary pointer's screen position; `buttons` / `down` reflect the
1001
+ * any-pointer aggregate that drives the `MouseLeft`/`Middle`/`Right` action codes.
1002
+ *
1003
+ * For multi-touch state, read {@link InputStateSnapshot.pointers}.
1004
+ */
1005
+ mouse: {
1006
+ x: number;
1007
+ y: number;
1008
+ buttons: number[];
1009
+ down: boolean;
1010
+ };
1011
+ /** All currently-tracked pointers (one per active mouse, pen, or finger). */
1012
+ pointers: PointerSnapshot[];
1013
+ gamepad: {
1014
+ /** Currently-held gamepad codes (e.g. `"GamepadA"`, `"GamepadLT"`). */
1015
+ buttons: string[];
1016
+ /**
1017
+ * Axis state keyed by `${padIndex}:${axisName}` (axisName is a
1018
+ * `GamepadAxisKey` from `@yagejs/input`).
1019
+ */
1020
+ axes: Array<{
1021
+ key: string;
1022
+ value: number;
1023
+ }>;
1024
+ };
1025
+ }
1026
+ /** Full deterministic inspector snapshot. */
1027
+ interface EngineSnapshot {
1028
+ version: 1;
1029
+ frame: number;
1030
+ sceneStack: SceneSnapshot[];
1031
+ entityCount: number;
1032
+ systemCount: number;
1033
+ errors: ErrorSnapshot;
1034
+ scenes: WorldSceneSnapshot[];
1035
+ camera: CameraSnapshot | null;
1036
+ input: InputStateSnapshot;
1037
+ }
1038
+ interface InspectorTimeController {
1039
+ readonly isFrozen: boolean;
1040
+ freeze(): void;
1041
+ thaw(): void;
1042
+ stepFrames(count: number): void;
1043
+ setDelta(ms: number): void;
1044
+ getFrame(): number;
1045
+ }
998
1046
  /** Internal engine reference to avoid circular dependency with Engine class. */
999
1047
  interface EngineRef {
1000
1048
  readonly context: EngineContext;
1001
1049
  readonly scenes: SceneManager;
1002
1050
  readonly loop: GameLoop;
1051
+ readonly events?: EventBus<EngineEvents>;
1003
1052
  }
1004
1053
  /**
1005
- * Programmatic state queries for testing and debugging.
1054
+ * Programmatic runtime control and state queries for testing and debugging.
1006
1055
  * Exposed on `window.__yage__` in debug mode.
1007
1056
  */
1008
1057
  declare class Inspector {
1009
- private engine;
1058
+ private readonly engine;
1059
+ private readonly extensions;
1060
+ private readonly sceneIds;
1061
+ private nextSceneId;
1062
+ private defaultSceneSeed;
1063
+ private sceneSeedOverride;
1064
+ private timeController;
1065
+ private eventLogEnabled;
1066
+ private eventCapacity;
1067
+ /**
1068
+ * Ring buffer of recent events. `eventLogHead` points at the oldest slot;
1069
+ * a full ring contains exactly `eventCapacity` entries. We avoid `splice` to
1070
+ * keep `appendEvent` O(1) — the previous shift-on-overflow approach was
1071
+ * O(n) per event once the buffer was full.
1072
+ */
1073
+ private eventLog;
1074
+ private eventLogHead;
1075
+ private eventWaiters;
1076
+ private detachBusTap;
1077
+ private readonly busEventObserver;
1078
+ private readonly sceneEventObserver;
1079
+ readonly time: {
1080
+ freeze: () => void;
1081
+ thaw: () => void;
1082
+ step: (frames?: number) => void;
1083
+ setDelta: (ms: number) => void;
1084
+ isFrozen: () => boolean;
1085
+ getFrame: () => number;
1086
+ };
1087
+ readonly input: {
1088
+ keyDown: (code: string) => void;
1089
+ keyUp: (code: string) => void;
1090
+ mouseMove: (x: number, y: number) => void;
1091
+ mouseDown: (button?: 0 | 1 | 2) => void;
1092
+ mouseUp: (button?: 0 | 1 | 2) => void;
1093
+ /**
1094
+ * Inject a synthetic pointer-move with full pointer addressing. Pass `opts`
1095
+ * with `id` / `type: "touch"` to drive a specific finger; defaults match
1096
+ * the primary mouse pointer (same as `mouseMove`).
1097
+ */
1098
+ pointerMove: (x: number, y: number, opts?: InspectorPointerOpts) => void;
1099
+ /**
1100
+ * Inject a synthetic pointer-down. With `opts.id` and `opts.type: "touch"`
1101
+ * this drives a multi-touch contact, exercising `getPointers()`,
1102
+ * per-pointer event hooks, and the any-pointer aggregate for `MouseLeft`.
1103
+ */
1104
+ pointerDown: (button?: 0 | 1 | 2, opts?: InspectorPointerOpts) => void;
1105
+ pointerUp: (button?: 0 | 1 | 2, opts?: {
1106
+ id?: number;
1107
+ }) => void;
1108
+ gamepadButton: (code: string, pressed: boolean) => void;
1109
+ gamepadAxis: (side: InspectorGamepadAxisKey, value: number) => void;
1110
+ tap: (code: string, frames?: number) => void;
1111
+ hold: (code: string, frames: number) => void;
1112
+ fireAction: (name: string, frames?: number) => void;
1113
+ clearAll: () => void;
1114
+ };
1115
+ readonly events: {
1116
+ getLog: () => EventLogEntry[];
1117
+ clearLog: () => void;
1118
+ setCapacity: (n: number) => void;
1119
+ waitFor: (pattern: string | RegExp, options?: {
1120
+ withinFrames?: number;
1121
+ source?: "bus" | "entity";
1122
+ }) => Promise<EventLogEntry>;
1123
+ };
1124
+ readonly capture: {
1125
+ png: () => Promise<Uint8Array>;
1126
+ dataURL: () => Promise<string>;
1127
+ pngBase64: () => Promise<string>;
1128
+ };
1010
1129
  constructor(engine: EngineRef);
1011
- /** Full state snapshot (serializable). */
1130
+ /** Register a namespaced extension API for plugin-specific debug helpers. */
1131
+ addExtension<T extends object>(namespace: string, api: T): T;
1132
+ /** Look up a previously registered extension API by namespace. */
1133
+ getExtension<T extends object>(namespace: string): T | undefined;
1134
+ /** Remove a previously registered extension namespace. */
1135
+ removeExtension(namespace: string): void;
1136
+ /** Full deterministic state snapshot (stable ordering, serializable). */
1012
1137
  snapshot(): EngineSnapshot;
1138
+ /** Stable JSON form of {@link snapshot}. */
1139
+ snapshotJSON(): string;
1140
+ /** Snapshot one scene by inspector scene id. */
1141
+ snapshotScene(id: string): WorldSceneSnapshot;
1013
1142
  /** Find entity by name in the active scene. */
1014
1143
  getEntityByName(name: string): EntitySnapshot | undefined;
1015
1144
  /** Get entity position (from Transform component). */
@@ -1021,7 +1150,7 @@ declare class Inspector {
1021
1150
  hasComponent(entityName: string, componentClass: string): boolean;
1022
1151
  /** Get component data (serializable subset) by class name string. */
1023
1152
  getComponentData(entityName: string, componentClass: string): unknown;
1024
- /** Get all entities in the active scene as snapshots. */
1153
+ /** Get all entities in the active scene as lightweight snapshots. */
1025
1154
  getEntities(): EntitySnapshot[];
1026
1155
  /** Get scene stack info. */
1027
1156
  getSceneStack(): SceneSnapshot[];
@@ -1029,80 +1158,65 @@ declare class Inspector {
1029
1158
  getSystems(): SystemSnapshot[];
1030
1159
  /** Get disabled components/systems from error boundary. */
1031
1160
  getErrors(): ErrorSnapshot;
1161
+ /** Create a new scene-scoped RNG instance using the current inspector seed policy. */
1162
+ createSceneRandom(): RandomService;
1163
+ /** Force every current and future scene RNG to the provided seed. */
1164
+ setSeed(seed: number): void;
1165
+ /** @internal DebugPlugin installs a deterministic default seed through this hook. */
1166
+ setDefaultSceneSeed(seed: number | undefined): void;
1167
+ private resolveInternalRandom;
1168
+ /** @internal DebugPlugin attaches the frozen-time controller through this hook. */
1169
+ attachTimeController(controller: InspectorTimeController): void;
1170
+ /** @internal Clear a previously attached time controller. */
1171
+ detachTimeController(controller?: InspectorTimeController): void;
1172
+ /** @internal Enable or disable event log recording. */
1173
+ setEventLogEnabled(enabled: boolean): void;
1174
+ /** @internal Install entity-event observation for one scene. No-op if disabled. */
1175
+ attachSceneEventObserver(scene: Scene): void;
1176
+ /** @internal Clear entity-event observation for one scene. */
1177
+ detachSceneEventObserver(scene: Scene): void;
1178
+ /** @internal Scene hooks forward entity events through this method. */
1179
+ recordEntityEvent(eventName: string, data: unknown, entity: Entity): void;
1180
+ /** @internal Engine teardown releases the event-bus tap through this hook. */
1181
+ dispose(): void;
1182
+ private requireTimeController;
1183
+ private requireInputManager;
1184
+ private recordBusEvent;
1185
+ private appendEvent;
1186
+ /** Resolve waiters whose deadline has passed without a match. */
1187
+ private expireDeadlineWaiters;
1188
+ /** Resolve any waiter that matches the just-appended entry. */
1189
+ private flushMatchingWaiter;
1190
+ /**
1191
+ * Walk the ring buffer in chronological order. We avoid materializing the
1192
+ * ordered array on every event append; instead, every consumer that needs
1193
+ * order calls this helper.
1194
+ */
1195
+ private iterateLog;
1196
+ private findMatchingEvent;
1197
+ private eventMatches;
1198
+ private sceneToWorldSnapshot;
1199
+ private getSceneEntities;
1200
+ private entityToWorldSnapshot;
1201
+ private componentToSnapshot;
1202
+ private buildUISnapshot;
1203
+ private buildUINodeSnapshot;
1204
+ private buildCameraSnapshot;
1205
+ private findTopmostCamera;
1206
+ private buildInputSnapshot;
1207
+ private getSceneEvents;
1208
+ private inferSceneIdFromPayload;
1209
+ private extractScene;
1210
+ private extractSceneFromEntity;
1032
1211
  private findActiveEntity;
1033
1212
  private findComponentByName;
1034
- private entityToSnapshot;
1213
+ private entityToQuerySnapshot;
1035
1214
  private getTransform;
1036
- private serializeComponent;
1215
+ private serializeComponentOwnProperties;
1037
1216
  private countEntities;
1038
- }
1039
-
1040
- type EntityRef = {
1041
- readonly id: number;
1042
- readonly name: string;
1043
- };
1044
- type SceneRef = {
1045
- readonly name: string;
1046
- };
1047
- /** Base type for event map definitions. */
1048
- type EventMap = Record<string, unknown>;
1049
- /** Well-known engine events. */
1050
- interface EngineEvents {
1051
- "entity:created": {
1052
- entity: EntityRef;
1053
- };
1054
- "entity:destroyed": {
1055
- entity: EntityRef;
1056
- };
1057
- "component:added": {
1058
- entity: EntityRef;
1059
- component: Component;
1060
- };
1061
- "component:removed": {
1062
- entity: EntityRef;
1063
- componentClass: ComponentClass;
1064
- };
1065
- "scene:pushed": {
1066
- scene: SceneRef;
1067
- };
1068
- "scene:popped": {
1069
- scene: SceneRef;
1070
- };
1071
- "scene:replaced": {
1072
- oldScene: SceneRef;
1073
- newScene: SceneRef;
1074
- };
1075
- "scene:transition:started": {
1076
- kind: SceneTransitionKind;
1077
- fromScene: SceneRef | undefined;
1078
- toScene: SceneRef | undefined;
1079
- };
1080
- "scene:transition:ended": {
1081
- kind: SceneTransitionKind;
1082
- fromScene: SceneRef | undefined;
1083
- toScene: SceneRef | undefined;
1084
- };
1085
- "scene:loading:progress": {
1086
- scene: Scene;
1087
- ratio: number;
1088
- };
1089
- "scene:loading:done": {
1090
- scene: Scene;
1091
- };
1092
- "engine:started": undefined;
1093
- "engine:stopped": undefined;
1094
- }
1095
- /** Typed publish/subscribe event bus. */
1096
- declare class EventBus<E = EventMap> {
1097
- private handlers;
1098
- /** Subscribe to an event. Returns an unsubscribe function. */
1099
- on<K extends keyof E>(event: K, handler: (data: E[K]) => void): () => void;
1100
- /** Subscribe to an event, auto-unsubscribe after first emission. */
1101
- once<K extends keyof E>(event: K, handler: (data: E[K]) => void): () => void;
1102
- /** Emit an event. Handlers are called synchronously in registration order. */
1103
- emit<K extends keyof E>(event: K, data: E[K]): void;
1104
- /** Remove all handlers for an event, or all handlers if no event specified. */
1105
- clear(event?: keyof E): void;
1217
+ private getSceneId;
1218
+ private assertNonNegativeInteger;
1219
+ private assertNonEmptyString;
1106
1220
  }
1107
1221
 
1108
1222
  /**
@@ -1150,51 +1264,266 @@ interface EngineConfig {
1150
1264
  logger?: LoggerConfig;
1151
1265
  }
1152
1266
  /**
1153
- * The top-level entry point. Owns the plugin registry, game loop,
1154
- * scene manager, and DI container.
1267
+ * The top-level entry point. Owns the plugin registry, game loop,
1268
+ * scene manager, and DI container.
1269
+ */
1270
+ declare class Engine {
1271
+ /** The dependency injection container. */
1272
+ readonly context: EngineContext;
1273
+ /** The scene manager. */
1274
+ readonly scenes: SceneManager;
1275
+ /** The event bus. */
1276
+ readonly events: EventBus<EngineEvents>;
1277
+ /** The game loop. */
1278
+ readonly loop: GameLoop;
1279
+ /** The logger. */
1280
+ readonly logger: Logger;
1281
+ /** The inspector (debug queries). */
1282
+ readonly inspector: Inspector;
1283
+ private readonly scheduler;
1284
+ private readonly errorBoundary;
1285
+ private readonly queryCache;
1286
+ private readonly sceneHooks;
1287
+ /** The asset manager. */
1288
+ readonly assets: AssetManager;
1289
+ private readonly plugins;
1290
+ private sortedPlugins;
1291
+ private started;
1292
+ private readonly debug;
1293
+ constructor(config?: EngineConfig);
1294
+ /**
1295
+ * Register scene lifecycle hooks. The returned function unregisters the
1296
+ * hooks. Infrastructure plugins (renderer, physics, debug) register hooks
1297
+ * in their `install` or `onStart` to set up and tear down per-scene state.
1298
+ */
1299
+ registerSceneHooks(hooks: SceneHooks): () => void;
1300
+ /** Register a plugin. Must be called before start(). */
1301
+ use(plugin: Plugin): this;
1302
+ /** Start the engine. Installs plugins in topological order, starts the game loop. */
1303
+ start(): Promise<void>;
1304
+ /** Stop the engine. Destroys all scenes, plugins, and the game loop. */
1305
+ destroy(): void;
1306
+ private registerBuiltInSystems;
1307
+ /**
1308
+ * Topological sort of plugins using Kahn's algorithm.
1309
+ * Errors on missing dependencies, circular dependencies, and duplicates.
1310
+ */
1311
+ private topologicalSort;
1312
+ }
1313
+
1314
+ /**
1315
+ * Base class for systems. Systems run in a specific game loop phase,
1316
+ * query for entities matching a component signature, and operate on them.
1317
+ *
1318
+ * Systems are primarily for engine plugins (physics, rendering, audio).
1319
+ * Game developers typically write Components instead.
1320
+ */
1321
+ declare abstract class System {
1322
+ /** The phase this system runs in. */
1323
+ abstract readonly phase: Phase;
1324
+ /** Execution priority within the phase. Lower = earlier. Default: 0. */
1325
+ readonly priority: number;
1326
+ /** Whether this system is active. */
1327
+ enabled: boolean;
1328
+ /** Reference to the engine context, set on registration. */
1329
+ protected context: EngineContext;
1330
+ private _serviceCache;
1331
+ /**
1332
+ * Set the engine context. Called by Engine during startup.
1333
+ * @internal
1334
+ */
1335
+ _setContext(context: EngineContext): void;
1336
+ /** Resolve a service by key, cached after first lookup. */
1337
+ protected use<T>(key: ServiceKey<T>): T;
1338
+ /** Called once when the system is registered with the engine. */
1339
+ onRegister?(context: EngineContext): void;
1340
+ /** Called every frame (or every fixed step for FixedUpdate). */
1341
+ abstract update(dt: number): void;
1342
+ /** Called when the system is removed. */
1343
+ onUnregister?(): void;
1344
+ }
1345
+
1346
+ /**
1347
+ * Wraps system and component execution. On error, disables the offending
1348
+ * system/component and logs the error. The game loop never crashes.
1349
+ */
1350
+ declare class ErrorBoundary {
1351
+ private logger;
1352
+ private disabledSystems;
1353
+ private disabledComponents;
1354
+ constructor(logger: Logger);
1355
+ /** Wrap a system update call. On throw, disables the system. */
1356
+ wrapSystem(system: System, fn: () => void): void;
1357
+ /** Wrap a component lifecycle or update call. On throw, disables the component. */
1358
+ wrapComponent(component: Component, fn: () => void): void;
1359
+ /** Get all disabled systems and components for inspection. */
1360
+ getDisabled(): {
1361
+ systems: ReadonlyArray<{
1362
+ system: System;
1363
+ error: string;
1364
+ }>;
1365
+ components: ReadonlyArray<{
1366
+ component: Component;
1367
+ error: string;
1368
+ }>;
1369
+ };
1370
+ }
1371
+
1372
+ /** Options for creating a Process. */
1373
+ interface ProcessOptions {
1374
+ /** Called each frame with dt (ms) and elapsed (ms). Return true to complete early. */
1375
+ update?: (dt: number, elapsed: number) => boolean | void;
1376
+ /** Called when the process completes. */
1377
+ onComplete?: () => void;
1378
+ /** Auto-complete after this duration in ms. */
1379
+ duration?: number;
1380
+ /** Loop the process. */
1381
+ loop?: boolean;
1382
+ /** Tags for process filtering. */
1383
+ tags?: string[];
1384
+ }
1385
+ /**
1386
+ * A Process represents an ongoing action updated each frame.
1387
+ * Used internally by Tween and Sequence, and directly for custom coroutines.
1388
+ */
1389
+ declare class Process {
1390
+ private readonly updateFn;
1391
+ private readonly onCompleteFn;
1392
+ private readonly duration;
1393
+ private readonly loop;
1394
+ /** Tags for filtering/grouping. */
1395
+ readonly tags: readonly string[];
1396
+ private elapsed;
1397
+ private _completed;
1398
+ private _paused;
1399
+ private _cancelled;
1400
+ private resolvePromise?;
1401
+ /** Create a timer that fires `onComplete` after `duration` ms. */
1402
+ static delay(duration: number, onComplete?: () => void, tags?: string[]): Process;
1403
+ constructor(options: ProcessOptions);
1404
+ /** Whether the process has completed. */
1405
+ get completed(): boolean;
1406
+ /** Whether the process is paused. */
1407
+ get paused(): boolean;
1408
+ /** Pause the process. */
1409
+ pause(): void;
1410
+ /** Resume the process. */
1411
+ resume(): void;
1412
+ /** Cancel the process. */
1413
+ cancel(): void;
1414
+ /** Returns a promise that resolves when the process completes or is cancelled. */
1415
+ toPromise(): Promise<void>;
1416
+ /**
1417
+ * Advance the process by dt milliseconds.
1418
+ * @internal
1419
+ */
1420
+ _update(dt: number): void;
1421
+ /**
1422
+ * Reset the process to its initial state so it can be re-run.
1423
+ * @internal Used by Sequence for loop/repeat with direct instances.
1424
+ */
1425
+ _reset(): void;
1426
+ private complete;
1427
+ }
1428
+ /** Linear easing (no easing). */
1429
+ declare const easeLinear: EasingFunction;
1430
+ /** Ease in quadratic. */
1431
+ declare const easeInQuad: EasingFunction;
1432
+ /** Ease out quadratic. */
1433
+ declare const easeOutQuad: EasingFunction;
1434
+ /** Ease in-out quadratic. */
1435
+ declare const easeInOutQuad: EasingFunction;
1436
+ /** Ease out bounce. */
1437
+ declare const easeOutBounce: EasingFunction;
1438
+
1439
+ /**
1440
+ * Built-in system that ticks all ProcessComponents on entities in non-paused
1441
+ * scenes, plus a scene-level set of global processes.
1442
+ *
1443
+ * Runs at Phase.Update with priority 500, ensuring tweened values are fresh
1444
+ * before ComponentUpdateSystem (priority 1000) reads them.
1155
1445
  */
1156
- declare class Engine {
1157
- /** The dependency injection container. */
1158
- readonly context: EngineContext;
1159
- /** The scene manager. */
1160
- readonly scenes: SceneManager;
1161
- /** The event bus. */
1162
- readonly events: EventBus<EngineEvents>;
1163
- /** The game loop. */
1164
- readonly loop: GameLoop;
1165
- /** The logger. */
1166
- readonly logger: Logger;
1167
- /** The inspector (debug queries). */
1168
- readonly inspector: Inspector;
1169
- private readonly scheduler;
1170
- private readonly errorBoundary;
1171
- private readonly queryCache;
1172
- private readonly sceneHooks;
1173
- /** The asset manager. */
1174
- readonly assets: AssetManager;
1175
- private readonly plugins;
1176
- private sortedPlugins;
1177
- private started;
1178
- private readonly debug;
1179
- constructor(config?: EngineConfig);
1446
+ declare class ProcessSystem extends System {
1447
+ readonly phase = Phase.Update;
1448
+ readonly priority = 500;
1449
+ /** Global time scale multiplier. Stacks multiplicatively with per-scene timeScale. */
1450
+ timeScale: number;
1451
+ private sceneManager;
1452
+ private globalProcesses;
1453
+ private scenePools;
1454
+ private _unregisterSceneHook;
1455
+ onRegister(context: EngineContext): void;
1456
+ onUnregister(): void;
1180
1457
  /**
1181
- * Register scene lifecycle hooks. The returned function unregisters the
1182
- * hooks. Infrastructure plugins (renderer, physics, debug) register hooks
1183
- * in their `install` or `onStart` to set up and tear down per-scene state.
1458
+ * Add an engine-global process. Ticked under the global timeScale only;
1459
+ * NOT gated by per-scene pause or scaled by per-scene timeScale. Use this
1460
+ * for cross-scene effects (e.g. screen-scope filter fades on `app.stage`)
1461
+ * or processes that have no owning scene.
1184
1462
  */
1185
- registerSceneHooks(hooks: SceneHooks): () => void;
1186
- /** Register a plugin. Must be called before start(). */
1187
- use(plugin: Plugin): this;
1188
- /** Start the engine. Installs plugins in topological order, starts the game loop. */
1189
- start(): Promise<void>;
1190
- /** Stop the engine. Destroys all scenes, plugins, and the game loop. */
1191
- destroy(): void;
1192
- private registerBuiltInSystems;
1463
+ add(process: Process): Process;
1193
1464
  /**
1194
- * Topological sort of plugins using Kahn's algorithm.
1195
- * Errors on missing dependencies, circular dependencies, and duplicates.
1465
+ * Add a process bound to a specific scene's lifecycle. Ticked only while
1466
+ * the scene is active (not paused) and scaled by the scene's `timeScale`,
1467
+ * exactly like an entity-owned `ProcessComponent`. Use this for layer or
1468
+ * scene-scope effect fades that should pause with the scene.
1196
1469
  */
1197
- private topologicalSort;
1470
+ addForScene(scene: Scene, process: Process): Process;
1471
+ /** Cancel engine-global processes, optionally by tag. */
1472
+ cancel(tag?: string): void;
1473
+ /** Cancel every scene-bound process for `scene`, optionally by tag. */
1474
+ cancelForScene(scene: Scene, tag?: string): void;
1475
+ update(dt: number): void;
1476
+ }
1477
+
1478
+ /** A filter used to register a query — an array of required component classes. */
1479
+ type QueryFilter = readonly ComponentClass[];
1480
+ /** A live, iterable set of entities matching a query filter. */
1481
+ declare class QueryResult {
1482
+ /** @internal */
1483
+ readonly _entities: Set<Entity>;
1484
+ /** @internal */
1485
+ readonly _filter: QueryFilter;
1486
+ /** @internal */
1487
+ constructor(filter: QueryFilter);
1488
+ /** Iterate matching entities. */
1489
+ [Symbol.iterator](): Iterator<Entity>;
1490
+ /** Number of matching entities. */
1491
+ get size(): number;
1492
+ /** Get the first match (useful for singleton queries). */
1493
+ get first(): Entity | undefined;
1494
+ /** Convert to array (allocates). */
1495
+ toArray(): Entity[];
1496
+ }
1497
+ /** Incrementally maintained entity sets based on component signatures. */
1498
+ declare class QueryCache {
1499
+ private queries;
1500
+ /** Register a query. Returns a stable reference to a live result set. */
1501
+ register(filter: QueryFilter): QueryResult;
1502
+ /** Called by Entity when a component is added. */
1503
+ onComponentAdded(entity: Entity): void;
1504
+ /** Called by Entity when a component is removed. */
1505
+ onComponentRemoved(entity: Entity): void;
1506
+ /** Called when an entity is destroyed. */
1507
+ onEntityDestroyed(entity: Entity): void;
1508
+ private matches;
1509
+ }
1510
+
1511
+ /** Manages ordered execution of systems within each phase. */
1512
+ declare class SystemScheduler {
1513
+ private phases;
1514
+ private errorBoundary;
1515
+ /** Set the error boundary for wrapping system execution. */
1516
+ setErrorBoundary(boundary: ErrorBoundary): void;
1517
+ /** Register a system. Sorted by priority within its phase. */
1518
+ add(system: System): void;
1519
+ /** Remove a system. */
1520
+ remove(system: System): void;
1521
+ /** Run all enabled systems in a given phase. Wraps each in ErrorBoundary if available. */
1522
+ run(phase: Phase, dt: number): void;
1523
+ /** Get all systems registered for a phase. */
1524
+ getSystems(phase: Phase): readonly System[];
1525
+ /** Get all systems across all phases. */
1526
+ getAllSystems(): System[];
1198
1527
  }
1199
1528
 
1200
1529
  /** The resolution scope for a service. */
@@ -1259,53 +1588,84 @@ declare const ProcessSystemKey: ServiceKey<ProcessSystem>;
1259
1588
  declare const AssetManagerKey: ServiceKey<AssetManager>;
1260
1589
 
1261
1590
  /**
1262
- * Base class for systems. Systems run in a specific game loop phase,
1263
- * query for entities matching a component signature, and operate on them.
1591
+ * Base class for all components.
1264
1592
  *
1265
- * Systems are primarily for engine plugins (physics, rendering, audio).
1266
- * Game developers typically write Components instead.
1593
+ * Components are the primary authoring model. Game developers write behavior
1594
+ * in components using optional `update(dt)` and `fixedUpdate(dt)` methods.
1595
+ * The built-in ComponentUpdateSystem calls these methods automatically.
1267
1596
  */
1268
- declare abstract class System {
1269
- /** The phase this system runs in. */
1270
- abstract readonly phase: Phase;
1271
- /** Execution priority within the phase. Lower = earlier. Default: 0. */
1272
- readonly priority: number;
1273
- /** Whether this system is active. */
1597
+ declare abstract class Component {
1598
+ /**
1599
+ * Back-reference to the owning entity. Set by the engine when the component
1600
+ * is added to an entity. Do not set manually.
1601
+ */
1602
+ entity: Entity;
1603
+ /** Whether this component is active. Disabled components are skipped by ComponentUpdateSystem. */
1274
1604
  enabled: boolean;
1275
- /** Reference to the engine context, set on registration. */
1276
- protected context: EngineContext;
1277
1605
  private _serviceCache;
1606
+ private _cleanups?;
1278
1607
  /**
1279
- * Set the engine context. Called by Engine during startup.
1280
- * @internal
1608
+ * Access the entity's scene. Throws if the entity is not in a scene.
1609
+ * Prefer this over threading through `this.entity.scene` in component
1610
+ * code.
1611
+ */
1612
+ get scene(): Scene;
1613
+ /**
1614
+ * Access the EngineContext from the entity's scene.
1615
+ * Throws if the entity is not in a scene.
1616
+ */
1617
+ get context(): EngineContext;
1618
+ /**
1619
+ * Resolve a service by key, cached after first lookup. Scene-scoped values
1620
+ * (registered via `scene._registerScoped`) take precedence over engine
1621
+ * scope. A key declared with `scope: "scene"` that falls back to engine
1622
+ * scope emits a one-shot dev warning — almost always signals a missed
1623
+ * `beforeEnter` hook.
1281
1624
  */
1282
- _setContext(context: EngineContext): void;
1283
- /** Resolve a service by key, cached after first lookup. */
1284
1625
  protected use<T>(key: ServiceKey<T>): T;
1285
- /** Called once when the system is registered with the engine. */
1286
- onRegister?(context: EngineContext): void;
1287
- /** Called every frame (or every fixed step for FixedUpdate). */
1288
- abstract update(dt: number): void;
1289
- /** Called when the system is removed. */
1290
- onUnregister?(): void;
1291
- }
1292
-
1293
- /** Manages ordered execution of systems within each phase. */
1294
- declare class SystemScheduler {
1295
- private phases;
1296
- private errorBoundary;
1297
- /** Set the error boundary for wrapping system execution. */
1298
- setErrorBoundary(boundary: ErrorBoundary): void;
1299
- /** Register a system. Sorted by priority within its phase. */
1300
- add(system: System): void;
1301
- /** Remove a system. */
1302
- remove(system: System): void;
1303
- /** Run all enabled systems in a given phase. Wraps each in ErrorBoundary if available. */
1304
- run(phase: Phase, dt: number): void;
1305
- /** Get all systems registered for a phase. */
1306
- getSystems(phase: Phase): readonly System[];
1307
- /** Get all systems across all phases. */
1308
- getAllSystems(): System[];
1626
+ private _warnScopedFallback;
1627
+ /**
1628
+ * Lazy proxy-based service resolution. Can be used at field-declaration time:
1629
+ * ```ts
1630
+ * readonly input = this.service(InputManagerKey);
1631
+ * ```
1632
+ * The actual resolution is deferred until first property access.
1633
+ */
1634
+ protected service<T extends object>(key: ServiceKey<T>): T;
1635
+ /**
1636
+ * Lazy proxy-based sibling component resolution. Can be used at field-declaration time:
1637
+ * ```ts
1638
+ * readonly anim = this.sibling(AnimatedSpriteComponent);
1639
+ * ```
1640
+ * The actual resolution is deferred until first property access.
1641
+ */
1642
+ protected sibling<C extends Component>(cls: ComponentClass<C>): C;
1643
+ /** Subscribe to events on any entity, auto-unsubscribe on removal. */
1644
+ protected listen<T>(entity: Entity, token: EventToken<T>, handler: (data: T) => void): void;
1645
+ /** Subscribe to scene-level bubbled events, auto-unsubscribe on removal. */
1646
+ protected listenScene<T>(token: EventToken<T>, handler: (data: T, entity: Entity) => void): void;
1647
+ /** Register a cleanup function to run when this component is removed or destroyed. */
1648
+ protected addCleanup(fn: () => void): void;
1649
+ /**
1650
+ * Run and clear all registered cleanups.
1651
+ * Called by Entity.remove() and Entity._performDestroy() before onRemove/onDestroy.
1652
+ * @internal
1653
+ */
1654
+ _runCleanups(): void;
1655
+ /** Called when the component is added to an entity. */
1656
+ onAdd?(): void;
1657
+ /** Called when the component is removed from an entity. */
1658
+ onRemove?(): void;
1659
+ /** Called when the component is destroyed (entity destroyed or component removed). */
1660
+ onDestroy?(): void;
1661
+ /** Called every frame by the built-in ComponentUpdateSystem. */
1662
+ update?(dt: number): void;
1663
+ /** Called every fixed timestep by the built-in ComponentUpdateSystem. */
1664
+ fixedUpdate?(dt: number): void;
1665
+ /** Return a JSON-serializable snapshot of this component's state. Used by the save system. */
1666
+ serialize?(): unknown;
1667
+ /** Called after onAdd() during save/load restoration. Apply state that depends on onAdd() having run. */
1668
+ afterRestore?(data: unknown, resolve: SnapshotResolver): void;
1309
1669
  }
1310
1670
 
1311
1671
  /** Constructor type for components. */
@@ -1431,10 +1791,6 @@ declare const MathUtils: {
1431
1791
  readonly remap: (value: number, inMin: number, inMax: number, outMin: number, outMax: number) => number;
1432
1792
  /** Bounce t between 0 and length. */
1433
1793
  readonly pingPong: (t: number, length: number) => number;
1434
- /** Random float in [min, max). */
1435
- readonly randomRange: (min: number, max: number) => number;
1436
- /** Random integer in [min, max] (inclusive). */
1437
- readonly randomInt: (min: number, max: number) => number;
1438
1794
  /** Convert degrees to radians. */
1439
1795
  readonly degToRad: (degrees: number) => number;
1440
1796
  /** Convert radians to degrees. */
@@ -1621,6 +1977,7 @@ declare abstract class LoadingScene extends Scene {
1621
1977
  private _active;
1622
1978
  private _continueRequested;
1623
1979
  private _continueGate?;
1980
+ private _pendingWaits;
1624
1981
  private _attempt;
1625
1982
  /** Current load progress, 0 → 1. Updated as the AssetManager reports progress. */
1626
1983
  get progress(): number;
@@ -1650,6 +2007,7 @@ declare abstract class LoadingScene extends Scene {
1650
2007
  continue(): void;
1651
2008
  onExit(): void;
1652
2009
  private _run;
2010
+ private _createEngineTimeDelay;
1653
2011
  }
1654
2012
 
1655
2013
  /** Static factory for creating tween Processes. */
@@ -1737,6 +2095,7 @@ declare class KeyframeAnimator<T extends string = string> extends Component {
1737
2095
  /** Whether a named animation is currently playing. */
1738
2096
  isPlaying(name: T): boolean;
1739
2097
  onDestroy(): void;
2098
+ serialize(): null;
1740
2099
  private stopInternal;
1741
2100
  }
1742
2101
 
@@ -1856,6 +2215,7 @@ declare class ProcessComponent extends Component {
1856
2215
  _tick(dt: number): void;
1857
2216
  /** Cancel all processes and slots on entity destroy. */
1858
2217
  onDestroy(): void;
2218
+ serialize(): null;
1859
2219
  }
1860
2220
 
1861
2221
  /**
@@ -1878,6 +2238,43 @@ declare class TimerEntity extends Entity {
1878
2238
  cancel(tag?: string): void;
1879
2239
  }
1880
2240
 
2241
+ /**
2242
+ * A scoped queue for `Process` instances. Tracks the processes it enqueued so
2243
+ * `cancelAll()` can tear them down without touching unrelated processes that
2244
+ * happen to share the same underlying pool (entity `ProcessComponent` or
2245
+ * engine-level `ProcessSystem`).
2246
+ *
2247
+ * Use one of the `make*ScopedQueue` factories to construct one — each picks
2248
+ * the right routing strategy and lifetime semantics for its scope.
2249
+ */
2250
+ interface ScopedProcessQueue {
2251
+ /** Enqueue a process. Returned for chaining. */
2252
+ run(p: Process): Process;
2253
+ /** Cancel every process this queue enqueued. Idempotent. */
2254
+ cancelAll(): void;
2255
+ }
2256
+ /**
2257
+ * Scoped queue that routes through the entity's `ProcessComponent`. Auto-adds
2258
+ * one if the entity doesn't already have it. `cancelAll()` only cancels the
2259
+ * processes this queue enqueued, so sharing the underlying ProcessComponent
2260
+ * with user code stays safe.
2261
+ */
2262
+ declare function makeEntityScopedQueue(entity: Entity): ScopedProcessQueue;
2263
+ /**
2264
+ * Scoped queue bound to a specific scene's lifecycle. Routes through
2265
+ * `ProcessSystem.addForScene`, so processes pause with the scene and are
2266
+ * scaled by its `timeScale` — matching the behaviour of entity-owned
2267
+ * `ProcessComponent` processes.
2268
+ */
2269
+ declare function makeSceneScopedQueue(processSystem: ProcessSystem, scene: Scene): ScopedProcessQueue;
2270
+ /**
2271
+ * Engine-global scoped queue. Routes through `ProcessSystem.add` — ticked
2272
+ * under the global timeScale only, NOT gated by per-scene pause or scaled
2273
+ * by per-scene timeScale. Right for cross-scene work that should keep
2274
+ * playing during scene transitions and across paused scenes.
2275
+ */
2276
+ declare function makeGlobalScopedQueue(processSystem: ProcessSystem): ScopedProcessQueue;
2277
+
1881
2278
  /**
1882
2279
  * Cross-package contract for "something that owns a canvas and can map
1883
2280
  * canvas-relative CSS pixels into virtual-space pixels".
@@ -1899,6 +2296,19 @@ interface RendererAdapter {
1899
2296
  x: number;
1900
2297
  y: number;
1901
2298
  };
2299
+ /**
2300
+ * Hit-test at virtual-space coordinates and return `true` when the topmost
2301
+ * interactive container under `(x, y)` is parented (directly or through any
2302
+ * ancestor) to a container marked via {@link markPointerConsumeContainer}.
2303
+ * Optional — when absent, the input plugin's UI auto-consume fallback is a
2304
+ * no-op.
2305
+ *
2306
+ * Implemented by `@yagejs/renderer` over Pixi's `EventBoundary`. The input
2307
+ * plugin calls this on `pointerdown` drains to auto-claim presses that land
2308
+ * on UI surfaces (UIPanel backgrounds, decorative UIText, etc.) without
2309
+ * requiring per-component handler boilerplate.
2310
+ */
2311
+ hitTestUI?(x: number, y: number): boolean;
1902
2312
  }
1903
2313
  /**
1904
2314
  * Well-known service key for the current renderer's pointer-input adapter.
@@ -1908,6 +2318,36 @@ interface RendererAdapter {
1908
2318
  */
1909
2319
  declare const RendererAdapterKey: ServiceKey<RendererAdapter>;
1910
2320
 
2321
+ /**
2322
+ * Cross-package WeakSet for marking display containers (Pixi `Container`s in
2323
+ * the canonical setup) as "swallow pointer input." The `@yagejs/input`
2324
+ * package's drain step consults this set via the renderer's optional
2325
+ * `hitTestUI(x, y)` — when the topmost interactive container under a
2326
+ * `pointerdown` is parented to a marked container, the pointer is auto-claimed
2327
+ * (`consumePointer`-equivalent), so the press never propagates to gameplay
2328
+ * action-map edges like `MouseLeft`.
2329
+ *
2330
+ * Lives in `@yagejs/core` so the renderer (read side) and the UI / sprite
2331
+ * components (write side) can both reach it without circular imports.
2332
+ *
2333
+ * Untyped on `Container` to keep `@yagejs/core` free of any Pixi dependency.
2334
+ * Callers pass their `Pixi.Container` instances directly; `WeakSet` accepts
2335
+ * any object reference.
2336
+ */
2337
+ /**
2338
+ * Mark a display container as a UI-input surface. Idempotent. Call from a
2339
+ * component's `onAdd` (or equivalent) after the underlying Pixi container is
2340
+ * created.
2341
+ */
2342
+ declare function markPointerConsumeContainer(container: object): void;
2343
+ /**
2344
+ * Remove the mark. Call from a component's `onDestroy` for symmetry, or to
2345
+ * implement an opt-out (`consumeInput: false`) escape hatch on UI primitives.
2346
+ */
2347
+ declare function unmarkPointerConsumeContainer(container: object): void;
2348
+ /** Whether a container has been marked as a UI-input surface. */
2349
+ declare function isPointerConsumeContainer(container: object): boolean;
2350
+
1911
2351
  /** Create a fully wired Engine for integration tests. */
1912
2352
  declare function createTestEngine(config?: EngineConfig): Promise<Engine>;
1913
2353
  /** Create a lightweight mock scene with EngineContext for unit tests. */
@@ -1926,4 +2366,4 @@ declare function advanceFrames(engine: Engine, n: number, dtMs?: number): void;
1926
2366
 
1927
2367
  declare const VERSION = "0.0.0";
1928
2368
 
1929
- export { AssetHandle, type AssetLoader, AssetManager, AssetManagerKey, type Blueprint, Component, type ComponentClass, ComponentFixedUpdateSystem, ComponentUpdateSystem, type EasingFunction, Engine, type EngineConfig, EngineContext, type EngineEvents, EngineKey, type EngineSnapshot, Entity, type EntityCallbacks, type EntityFilter, type EntitySnapshot, ErrorBoundary, ErrorBoundaryKey, type ErrorSnapshot, EventBus, EventBusKey, type EventMap, EventToken, GameLoop, type GameLoopCallbacks, type GameLoopConfig, GameLoopKey, Inspector, InspectorKey, type Interpolatable, type Keyframe, type KeyframeAnimationDef, KeyframeAnimator, type KeyframeTrackOptions, LoadingScene, type LogEntry, LogLevel, Logger, type LoggerConfig, LoggerKey, MathUtils, Phase, type Plugin, Process, ProcessComponent, type ProcessOptions, ProcessSlot, type ProcessSlotConfig, ProcessSystem, ProcessSystemKey, QueryCache, QueryCacheKey, QueryResult, type RendererAdapter, RendererAdapterKey, SERIALIZABLE_KEY, Scene, SceneHookRegistry, SceneHookRegistryKey, type SceneHooks, SceneManager, SceneManagerKey, type SceneSnapshot, type SceneTransition, type SceneTransitionContext, type SceneTransitionKind, type SceneTransitionOptions, Sequence, SerializableRegistry, ServiceKey, type ServiceKeyOptions, type ServiceScope, type SmoothDampResult, type SnapshotResolver, System, SystemScheduler, SystemSchedulerKey, type SystemSnapshot, TimerEntity, TraitToken, Transform, type TransformData, Tween, VERSION, Vec2, type Vec2Like, _resetEntityIdCounter, advanceFrames, createKeyframeTrack, createMockEntity, createMockScene, createTestEngine, defineBlueprint, defineEvent, defineTrait, easeInOutQuad, easeInQuad, easeLinear, easeOutBounce, easeOutQuad, filterEntities, getSerializableType, interpolate, isSerializable, resolveTransition, serializable, trait };
2369
+ export { AssetHandle, type AssetLoader, AssetManager, AssetManagerKey, type Blueprint, type CameraSnapshot, Component, type ComponentClass, ComponentFixedUpdateSystem, type ComponentStateSnapshot, ComponentUpdateSystem, type EasingFunction, Engine, type EngineConfig, EngineContext, type EngineEvents, EngineKey, type EngineSnapshot, Entity, type EntityCallbacks, type EntityFilter, type EntitySnapshot, ErrorBoundary, ErrorBoundaryKey, type ErrorSnapshot, EventBus, EventBusKey, type EventLogEntry, type EventMap, EventToken, GameLoop, type GameLoopCallbacks, type GameLoopConfig, GameLoopKey, type InputStateSnapshot, Inspector, InspectorKey, type InspectorTimeController, type Interpolatable, type Keyframe, type KeyframeAnimationDef, KeyframeAnimator, type KeyframeTrackOptions, LoadingScene, type LogEntry, LogLevel, Logger, type LoggerConfig, LoggerKey, MathUtils, Phase, type PhysicsSnapshot, type Plugin, type PointerSnapshot, Process, ProcessComponent, type ProcessOptions, ProcessSlot, type ProcessSlotConfig, ProcessSystem, ProcessSystemKey, QueryCache, QueryCacheKey, QueryResult, RandomKey, type RandomService, type RendererAdapter, RendererAdapterKey, SERIALIZABLE_KEY, Scene, SceneHookRegistry, SceneHookRegistryKey, type SceneHooks, SceneManager, SceneManagerKey, type SceneSnapshot, type SceneTransition, type SceneTransitionContext, type SceneTransitionKind, type SceneTransitionOptions, type ScopedProcessQueue, Sequence, SerializableRegistry, ServiceKey, type ServiceKeyOptions, type ServiceScope, type SmoothDampResult, type SnapshotResolver, System, SystemScheduler, SystemSchedulerKey, type SystemSnapshot, TimerEntity, TraitToken, Transform, type TransformData, Tween, type UINodeSnapshot, type UITreeSnapshot, VERSION, Vec2, type Vec2Like, type WorldEntitySnapshot, type WorldSceneSnapshot, _resetEntityIdCounter, advanceFrames, createDefaultRandomSeed, createKeyframeTrack, createMockEntity, createMockScene, createRandomService, createTestEngine, defineBlueprint, defineEvent, defineTrait, easeInOutQuad, easeInQuad, easeLinear, easeOutBounce, easeOutQuad, filterEntities, getSerializableType, globalRandom, interpolate, isPointerConsumeContainer, isSerializable, makeEntityScopedQueue, makeGlobalScopedQueue, makeSceneScopedQueue, markPointerConsumeContainer, normalizeSeed, resolveTransition, serializable, trait, unmarkPointerConsumeContainer };