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.
- package/README.md +571 -9
- package/dist/asset-manager.d.ts +111 -0
- package/dist/asset-types.d.ts +104 -0
- package/dist/bundle.d.ts +65 -6
- package/dist/bundles/renderers/pixi.d.ts +248 -0
- package/dist/bundles/renderers/pixi.js +4 -0
- package/dist/bundles/renderers/pixi.js.map +12 -0
- package/dist/bundles/utils/timers.d.ts +113 -0
- package/dist/bundles/utils/timers.js +4 -0
- package/dist/bundles/utils/timers.js.map +12 -0
- package/dist/ecspresso.d.ts +402 -15
- package/dist/entity-manager.d.ts +118 -4
- package/dist/event-bus.d.ts +5 -0
- package/dist/hierarchy-manager.d.ts +122 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +15 -11
- package/dist/reactive-query-manager.d.ts +59 -0
- package/dist/resource-manager.d.ts +37 -5
- package/dist/screen-manager.d.ts +116 -0
- package/dist/screen-types.d.ts +119 -0
- package/dist/system-builder.d.ts +37 -2
- package/dist/types.d.ts +62 -5
- package/package.json +23 -3
|
@@ -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
|
|
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]>)
|
|
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
|
|
82
|
-
export declare function mergeBundles<ComponentTypes extends Record<string, any>, EventTypes extends Record<string, any>, ResourceTypes extends Record<string, any
|
|
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
|