ecspresso 0.4.2 → 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.
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Asset management types for ECSpresso ECS framework
3
+ */
4
+ /**
5
+ * Status of an asset in the loading lifecycle
6
+ */
7
+ export type AssetStatus = 'pending' | 'loading' | 'loaded' | 'failed';
8
+ /**
9
+ * Definition for an asset including its loader and configuration
10
+ */
11
+ export interface AssetDefinition<T> {
12
+ readonly loader: () => Promise<T>;
13
+ readonly eager?: boolean;
14
+ readonly group?: string;
15
+ }
16
+ /**
17
+ * Handle to an asset that provides status information and access methods
18
+ */
19
+ export interface AssetHandle<T> {
20
+ readonly status: AssetStatus;
21
+ readonly isLoaded: boolean;
22
+ /**
23
+ * Get the asset value. Throws if asset is not loaded.
24
+ */
25
+ get(): T;
26
+ /**
27
+ * Get the asset value if loaded, undefined otherwise.
28
+ */
29
+ getOrUndefined(): T | undefined;
30
+ }
31
+ /**
32
+ * Resource interface for accessing assets in systems
33
+ * Exposed as $assets resource
34
+ */
35
+ export interface AssetsResource<A extends Record<string, unknown>> {
36
+ /**
37
+ * Get the loading status of an asset
38
+ */
39
+ getStatus<K extends keyof A>(key: K): AssetStatus;
40
+ /**
41
+ * Check if an asset is loaded
42
+ */
43
+ isLoaded<K extends keyof A>(key: K): boolean;
44
+ /**
45
+ * Check if all assets in a group are loaded
46
+ */
47
+ isGroupLoaded(groupName: string): boolean;
48
+ /**
49
+ * Get the loading progress of a group (0-1)
50
+ */
51
+ getGroupProgress(groupName: string): number;
52
+ /**
53
+ * Get a loaded asset. Throws if not loaded.
54
+ */
55
+ get<K extends keyof A>(key: K): A[K];
56
+ /**
57
+ * Get a loaded asset or undefined if not loaded
58
+ */
59
+ getOrUndefined<K extends keyof A>(key: K): A[K] | undefined;
60
+ /**
61
+ * Get a handle to an asset with status information
62
+ */
63
+ getHandle<K extends keyof A>(key: K): AssetHandle<A[K]>;
64
+ }
65
+ /**
66
+ * Events emitted by the asset system
67
+ */
68
+ export interface AssetEvents {
69
+ assetLoaded: {
70
+ key: string;
71
+ };
72
+ assetFailed: {
73
+ key: string;
74
+ error: Error;
75
+ };
76
+ assetGroupLoaded: {
77
+ group: string;
78
+ };
79
+ assetGroupProgress: {
80
+ group: string;
81
+ progress: number;
82
+ loaded: number;
83
+ total: number;
84
+ };
85
+ }
86
+ /**
87
+ * Configuration for asset definitions during builder setup
88
+ */
89
+ export interface AssetConfigurator<A extends Record<string, unknown>> {
90
+ /**
91
+ * Add a single eager asset
92
+ */
93
+ add<K extends string, T>(key: K, loader: () => Promise<T>): AssetConfigurator<A & Record<K, T>>;
94
+ /**
95
+ * Add a single asset with full configuration
96
+ */
97
+ addWithConfig<K extends string, T>(key: K, definition: AssetDefinition<T>): AssetConfigurator<A & Record<K, T>>;
98
+ /**
99
+ * Add a group of assets that can be loaded together
100
+ */
101
+ addGroup<G extends string, T extends Record<string, () => Promise<unknown>>>(groupName: G, assets: T): AssetConfigurator<A & {
102
+ [K in keyof T]: Awaited<ReturnType<T[K]>>;
103
+ }>;
104
+ }
package/dist/bundle.d.ts CHANGED
@@ -1,12 +1,17 @@
1
1
  import { SystemBuilderWithBundle } from './system-builder';
2
2
  import type ECSpresso from './ecspresso';
3
+ import type { AssetDefinition } from './asset-types';
4
+ import type { ScreenDefinition } from './screen-types';
3
5
  /**
4
6
  * Bundle class that encapsulates a set of components, resources, events, and systems
5
7
  * that can be merged into a ECSpresso instance
6
8
  */
7
- export default class Bundle<ComponentTypes extends Record<string, any> = {}, EventTypes extends Record<string, any> = {}, ResourceTypes extends Record<string, any> = {}> {
9
+ export default class Bundle<ComponentTypes extends Record<string, any> = {}, EventTypes extends Record<string, any> = {}, ResourceTypes extends Record<string, any> = {}, AssetTypes extends Record<string, unknown> = {}, ScreenStates extends Record<string, ScreenDefinition<any, any>> = {}> {
8
10
  private _systems;
9
11
  private _resources;
12
+ private _assets;
13
+ private _assetGroups;
14
+ private _screens;
10
15
  private _id;
11
16
  constructor(id?: string);
12
17
  /**
@@ -29,6 +34,53 @@ export default class Bundle<ComponentTypes extends Record<string, any> = {}, Eve
29
34
  * @param resource The resource value or a factory function that returns the resource
30
35
  */
31
36
  addResource<K extends keyof ResourceTypes>(label: K, resource: ResourceTypes[K] | ((ecs: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>) => ResourceTypes[K] | Promise<ResourceTypes[K]>)): this;
37
+ /**
38
+ * Add an asset to this bundle
39
+ * @param key The asset key
40
+ * @param loader Function that loads and returns the asset
41
+ * @param options Optional asset configuration
42
+ */
43
+ addAsset<K extends string, T>(key: K, loader: () => Promise<T>, options?: {
44
+ eager?: boolean;
45
+ group?: string;
46
+ }): Bundle<ComponentTypes, EventTypes, ResourceTypes, AssetTypes & Record<K, T>, ScreenStates>;
47
+ /**
48
+ * Add a group of assets to this bundle
49
+ * @param groupName The group name
50
+ * @param assets Object mapping asset keys to loader functions
51
+ */
52
+ addAssetGroup<G extends string, T extends Record<string, () => Promise<unknown>>>(groupName: G, assets: T): Bundle<ComponentTypes, EventTypes, ResourceTypes, AssetTypes & {
53
+ [K in keyof T]: Awaited<ReturnType<T[K]>>;
54
+ }, ScreenStates>;
55
+ /**
56
+ * Add a screen to this bundle
57
+ * @param name The screen name
58
+ * @param definition The screen definition
59
+ */
60
+ addScreen<K extends string, Config extends Record<string, unknown>, State extends Record<string, unknown>>(name: K, definition: ScreenDefinition<Config, State>): Bundle<ComponentTypes, EventTypes, ResourceTypes, AssetTypes, ScreenStates & Record<K, ScreenDefinition<Config, State>>>;
61
+ /**
62
+ * Get all asset definitions in this bundle
63
+ */
64
+ getAssets(): Map<string, AssetDefinition<unknown>>;
65
+ /**
66
+ * Get all screen definitions in this bundle
67
+ */
68
+ getScreens(): Map<string, ScreenDefinition<any, any>>;
69
+ /**
70
+ * Internal method to set a resource
71
+ * @internal Used by mergeBundles
72
+ */
73
+ _setResource(key: string, value: unknown): void;
74
+ /**
75
+ * Internal method to set an asset definition
76
+ * @internal Used by mergeBundles
77
+ */
78
+ _setAsset(key: string, definition: AssetDefinition<unknown>): void;
79
+ /**
80
+ * Internal method to set a screen definition
81
+ * @internal Used by mergeBundles
82
+ */
83
+ _setScreen(name: string, definition: ScreenDefinition<any, any>): void;
32
84
  /**
33
85
  * Get all systems defined in this bundle
34
86
  * Returns built System objects instead of SystemBuilders
@@ -68,16 +120,20 @@ type Exactly<T, U> = T extends U ? U extends T ? true : false : false;
68
120
  * Simplified type constraint for bundle compatibility
69
121
  * Ensures that overlapping keys have exactly the same types
70
122
  */
71
- type CompatibleBundles<C1 extends Record<string, any>, C2 extends Record<string, any>, E1 extends Record<string, any>, E2 extends Record<string, any>, R1 extends Record<string, any>, R2 extends Record<string, any>> = {
123
+ type CompatibleBundles<C1 extends Record<string, any>, C2 extends Record<string, any>, E1 extends Record<string, any>, E2 extends Record<string, any>, R1 extends Record<string, any>, R2 extends Record<string, any>, A1 extends Record<string, unknown> = {}, A2 extends Record<string, unknown> = {}, S1 extends Record<string, ScreenDefinition<any, any>> = {}, S2 extends Record<string, ScreenDefinition<any, any>> = {}> = {
72
124
  [K in keyof C1 & keyof C2]: Exactly<C1[K], C2[K]> extends true ? C1[K] : never;
73
125
  } & {
74
126
  [K in keyof E1 & keyof E2]: Exactly<E1[K], E2[K]> extends true ? E1[K] : never;
75
127
  } & {
76
128
  [K in keyof R1 & keyof R2]: Exactly<R1[K], R2[K]> extends true ? R1[K] : never;
129
+ } & {
130
+ [K in keyof A1 & keyof A2]: Exactly<A1[K], A2[K]> extends true ? A1[K] : never;
131
+ } & {
132
+ [K in keyof S1 & keyof S2]: Exactly<S1[K], S2[K]> extends true ? S1[K] : never;
77
133
  };
78
134
  /**
79
135
  * Function that merges multiple bundles into a single bundle
80
136
  */
81
- export declare function mergeBundles<C1 extends Record<string, any>, E1 extends Record<string, any>, R1 extends Record<string, any>, C2 extends Record<string, any>, E2 extends Record<string, any>, R2 extends Record<string, any>>(id: string, bundle1: Bundle<C1, E1, R1>, bundle2: Bundle<C2, E2, R2> & CompatibleBundles<C1, C2, E1, E2, R1, R2>): Bundle<C1 & C2, E1 & E2, R1 & R2>;
82
- export declare function mergeBundles<ComponentTypes extends Record<string, any>, EventTypes extends Record<string, any>, ResourceTypes extends Record<string, any>>(id: string, ...bundles: Array<Bundle<ComponentTypes, EventTypes, ResourceTypes>>): Bundle<ComponentTypes, EventTypes, ResourceTypes>;
137
+ export declare function mergeBundles<C1 extends Record<string, any>, E1 extends Record<string, any>, R1 extends Record<string, any>, A1 extends Record<string, unknown>, S1 extends Record<string, ScreenDefinition<any, any>>, C2 extends Record<string, any>, E2 extends Record<string, any>, R2 extends Record<string, any>, A2 extends Record<string, unknown>, S2 extends Record<string, ScreenDefinition<any, any>>>(id: string, bundle1: Bundle<C1, E1, R1, A1, S1>, bundle2: Bundle<C2, E2, R2, A2, S2> & CompatibleBundles<C1, C2, E1, E2, R1, R2, A1, A2, S1, S2>): Bundle<C1 & C2, E1 & E2, R1 & R2, A1 & A2, S1 & S2>;
138
+ export declare function mergeBundles<ComponentTypes extends Record<string, any>, EventTypes extends Record<string, any>, ResourceTypes extends Record<string, any>, AssetTypes extends Record<string, unknown>, ScreenStates extends Record<string, ScreenDefinition<any, any>>>(id: string, ...bundles: Array<Bundle<ComponentTypes, EventTypes, ResourceTypes, AssetTypes, ScreenStates>>): Bundle<ComponentTypes, EventTypes, ResourceTypes, AssetTypes, ScreenStates>;
83
139
  export {};
@@ -1,23 +1,27 @@
1
1
  import EntityManager from "./entity-manager";
2
2
  import EventBus from "./event-bus";
3
- import type { System, FilteredEntity, Entity } from "./types";
3
+ import AssetManager from "./asset-manager";
4
+ import ScreenManager from "./screen-manager";
5
+ import type { System, FilteredEntity, Entity, RemoveEntityOptions } from "./types";
4
6
  import type Bundle from "./bundle";
5
7
  import type { BundlesAreCompatible } from "./type-utils";
8
+ import type { AssetHandle, AssetConfigurator } from "./asset-types";
9
+ import type { ScreenDefinition, ScreenConfigurator } from "./screen-types";
6
10
  /**
7
11
  * Interface declaration for ECSpresso constructor to ensure type augmentation works properly.
8
12
  * This merges with the class declaration below.
9
13
  */
10
- export default interface ECSpresso<ComponentTypes extends Record<string, any> = {}, EventTypes extends Record<string, any> = {}, ResourceTypes extends Record<string, any> = {}> {
14
+ export default interface ECSpresso<ComponentTypes extends Record<string, any> = {}, EventTypes extends Record<string, any> = {}, ResourceTypes extends Record<string, any> = {}, AssetTypes extends Record<string, unknown> = {}, ScreenStates extends Record<string, ScreenDefinition<any, any>> = {}> {
11
15
  /**
12
16
  * Default constructor
13
17
  */
14
- new (): ECSpresso<ComponentTypes, EventTypes, ResourceTypes>;
18
+ new (): ECSpresso<ComponentTypes, EventTypes, ResourceTypes, AssetTypes, ScreenStates>;
15
19
  }
16
20
  /**
17
21
  * ECSpresso is the central ECS framework class that connects all features.
18
22
  * It handles creation and management of entities, components, and systems, and provides lifecycle hooks.
19
23
  */
20
- export default class ECSpresso<ComponentTypes extends Record<string, any> = {}, EventTypes extends Record<string, any> = {}, ResourceTypes extends Record<string, any> = {}> {
24
+ export default class ECSpresso<ComponentTypes extends Record<string, any> = {}, EventTypes extends Record<string, any> = {}, ResourceTypes extends Record<string, any> = {}, AssetTypes extends Record<string, unknown> = {}, ScreenStates extends Record<string, ScreenDefinition<any, any>> = {}> {
21
25
  /** Library version*/
22
26
  static readonly VERSION: string;
23
27
  /** Access/modify stored components and entities*/
@@ -32,6 +36,12 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
32
36
  private _sortedSystems;
33
37
  /** Track installed bundles to prevent duplicates*/
34
38
  private _installedBundles;
39
+ /** Asset manager for loading and accessing assets */
40
+ private _assetManager;
41
+ /** Screen manager for state/screen transitions */
42
+ private _screenManager;
43
+ /** Post-update hooks to be called after all systems in update() */
44
+ private _postUpdateHooks;
35
45
  /**
36
46
  * Creates a new ECSpresso instance.
37
47
  */
@@ -50,7 +60,7 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
50
60
  * .build();
51
61
  * ```
52
62
  */
53
- static create<C extends Record<string, any> = {}, E extends Record<string, any> = {}, R extends Record<string, any> = {}>(): ECSpressoBuilder<C, E, R>;
63
+ static create<C extends Record<string, any> = {}, E extends Record<string, any> = {}, R extends Record<string, any> = {}, A extends Record<string, unknown> = {}, S extends Record<string, ScreenDefinition<any, any>> = {}>(): ECSpressoBuilder<C, E, R, A, S>;
54
64
  /**
55
65
  * Adds a system directly to this ECSpresso instance
56
66
  * @param label Unique name to identify the system
@@ -66,7 +76,9 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
66
76
  * Initialize all resources and systems
67
77
  * This method:
68
78
  * 1. Initializes all resources that were added as factory functions
69
- * 2. Calls the onInitialize lifecycle hook on all systems
79
+ * 2. Sets up asset manager and loads eager assets
80
+ * 3. Sets up screen manager
81
+ * 4. Calls the onInitialize lifecycle hook on all systems
70
82
  *
71
83
  * This is useful for game startup to ensure all resources are ready
72
84
  * and systems are properly initialized before the game loop begins.
@@ -106,7 +118,7 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
106
118
  * Internal method to register a system with this ECSpresso instance
107
119
  * @internal Used by SystemBuilder - replaces direct private property access
108
120
  */
109
- _registerSystem(system: System<ComponentTypes, any, any, EventTypes, ResourceTypes>): void;
121
+ _registerSystem(system: System<ComponentTypes, any, any, EventTypes, ResourceTypes, AssetTypes, ScreenStates>): void;
110
122
  /**
111
123
  * Check if a resource exists
112
124
  */
@@ -155,44 +167,300 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
155
167
  */
156
168
  spawn<T extends {
157
169
  [K in keyof ComponentTypes]?: ComponentTypes[K];
158
- }>(components: T & Record<Exclude<keyof T, keyof ComponentTypes>, never>): Entity<ComponentTypes>;
170
+ }>(components: T & Record<Exclude<keyof T, keyof ComponentTypes>, never>): FilteredEntity<ComponentTypes, keyof T & keyof ComponentTypes, never>;
159
171
  /**
160
172
  * Get all entities with specific components
161
173
  */
162
174
  getEntitiesWithQuery<WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never>(withComponents: ReadonlyArray<WithComponents>, withoutComponents?: ReadonlyArray<WithoutComponents>): Array<FilteredEntity<ComponentTypes, WithComponents, WithoutComponents>>;
175
+ /**
176
+ * Remove an entity (and optionally its descendants)
177
+ * @param entityOrId Entity or entity ID to remove
178
+ * @param options Options for removal (cascade: true by default)
179
+ * @returns true if entity was removed
180
+ */
181
+ removeEntity(entityOrId: number | Entity<ComponentTypes>, options?: RemoveEntityOptions): boolean;
182
+ /**
183
+ * Create an entity as a child of another entity with initial components
184
+ * @param parentId The parent entity ID
185
+ * @param components Initial components to add
186
+ * @returns The created child entity
187
+ */
188
+ spawnChild<T extends {
189
+ [K in keyof ComponentTypes]?: ComponentTypes[K];
190
+ }>(parentId: number, components: T & Record<Exclude<keyof T, keyof ComponentTypes>, never>): FilteredEntity<ComponentTypes, keyof T & keyof ComponentTypes, never>;
191
+ /**
192
+ * Set the parent of an entity
193
+ * @param childId The entity to set as a child
194
+ * @param parentId The entity to set as the parent
195
+ */
196
+ setParent(childId: number, parentId: number): this;
197
+ /**
198
+ * Remove the parent relationship for an entity (orphan it)
199
+ * @param childId The entity to orphan
200
+ * @returns true if a parent was removed, false if entity had no parent
201
+ */
202
+ removeParent(childId: number): boolean;
203
+ /**
204
+ * Get the parent of an entity
205
+ * @param entityId The entity to get the parent of
206
+ * @returns The parent entity ID, or null if no parent
207
+ */
208
+ getParent(entityId: number): number | null;
209
+ /**
210
+ * Get all children of an entity in insertion order
211
+ * @param parentId The parent entity
212
+ * @returns Readonly array of child entity IDs
213
+ */
214
+ getChildren(parentId: number): readonly number[];
215
+ /**
216
+ * Get a child at a specific index
217
+ * @param parentId The parent entity
218
+ * @param index The index of the child
219
+ * @returns The child entity ID, or null if index is out of bounds
220
+ */
221
+ getChildAt(parentId: number, index: number): number | null;
222
+ /**
223
+ * Get the index of a child within its parent's children list
224
+ * @param parentId The parent entity
225
+ * @param childId The child entity to find
226
+ * @returns The index of the child, or -1 if not found
227
+ */
228
+ getChildIndex(parentId: number, childId: number): number;
229
+ /**
230
+ * Get all ancestors of an entity in order [parent, grandparent, ...]
231
+ * @param entityId The entity to get ancestors of
232
+ * @returns Readonly array of ancestor entity IDs
233
+ */
234
+ getAncestors(entityId: number): readonly number[];
235
+ /**
236
+ * Get all descendants of an entity in depth-first order
237
+ * @param entityId The entity to get descendants of
238
+ * @returns Readonly array of descendant entity IDs
239
+ */
240
+ getDescendants(entityId: number): readonly number[];
241
+ /**
242
+ * Get the root ancestor of an entity (topmost parent), or self if no parent
243
+ * @param entityId The entity to get the root of
244
+ * @returns The root entity ID
245
+ */
246
+ getRoot(entityId: number): number;
247
+ /**
248
+ * Get siblings of an entity (other children of the same parent)
249
+ * @param entityId The entity to get siblings of
250
+ * @returns Readonly array of sibling entity IDs
251
+ */
252
+ getSiblings(entityId: number): readonly number[];
253
+ /**
254
+ * Check if an entity is a descendant of another entity
255
+ * @param entityId The potential descendant
256
+ * @param ancestorId The potential ancestor
257
+ * @returns true if entityId is a descendant of ancestorId
258
+ */
259
+ isDescendantOf(entityId: number, ancestorId: number): boolean;
260
+ /**
261
+ * Check if an entity is an ancestor of another entity
262
+ * @param entityId The potential ancestor
263
+ * @param descendantId The potential descendant
264
+ * @returns true if entityId is an ancestor of descendantId
265
+ */
266
+ isAncestorOf(entityId: number, descendantId: number): boolean;
267
+ /**
268
+ * Get all root entities (entities that have children but no parent)
269
+ * @returns Readonly array of root entity IDs
270
+ */
271
+ getRootEntities(): readonly number[];
272
+ /**
273
+ * Emit a hierarchy changed event
274
+ * @internal
275
+ */
276
+ private _emitHierarchyChanged;
163
277
  /**
164
278
  * Get all installed bundle IDs
165
279
  */
166
280
  get installedBundles(): string[];
167
281
  get entityManager(): EntityManager<ComponentTypes>;
168
282
  get eventBus(): EventBus<EventTypes>;
283
+ /**
284
+ * Subscribe to an event (convenience wrapper for eventBus.subscribe)
285
+ * @param eventType The event type to subscribe to
286
+ * @param callback The callback to invoke when the event is published
287
+ * @returns An unsubscribe function
288
+ */
289
+ on<E extends keyof EventTypes>(eventType: E, callback: (data: EventTypes[E]) => void): () => void;
290
+ /**
291
+ * Unsubscribe from an event by callback reference (convenience wrapper for eventBus.unsubscribe)
292
+ * @param eventType The event type to unsubscribe from
293
+ * @param callback The callback to remove
294
+ * @returns true if the callback was found and removed, false otherwise
295
+ */
296
+ off<E extends keyof EventTypes>(eventType: E, callback: (data: EventTypes[E]) => void): boolean;
297
+ /**
298
+ * Register a hook that runs after all systems in update()
299
+ * @param callback The hook to call after all systems have processed
300
+ * @returns An unsubscribe function to remove the hook
301
+ */
302
+ onPostUpdate(callback: (ecs: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>, deltaTime: number) => void): () => void;
303
+ /**
304
+ * Get a loaded asset by key. Throws if not loaded.
305
+ */
306
+ getAsset<K extends keyof AssetTypes>(key: K): AssetTypes[K];
307
+ /**
308
+ * Get a loaded asset or undefined if not loaded
309
+ */
310
+ getAssetOrUndefined<K extends keyof AssetTypes>(key: K): AssetTypes[K] | undefined;
311
+ /**
312
+ * Get a handle to an asset with status information
313
+ */
314
+ getAssetHandle<K extends keyof AssetTypes>(key: K): AssetHandle<AssetTypes[K]>;
315
+ /**
316
+ * Check if an asset is loaded
317
+ */
318
+ isAssetLoaded<K extends keyof AssetTypes>(key: K): boolean;
319
+ /**
320
+ * Load a single asset
321
+ */
322
+ loadAsset<K extends keyof AssetTypes>(key: K): Promise<AssetTypes[K]>;
323
+ /**
324
+ * Load all assets in a group
325
+ */
326
+ loadAssetGroup(groupName: string): Promise<void>;
327
+ /**
328
+ * Check if all assets in a group are loaded
329
+ */
330
+ isAssetGroupLoaded(groupName: string): boolean;
331
+ /**
332
+ * Get the loading progress of a group (0-1)
333
+ */
334
+ getAssetGroupProgress(groupName: string): number;
335
+ /**
336
+ * Transition to a new screen, clearing the stack
337
+ */
338
+ setScreen<K extends keyof ScreenStates>(name: K, config: ScreenStates[K] extends ScreenDefinition<infer C, any> ? C : never): Promise<void>;
339
+ /**
340
+ * Push a screen onto the stack (overlay)
341
+ */
342
+ pushScreen<K extends keyof ScreenStates>(name: K, config: ScreenStates[K] extends ScreenDefinition<infer C, any> ? C : never): Promise<void>;
343
+ /**
344
+ * Pop the current screen and return to the previous one
345
+ */
346
+ popScreen(): Promise<void>;
347
+ /**
348
+ * Get the current screen name
349
+ */
350
+ getCurrentScreen(): keyof ScreenStates | null;
351
+ /**
352
+ * Get the current screen config (immutable)
353
+ */
354
+ getScreenConfig<K extends keyof ScreenStates>(): ScreenStates[K] extends ScreenDefinition<infer C, any> ? Readonly<C> : never;
355
+ /**
356
+ * Get the current screen config or null
357
+ */
358
+ getScreenConfigOrNull<K extends keyof ScreenStates>(): (ScreenStates[K] extends ScreenDefinition<infer C, any> ? Readonly<C> : never) | null;
359
+ /**
360
+ * Get the current screen state (mutable)
361
+ */
362
+ getScreenState<K extends keyof ScreenStates>(): ScreenStates[K] extends ScreenDefinition<any, infer S> ? S : never;
363
+ /**
364
+ * Get the current screen state or null
365
+ */
366
+ getScreenStateOrNull<K extends keyof ScreenStates>(): (ScreenStates[K] extends ScreenDefinition<any, infer S> ? S : never) | null;
367
+ /**
368
+ * Update the current screen state
369
+ */
370
+ updateScreenState<K extends keyof ScreenStates>(update: Partial<ScreenStates[K] extends ScreenDefinition<any, infer S> ? S : never> | ((current: ScreenStates[K] extends ScreenDefinition<any, infer S> ? S : never) => Partial<ScreenStates[K] extends ScreenDefinition<any, infer S> ? S : never>)): void;
371
+ /**
372
+ * Check if a screen is the current screen
373
+ */
374
+ isCurrentScreen(screenName: keyof ScreenStates): boolean;
375
+ /**
376
+ * Check if a screen is active (current or in stack)
377
+ */
378
+ isScreenActive(screenName: keyof ScreenStates): boolean;
379
+ /**
380
+ * Get the screen stack depth
381
+ */
382
+ getScreenStackDepth(): number;
383
+ /**
384
+ * Internal method to set the asset manager
385
+ * @internal Used by ECSpressoBuilder
386
+ */
387
+ _setAssetManager(manager: AssetManager<AssetTypes>): void;
388
+ /**
389
+ * Internal method to set the screen manager
390
+ * @internal Used by ECSpressoBuilder
391
+ */
392
+ _setScreenManager(manager: ScreenManager<ScreenStates>): void;
169
393
  /**
170
394
  * Internal method to install a bundle into this ECSpresso instance.
171
395
  * Called by the ECSpressoBuilder during the build process.
172
396
  * The type safety is guaranteed by the builder's type system.
173
397
  */
174
- _installBundle<C extends Record<string, any>, E extends Record<string, any>, R extends Record<string, any>>(bundle: Bundle<C, E, R>): this;
398
+ _installBundle<C extends Record<string, any>, E extends Record<string, any>, R extends Record<string, any>, A extends Record<string, unknown> = {}, S extends Record<string, ScreenDefinition<any, any>> = {}>(bundle: Bundle<C, E, R, A, S>): this;
175
399
  }
176
400
  /**
177
401
  * Builder class for ECSpresso that provides fluent type-safe bundle installation.
178
402
  * Handles type checking during build process to ensure type safety.
179
403
  */
180
- export declare class ECSpressoBuilder<C extends Record<string, any> = {}, E extends Record<string, any> = {}, R extends Record<string, any> = {}> {
404
+ export declare class ECSpressoBuilder<C extends Record<string, any> = {}, E extends Record<string, any> = {}, R extends Record<string, any> = {}, A extends Record<string, unknown> = {}, S extends Record<string, ScreenDefinition<any, any>> = {}> {
181
405
  /** The ECSpresso instance being built*/
182
406
  private ecspresso;
407
+ /** Asset configurator for collecting asset definitions */
408
+ private assetConfigurator;
409
+ /** Screen configurator for collecting screen definitions */
410
+ private screenConfigurator;
183
411
  constructor();
184
412
  /**
185
413
  * Add the first bundle when starting with empty types.
186
414
  * This overload allows any bundle to be added to an empty ECSpresso instance.
187
415
  */
188
- withBundle<BC extends Record<string, any>, BE extends Record<string, any>, BR extends Record<string, any>>(this: ECSpressoBuilder<{}, {}, {}>, bundle: Bundle<BC, BE, BR>): ECSpressoBuilder<BC, BE, BR>;
416
+ withBundle<BC extends Record<string, any>, BE extends Record<string, any>, BR extends Record<string, any>>(this: ECSpressoBuilder<{}, {}, {}, A, S>, bundle: Bundle<BC, BE, BR>): ECSpressoBuilder<BC, BE, BR, A, S>;
189
417
  /**
190
418
  * Add a subsequent bundle with type checking.
191
419
  * This overload enforces bundle type compatibility.
192
420
  */
193
- withBundle<BC extends Record<string, any>, BE extends Record<string, any>, BR extends Record<string, any>>(bundle: BundlesAreCompatible<C, BC, E, BE, R, BR> extends true ? Bundle<BC, BE, BR> : never): ECSpressoBuilder<C & BC, E & BE, R & BR>;
421
+ withBundle<BC extends Record<string, any>, BE extends Record<string, any>, BR extends Record<string, any>>(bundle: BundlesAreCompatible<C, BC, E, BE, R, BR> extends true ? Bundle<BC, BE, BR> : never): ECSpressoBuilder<C & BC, E & BE, R & BR, A, S>;
422
+ /**
423
+ * Configure assets for this ECSpresso instance
424
+ * @param configurator Function that receives an AssetConfigurator and returns it after adding assets
425
+ * @returns This builder with updated asset types
426
+ *
427
+ * @example
428
+ * ```typescript
429
+ * ECSpresso.create<Components, Events, Resources>()
430
+ * .withAssets(assets => assets
431
+ * .add('playerSprite', () => loadTexture('player.png'))
432
+ * .addGroup('level1', {
433
+ * background: () => loadTexture('level1-bg.png'),
434
+ * music: () => loadAudio('level1.mp3'),
435
+ * })
436
+ * )
437
+ * .build();
438
+ * ```
439
+ */
440
+ withAssets<NewA extends Record<string, unknown>>(configurator: (assets: AssetConfigurator<{}>) => AssetConfigurator<NewA>): ECSpressoBuilder<C, E, R, A & NewA, S>;
441
+ /**
442
+ * Configure screens for this ECSpresso instance
443
+ * @param configurator Function that receives a ScreenConfigurator and returns it after adding screens
444
+ * @returns This builder with updated screen types
445
+ *
446
+ * @example
447
+ * ```typescript
448
+ * ECSpresso.create<Components, Events, Resources>()
449
+ * .withScreens(screens => screens
450
+ * .add('loading', {
451
+ * initialState: () => ({ progress: 0 }),
452
+ * })
453
+ * .add('gameplay', {
454
+ * initialState: ({ level }) => ({ score: 0, level }),
455
+ * requiredAssetGroups: ['level1'],
456
+ * })
457
+ * )
458
+ * .build();
459
+ * ```
460
+ */
461
+ withScreens<NewS extends Record<string, ScreenDefinition<any, any>>>(configurator: (screens: ScreenConfigurator<{}>) => ScreenConfigurator<NewS>): ECSpressoBuilder<C, E, R, A, S & NewS>;
194
462
  /**
195
463
  * Complete the build process and return the built ECSpresso instance
196
464
  */
197
- build(): ECSpresso<C, E, R>;
465
+ build(): ECSpresso<C, E, R, A, S>;
198
466
  }