ecspresso 0.4.3 → 0.6.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,111 @@
1
+ /**
2
+ * Asset management for ECSpresso ECS framework
3
+ */
4
+ import type EventBus from './event-bus';
5
+ import type { AssetStatus, AssetDefinition, AssetHandle, AssetsResource, AssetEvents, AssetConfigurator } from './asset-types';
6
+ /**
7
+ * Manages asset loading and access for ECSpresso
8
+ */
9
+ export default class AssetManager<AssetTypes extends Record<string, unknown> = Record<string, never>> {
10
+ private readonly assets;
11
+ private readonly groups;
12
+ private eventBus;
13
+ /**
14
+ * Set the event bus for asset events
15
+ * @internal
16
+ */
17
+ setEventBus(eventBus: EventBus<AssetEvents>): void;
18
+ /**
19
+ * Register an asset definition
20
+ */
21
+ register<K extends string, T>(key: K, definition: AssetDefinition<T>): void;
22
+ /**
23
+ * Load all assets marked as eager
24
+ */
25
+ loadEagerAssets(): Promise<void>;
26
+ /**
27
+ * Load a single asset by key
28
+ */
29
+ loadAsset<K extends keyof AssetTypes>(key: K): Promise<AssetTypes[K]>;
30
+ /**
31
+ * Load all assets in a group
32
+ */
33
+ loadAssetGroup(groupName: string): Promise<void>;
34
+ /**
35
+ * Get a loaded asset. Throws if not loaded.
36
+ */
37
+ get<K extends keyof AssetTypes>(key: K): AssetTypes[K];
38
+ /**
39
+ * Get a loaded asset or undefined
40
+ */
41
+ getOrUndefined<K extends keyof AssetTypes>(key: K): AssetTypes[K] | undefined;
42
+ /**
43
+ * Get a handle to an asset with status information
44
+ */
45
+ getHandle<K extends keyof AssetTypes>(key: K): AssetHandle<AssetTypes[K]>;
46
+ /**
47
+ * Get the status of an asset
48
+ */
49
+ getStatus<K extends keyof AssetTypes>(key: K): AssetStatus;
50
+ /**
51
+ * Check if an asset is loaded
52
+ */
53
+ isLoaded<K extends keyof AssetTypes>(key: K): boolean;
54
+ /**
55
+ * Check if all assets in a group are loaded
56
+ */
57
+ isGroupLoaded(groupName: string): boolean;
58
+ /**
59
+ * Get the loading progress of a group (0-1)
60
+ */
61
+ getGroupProgress(groupName: string): number;
62
+ /**
63
+ * Get detailed group progress
64
+ */
65
+ getGroupProgressDetails(groupName: string): {
66
+ loaded: number;
67
+ total: number;
68
+ progress: number;
69
+ };
70
+ /**
71
+ * Check group progress and emit events
72
+ */
73
+ private checkGroupProgress;
74
+ /**
75
+ * Create the $assets resource object
76
+ */
77
+ createResource(): AssetsResource<AssetTypes>;
78
+ /**
79
+ * Get all registered asset keys
80
+ */
81
+ getKeys(): Array<keyof AssetTypes>;
82
+ /**
83
+ * Get all group names
84
+ */
85
+ getGroupNames(): string[];
86
+ /**
87
+ * Get all asset keys in a group
88
+ */
89
+ getGroupKeys(groupName: string): Array<keyof AssetTypes>;
90
+ }
91
+ /**
92
+ * Implementation of AssetConfigurator for builder pattern
93
+ */
94
+ export declare class AssetConfiguratorImpl<A extends Record<string, unknown>> implements AssetConfigurator<A> {
95
+ private readonly manager;
96
+ constructor(manager: AssetManager<A>);
97
+ add<K extends string, T>(key: K, loader: () => Promise<T>): AssetConfigurator<A & Record<K, T>>;
98
+ addWithConfig<K extends string, T>(key: K, definition: AssetDefinition<T>): AssetConfigurator<A & Record<K, T>>;
99
+ addGroup<G extends string, T extends Record<string, () => Promise<unknown>>>(groupName: G, assets: T): AssetConfigurator<A & {
100
+ [K in keyof T]: Awaited<ReturnType<T[K]>>;
101
+ }>;
102
+ /**
103
+ * Get the underlying manager
104
+ * @internal
105
+ */
106
+ getManager(): AssetManager<A>;
107
+ }
108
+ /**
109
+ * Create a new AssetConfigurator for builder pattern usage
110
+ */
111
+ export declare function createAssetConfigurator<A extends Record<string, unknown> = Record<string, never>>(manager?: AssetManager<A>): AssetConfiguratorImpl<A>;
@@ -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
  /**
@@ -26,9 +31,59 @@ export default class Bundle<ComponentTypes extends Record<string, any> = {}, Eve
26
31
  /**
27
32
  * Add a resource to this bundle
28
33
  * @param label The resource key
29
- * @param resource The resource value or a factory function that returns the resource
34
+ * @param resource The resource value, a factory function, or a factory with dependencies
30
35
  */
31
- addResource<K extends keyof ResourceTypes>(label: K, resource: ResourceTypes[K] | ((ecs: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>) => ResourceTypes[K] | Promise<ResourceTypes[K]>)): this;
36
+ addResource<K extends keyof ResourceTypes>(label: K, resource: ResourceTypes[K] | ((ecs: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>) => ResourceTypes[K] | Promise<ResourceTypes[K]>) | {
37
+ dependsOn: readonly string[];
38
+ factory: (ecs: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>) => ResourceTypes[K] | Promise<ResourceTypes[K]>;
39
+ }): this;
40
+ /**
41
+ * Add an asset to this bundle
42
+ * @param key The asset key
43
+ * @param loader Function that loads and returns the asset
44
+ * @param options Optional asset configuration
45
+ */
46
+ addAsset<K extends string, T>(key: K, loader: () => Promise<T>, options?: {
47
+ eager?: boolean;
48
+ group?: string;
49
+ }): Bundle<ComponentTypes, EventTypes, ResourceTypes, AssetTypes & Record<K, T>, ScreenStates>;
50
+ /**
51
+ * Add a group of assets to this bundle
52
+ * @param groupName The group name
53
+ * @param assets Object mapping asset keys to loader functions
54
+ */
55
+ addAssetGroup<G extends string, T extends Record<string, () => Promise<unknown>>>(groupName: G, assets: T): Bundle<ComponentTypes, EventTypes, ResourceTypes, AssetTypes & {
56
+ [K in keyof T]: Awaited<ReturnType<T[K]>>;
57
+ }, ScreenStates>;
58
+ /**
59
+ * Add a screen to this bundle
60
+ * @param name The screen name
61
+ * @param definition The screen definition
62
+ */
63
+ 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>>>;
64
+ /**
65
+ * Get all asset definitions in this bundle
66
+ */
67
+ getAssets(): Map<string, AssetDefinition<unknown>>;
68
+ /**
69
+ * Get all screen definitions in this bundle
70
+ */
71
+ getScreens(): Map<string, ScreenDefinition<any, any>>;
72
+ /**
73
+ * Internal method to set a resource
74
+ * @internal Used by mergeBundles
75
+ */
76
+ _setResource(key: string, value: unknown): void;
77
+ /**
78
+ * Internal method to set an asset definition
79
+ * @internal Used by mergeBundles
80
+ */
81
+ _setAsset(key: string, definition: AssetDefinition<unknown>): void;
82
+ /**
83
+ * Internal method to set a screen definition
84
+ * @internal Used by mergeBundles
85
+ */
86
+ _setScreen(name: string, definition: ScreenDefinition<any, any>): void;
32
87
  /**
33
88
  * Get all systems defined in this bundle
34
89
  * Returns built System objects instead of SystemBuilders
@@ -68,16 +123,20 @@ type Exactly<T, U> = T extends U ? U extends T ? true : false : false;
68
123
  * Simplified type constraint for bundle compatibility
69
124
  * Ensures that overlapping keys have exactly the same types
70
125
  */
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>> = {
126
+ 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
127
  [K in keyof C1 & keyof C2]: Exactly<C1[K], C2[K]> extends true ? C1[K] : never;
73
128
  } & {
74
129
  [K in keyof E1 & keyof E2]: Exactly<E1[K], E2[K]> extends true ? E1[K] : never;
75
130
  } & {
76
131
  [K in keyof R1 & keyof R2]: Exactly<R1[K], R2[K]> extends true ? R1[K] : never;
132
+ } & {
133
+ [K in keyof A1 & keyof A2]: Exactly<A1[K], A2[K]> extends true ? A1[K] : never;
134
+ } & {
135
+ [K in keyof S1 & keyof S2]: Exactly<S1[K], S2[K]> extends true ? S1[K] : never;
77
136
  };
78
137
  /**
79
138
  * Function that merges multiple bundles into a single bundle
80
139
  */
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>;
140
+ 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>;
141
+ 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
142
  export {};
@@ -0,0 +1,248 @@
1
+ /**
2
+ * PixiJS Renderer Bundle for ECSpresso
3
+ *
4
+ * An opt-in PixiJS rendering bundle that automates scene graph wiring.
5
+ * Import from 'ecspresso/bundles/renderers/pixi'
6
+ */
7
+ import type { Application, ApplicationOptions, Container, Sprite, Graphics } from 'pixi.js';
8
+ import Bundle from '../../bundle';
9
+ /**
10
+ * Local transform relative to parent (or world if no parent)
11
+ */
12
+ export interface LocalTransform {
13
+ x: number;
14
+ y: number;
15
+ rotation: number;
16
+ scaleX: number;
17
+ scaleY: number;
18
+ }
19
+ /**
20
+ * Computed world transform (accumulated from parent chain)
21
+ */
22
+ export interface WorldTransform {
23
+ x: number;
24
+ y: number;
25
+ rotation: number;
26
+ scaleX: number;
27
+ scaleY: number;
28
+ }
29
+ /**
30
+ * PixiJS Sprite component
31
+ */
32
+ export interface PixiSprite {
33
+ sprite: Sprite;
34
+ anchor?: {
35
+ x: number;
36
+ y: number;
37
+ };
38
+ }
39
+ /**
40
+ * PixiJS Graphics component
41
+ */
42
+ export interface PixiGraphics {
43
+ graphics: Graphics;
44
+ }
45
+ /**
46
+ * PixiJS Container component
47
+ */
48
+ export interface PixiContainer {
49
+ container: Container;
50
+ }
51
+ /**
52
+ * Visibility and alpha component
53
+ */
54
+ export interface PixiVisible {
55
+ visible: boolean;
56
+ alpha?: number;
57
+ }
58
+ /**
59
+ * Aggregate component types for PixiJS bundle.
60
+ * Users should extend this interface with their own component types.
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * interface GameComponents extends PixiComponentTypes {
65
+ * velocity: { x: number; y: number };
66
+ * player: true;
67
+ * }
68
+ * ```
69
+ */
70
+ export interface PixiComponentTypes {
71
+ localTransform: LocalTransform;
72
+ worldTransform: WorldTransform;
73
+ pixiSprite: PixiSprite;
74
+ pixiGraphics: PixiGraphics;
75
+ pixiContainer: PixiContainer;
76
+ pixiVisible: PixiVisible;
77
+ }
78
+ /**
79
+ * Events emitted by the PixiJS bundle
80
+ */
81
+ export interface PixiEventTypes {
82
+ hierarchyChanged: {
83
+ entityId: number;
84
+ oldParent: number | null;
85
+ newParent: number | null;
86
+ };
87
+ }
88
+ /**
89
+ * Resources provided by the PixiJS bundle
90
+ */
91
+ export interface PixiResourceTypes {
92
+ pixiApp: Application;
93
+ pixiRootContainer: Container;
94
+ }
95
+ /**
96
+ * Common options shared between both initialization modes
97
+ */
98
+ interface PixiBundleCommonOptions {
99
+ /** Optional custom root container (defaults to app.stage) */
100
+ rootContainer?: Container;
101
+ /** System group name (default: 'pixi-renderer') */
102
+ systemGroup?: string;
103
+ /** Priority for transform propagation system (default: 1000) */
104
+ transformPriority?: number;
105
+ /** Priority for render sync system (default: 500) */
106
+ renderSyncPriority?: number;
107
+ }
108
+ /**
109
+ * Options when providing a pre-initialized PixiJS Application
110
+ */
111
+ export interface PixiBundleAppOptions extends PixiBundleCommonOptions {
112
+ /** The PixiJS Application instance (already initialized) */
113
+ app: Application;
114
+ init?: never;
115
+ container?: never;
116
+ }
117
+ /**
118
+ * Options when letting the bundle create and manage the PixiJS Application
119
+ */
120
+ export interface PixiBundleManagedOptions extends PixiBundleCommonOptions {
121
+ app?: never;
122
+ /** PixiJS ApplicationOptions - bundle will create and initialize the Application */
123
+ init: Partial<ApplicationOptions>;
124
+ /** Container element to append the canvas to, or CSS selector string */
125
+ container?: HTMLElement | string;
126
+ }
127
+ /**
128
+ * Configuration options for the PixiJS bundle.
129
+ *
130
+ * Supports two modes:
131
+ * 1. **Pre-initialized**: Pass an already-initialized Application via `app`
132
+ * 2. **Managed**: Pass `init` options and the bundle creates the Application during `ecs.initialize()`
133
+ *
134
+ * @example Pre-initialized mode (full control)
135
+ * ```typescript
136
+ * const app = new Application();
137
+ * await app.init({ resizeTo: window });
138
+ * const ecs = ECSpresso.create<...>()
139
+ * .withBundle(createPixiBundle({ app }))
140
+ * .build();
141
+ * ```
142
+ *
143
+ * @example Managed mode (convenience)
144
+ * ```typescript
145
+ * const ecs = ECSpresso.create<...>()
146
+ * .withBundle(createPixiBundle({
147
+ * init: { background: '#1099bb', resizeTo: window },
148
+ * container: document.body,
149
+ * }))
150
+ * .build();
151
+ * await ecs.initialize(); // Application created here
152
+ * ```
153
+ */
154
+ export type PixiBundleOptions = PixiBundleAppOptions | PixiBundleManagedOptions;
155
+ /**
156
+ * Default local transform values
157
+ */
158
+ export declare const DEFAULT_LOCAL_TRANSFORM: Readonly<LocalTransform>;
159
+ /**
160
+ * Default world transform values
161
+ */
162
+ export declare const DEFAULT_WORLD_TRANSFORM: Readonly<WorldTransform>;
163
+ interface PositionOption {
164
+ x?: number;
165
+ y?: number;
166
+ }
167
+ interface TransformOptions {
168
+ rotation?: number;
169
+ scale?: number | {
170
+ x: number;
171
+ y: number;
172
+ };
173
+ visible?: boolean;
174
+ alpha?: number;
175
+ }
176
+ /**
177
+ * Create components for a sprite entity.
178
+ * Returns an object suitable for spreading into spawn().
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * const player = ecs.spawn({
183
+ * ...createSpriteComponents(new Sprite(texture), { x: 100, y: 100 }),
184
+ * velocity: { x: 0, y: 0 },
185
+ * });
186
+ * ```
187
+ */
188
+ export declare function createSpriteComponents(sprite: Sprite, position?: PositionOption, options?: TransformOptions & {
189
+ anchor?: {
190
+ x: number;
191
+ y: number;
192
+ };
193
+ }): Pick<PixiComponentTypes, 'pixiSprite' | 'localTransform' | 'worldTransform' | 'pixiVisible'>;
194
+ /**
195
+ * Create components for a graphics entity.
196
+ * Returns an object suitable for spreading into spawn().
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * const rect = ecs.spawn({
201
+ * ...createGraphicsComponents(graphics, { x: 50, y: 50 }),
202
+ * });
203
+ * ```
204
+ */
205
+ export declare function createGraphicsComponents(graphics: Graphics, position?: PositionOption, options?: TransformOptions): Pick<PixiComponentTypes, 'pixiGraphics' | 'localTransform' | 'worldTransform' | 'pixiVisible'>;
206
+ /**
207
+ * Create components for a container entity.
208
+ * Returns an object suitable for spreading into spawn().
209
+ *
210
+ * @example
211
+ * ```typescript
212
+ * const group = ecs.spawn({
213
+ * ...createContainerComponents(new Container(), { x: 0, y: 0 }),
214
+ * });
215
+ * ```
216
+ */
217
+ export declare function createContainerComponents(container: Container, position?: PositionOption, options?: TransformOptions): Pick<PixiComponentTypes, 'pixiContainer' | 'localTransform' | 'worldTransform' | 'pixiVisible'>;
218
+ /**
219
+ * Create a PixiJS rendering bundle for ECSpresso.
220
+ *
221
+ * This bundle provides:
222
+ * - Transform propagation system (computes world transforms from hierarchy)
223
+ * - Render sync system (updates PixiJS objects from ECS components)
224
+ * - Scene graph management (mirrors ECS hierarchy in PixiJS scene graph)
225
+ *
226
+ * @example Pre-initialized mode
227
+ * ```typescript
228
+ * const app = new Application();
229
+ * await app.init({ resizeTo: window });
230
+ *
231
+ * const ecs = ECSpresso.create<GameComponents, {}, {}>()
232
+ * .withBundle(createPixiBundle({ app }))
233
+ * .build();
234
+ * ```
235
+ *
236
+ * @example Managed mode
237
+ * ```typescript
238
+ * const ecs = ECSpresso.create<GameComponents, {}, {}>()
239
+ * .withBundle(createPixiBundle({
240
+ * init: { background: '#1099bb', resizeTo: window },
241
+ * container: document.body,
242
+ * }))
243
+ * .build();
244
+ * await ecs.initialize();
245
+ * ```
246
+ */
247
+ export declare function createPixiBundle(options: PixiBundleOptions): Bundle<PixiComponentTypes, PixiEventTypes, PixiResourceTypes>;
248
+ export {};
@@ -0,0 +1,4 @@
1
+ var O=Object.create;var{getPrototypeOf:I,defineProperty:j,getOwnPropertyNames:T}=Object;var f=Object.prototype.hasOwnProperty;var u=(H,J,K)=>{K=H!=null?O(I(H)):{};let F=J||!H||!H.__esModule?j(K,"default",{value:H,enumerable:!0}):K;for(let R of T(H))if(!f.call(F,R))j(F,R,{get:()=>H[R],enumerable:!0});return F};var b=((H)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(H,{get:(J,K)=>(typeof require<"u"?require:J)[K]}):H)(function(H){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+H+'" is not supported')});class k{_label;_ecspresso;_bundle;queries={};processFunction;detachFunction;initializeFunction;eventHandlers;_priority=0;_isRegistered=!1;_groups=[];_inScreens;_excludeScreens;_requiredAssets;constructor(H,J=null,K=null){this._label=H;this._ecspresso=J;this._bundle=K}get label(){return this._label}get bundle(){return this._bundle}get ecspresso(){return this._ecspresso}_autoRegister(){if(this._isRegistered||!this._ecspresso)return;let H=this._buildSystemObject();G(H,this._ecspresso),this._isRegistered=!0}_buildSystemObject(){return this._createSystemObject()}_createSystemObject(){let H={label:this._label,entityQueries:this.queries,priority:this._priority};if(this.processFunction)H.process=this.processFunction;if(this.detachFunction)H.onDetach=this.detachFunction;if(this.initializeFunction)H.onInitialize=this.initializeFunction;if(this.eventHandlers)H.eventHandlers=this.eventHandlers;if(this._groups.length>0)H.groups=[...this._groups];if(this._inScreens)H.inScreens=this._inScreens;if(this._excludeScreens)H.excludeScreens=this._excludeScreens;if(this._requiredAssets)H.requiredAssets=this._requiredAssets;return H}setPriority(H){return this._priority=H,this}inGroup(H){if(!this._groups.includes(H))this._groups.push(H);return this}inScreens(H){return this._inScreens=[...H],this}excludeScreens(H){return this._excludeScreens=[...H],this}requiresAssets(H){return this._requiredAssets=[...H],this}addQuery(H,J){let K=this;return K.queries={...this.queries,[H]:J},K}setProcess(H){return this.processFunction=H,this}registerAndContinue(){if(!this._ecspresso)throw Error(`Cannot register system '${this._label}': SystemBuilder is not attached to an ECSpresso instance. Use Bundle.addSystem() or ECSpresso.addSystem() instead.`);return this._autoRegister(),this._ecspresso}and(){if(this._ecspresso)return this._autoRegister(),this._ecspresso;if(this._bundle)return this._bundle;throw Error(`Cannot use and() on system '${this._label}': not attached to ECSpresso or Bundle.`)}setOnDetach(H){return this.detachFunction=H,this}setOnInitialize(H){return this.initializeFunction=H,this}setEventHandlers(H){return this.eventHandlers=H,this}build(H){let J=this._createSystemObject();if(this._ecspresso)G(J,this._ecspresso);if(H)G(J,H);return this}}function G(H,J){J._registerSystem(H)}function c(H,J){return new k(H,J)}function x(H,J){return new k(H,null,J)}function y(){return`bundle_${Date.now().toString(36)}_${Math.random().toString(36).substring(2,9)}`}class E{_systems=[];_resources=new Map;_assets=new Map;_assetGroups=new Map;_screens=new Map;_id;constructor(H){this._id=H||y()}get id(){return this._id}set id(H){this._id=H}addSystem(H){if(typeof H==="string"){let J=x(H,this);return this._systems.push(J),J}else return this._systems.push(H),H}addResource(H,J){return this._resources.set(H,J),this}addAsset(H,J,K){return this._assets.set(H,{loader:J,eager:K?.eager??!0,group:K?.group}),this}addAssetGroup(H,J){let K=new Map;for(let[F,R]of Object.entries(J))K.set(F,R),this._assets.set(F,{loader:R,eager:!1,group:H});return this._assetGroups.set(H,K),this}addScreen(H,J){return this._screens.set(H,J),this}getAssets(){return new Map(this._assets)}getScreens(){return new Map(this._screens)}_setResource(H,J){this._resources.set(H,J)}_setAsset(H,J){this._assets.set(H,J)}_setScreen(H,J){this._screens.set(H,J)}getSystems(){return this._systems.map((H)=>H.build())}registerSystemsWithEcspresso(H){for(let J of this._systems)J.build(H)}getResources(){return new Map(this._resources)}getResource(H){return this._resources.get(H)}getSystemBuilders(){return[...this._systems]}hasResource(H){return this._resources.has(H)}}function n(H,...J){if(J.length===0)return new E(H);let K=new E(H);for(let F of J){for(let R of F.getSystemBuilders())K.addSystem(R);for(let[R,Y]of F.getResources().entries())K._setResource(R,Y);for(let[R,Y]of F.getAssets().entries())K._setAsset(R,Y);for(let[R,Y]of F.getScreens().entries())K._setScreen(R,Y)}return K}async function m(H){let{Application:J}=await import("pixi.js"),K=new J;return await K.init(H),K}var t={x:0,y:0,rotation:0,scaleX:1,scaleY:1},o={x:0,y:0,rotation:0,scaleX:1,scaleY:1};function L(H,J){let K=J?.scale,F=typeof K==="number"?K:K?.x??1,R=typeof K==="number"?K:K?.y??1;return{x:H?.x??0,y:H?.y??0,rotation:J?.rotation??0,scaleX:F,scaleY:R}}function V(H,J){let K=J?.scale,F=typeof K==="number"?K:K?.x??1,R=typeof K==="number"?K:K?.y??1;return{x:H?.x??0,y:H?.y??0,rotation:J?.rotation??0,scaleX:F,scaleY:R}}function B(H){return{visible:H?.visible??!0,alpha:H?.alpha}}function e(H,J,K){return{pixiSprite:{sprite:H,anchor:K?.anchor},localTransform:L(J,K),worldTransform:V(J,K),pixiVisible:B(K)}}function HH(H,J,K){return{pixiGraphics:{graphics:H},localTransform:L(J,K),worldTransform:V(J,K),pixiVisible:B(K)}}function JH(H,J,K){return{pixiContainer:{container:H},localTransform:L(J,K),worldTransform:V(J,K),pixiVisible:B(K)}}function KH(H){let{rootContainer:J,systemGroup:K="pixi-renderer",transformPriority:F=1000,renderSyncPriority:R=500}=H,Y=new E("pixi-renderer");if("init"in H&&H.init!==void 0){let{init:_,container:Q}=H;Y.addResource("pixiApp",async()=>{let U=await m(_);if(Q){let D=typeof Q==="string"?document.querySelector(Q):Q;if(D)D.appendChild(U.canvas);else if(typeof Q==="string")console.warn(`PixiJS bundle: container selector "${Q}" not found`)}return U}),Y.addResource("pixiRootContainer",{dependsOn:["pixiApp"],factory:(U)=>J??U.getResource("pixiApp").stage})}else{let _=H.app;Y.addResource("pixiApp",_),Y.addResource("pixiRootContainer",J??_.stage)}let q=new Map;function W(_,Q){let U=q.get(_);if(U)return U;let D=Q.entityManager.getComponent(_,"pixiSprite");if(D)return q.set(_,D.sprite),D.sprite;let z=Q.entityManager.getComponent(_,"pixiGraphics");if(z)return q.set(_,z.graphics),z.graphics;let $=Q.entityManager.getComponent(_,"pixiContainer");if($)return q.set(_,$.container),$.container;return null}function A(_,Q,U){let D=U.getResource("pixiRootContainer"),z=U.getParent(_),M=(z!==null?W(z,U):null)??D;if(Q.parent!==M)M.addChild(Q)}function N(_){let Q=q.get(_);if(Q)Q.removeFromParent(),q.delete(_)}function g(_,Q){let U=q.get(_);if(!U)return;let D=Q.getResource("pixiRootContainer"),z=Q.getParent(_),M=(z!==null?W(z,Q):null)??D;if(U.parent!==M)U.removeFromParent(),M.addChild(U)}return Y.addSystem("pixi-transform-propagation").setPriority(F).inGroup(K).setProcess((_,Q,U)=>{U.forEachInHierarchy((z,$)=>{let M=U.entityManager.getComponent(z,"localTransform"),Z=U.entityManager.getComponent(z,"worldTransform");if(!M||!Z)return;if($===null)Z.x=M.x,Z.y=M.y,Z.rotation=M.rotation,Z.scaleX=M.scaleX,Z.scaleY=M.scaleY;else{let X=U.entityManager.getComponent($,"worldTransform");if(X){let P=M.x*X.scaleX,v=M.y*X.scaleY,S=Math.cos(X.rotation),C=Math.sin(X.rotation),w=P*S-v*C,h=P*C+v*S;Z.x=X.x+w,Z.y=X.y+h,Z.rotation=X.rotation+M.rotation,Z.scaleX=X.scaleX*M.scaleX,Z.scaleY=X.scaleY*M.scaleY}else Z.x=M.x,Z.y=M.y,Z.rotation=M.rotation,Z.scaleX=M.scaleX,Z.scaleY=M.scaleY}});let D=U.getEntitiesWithQuery(["localTransform","worldTransform"]);for(let z of D)if(U.getParent(z.id)===null&&U.getChildren(z.id).length===0){let{localTransform:M,worldTransform:Z}=z.components;Z.x=M.x,Z.y=M.y,Z.rotation=M.rotation,Z.scaleX=M.scaleX,Z.scaleY=M.scaleY}}).and(),Y.addSystem("pixi-render-sync").setPriority(R).inGroup(K).addQuery("sprites",{with:["pixiSprite","worldTransform"]}).addQuery("graphics",{with:["pixiGraphics","worldTransform"]}).addQuery("containers",{with:["pixiContainer","worldTransform"]}).setProcess((_,Q,U)=>{for(let D of _.sprites){let{pixiSprite:z,worldTransform:$}=D.components,{sprite:M,anchor:Z}=z;if(M.position.set($.x,$.y),M.rotation=$.rotation,M.scale.set($.scaleX,$.scaleY),Z)M.anchor.set(Z.x,Z.y);let X=U.entityManager.getComponent(D.id,"pixiVisible");if(X){if(M.visible=X.visible,X.alpha!==void 0)M.alpha=X.alpha}}for(let D of _.graphics){let{pixiGraphics:z,worldTransform:$}=D.components,{graphics:M}=z;M.position.set($.x,$.y),M.rotation=$.rotation,M.scale.set($.scaleX,$.scaleY);let Z=U.entityManager.getComponent(D.id,"pixiVisible");if(Z){if(M.visible=Z.visible,Z.alpha!==void 0)M.alpha=Z.alpha}}for(let D of _.containers){let{pixiContainer:z,worldTransform:$}=D.components,{container:M}=z;M.position.set($.x,$.y),M.rotation=$.rotation,M.scale.set($.scaleX,$.scaleY);let Z=U.entityManager.getComponent(D.id,"pixiVisible");if(Z){if(M.visible=Z.visible,Z.alpha!==void 0)M.alpha=Z.alpha}}}).and(),Y.addSystem("pixi-scene-graph-manager").setPriority(9999).inGroup(K).setOnInitialize((_)=>{_.addReactiveQuery("pixi-sprites",{with:["pixiSprite"],onEnter:(Q)=>{let U=Q.components.pixiSprite.sprite;q.set(Q.id,U),A(Q.id,U,_)},onExit:(Q)=>{N(Q)}}),_.addReactiveQuery("pixi-graphics",{with:["pixiGraphics"],onEnter:(Q)=>{let U=Q.components.pixiGraphics.graphics;q.set(Q.id,U),A(Q.id,U,_)},onExit:(Q)=>{N(Q)}}),_.addReactiveQuery("pixi-containers",{with:["pixiContainer"],onEnter:(Q)=>{let U=Q.components.pixiContainer.container;q.set(Q.id,U),A(Q.id,U,_)},onExit:(Q)=>{N(Q)}}),_.on("hierarchyChanged",({entityId:Q})=>{g(Q,_)})}).and(),Y}export{e as createSpriteComponents,KH as createPixiBundle,HH as createGraphicsComponents,JH as createContainerComponents,o as DEFAULT_WORLD_TRANSFORM,t as DEFAULT_LOCAL_TRANSFORM};
2
+
3
+ //# debugId=3807489A54FF20AF64756E2164756E21
4
+ //# sourceMappingURL=pixi.js.map