@yagejs/core 0.1.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/README.md +55 -0
- package/dist/index.cjs +3035 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1512 -0
- package/dist/index.d.ts +1512 -0
- package/dist/index.js +2943 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,1512 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A phantom-typed handle referencing an asset by type and path.
|
|
3
|
+
* Created by plugin-specific factory functions (e.g. `texture()`, `sound()`).
|
|
4
|
+
* Core knows nothing about concrete asset types.
|
|
5
|
+
*/
|
|
6
|
+
declare class AssetHandle<T> {
|
|
7
|
+
/** Loader type key (e.g. "texture", "sound"). */
|
|
8
|
+
readonly type: string;
|
|
9
|
+
/** Asset path or URL. */
|
|
10
|
+
readonly path: string;
|
|
11
|
+
constructor(
|
|
12
|
+
/** Loader type key (e.g. "texture", "sound"). */
|
|
13
|
+
type: string,
|
|
14
|
+
/** Asset path or URL. */
|
|
15
|
+
path: string);
|
|
16
|
+
/** Phantom field to preserve the generic type at compile time. */
|
|
17
|
+
readonly _type: T;
|
|
18
|
+
}
|
|
19
|
+
/** Interface that plugins implement to load/unload a specific asset type. */
|
|
20
|
+
interface AssetLoader<T = unknown> {
|
|
21
|
+
load(path: string): Promise<T>;
|
|
22
|
+
unload?(path: string, asset: T): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Orchestrates asset loading across plugin-provided loaders.
|
|
27
|
+
* Core owns the "when" and "what"; plugins own the "how".
|
|
28
|
+
*/
|
|
29
|
+
declare class AssetManager {
|
|
30
|
+
private loaders;
|
|
31
|
+
private cache;
|
|
32
|
+
/** Register a loader for a given asset type. Called by plugins during install(). */
|
|
33
|
+
registerLoader(type: string, loader: AssetLoader): void;
|
|
34
|
+
/** Retrieve a loaded asset. Throws if not loaded. */
|
|
35
|
+
get<T>(handle: AssetHandle<T>): T;
|
|
36
|
+
/** Check if an asset is loaded. */
|
|
37
|
+
has(handle: AssetHandle<unknown>): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Load all assets, skipping already-cached ones.
|
|
40
|
+
* Reports progress via optional callback (0→1).
|
|
41
|
+
*/
|
|
42
|
+
loadAll(handles: readonly AssetHandle<unknown>[], onProgress?: (ratio: number) => void): Promise<void>;
|
|
43
|
+
/** Unload a single asset and remove from cache. */
|
|
44
|
+
unload(handle: AssetHandle<unknown>): void;
|
|
45
|
+
/** Unload all cached assets. */
|
|
46
|
+
clear(): void;
|
|
47
|
+
private key;
|
|
48
|
+
}
|
|
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
|
+
/**
|
|
197
|
+
* A phantom-typed token for entity events.
|
|
198
|
+
* Similar to ServiceKey, but used for entity-level event pub/sub.
|
|
199
|
+
*/
|
|
200
|
+
declare class EventToken<T = void> {
|
|
201
|
+
/** Unique string identifier for this event. */
|
|
202
|
+
readonly name: string;
|
|
203
|
+
constructor(
|
|
204
|
+
/** Unique string identifier for this event. */
|
|
205
|
+
name: string);
|
|
206
|
+
/** Phantom field to preserve the generic type. */
|
|
207
|
+
readonly _type: T;
|
|
208
|
+
}
|
|
209
|
+
/** Create a typed event token. */
|
|
210
|
+
declare function defineEvent<T = void>(name: string): EventToken<T>;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Passed to `afterRestore` hooks so user code can resolve entity references
|
|
214
|
+
* that were captured as IDs at save time.
|
|
215
|
+
*/
|
|
216
|
+
interface SnapshotResolver {
|
|
217
|
+
/** Resolve a save-time entity ID to the restored entity instance. Returns null if not found. */
|
|
218
|
+
entity(savedId: number): Entity | null;
|
|
219
|
+
}
|
|
220
|
+
/** Symbol stored on classes decorated with @serializable. Holds the type string. */
|
|
221
|
+
declare const SERIALIZABLE_KEY: unique symbol;
|
|
222
|
+
/** Read-only access to the serializable type registry. */
|
|
223
|
+
declare const SerializableRegistry: {
|
|
224
|
+
/** Look up a class by its type string. */
|
|
225
|
+
get(type: string): (new (...args: any[]) => any) | undefined;
|
|
226
|
+
/** Check if a type string is registered. */
|
|
227
|
+
has(type: string): boolean;
|
|
228
|
+
/** Iterate all registered [type, class] entries. */
|
|
229
|
+
entries(): IterableIterator<[string, new (...args: any[]) => any]>;
|
|
230
|
+
/** Remove a type from the registry. */
|
|
231
|
+
delete(type: string): boolean;
|
|
232
|
+
};
|
|
233
|
+
/** Check if an instance belongs to a @serializable-decorated class. */
|
|
234
|
+
declare function isSerializable(instance: object): boolean;
|
|
235
|
+
/** Get the type string from a @serializable-decorated class or instance. */
|
|
236
|
+
declare function getSerializableType(target: object | (new (...args: any[]) => any)): string | undefined;
|
|
237
|
+
/**
|
|
238
|
+
* Decorator that registers a class in the global SerializableRegistry.
|
|
239
|
+
*
|
|
240
|
+
* Works on Component, Entity, and Scene subclasses.
|
|
241
|
+
*
|
|
242
|
+
* ```ts
|
|
243
|
+
* // Zero-arg — uses class.name as type string
|
|
244
|
+
* @serializable
|
|
245
|
+
* class Transform extends Component { ... }
|
|
246
|
+
*
|
|
247
|
+
* // With override — for name collisions or minified builds
|
|
248
|
+
* @serializable({ type: "MyTransform" })
|
|
249
|
+
* class Transform extends Component { ... }
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
declare function serializable<T extends new (...args: any[]) => any>(target: T): T;
|
|
253
|
+
declare function serializable(config: {
|
|
254
|
+
type: string;
|
|
255
|
+
}): <T extends new (...args: any[]) => any>(target: T) => T;
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Trait system — discoverable, type-safe entity capabilities.
|
|
259
|
+
*
|
|
260
|
+
* Traits let entity subclasses declare capabilities (`Interactable`, `Damageable`)
|
|
261
|
+
* that are enforced at compile time (via decorator constraint) and queryable at
|
|
262
|
+
* runtime via `hasTrait()`.
|
|
263
|
+
*/
|
|
264
|
+
/** Symbol key for storing the set of trait symbols on a class. */
|
|
265
|
+
declare const TRAITS_KEY: unique symbol;
|
|
266
|
+
/**
|
|
267
|
+
* A phantom-typed token representing a trait.
|
|
268
|
+
* Follows the same pattern as EventToken / ServiceKey.
|
|
269
|
+
*/
|
|
270
|
+
declare class TraitToken<T> {
|
|
271
|
+
/** Human-readable name for debugging. */
|
|
272
|
+
readonly name: string;
|
|
273
|
+
readonly symbol: symbol;
|
|
274
|
+
constructor(
|
|
275
|
+
/** Human-readable name for debugging. */
|
|
276
|
+
name: string);
|
|
277
|
+
/** Phantom field to preserve the generic type. */
|
|
278
|
+
readonly _type: T;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Create a typed trait token.
|
|
282
|
+
*
|
|
283
|
+
* ```ts
|
|
284
|
+
* const Interactable = defineTrait<{ interact(): void; priority: number }>("Interactable");
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
declare function defineTrait<T>(name: string): TraitToken<T>;
|
|
288
|
+
/**
|
|
289
|
+
* Class decorator that registers a trait on an entity subclass.
|
|
290
|
+
* The type constraint enforces that the class implements all trait members.
|
|
291
|
+
*
|
|
292
|
+
* ```ts
|
|
293
|
+
* @trait(Interactable)
|
|
294
|
+
* class LightEntity extends Entity {
|
|
295
|
+
* priority = 4;
|
|
296
|
+
* interact() { ... } // TS error if missing
|
|
297
|
+
* }
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
300
|
+
declare function trait<Trait>(token: TraitToken<Trait>): <T extends typeof Entity & {
|
|
301
|
+
prototype: Trait;
|
|
302
|
+
}>(target: T) => T;
|
|
303
|
+
|
|
304
|
+
/** Reset the entity ID counter. Exposed for testing only. */
|
|
305
|
+
declare function _resetEntityIdCounter(): void;
|
|
306
|
+
/**
|
|
307
|
+
* Callback interface for notifying external systems (QueryCache, EventBus)
|
|
308
|
+
* about entity component changes. Injected by Scene.
|
|
309
|
+
*/
|
|
310
|
+
interface EntityCallbacks {
|
|
311
|
+
onComponentAdded(entity: Entity, componentClass: ComponentClass): void;
|
|
312
|
+
onComponentRemoved(entity: Entity, componentClass: ComponentClass): void;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* An entity is a named container of components with O(1) lookups by type.
|
|
316
|
+
*/
|
|
317
|
+
declare class Entity {
|
|
318
|
+
static [TRAITS_KEY]: Set<symbol>;
|
|
319
|
+
/** Unique auto-incrementing ID. */
|
|
320
|
+
readonly id: number;
|
|
321
|
+
/** Display name for debugging. */
|
|
322
|
+
readonly name: string;
|
|
323
|
+
/** Tags for group queries. */
|
|
324
|
+
readonly tags: Set<string>;
|
|
325
|
+
private components;
|
|
326
|
+
private _destroyed;
|
|
327
|
+
private _scene;
|
|
328
|
+
private callbacks;
|
|
329
|
+
private _eventHandlers?;
|
|
330
|
+
private _parent;
|
|
331
|
+
private _children;
|
|
332
|
+
constructor(name?: string, tags?: Iterable<string>);
|
|
333
|
+
/** The scene this entity belongs to, or null. */
|
|
334
|
+
get scene(): Scene | null;
|
|
335
|
+
/** True if destroy() has been called. */
|
|
336
|
+
get isDestroyed(): boolean;
|
|
337
|
+
/** The parent entity, or null if this is a root entity. */
|
|
338
|
+
get parent(): Entity | null;
|
|
339
|
+
/** Named children as a read-only map. Empty map if no children. */
|
|
340
|
+
get children(): ReadonlyMap<string, Entity>;
|
|
341
|
+
/** Add a named child entity. Auto-adds to parent's scene if not already in one. */
|
|
342
|
+
addChild(name: string, child: Entity): void;
|
|
343
|
+
/** Remove a named child. Returns the detached entity. */
|
|
344
|
+
removeChild(name: string): Entity;
|
|
345
|
+
/** Get a child by name. Throws if not found. */
|
|
346
|
+
getChild(name: string): Entity;
|
|
347
|
+
/** Get a child by name, or undefined if not found. */
|
|
348
|
+
tryGetChild(name: string): Entity | undefined;
|
|
349
|
+
/** Add a component instance. Returns the component for chaining. */
|
|
350
|
+
add<C extends Component>(component: C): C;
|
|
351
|
+
/** Get a component by class. Throws if not found. */
|
|
352
|
+
get<C extends Component>(cls: ComponentClass<C>): C;
|
|
353
|
+
/** Get a component by class, or undefined if not found. */
|
|
354
|
+
tryGet<C extends Component>(cls: ComponentClass<C>): C | undefined;
|
|
355
|
+
/** Check if entity has a component of the given class. */
|
|
356
|
+
has(cls: ComponentClass): boolean;
|
|
357
|
+
/** Remove a component by class. */
|
|
358
|
+
remove(cls: ComponentClass): void;
|
|
359
|
+
/** Subscribe to a typed event on this entity. Returns an unsubscribe function. */
|
|
360
|
+
on<T>(token: EventToken<T>, handler: (data: T) => void): () => void;
|
|
361
|
+
/** Emit a typed event on this entity. Bubbles to the scene. */
|
|
362
|
+
emit(token: EventToken<void>): void;
|
|
363
|
+
emit<T>(token: EventToken<T>, data: T): void;
|
|
364
|
+
/** Get all components as an iterable. */
|
|
365
|
+
getAll(): Iterable<Component>;
|
|
366
|
+
/** Mark for deferred destruction. Actual cleanup happens at end of frame. */
|
|
367
|
+
destroy(): void;
|
|
368
|
+
/**
|
|
369
|
+
* Internal: perform actual destruction — remove all components and clear state.
|
|
370
|
+
* Called by Scene during endOfFrame flush.
|
|
371
|
+
* @internal
|
|
372
|
+
*/
|
|
373
|
+
_performDestroy(): void;
|
|
374
|
+
/**
|
|
375
|
+
* Optional setup method. Called by `scene.spawn(Class, params)` after the
|
|
376
|
+
* entity is wired to its scene, so components can access services.
|
|
377
|
+
* Override in subclasses — do NOT use the constructor for component setup.
|
|
378
|
+
*/
|
|
379
|
+
setup?(params: unknown): void;
|
|
380
|
+
/** Return a JSON-serializable snapshot of this entity's custom state. Used by the save system. */
|
|
381
|
+
serialize?(): unknown;
|
|
382
|
+
/** Called after components are restored during save/load. Rebuild non-serializable state here. */
|
|
383
|
+
afterRestore?(data: unknown, resolve: SnapshotResolver): void;
|
|
384
|
+
/** Check if this entity's class implements a given trait. Acts as a type guard. */
|
|
385
|
+
hasTrait<T>(token: TraitToken<T>): this is this & T;
|
|
386
|
+
/**
|
|
387
|
+
* Internal: set the scene and callbacks. Called by Scene.spawn().
|
|
388
|
+
* @internal
|
|
389
|
+
*/
|
|
390
|
+
_setScene(scene: Scene | null, callbacks: EntityCallbacks | null): void;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* A reusable entity template. Blueprints define how to assemble
|
|
395
|
+
* an entity from components, given optional parameters.
|
|
396
|
+
*/
|
|
397
|
+
interface Blueprint<P = void> {
|
|
398
|
+
readonly name: string;
|
|
399
|
+
build(entity: Entity, params: P): void;
|
|
400
|
+
}
|
|
401
|
+
/** Create a blueprint from a name and a build function. */
|
|
402
|
+
declare function defineBlueprint<P = void>(name: string, build: (entity: Entity, params: P) => void): Blueprint<P>;
|
|
403
|
+
|
|
404
|
+
/** Filter criteria for entity queries. All fields are AND'd together. */
|
|
405
|
+
interface EntityFilter {
|
|
406
|
+
/** Match entities whose class implements this trait. */
|
|
407
|
+
trait?: TraitToken<any>;
|
|
408
|
+
/** Match entities that have ALL of these tags. */
|
|
409
|
+
tags?: string[];
|
|
410
|
+
/** Match entities with this exact name. */
|
|
411
|
+
name?: string;
|
|
412
|
+
/** Custom predicate — called after other checks pass. */
|
|
413
|
+
filter?: (entity: Entity) => boolean;
|
|
414
|
+
}
|
|
415
|
+
/** Apply a filter to an iterable of entities. Skips destroyed entities. */
|
|
416
|
+
declare function filterEntities(entities: Iterable<Entity>, filter: EntityFilter): Entity[];
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Scenes own entities and define lifecycle hooks.
|
|
420
|
+
* Each scene is a self-contained world with its own entity pool.
|
|
421
|
+
*/
|
|
422
|
+
declare abstract class Scene {
|
|
423
|
+
/** Name for debugging/inspection. */
|
|
424
|
+
abstract readonly name: string;
|
|
425
|
+
/** Whether scenes below this one in the stack should be paused. Default: true. */
|
|
426
|
+
readonly pauseBelow: boolean;
|
|
427
|
+
/** Whether scenes below this one should still render. Default: false. */
|
|
428
|
+
readonly transparentBelow: boolean;
|
|
429
|
+
/** Asset handles to load before onEnter(). Override in subclasses. */
|
|
430
|
+
readonly preload?: readonly AssetHandle<unknown>[];
|
|
431
|
+
/** Manual pause flag. Set by game code to pause this scene regardless of stack position. */
|
|
432
|
+
paused: boolean;
|
|
433
|
+
/** Time scale multiplier for this scene. 1.0 = normal, 0.5 = half speed. Default: 1. */
|
|
434
|
+
timeScale: number;
|
|
435
|
+
private entities;
|
|
436
|
+
private destroyQueue;
|
|
437
|
+
private _context;
|
|
438
|
+
private entityCallbacks;
|
|
439
|
+
private queryCache;
|
|
440
|
+
private bus;
|
|
441
|
+
private _entityEventHandlers?;
|
|
442
|
+
/** Access the EngineContext. */
|
|
443
|
+
get context(): EngineContext;
|
|
444
|
+
/** Whether this scene is effectively paused (manual pause or paused by stack). */
|
|
445
|
+
get isPaused(): boolean;
|
|
446
|
+
/** Convenience accessor for the AssetManager. */
|
|
447
|
+
get assets(): AssetManager;
|
|
448
|
+
/**
|
|
449
|
+
* Lazy proxy-based service resolution. Can be used at field-declaration time:
|
|
450
|
+
* ```ts
|
|
451
|
+
* readonly layers = this.service(RenderLayerManagerKey);
|
|
452
|
+
* ```
|
|
453
|
+
* The actual resolution is deferred until first property access.
|
|
454
|
+
*/
|
|
455
|
+
protected service<T extends object>(key: ServiceKey<T>): T;
|
|
456
|
+
/** Spawn a new entity in this scene. */
|
|
457
|
+
spawn(name?: string): Entity;
|
|
458
|
+
spawn<P>(blueprint: Blueprint<P>, params: P): Entity;
|
|
459
|
+
spawn(blueprint: Blueprint<void>): Entity;
|
|
460
|
+
/** Spawn an entity subclass with setup params. */
|
|
461
|
+
spawn<E extends Entity, P>(Class: new () => E & {
|
|
462
|
+
setup(params: P): void;
|
|
463
|
+
}, params: P): E;
|
|
464
|
+
/** Spawn an entity subclass without setup params. */
|
|
465
|
+
spawn<E extends Entity>(Class: new () => E): E;
|
|
466
|
+
/**
|
|
467
|
+
* Add an existing entity to this scene (used by Entity.addChild for auto-scene-membership).
|
|
468
|
+
* @internal
|
|
469
|
+
*/
|
|
470
|
+
_addExistingEntity(entity: Entity): void;
|
|
471
|
+
/** Mark an entity for destruction. Deferred to endOfFrame flush. */
|
|
472
|
+
destroyEntity(entity: Entity): void;
|
|
473
|
+
/**
|
|
474
|
+
* Add an entity to the destroy queue. Called by Entity.destroy().
|
|
475
|
+
* @internal
|
|
476
|
+
*/
|
|
477
|
+
_queueDestroy(entity: Entity): void;
|
|
478
|
+
/** Get all active entities. */
|
|
479
|
+
getEntities(): ReadonlySet<Entity>;
|
|
480
|
+
/** Find entity by name (first match). */
|
|
481
|
+
findEntity(name: string): Entity | undefined;
|
|
482
|
+
/** Find entities by tag. */
|
|
483
|
+
findEntitiesByTag(tag: string): Entity[];
|
|
484
|
+
/** Find entities matching a filter. Trait filter narrows the return type. */
|
|
485
|
+
findEntities<T>(filter: EntityFilter & {
|
|
486
|
+
trait: TraitToken<T>;
|
|
487
|
+
}): (Entity & T)[];
|
|
488
|
+
findEntities(filter?: EntityFilter): Entity[];
|
|
489
|
+
/** Subscribe to bubbled entity events at the scene level. Handler receives (data, emittingEntity). */
|
|
490
|
+
on<T>(token: EventToken<T>, handler: (data: T, entity: Entity) => void): () => void;
|
|
491
|
+
/**
|
|
492
|
+
* Called by Entity.emit() for bubbling entity events to the scene.
|
|
493
|
+
* @internal
|
|
494
|
+
*/
|
|
495
|
+
_onEntityEvent(eventName: string, data: unknown, entity: Entity): void;
|
|
496
|
+
/** Called during asset preloading with progress ratio (0→1). */
|
|
497
|
+
onProgress?(ratio: number): void;
|
|
498
|
+
/** Called when the scene is entered (after preload completes). */
|
|
499
|
+
onEnter?(): void;
|
|
500
|
+
/** Called when the scene is exited (popped or replaced). */
|
|
501
|
+
onExit?(): void;
|
|
502
|
+
/** Called when a scene is pushed on top of this one. */
|
|
503
|
+
onPause?(): void;
|
|
504
|
+
/** Called when the scene above is popped, restoring this scene. */
|
|
505
|
+
onResume?(): void;
|
|
506
|
+
/** Return a JSON-serializable snapshot of this scene's custom state. Used by the save system. */
|
|
507
|
+
serialize?(): unknown;
|
|
508
|
+
/** Called after entities are restored during save/load. Rebuild non-serializable state here. */
|
|
509
|
+
afterRestore?(data: unknown, resolve: SnapshotResolver): void;
|
|
510
|
+
/**
|
|
511
|
+
* Set the engine context. Called by SceneManager when the scene is pushed.
|
|
512
|
+
* @internal
|
|
513
|
+
*/
|
|
514
|
+
_setContext(context: EngineContext): void;
|
|
515
|
+
/**
|
|
516
|
+
* Flush the destroy queue — destroy pending entities.
|
|
517
|
+
* Called by the engine during the endOfFrame phase.
|
|
518
|
+
* @internal
|
|
519
|
+
*/
|
|
520
|
+
_flushDestroyQueue(): void;
|
|
521
|
+
/**
|
|
522
|
+
* Destroy all entities — used during scene exit.
|
|
523
|
+
* @internal
|
|
524
|
+
*/
|
|
525
|
+
_destroyAllEntities(): void;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Base class for all components.
|
|
530
|
+
*
|
|
531
|
+
* Components are the primary authoring model. Game developers write behavior
|
|
532
|
+
* in components using optional `update(dt)` and `fixedUpdate(dt)` methods.
|
|
533
|
+
* The built-in ComponentUpdateSystem calls these methods automatically.
|
|
534
|
+
*/
|
|
535
|
+
declare abstract class Component {
|
|
536
|
+
/**
|
|
537
|
+
* Back-reference to the owning entity. Set by the engine when the component
|
|
538
|
+
* is added to an entity. Do not set manually.
|
|
539
|
+
*/
|
|
540
|
+
entity: Entity;
|
|
541
|
+
/** Whether this component is active. Disabled components are skipped by ComponentUpdateSystem. */
|
|
542
|
+
enabled: boolean;
|
|
543
|
+
private _serviceCache;
|
|
544
|
+
private _cleanups?;
|
|
545
|
+
/**
|
|
546
|
+
* Access the entity's scene. Throws if the entity is not in a scene.
|
|
547
|
+
* Prefer this over `this.entity.scene!` in component methods.
|
|
548
|
+
*/
|
|
549
|
+
get scene(): Scene;
|
|
550
|
+
/**
|
|
551
|
+
* Access the EngineContext from the entity's scene.
|
|
552
|
+
* Throws if the entity is not in a scene.
|
|
553
|
+
*/
|
|
554
|
+
get context(): EngineContext;
|
|
555
|
+
/** Resolve a service by key, cached after first lookup. */
|
|
556
|
+
protected use<T>(key: ServiceKey<T>): T;
|
|
557
|
+
/**
|
|
558
|
+
* Lazy proxy-based service resolution. Can be used at field-declaration time:
|
|
559
|
+
* ```ts
|
|
560
|
+
* readonly camera = this.service(CameraKey);
|
|
561
|
+
* ```
|
|
562
|
+
* The actual resolution is deferred until first property access.
|
|
563
|
+
*/
|
|
564
|
+
protected service<T extends object>(key: ServiceKey<T>): T;
|
|
565
|
+
/**
|
|
566
|
+
* Lazy proxy-based sibling component resolution. Can be used at field-declaration time:
|
|
567
|
+
* ```ts
|
|
568
|
+
* readonly anim = this.sibling(AnimatedSpriteComponent);
|
|
569
|
+
* ```
|
|
570
|
+
* The actual resolution is deferred until first property access.
|
|
571
|
+
*/
|
|
572
|
+
protected sibling<C extends Component>(cls: ComponentClass<C>): C;
|
|
573
|
+
/** Subscribe to events on any entity, auto-unsubscribe on removal. */
|
|
574
|
+
protected listen<T>(entity: Entity, token: EventToken<T>, handler: (data: T) => void): void;
|
|
575
|
+
/** Subscribe to scene-level bubbled events, auto-unsubscribe on removal. */
|
|
576
|
+
protected listenScene<T>(token: EventToken<T>, handler: (data: T, entity: Entity) => void): void;
|
|
577
|
+
/** Register a cleanup function to run when this component is removed or destroyed. */
|
|
578
|
+
protected addCleanup(fn: () => void): void;
|
|
579
|
+
/**
|
|
580
|
+
* Run and clear all registered cleanups.
|
|
581
|
+
* Called by Entity.remove() and Entity._performDestroy() before onRemove/onDestroy.
|
|
582
|
+
* @internal
|
|
583
|
+
*/
|
|
584
|
+
_runCleanups(): void;
|
|
585
|
+
/** Called when the component is added to an entity. */
|
|
586
|
+
onAdd?(): void;
|
|
587
|
+
/** Called when the component is removed from an entity. */
|
|
588
|
+
onRemove?(): void;
|
|
589
|
+
/** Called when the component is destroyed (entity destroyed or component removed). */
|
|
590
|
+
onDestroy?(): void;
|
|
591
|
+
/** Called every frame by the built-in ComponentUpdateSystem. */
|
|
592
|
+
update?(dt: number): void;
|
|
593
|
+
/** Called every fixed timestep by the built-in ComponentUpdateSystem. */
|
|
594
|
+
fixedUpdate?(dt: number): void;
|
|
595
|
+
/** Return a JSON-serializable snapshot of this component's state. Used by the save system. */
|
|
596
|
+
serialize?(): unknown;
|
|
597
|
+
/** Called after onAdd() during save/load restoration. Apply state that depends on onAdd() having run. */
|
|
598
|
+
afterRestore?(data: unknown, resolve: SnapshotResolver): void;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/** Log severity levels. */
|
|
602
|
+
declare enum LogLevel {
|
|
603
|
+
Debug = 0,
|
|
604
|
+
Info = 1,
|
|
605
|
+
Warn = 2,
|
|
606
|
+
Error = 3,
|
|
607
|
+
None = 4
|
|
608
|
+
}
|
|
609
|
+
/** Configuration for the Logger. */
|
|
610
|
+
interface LoggerConfig {
|
|
611
|
+
/** Minimum log level. Default: Info. */
|
|
612
|
+
level?: LogLevel;
|
|
613
|
+
/** Category whitelist. Empty = all categories allowed. */
|
|
614
|
+
categories?: string[];
|
|
615
|
+
/** Ring buffer size. Default: 500. */
|
|
616
|
+
bufferSize?: number;
|
|
617
|
+
/** Custom output handler. */
|
|
618
|
+
output?: (entry: LogEntry) => void;
|
|
619
|
+
}
|
|
620
|
+
/** A single log entry. */
|
|
621
|
+
interface LogEntry {
|
|
622
|
+
/** Log severity level. */
|
|
623
|
+
level: LogLevel;
|
|
624
|
+
/** Category string (e.g., "physics", "core"). */
|
|
625
|
+
category: string;
|
|
626
|
+
/** Log message. */
|
|
627
|
+
message: string;
|
|
628
|
+
/** Optional structured data. */
|
|
629
|
+
data?: unknown;
|
|
630
|
+
/** Timestamp in milliseconds since epoch. */
|
|
631
|
+
timestamp: number;
|
|
632
|
+
/** Game frame number at time of log. */
|
|
633
|
+
frame: number;
|
|
634
|
+
}
|
|
635
|
+
/** Structured logger with ring buffer, levels, and category filtering. */
|
|
636
|
+
declare class Logger {
|
|
637
|
+
private readonly level;
|
|
638
|
+
private readonly categories;
|
|
639
|
+
private readonly bufferSize;
|
|
640
|
+
private readonly output;
|
|
641
|
+
private readonly buffer;
|
|
642
|
+
private writeIndex;
|
|
643
|
+
private count;
|
|
644
|
+
private currentFrame;
|
|
645
|
+
constructor(config?: LoggerConfig);
|
|
646
|
+
/** Set the current frame number (incremented externally by the game loop). */
|
|
647
|
+
setFrame(frame: number): void;
|
|
648
|
+
/** Log a debug message. */
|
|
649
|
+
debug(category: string, message: string, data?: unknown): void;
|
|
650
|
+
/** Log an info message. */
|
|
651
|
+
info(category: string, message: string, data?: unknown): void;
|
|
652
|
+
/** Log a warning message. */
|
|
653
|
+
warn(category: string, message: string, data?: unknown): void;
|
|
654
|
+
/** Log an error message. */
|
|
655
|
+
error(category: string, message: string, data?: unknown): void;
|
|
656
|
+
/** Get recent log entries from the ring buffer. */
|
|
657
|
+
getRecent(count?: number): LogEntry[];
|
|
658
|
+
/** Format recent logs as structured text for agent consumption. */
|
|
659
|
+
formatRecentLogs(count?: number): string;
|
|
660
|
+
/** Clear the ring buffer. */
|
|
661
|
+
clear(): void;
|
|
662
|
+
private log;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Wraps system and component execution. On error, disables the offending
|
|
667
|
+
* system/component and logs the error. The game loop never crashes.
|
|
668
|
+
*/
|
|
669
|
+
declare class ErrorBoundary {
|
|
670
|
+
private logger;
|
|
671
|
+
private disabledSystems;
|
|
672
|
+
private disabledComponents;
|
|
673
|
+
constructor(logger: Logger);
|
|
674
|
+
/** Wrap a system update call. On throw, disables the system. */
|
|
675
|
+
wrapSystem(system: System, fn: () => void): void;
|
|
676
|
+
/** Wrap a component lifecycle or update call. On throw, disables the component. */
|
|
677
|
+
wrapComponent(component: Component, fn: () => void): void;
|
|
678
|
+
/** Get all disabled systems and components for inspection. */
|
|
679
|
+
getDisabled(): {
|
|
680
|
+
systems: ReadonlyArray<{
|
|
681
|
+
system: System;
|
|
682
|
+
error: string;
|
|
683
|
+
}>;
|
|
684
|
+
components: ReadonlyArray<{
|
|
685
|
+
component: Component;
|
|
686
|
+
error: string;
|
|
687
|
+
}>;
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/** A filter used to register a query — an array of required component classes. */
|
|
692
|
+
type QueryFilter = readonly ComponentClass[];
|
|
693
|
+
/** A live, iterable set of entities matching a query filter. */
|
|
694
|
+
declare class QueryResult {
|
|
695
|
+
/** @internal */
|
|
696
|
+
readonly _entities: Set<Entity>;
|
|
697
|
+
/** @internal */
|
|
698
|
+
readonly _filter: QueryFilter;
|
|
699
|
+
/** @internal */
|
|
700
|
+
constructor(filter: QueryFilter);
|
|
701
|
+
/** Iterate matching entities. */
|
|
702
|
+
[Symbol.iterator](): Iterator<Entity>;
|
|
703
|
+
/** Number of matching entities. */
|
|
704
|
+
get size(): number;
|
|
705
|
+
/** Get the first match (useful for singleton queries). */
|
|
706
|
+
get first(): Entity | undefined;
|
|
707
|
+
/** Convert to array (allocates). */
|
|
708
|
+
toArray(): Entity[];
|
|
709
|
+
}
|
|
710
|
+
/** Incrementally maintained entity sets based on component signatures. */
|
|
711
|
+
declare class QueryCache {
|
|
712
|
+
private queries;
|
|
713
|
+
/** Register a query. Returns a stable reference to a live result set. */
|
|
714
|
+
register(filter: QueryFilter): QueryResult;
|
|
715
|
+
/** Called by Entity when a component is added. */
|
|
716
|
+
onComponentAdded(entity: Entity): void;
|
|
717
|
+
/** Called by Entity when a component is removed. */
|
|
718
|
+
onComponentRemoved(entity: Entity): void;
|
|
719
|
+
/** Called when an entity is destroyed. */
|
|
720
|
+
onEntityDestroyed(entity: Entity): void;
|
|
721
|
+
private matches;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/** Stack-based scene manager with push/pop/replace semantics. */
|
|
725
|
+
declare class SceneManager {
|
|
726
|
+
private stack;
|
|
727
|
+
private _context;
|
|
728
|
+
private bus;
|
|
729
|
+
private assetManager;
|
|
730
|
+
/**
|
|
731
|
+
* Set the engine context.
|
|
732
|
+
* @internal
|
|
733
|
+
*/
|
|
734
|
+
_setContext(context: EngineContext): void;
|
|
735
|
+
/** The topmost (active) scene. */
|
|
736
|
+
get active(): Scene | undefined;
|
|
737
|
+
/** All scenes in the stack, bottom to top. */
|
|
738
|
+
get all(): readonly Scene[];
|
|
739
|
+
/** All non-paused scenes in the stack, bottom to top. */
|
|
740
|
+
get activeScenes(): readonly Scene[];
|
|
741
|
+
/**
|
|
742
|
+
* Push a scene onto the stack. Scenes below may receive onPause().
|
|
743
|
+
* If the scene declares a `preload` array, assets are loaded before onEnter().
|
|
744
|
+
* Await the returned promise when using preloaded scenes.
|
|
745
|
+
*/
|
|
746
|
+
push(scene: Scene): Promise<void>;
|
|
747
|
+
/** Pop the top scene. Scenes below may receive onResume(). */
|
|
748
|
+
pop(): Scene | undefined;
|
|
749
|
+
/**
|
|
750
|
+
* Replace the top scene. Old scene receives onExit().
|
|
751
|
+
* New scene receives onEnter() (after preload, if declared).
|
|
752
|
+
*/
|
|
753
|
+
replace(scene: Scene): Promise<void>;
|
|
754
|
+
/** Clear all scenes. Each receives onExit() from top to bottom. */
|
|
755
|
+
clear(): void;
|
|
756
|
+
/**
|
|
757
|
+
* Flush destroy queues for all active scenes.
|
|
758
|
+
* Called by the engine during endOfFrame.
|
|
759
|
+
* @internal
|
|
760
|
+
*/
|
|
761
|
+
_flushDestroyQueues(): void;
|
|
762
|
+
/** Fire onPause() for scenes that transitioned from not-paused to paused. */
|
|
763
|
+
private _firePauseTransitions;
|
|
764
|
+
/** Fire onResume() for scenes that transitioned from paused to not-paused. */
|
|
765
|
+
private _fireResumeTransitions;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/** Full engine state snapshot. */
|
|
769
|
+
interface EngineSnapshot {
|
|
770
|
+
frameCount: number;
|
|
771
|
+
sceneStack: SceneSnapshot[];
|
|
772
|
+
entityCount: number;
|
|
773
|
+
systemCount: number;
|
|
774
|
+
errors: ErrorSnapshot;
|
|
775
|
+
}
|
|
776
|
+
/** Snapshot of a single entity. */
|
|
777
|
+
interface EntitySnapshot {
|
|
778
|
+
id: number;
|
|
779
|
+
name: string;
|
|
780
|
+
tags: string[];
|
|
781
|
+
components: string[];
|
|
782
|
+
position?: {
|
|
783
|
+
x: number;
|
|
784
|
+
y: number;
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
/** Snapshot of a scene in the stack. */
|
|
788
|
+
interface SceneSnapshot {
|
|
789
|
+
name: string;
|
|
790
|
+
entityCount: number;
|
|
791
|
+
paused: boolean;
|
|
792
|
+
}
|
|
793
|
+
/** Snapshot of a registered system. */
|
|
794
|
+
interface SystemSnapshot {
|
|
795
|
+
name: string;
|
|
796
|
+
phase: string;
|
|
797
|
+
priority: number;
|
|
798
|
+
enabled: boolean;
|
|
799
|
+
}
|
|
800
|
+
/** Snapshot of error boundary state. */
|
|
801
|
+
interface ErrorSnapshot {
|
|
802
|
+
disabledSystems: string[];
|
|
803
|
+
disabledComponents: Array<{
|
|
804
|
+
entity: string;
|
|
805
|
+
component: string;
|
|
806
|
+
error: string;
|
|
807
|
+
}>;
|
|
808
|
+
}
|
|
809
|
+
/** Internal engine reference to avoid circular dependency with Engine class. */
|
|
810
|
+
interface EngineRef {
|
|
811
|
+
readonly context: EngineContext;
|
|
812
|
+
readonly scenes: SceneManager;
|
|
813
|
+
readonly loop: GameLoop;
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Programmatic state queries for testing and debugging.
|
|
817
|
+
* Exposed on `window.__yage__` in debug mode.
|
|
818
|
+
*/
|
|
819
|
+
declare class Inspector {
|
|
820
|
+
private engine;
|
|
821
|
+
constructor(engine: EngineRef);
|
|
822
|
+
/** Full state snapshot (serializable). */
|
|
823
|
+
snapshot(): EngineSnapshot;
|
|
824
|
+
/** Find entity by name in the active scene. */
|
|
825
|
+
getEntityByName(name: string): EntitySnapshot | undefined;
|
|
826
|
+
/** Get entity position (from Transform component). */
|
|
827
|
+
getEntityPosition(name: string): {
|
|
828
|
+
x: number;
|
|
829
|
+
y: number;
|
|
830
|
+
} | undefined;
|
|
831
|
+
/** Check if an entity has a component by class name string. */
|
|
832
|
+
hasComponent(entityName: string, componentClass: string): boolean;
|
|
833
|
+
/** Get component data (serializable subset) by class name string. */
|
|
834
|
+
getComponentData(entityName: string, componentClass: string): unknown;
|
|
835
|
+
/** Get all entities in the active scene as snapshots. */
|
|
836
|
+
getEntities(): EntitySnapshot[];
|
|
837
|
+
/** Get scene stack info. */
|
|
838
|
+
getSceneStack(): SceneSnapshot[];
|
|
839
|
+
/** Get active system info. */
|
|
840
|
+
getSystems(): SystemSnapshot[];
|
|
841
|
+
/** Get disabled components/systems from error boundary. */
|
|
842
|
+
getErrors(): ErrorSnapshot;
|
|
843
|
+
private findActiveEntity;
|
|
844
|
+
private findComponentByName;
|
|
845
|
+
private entityToSnapshot;
|
|
846
|
+
private getTransform;
|
|
847
|
+
private serializeComponent;
|
|
848
|
+
private countEntities;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
type EntityRef = {
|
|
852
|
+
readonly id: number;
|
|
853
|
+
readonly name: string;
|
|
854
|
+
};
|
|
855
|
+
type SceneRef = {
|
|
856
|
+
readonly name: string;
|
|
857
|
+
};
|
|
858
|
+
/** Base type for event map definitions. */
|
|
859
|
+
type EventMap = Record<string, unknown>;
|
|
860
|
+
/** Well-known engine events. */
|
|
861
|
+
interface EngineEvents {
|
|
862
|
+
"entity:created": {
|
|
863
|
+
entity: EntityRef;
|
|
864
|
+
};
|
|
865
|
+
"entity:destroyed": {
|
|
866
|
+
entity: EntityRef;
|
|
867
|
+
};
|
|
868
|
+
"component:added": {
|
|
869
|
+
entity: EntityRef;
|
|
870
|
+
component: Component;
|
|
871
|
+
};
|
|
872
|
+
"component:removed": {
|
|
873
|
+
entity: EntityRef;
|
|
874
|
+
componentClass: ComponentClass;
|
|
875
|
+
};
|
|
876
|
+
"scene:pushed": {
|
|
877
|
+
scene: SceneRef;
|
|
878
|
+
};
|
|
879
|
+
"scene:popped": {
|
|
880
|
+
scene: SceneRef;
|
|
881
|
+
};
|
|
882
|
+
"scene:replaced": {
|
|
883
|
+
oldScene: SceneRef;
|
|
884
|
+
newScene: SceneRef;
|
|
885
|
+
};
|
|
886
|
+
"engine:started": undefined;
|
|
887
|
+
"engine:stopped": undefined;
|
|
888
|
+
}
|
|
889
|
+
/** Typed publish/subscribe event bus. */
|
|
890
|
+
declare class EventBus<E = EventMap> {
|
|
891
|
+
private handlers;
|
|
892
|
+
/** Subscribe to an event. Returns an unsubscribe function. */
|
|
893
|
+
on<K extends keyof E>(event: K, handler: (data: E[K]) => void): () => void;
|
|
894
|
+
/** Subscribe to an event, auto-unsubscribe after first emission. */
|
|
895
|
+
once<K extends keyof E>(event: K, handler: (data: E[K]) => void): () => void;
|
|
896
|
+
/** Emit an event. Handlers are called synchronously in registration order. */
|
|
897
|
+
emit<K extends keyof E>(event: K, data: E[K]): void;
|
|
898
|
+
/** Remove all handlers for an event, or all handlers if no event specified. */
|
|
899
|
+
clear(event?: keyof E): void;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/** Engine configuration. */
|
|
903
|
+
interface EngineConfig {
|
|
904
|
+
/** Enable debug mode (Inspector API, debug logging). */
|
|
905
|
+
debug?: boolean;
|
|
906
|
+
/** Fixed timestep in ms (default: 1000/60). */
|
|
907
|
+
fixedTimestep?: number;
|
|
908
|
+
/** Max fixed steps per frame to prevent spiral of death (default: 5). */
|
|
909
|
+
maxFixedStepsPerFrame?: number;
|
|
910
|
+
/** Logger configuration. */
|
|
911
|
+
logger?: LoggerConfig;
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* The top-level entry point. Owns the plugin registry, game loop,
|
|
915
|
+
* scene manager, and DI container.
|
|
916
|
+
*/
|
|
917
|
+
declare class Engine {
|
|
918
|
+
/** The dependency injection container. */
|
|
919
|
+
readonly context: EngineContext;
|
|
920
|
+
/** The scene manager. */
|
|
921
|
+
readonly scenes: SceneManager;
|
|
922
|
+
/** The event bus. */
|
|
923
|
+
readonly events: EventBus<EngineEvents>;
|
|
924
|
+
/** The game loop. */
|
|
925
|
+
readonly loop: GameLoop;
|
|
926
|
+
/** The logger. */
|
|
927
|
+
readonly logger: Logger;
|
|
928
|
+
/** The inspector (debug queries). */
|
|
929
|
+
readonly inspector: Inspector;
|
|
930
|
+
private readonly scheduler;
|
|
931
|
+
private readonly errorBoundary;
|
|
932
|
+
private readonly queryCache;
|
|
933
|
+
/** The asset manager. */
|
|
934
|
+
readonly assets: AssetManager;
|
|
935
|
+
private readonly plugins;
|
|
936
|
+
private sortedPlugins;
|
|
937
|
+
private started;
|
|
938
|
+
private readonly debug;
|
|
939
|
+
constructor(config?: EngineConfig);
|
|
940
|
+
/** Register a plugin. Must be called before start(). */
|
|
941
|
+
use(plugin: Plugin): this;
|
|
942
|
+
/** Start the engine. Installs plugins in topological order, starts the game loop. */
|
|
943
|
+
start(): Promise<void>;
|
|
944
|
+
/** Stop the engine. Destroys all scenes, plugins, and the game loop. */
|
|
945
|
+
destroy(): void;
|
|
946
|
+
private registerBuiltInSystems;
|
|
947
|
+
/**
|
|
948
|
+
* Topological sort of plugins using Kahn's algorithm.
|
|
949
|
+
* Errors on missing dependencies, circular dependencies, and duplicates.
|
|
950
|
+
*/
|
|
951
|
+
private topologicalSort;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/** A typed key for service registration and resolution. */
|
|
955
|
+
declare class ServiceKey<T> {
|
|
956
|
+
/** Unique string identifier for this service. */
|
|
957
|
+
readonly id: string;
|
|
958
|
+
constructor(
|
|
959
|
+
/** Unique string identifier for this service. */
|
|
960
|
+
id: string);
|
|
961
|
+
/** Phantom field to preserve the generic type. */
|
|
962
|
+
readonly _type: T;
|
|
963
|
+
}
|
|
964
|
+
/** Dependency injection container for engine services. */
|
|
965
|
+
declare class EngineContext {
|
|
966
|
+
private services;
|
|
967
|
+
/** Register a service. Throws if the key is already registered. */
|
|
968
|
+
register<T>(key: ServiceKey<T>, service: T): void;
|
|
969
|
+
/** Resolve a service. Throws if not registered. */
|
|
970
|
+
resolve<T>(key: ServiceKey<T>): T;
|
|
971
|
+
/** Resolve a service, returning undefined if not registered. */
|
|
972
|
+
tryResolve<T>(key: ServiceKey<T>): T | undefined;
|
|
973
|
+
/** Remove a registered service. No-op if not registered. */
|
|
974
|
+
unregister<T>(key: ServiceKey<T>): void;
|
|
975
|
+
/** Check if a service is registered. */
|
|
976
|
+
has<T>(key: ServiceKey<T>): boolean;
|
|
977
|
+
}
|
|
978
|
+
/** Key for the Engine instance. */
|
|
979
|
+
declare const EngineKey: ServiceKey<Engine>;
|
|
980
|
+
/** Key for the EventBus instance. */
|
|
981
|
+
declare const EventBusKey: ServiceKey<EventBus<EngineEvents>>;
|
|
982
|
+
/** Key for the SceneManager instance. */
|
|
983
|
+
declare const SceneManagerKey: ServiceKey<SceneManager>;
|
|
984
|
+
/** Key for the Logger instance. */
|
|
985
|
+
declare const LoggerKey: ServiceKey<Logger>;
|
|
986
|
+
/** Key for the Inspector instance. */
|
|
987
|
+
declare const InspectorKey: ServiceKey<Inspector>;
|
|
988
|
+
/** Key for the QueryCache instance. */
|
|
989
|
+
declare const QueryCacheKey: ServiceKey<QueryCache>;
|
|
990
|
+
/** Key for the ErrorBoundary instance. */
|
|
991
|
+
declare const ErrorBoundaryKey: ServiceKey<ErrorBoundary>;
|
|
992
|
+
/** Key for the GameLoop instance. */
|
|
993
|
+
declare const GameLoopKey: ServiceKey<GameLoop>;
|
|
994
|
+
/** Key for the SystemScheduler instance. */
|
|
995
|
+
declare const SystemSchedulerKey: ServiceKey<SystemScheduler>;
|
|
996
|
+
/** Key for the ProcessSystem instance. */
|
|
997
|
+
declare const ProcessSystemKey: ServiceKey<ProcessSystem>;
|
|
998
|
+
/** Key for the AssetManager instance. */
|
|
999
|
+
declare const AssetManagerKey: ServiceKey<AssetManager>;
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Base class for systems. Systems run in a specific game loop phase,
|
|
1003
|
+
* query for entities matching a component signature, and operate on them.
|
|
1004
|
+
*
|
|
1005
|
+
* Systems are primarily for engine plugins (physics, rendering, audio).
|
|
1006
|
+
* Game developers typically write Components instead.
|
|
1007
|
+
*/
|
|
1008
|
+
declare abstract class System {
|
|
1009
|
+
/** The phase this system runs in. */
|
|
1010
|
+
abstract readonly phase: Phase;
|
|
1011
|
+
/** Execution priority within the phase. Lower = earlier. Default: 0. */
|
|
1012
|
+
readonly priority: number;
|
|
1013
|
+
/** Whether this system is active. */
|
|
1014
|
+
enabled: boolean;
|
|
1015
|
+
/** Reference to the engine context, set on registration. */
|
|
1016
|
+
protected context: EngineContext;
|
|
1017
|
+
private _serviceCache;
|
|
1018
|
+
/**
|
|
1019
|
+
* Set the engine context. Called by Engine during startup.
|
|
1020
|
+
* @internal
|
|
1021
|
+
*/
|
|
1022
|
+
_setContext(context: EngineContext): void;
|
|
1023
|
+
/** Resolve a service by key, cached after first lookup. */
|
|
1024
|
+
protected use<T>(key: ServiceKey<T>): T;
|
|
1025
|
+
/** Called once when the system is registered with the engine. */
|
|
1026
|
+
onRegister?(context: EngineContext): void;
|
|
1027
|
+
/** Called every frame (or every fixed step for FixedUpdate). */
|
|
1028
|
+
abstract update(dt: number): void;
|
|
1029
|
+
/** Called when the system is removed. */
|
|
1030
|
+
onUnregister?(): void;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
/** Manages ordered execution of systems within each phase. */
|
|
1034
|
+
declare class SystemScheduler {
|
|
1035
|
+
private phases;
|
|
1036
|
+
private errorBoundary;
|
|
1037
|
+
/** Set the error boundary for wrapping system execution. */
|
|
1038
|
+
setErrorBoundary(boundary: ErrorBoundary): void;
|
|
1039
|
+
/** Register a system. Sorted by priority within its phase. */
|
|
1040
|
+
add(system: System): void;
|
|
1041
|
+
/** Remove a system. */
|
|
1042
|
+
remove(system: System): void;
|
|
1043
|
+
/** Run all enabled systems in a given phase. Wraps each in ErrorBoundary if available. */
|
|
1044
|
+
run(phase: Phase, dt: number): void;
|
|
1045
|
+
/** Get all systems registered for a phase. */
|
|
1046
|
+
getSystems(phase: Phase): readonly System[];
|
|
1047
|
+
/** Get all systems across all phases. */
|
|
1048
|
+
getAllSystems(): System[];
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
/** Constructor type for components. */
|
|
1052
|
+
type ComponentClass<C extends Component = Component> = new (...args: never[]) => C;
|
|
1053
|
+
/** Game loop phase identifiers. Systems run in one specific phase. */
|
|
1054
|
+
declare enum Phase {
|
|
1055
|
+
EarlyUpdate = "earlyUpdate",
|
|
1056
|
+
FixedUpdate = "fixedUpdate",
|
|
1057
|
+
Update = "update",
|
|
1058
|
+
LateUpdate = "lateUpdate",
|
|
1059
|
+
Render = "render",
|
|
1060
|
+
EndOfFrame = "endOfFrame"
|
|
1061
|
+
}
|
|
1062
|
+
/** Plugin interface for extending the engine. */
|
|
1063
|
+
interface Plugin {
|
|
1064
|
+
/** Unique plugin name. */
|
|
1065
|
+
readonly name: string;
|
|
1066
|
+
/** Semantic version string. */
|
|
1067
|
+
readonly version: string;
|
|
1068
|
+
/** Names of plugins this plugin depends on. */
|
|
1069
|
+
readonly dependencies?: readonly string[];
|
|
1070
|
+
/** Install services into the engine context. Called in topological order. */
|
|
1071
|
+
install?(context: EngineContext): void | Promise<void>;
|
|
1072
|
+
/** Register systems with the scheduler. Called after install. */
|
|
1073
|
+
registerSystems?(scheduler: SystemScheduler): void;
|
|
1074
|
+
/** Called after all plugins are installed and the engine has started. */
|
|
1075
|
+
onStart?(): void;
|
|
1076
|
+
/** Called when the engine is destroyed. */
|
|
1077
|
+
onDestroy?(): void;
|
|
1078
|
+
}
|
|
1079
|
+
/** An easing function mapping t in [0,1] to a value in [0,1]. */
|
|
1080
|
+
type EasingFunction = (t: number) => number;
|
|
1081
|
+
|
|
1082
|
+
/** Any object with x and y numeric properties. */
|
|
1083
|
+
interface Vec2Like {
|
|
1084
|
+
readonly x: number;
|
|
1085
|
+
readonly y: number;
|
|
1086
|
+
}
|
|
1087
|
+
/** Immutable 2D vector. All operations return new instances. */
|
|
1088
|
+
declare class Vec2 implements Vec2Like {
|
|
1089
|
+
/** The x component. */
|
|
1090
|
+
readonly x: number;
|
|
1091
|
+
/** The y component. */
|
|
1092
|
+
readonly y: number;
|
|
1093
|
+
/** The zero vector (0, 0). */
|
|
1094
|
+
static readonly ZERO: Vec2;
|
|
1095
|
+
/** The one vector (1, 1). */
|
|
1096
|
+
static readonly ONE: Vec2;
|
|
1097
|
+
/** Up direction (0, -1) — screen coordinates. */
|
|
1098
|
+
static readonly UP: Vec2;
|
|
1099
|
+
/** Down direction (0, 1) — screen coordinates. */
|
|
1100
|
+
static readonly DOWN: Vec2;
|
|
1101
|
+
/** Left direction (-1, 0). */
|
|
1102
|
+
static readonly LEFT: Vec2;
|
|
1103
|
+
/** Right direction (1, 0). */
|
|
1104
|
+
static readonly RIGHT: Vec2;
|
|
1105
|
+
constructor(
|
|
1106
|
+
/** The x component. */
|
|
1107
|
+
x: number,
|
|
1108
|
+
/** The y component. */
|
|
1109
|
+
y: number);
|
|
1110
|
+
/** Add another vector. */
|
|
1111
|
+
add(other: Vec2Like): Vec2;
|
|
1112
|
+
/** Subtract another vector. */
|
|
1113
|
+
sub(other: Vec2Like): Vec2;
|
|
1114
|
+
/** Scale by a scalar. */
|
|
1115
|
+
scale(scalar: number): Vec2;
|
|
1116
|
+
/** Component-wise multiply with another vector. */
|
|
1117
|
+
multiply(other: Vec2Like): Vec2;
|
|
1118
|
+
/** Dot product with another vector. */
|
|
1119
|
+
dot(other: Vec2Like): number;
|
|
1120
|
+
/** Cross product (z-component of the 3D cross product). */
|
|
1121
|
+
cross(other: Vec2Like): number;
|
|
1122
|
+
/** Magnitude of this vector. */
|
|
1123
|
+
length(): number;
|
|
1124
|
+
/** Squared magnitude (avoids sqrt). */
|
|
1125
|
+
lengthSq(): number;
|
|
1126
|
+
/** Return a unit vector in the same direction. Returns ZERO for zero-length vectors. */
|
|
1127
|
+
normalize(): Vec2;
|
|
1128
|
+
/** Euclidean distance to another vector. */
|
|
1129
|
+
distance(other: Vec2Like): number;
|
|
1130
|
+
/** Squared distance to another vector (avoids sqrt). */
|
|
1131
|
+
distanceSq(other: Vec2Like): number;
|
|
1132
|
+
/** Linear interpolation toward another vector. */
|
|
1133
|
+
lerp(other: Vec2Like, t: number): Vec2;
|
|
1134
|
+
/** Angle of this vector in radians (atan2). */
|
|
1135
|
+
angle(): number;
|
|
1136
|
+
/** Rotate this vector by radians. */
|
|
1137
|
+
rotate(radians: number): Vec2;
|
|
1138
|
+
/** Check equality with optional epsilon tolerance. */
|
|
1139
|
+
equals(other: Vec2Like, epsilon?: number): boolean;
|
|
1140
|
+
/** String representation. */
|
|
1141
|
+
toString(): string;
|
|
1142
|
+
/** Create a unit vector from an angle in radians, optionally scaled. */
|
|
1143
|
+
static fromAngle(radians: number, length?: number): Vec2;
|
|
1144
|
+
/** Euclidean distance between two vectors. */
|
|
1145
|
+
static distance(a: Vec2Like, b: Vec2Like): number;
|
|
1146
|
+
/** Linear interpolation between two vectors. */
|
|
1147
|
+
static lerp(a: Vec2Like, b: Vec2Like, t: number): Vec2;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
/** Common math utility functions. */
|
|
1151
|
+
declare const MathUtils: {
|
|
1152
|
+
/** Linear interpolation between a and b. */
|
|
1153
|
+
readonly lerp: (a: number, b: number, t: number) => number;
|
|
1154
|
+
/** Clamp a value between min and max. */
|
|
1155
|
+
readonly clamp: (value: number, min: number, max: number) => number;
|
|
1156
|
+
/** Remap a value from one range to another. */
|
|
1157
|
+
readonly remap: (value: number, inMin: number, inMax: number, outMin: number, outMax: number) => number;
|
|
1158
|
+
/** Random float in [min, max). */
|
|
1159
|
+
readonly randomRange: (min: number, max: number) => number;
|
|
1160
|
+
/** Random integer in [min, max] (inclusive). */
|
|
1161
|
+
readonly randomInt: (min: number, max: number) => number;
|
|
1162
|
+
/** Convert degrees to radians. */
|
|
1163
|
+
readonly degToRad: (degrees: number) => number;
|
|
1164
|
+
/** Convert radians to degrees. */
|
|
1165
|
+
readonly radToDeg: (radians: number) => number;
|
|
1166
|
+
/** Move current toward target by at most step. */
|
|
1167
|
+
readonly approach: (current: number, target: number, step: number) => number;
|
|
1168
|
+
/** Wrap value into the range [min, max). */
|
|
1169
|
+
readonly wrap: (value: number, min: number, max: number) => number;
|
|
1170
|
+
};
|
|
1171
|
+
|
|
1172
|
+
/** Serialized transform state. */
|
|
1173
|
+
interface TransformData {
|
|
1174
|
+
position: {
|
|
1175
|
+
x: number;
|
|
1176
|
+
y: number;
|
|
1177
|
+
};
|
|
1178
|
+
rotation: number;
|
|
1179
|
+
scale: {
|
|
1180
|
+
x: number;
|
|
1181
|
+
y: number;
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
/** Mutable transform component for entity positioning. */
|
|
1185
|
+
declare class Transform extends Component {
|
|
1186
|
+
private _position;
|
|
1187
|
+
private _rotation;
|
|
1188
|
+
private _scale;
|
|
1189
|
+
private _worldPosition;
|
|
1190
|
+
private _worldRotation;
|
|
1191
|
+
private _worldScale;
|
|
1192
|
+
private _dirty;
|
|
1193
|
+
constructor(options?: {
|
|
1194
|
+
position?: Vec2Like;
|
|
1195
|
+
rotation?: number;
|
|
1196
|
+
scale?: Vec2Like;
|
|
1197
|
+
});
|
|
1198
|
+
/** Local position (relative to parent, or world if no parent). */
|
|
1199
|
+
get position(): Vec2;
|
|
1200
|
+
set position(v: Vec2);
|
|
1201
|
+
/** Local rotation in radians. */
|
|
1202
|
+
get rotation(): number;
|
|
1203
|
+
set rotation(v: number);
|
|
1204
|
+
/** Local scale factor. */
|
|
1205
|
+
get scale(): Vec2;
|
|
1206
|
+
set scale(v: Vec2);
|
|
1207
|
+
/** Computed world position. Recomputed lazily when dirty. */
|
|
1208
|
+
get worldPosition(): Vec2;
|
|
1209
|
+
/** Set position in world space. Back-computes the local position from the parent chain. */
|
|
1210
|
+
set worldPosition(v: Vec2);
|
|
1211
|
+
/** Computed world rotation. Recomputed lazily when dirty. */
|
|
1212
|
+
get worldRotation(): number;
|
|
1213
|
+
/** Set rotation in world space. Back-computes the local rotation from the parent chain. */
|
|
1214
|
+
set worldRotation(v: number);
|
|
1215
|
+
/** Computed world scale. Recomputed lazily when dirty. */
|
|
1216
|
+
get worldScale(): Vec2;
|
|
1217
|
+
/** Set position directly. */
|
|
1218
|
+
setPosition(x: number, y: number): void;
|
|
1219
|
+
/** Translate by an offset. */
|
|
1220
|
+
translate(dx: number, dy: number): void;
|
|
1221
|
+
/** Set rotation in radians. */
|
|
1222
|
+
setRotation(radians: number): void;
|
|
1223
|
+
/** Rotate by a delta in radians. */
|
|
1224
|
+
rotate(deltaRadians: number): void;
|
|
1225
|
+
/** Set scale. */
|
|
1226
|
+
setScale(x: number, y: number): void;
|
|
1227
|
+
/**
|
|
1228
|
+
* Mark this transform and all descendant transforms as dirty.
|
|
1229
|
+
* @internal
|
|
1230
|
+
*/
|
|
1231
|
+
_markDirty(): void;
|
|
1232
|
+
private _recompute;
|
|
1233
|
+
serialize(): TransformData;
|
|
1234
|
+
static fromSnapshot(data: TransformData): Transform;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
/**
|
|
1238
|
+
* Built-in system that bridges the OOP and ECS worlds.
|
|
1239
|
+
*
|
|
1240
|
+
* Iterates all entities in non-paused scenes and calls component
|
|
1241
|
+
* `update(dt)` or `fixedUpdate(dt)` methods on enabled components.
|
|
1242
|
+
*
|
|
1243
|
+
* This system runs at two phases:
|
|
1244
|
+
* - Phase.FixedUpdate for fixedUpdate(dt)
|
|
1245
|
+
* - Phase.Update for update(dt)
|
|
1246
|
+
*
|
|
1247
|
+
* We actually register two separate instances — one per phase — since
|
|
1248
|
+
* a System can only belong to one phase.
|
|
1249
|
+
*/
|
|
1250
|
+
declare abstract class BaseComponentUpdateSystem extends System {
|
|
1251
|
+
/** High priority so game logic runs after engine systems like physics. */
|
|
1252
|
+
readonly priority = 1000;
|
|
1253
|
+
protected sceneManager: SceneManager;
|
|
1254
|
+
protected errorBoundary: ErrorBoundary;
|
|
1255
|
+
onRegister(context: EngineContext): void;
|
|
1256
|
+
}
|
|
1257
|
+
/** Calls `fixedUpdate(dt)` on all enabled components in non-paused scenes. */
|
|
1258
|
+
declare class ComponentFixedUpdateSystem extends BaseComponentUpdateSystem {
|
|
1259
|
+
readonly phase = Phase.FixedUpdate;
|
|
1260
|
+
update(dt: number): void;
|
|
1261
|
+
}
|
|
1262
|
+
/** Calls `update(dt)` on all enabled components in non-paused scenes. */
|
|
1263
|
+
declare class ComponentUpdateSystem extends BaseComponentUpdateSystem {
|
|
1264
|
+
readonly phase = Phase.Update;
|
|
1265
|
+
update(dt: number): void;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
/** Static factory for creating tween Processes. */
|
|
1269
|
+
declare const Tween: {
|
|
1270
|
+
/** Tween a numeric property on a target object. */
|
|
1271
|
+
to(target: Record<string, number>, property: string, to: number, duration: number, easing?: EasingFunction): Process;
|
|
1272
|
+
/** Tween using a custom setter. */
|
|
1273
|
+
custom(setter: (value: number) => void, from: number, to: number, duration: number, easing?: EasingFunction): Process;
|
|
1274
|
+
/** Tween a Vec2 value. */
|
|
1275
|
+
vec2(setter: (value: Vec2) => void, from: Vec2Like, to: Vec2Like, duration: number, easing?: EasingFunction): Process;
|
|
1276
|
+
};
|
|
1277
|
+
|
|
1278
|
+
/** Types that can be interpolated by keyframe tracks. */
|
|
1279
|
+
type Interpolatable = number | Vec2Like;
|
|
1280
|
+
/**
|
|
1281
|
+
* Interpolate between two values of the same type.
|
|
1282
|
+
* - `number` → linear interpolation
|
|
1283
|
+
* - `Vec2Like` → component-wise lerp, returns `Vec2`
|
|
1284
|
+
*/
|
|
1285
|
+
declare function interpolate<T extends Interpolatable>(from: T, to: T, t: number, easing?: EasingFunction): T;
|
|
1286
|
+
|
|
1287
|
+
/** A single keyframe in an animation track. */
|
|
1288
|
+
interface Keyframe<T extends Interpolatable> {
|
|
1289
|
+
/** Time in ms from the start of the track. */
|
|
1290
|
+
time: number;
|
|
1291
|
+
/** Value at this keyframe. */
|
|
1292
|
+
data: T;
|
|
1293
|
+
/** Easing from this keyframe to the next (overrides track default). */
|
|
1294
|
+
easing?: EasingFunction;
|
|
1295
|
+
/** Fired once when playback passes this keyframe's time. */
|
|
1296
|
+
event?: () => void;
|
|
1297
|
+
}
|
|
1298
|
+
/** Options for creating a keyframe track. */
|
|
1299
|
+
interface KeyframeTrackOptions<T extends Interpolatable> {
|
|
1300
|
+
/** At least 2 keyframes, sorted by time. */
|
|
1301
|
+
keyframes: Keyframe<T>[];
|
|
1302
|
+
/** Called each frame with the interpolated value. */
|
|
1303
|
+
setter: (value: T) => void;
|
|
1304
|
+
/** Total duration in ms. Defaults to the last keyframe's time. */
|
|
1305
|
+
duration?: number;
|
|
1306
|
+
/** Whether to loop the track. */
|
|
1307
|
+
loop?: boolean;
|
|
1308
|
+
/** Playback speed multiplier (default 1). */
|
|
1309
|
+
speed?: number;
|
|
1310
|
+
/** Default easing between keyframes (default easeLinear). */
|
|
1311
|
+
easing?: EasingFunction;
|
|
1312
|
+
/** Called when the track completes (non-looping only). */
|
|
1313
|
+
onComplete?: () => void;
|
|
1314
|
+
}
|
|
1315
|
+
/**
|
|
1316
|
+
* Create a Process that animates through keyframes.
|
|
1317
|
+
* Returns a standard Process — composable with Sequence, ProcessComponent.run(), etc.
|
|
1318
|
+
*/
|
|
1319
|
+
declare function createKeyframeTrack<T extends Interpolatable>(options: KeyframeTrackOptions<T>): Process;
|
|
1320
|
+
|
|
1321
|
+
/** Definition for a named keyframe animation. */
|
|
1322
|
+
interface KeyframeAnimationDef<T extends Interpolatable = Interpolatable> {
|
|
1323
|
+
keyframes: Keyframe<T>[];
|
|
1324
|
+
setter: (value: T) => void;
|
|
1325
|
+
loop?: boolean;
|
|
1326
|
+
speed?: number;
|
|
1327
|
+
duration?: number;
|
|
1328
|
+
easing?: EasingFunction;
|
|
1329
|
+
onEnter?: () => void;
|
|
1330
|
+
onExit?: (complete: boolean) => void;
|
|
1331
|
+
}
|
|
1332
|
+
/**
|
|
1333
|
+
* Component that manages named keyframe animations.
|
|
1334
|
+
*
|
|
1335
|
+
* Multiple animations can play concurrently (bob + pulse).
|
|
1336
|
+
* Each animation runs as a Process on the sibling ProcessComponent.
|
|
1337
|
+
* Requires a sibling ProcessComponent on the same entity.
|
|
1338
|
+
*/
|
|
1339
|
+
declare class KeyframeAnimator<T extends string = string> extends Component {
|
|
1340
|
+
private readonly defs;
|
|
1341
|
+
private readonly active;
|
|
1342
|
+
private readonly pc;
|
|
1343
|
+
constructor(animations: Record<T, KeyframeAnimationDef>);
|
|
1344
|
+
/** Start (or restart) a named animation. */
|
|
1345
|
+
play(name: T): void;
|
|
1346
|
+
/** Stop a named animation. */
|
|
1347
|
+
stop(name: T): void;
|
|
1348
|
+
/** Stop all playing animations. */
|
|
1349
|
+
stopAll(): void;
|
|
1350
|
+
/** Whether a named animation is currently playing. */
|
|
1351
|
+
isPlaying(name: T): boolean;
|
|
1352
|
+
onDestroy(): void;
|
|
1353
|
+
private stopInternal;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
type StepFactory = () => Process;
|
|
1357
|
+
/**
|
|
1358
|
+
* Builds a chain of Processes that run in order.
|
|
1359
|
+
* Supports sequential steps, waits, callbacks, and parallel groups.
|
|
1360
|
+
*/
|
|
1361
|
+
declare class Sequence {
|
|
1362
|
+
private steps;
|
|
1363
|
+
private _loop;
|
|
1364
|
+
private _repeatCount;
|
|
1365
|
+
/** Add a step (Process or factory function). */
|
|
1366
|
+
then(step: Process | StepFactory): this;
|
|
1367
|
+
/** Add a delay in ms. */
|
|
1368
|
+
wait(ms: number): this;
|
|
1369
|
+
/** Add an instant callback. */
|
|
1370
|
+
call(fn: () => void): this;
|
|
1371
|
+
/** Run steps in parallel (all must complete before sequence continues). */
|
|
1372
|
+
parallel(...steps: Array<Process | StepFactory>): this;
|
|
1373
|
+
/** Loop the sequence indefinitely. */
|
|
1374
|
+
loop(): this;
|
|
1375
|
+
/** Repeat the sequence a fixed number of times (1 = play once, 2 = play twice, etc.). */
|
|
1376
|
+
repeat(times: number): this;
|
|
1377
|
+
/**
|
|
1378
|
+
* Build the sequence into a Process without registering with a scene.
|
|
1379
|
+
* Exposed for unit testing.
|
|
1380
|
+
* @internal
|
|
1381
|
+
*/
|
|
1382
|
+
_build(): Process;
|
|
1383
|
+
/** Build and start the sequence. Returns the wrapping Process. */
|
|
1384
|
+
start(): Process;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
/** Configuration for a ProcessSlot. */
|
|
1388
|
+
interface ProcessSlotConfig {
|
|
1389
|
+
/** Auto-complete after this duration in ms. */
|
|
1390
|
+
duration?: number;
|
|
1391
|
+
/** Called each frame with dt (ms) and elapsed (ms). Return true to complete early. */
|
|
1392
|
+
update?: (dt: number, elapsed: number) => boolean | void;
|
|
1393
|
+
/** Called on natural completion only. */
|
|
1394
|
+
onComplete?: () => void;
|
|
1395
|
+
/** Called on complete, cancel, OR restart — like `finally`. */
|
|
1396
|
+
cleanup?: () => void;
|
|
1397
|
+
/** Tags for filtering. */
|
|
1398
|
+
tags?: string[];
|
|
1399
|
+
/** Loop the slot's process. */
|
|
1400
|
+
loop?: boolean;
|
|
1401
|
+
}
|
|
1402
|
+
/**
|
|
1403
|
+
* A reusable, restartable process handle owned by a ProcessComponent.
|
|
1404
|
+
*
|
|
1405
|
+
* Starts in `completed` state (ready to use). Call `start()` to activate.
|
|
1406
|
+
* Use for cooldowns, invincibility windows, flash effects, shakes, etc.
|
|
1407
|
+
*/
|
|
1408
|
+
declare class ProcessSlot {
|
|
1409
|
+
private config;
|
|
1410
|
+
private _elapsed;
|
|
1411
|
+
private _completed;
|
|
1412
|
+
private _paused;
|
|
1413
|
+
/** Tags for filtering/grouping. */
|
|
1414
|
+
readonly tags: readonly string[];
|
|
1415
|
+
constructor(config?: ProcessSlotConfig);
|
|
1416
|
+
/** Whether the slot has completed (starts true). */
|
|
1417
|
+
get completed(): boolean;
|
|
1418
|
+
/** Whether the slot is actively running (not completed and not paused). */
|
|
1419
|
+
get running(): boolean;
|
|
1420
|
+
/** Milliseconds elapsed since start. */
|
|
1421
|
+
get elapsed(): number;
|
|
1422
|
+
/** Progress ratio 0..1 (elapsed / duration). 0 if no duration set. */
|
|
1423
|
+
get ratio(): number;
|
|
1424
|
+
/** Start the slot. No-op if already running (use restart() to force). */
|
|
1425
|
+
start(overrides?: Partial<ProcessSlotConfig>): this;
|
|
1426
|
+
/** Cancel if running, then start fresh. Always restarts. */
|
|
1427
|
+
restart(overrides?: Partial<ProcessSlotConfig>): this;
|
|
1428
|
+
/** Cancel the slot. Calls cleanup if running. */
|
|
1429
|
+
cancel(): void;
|
|
1430
|
+
/** Pause the slot. */
|
|
1431
|
+
pause(): void;
|
|
1432
|
+
/** Resume the slot. */
|
|
1433
|
+
resume(): void;
|
|
1434
|
+
/** Set/override the onComplete callback. Chainable. */
|
|
1435
|
+
onComplete(fn: () => void): this;
|
|
1436
|
+
/**
|
|
1437
|
+
* Advance the slot by dt milliseconds.
|
|
1438
|
+
* @internal — called by ProcessComponent
|
|
1439
|
+
*/
|
|
1440
|
+
_tick(dt: number): void;
|
|
1441
|
+
private _complete;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
/**
|
|
1445
|
+
* A component that holds a set of processes on an entity.
|
|
1446
|
+
* Processes are ticked automatically by ProcessSystem each frame.
|
|
1447
|
+
* All processes are cancelled when the entity is destroyed.
|
|
1448
|
+
*/
|
|
1449
|
+
declare class ProcessComponent extends Component {
|
|
1450
|
+
private processes;
|
|
1451
|
+
private slots;
|
|
1452
|
+
/**
|
|
1453
|
+
* Run a one-off process (tween, sequence, delay).
|
|
1454
|
+
* Optionally apply tags for cancel-by-tag.
|
|
1455
|
+
*/
|
|
1456
|
+
run(process: Process, options?: {
|
|
1457
|
+
tags?: string[];
|
|
1458
|
+
}): Process;
|
|
1459
|
+
/** Create a reusable, restartable process slot. */
|
|
1460
|
+
slot(config?: ProcessSlotConfig): ProcessSlot;
|
|
1461
|
+
/** Cancel all processes and slots, or only those matching a tag. */
|
|
1462
|
+
cancel(tag?: string): void;
|
|
1463
|
+
/** Number of active (non-completed) processes and slots. */
|
|
1464
|
+
get count(): number;
|
|
1465
|
+
/**
|
|
1466
|
+
* Advance all processes and slots by dt milliseconds and remove completed one-offs.
|
|
1467
|
+
* @internal — called by ProcessSystem
|
|
1468
|
+
*/
|
|
1469
|
+
_tick(dt: number): void;
|
|
1470
|
+
/** Cancel all processes and slots on entity destroy. */
|
|
1471
|
+
onDestroy(): void;
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
/**
|
|
1475
|
+
* A pre-built entity that exposes the ProcessComponent API directly.
|
|
1476
|
+
* Useful for scene-level timing without manual component wiring.
|
|
1477
|
+
*
|
|
1478
|
+
* ```ts
|
|
1479
|
+
* const timers = this.spawn(TimerEntity);
|
|
1480
|
+
* timers.run(Process.delay(500, () => { ... }));
|
|
1481
|
+
* const cd = timers.slot({ duration: 300 });
|
|
1482
|
+
* ```
|
|
1483
|
+
*/
|
|
1484
|
+
declare class TimerEntity extends Entity {
|
|
1485
|
+
private pc;
|
|
1486
|
+
setup(): void;
|
|
1487
|
+
run(process: Process, options?: {
|
|
1488
|
+
tags?: string[];
|
|
1489
|
+
}): Process;
|
|
1490
|
+
slot(config?: ProcessSlotConfig): ProcessSlot;
|
|
1491
|
+
cancel(tag?: string): void;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
/** Create a fully wired Engine for integration tests. */
|
|
1495
|
+
declare function createTestEngine(config?: EngineConfig): Promise<Engine>;
|
|
1496
|
+
/** Create a lightweight mock scene with EngineContext for unit tests. */
|
|
1497
|
+
declare function createMockScene(name?: string): {
|
|
1498
|
+
scene: Scene;
|
|
1499
|
+
context: EngineContext;
|
|
1500
|
+
};
|
|
1501
|
+
/** Create a mock entity spawned in a mock scene with full EngineContext access. */
|
|
1502
|
+
declare function createMockEntity(name?: string): {
|
|
1503
|
+
entity: Entity;
|
|
1504
|
+
scene: Scene;
|
|
1505
|
+
context: EngineContext;
|
|
1506
|
+
};
|
|
1507
|
+
/** Advance the game loop by N frames (manual tick). */
|
|
1508
|
+
declare function advanceFrames(engine: Engine, n: number, dtMs?: number): void;
|
|
1509
|
+
|
|
1510
|
+
declare const VERSION = "0.0.0";
|
|
1511
|
+
|
|
1512
|
+
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, type LogEntry, LogLevel, Logger, type LoggerConfig, LoggerKey, MathUtils, Phase, type Plugin, Process, ProcessComponent, type ProcessOptions, ProcessSlot, type ProcessSlotConfig, ProcessSystem, ProcessSystemKey, QueryCache, QueryCacheKey, QueryResult, SERIALIZABLE_KEY, Scene, SceneManager, SceneManagerKey, type SceneSnapshot, Sequence, SerializableRegistry, ServiceKey, 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, serializable, trait };
|