ecspresso 0.11.0 → 0.12.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 +200 -148
- package/dist/asset-manager.d.ts +1 -1
- package/dist/asset-types.d.ts +2 -2
- package/dist/command-buffer.d.ts +34 -24
- package/dist/ecspresso-builder.d.ts +100 -72
- package/dist/ecspresso.d.ts +257 -122
- package/dist/entity-manager.d.ts +57 -47
- package/dist/index.d.ts +5 -4
- package/dist/plugin.d.ts +61 -0
- package/dist/{bundles → plugins}/audio.d.ts +27 -47
- package/dist/{bundles → plugins}/bounds.d.ts +17 -25
- package/dist/{bundles → plugins}/camera.d.ts +8 -9
- package/dist/{bundles → plugins}/collision.d.ts +22 -26
- package/dist/plugins/coroutine.d.ts +126 -0
- package/dist/{bundles → plugins}/diagnostics.d.ts +5 -4
- package/dist/{bundles → plugins}/input.d.ts +9 -15
- package/dist/plugins/particles.d.ts +225 -0
- package/dist/{bundles → plugins}/physics2D.d.ts +27 -23
- package/dist/{bundles → plugins}/renderers/renderer2D.d.ts +40 -39
- package/dist/{bundles → plugins}/spatial-index.d.ts +11 -10
- package/dist/plugins/sprite-animation.d.ts +150 -0
- package/dist/{bundles → plugins}/state-machine.d.ts +50 -104
- package/dist/plugins/timers.d.ts +151 -0
- package/dist/{bundles → plugins}/transform.d.ts +18 -19
- package/dist/{bundles → plugins}/tween.d.ts +36 -71
- package/dist/resource-manager.d.ts +32 -7
- package/dist/screen-manager.d.ts +17 -11
- package/dist/screen-types.d.ts +5 -2
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +17 -17
- package/dist/src/plugins/audio.js +4 -0
- package/dist/src/plugins/audio.js.map +10 -0
- package/dist/src/plugins/bounds.js +4 -0
- package/dist/src/plugins/bounds.js.map +10 -0
- package/dist/src/plugins/camera.js +4 -0
- package/dist/src/plugins/camera.js.map +10 -0
- package/dist/src/plugins/collision.js +4 -0
- package/dist/src/plugins/collision.js.map +11 -0
- package/dist/src/plugins/coroutine.js +4 -0
- package/dist/src/plugins/coroutine.js.map +10 -0
- package/dist/src/plugins/diagnostics.js +5 -0
- package/dist/src/plugins/diagnostics.js.map +10 -0
- package/dist/src/plugins/input.js +4 -0
- package/dist/src/plugins/input.js.map +10 -0
- package/dist/src/plugins/particles.js +4 -0
- package/dist/src/plugins/particles.js.map +10 -0
- package/dist/src/plugins/physics2D.js +4 -0
- package/dist/src/plugins/physics2D.js.map +11 -0
- package/dist/src/plugins/renderers/renderer2D.js +4 -0
- package/dist/src/plugins/renderers/renderer2D.js.map +10 -0
- package/dist/src/plugins/spatial-index.js +4 -0
- package/dist/src/plugins/spatial-index.js.map +11 -0
- package/dist/src/plugins/sprite-animation.js +4 -0
- package/dist/src/plugins/sprite-animation.js.map +10 -0
- package/dist/src/plugins/state-machine.js +4 -0
- package/dist/src/plugins/state-machine.js.map +10 -0
- package/dist/src/plugins/timers.js +4 -0
- package/dist/src/plugins/timers.js.map +10 -0
- package/dist/src/plugins/transform.js +4 -0
- package/dist/src/plugins/transform.js.map +10 -0
- package/dist/src/plugins/tween.js +4 -0
- package/dist/src/plugins/tween.js.map +11 -0
- package/dist/system-builder.d.ts +66 -97
- package/dist/type-utils.d.ts +218 -27
- package/dist/types.d.ts +52 -24
- package/dist/utils/check-required-cycle.d.ts +1 -1
- package/dist/utils/narrowphase.d.ts +7 -7
- package/package.json +53 -45
- package/dist/bundle.d.ts +0 -173
- package/dist/bundles/timers.d.ts +0 -173
- package/dist/src/bundles/audio.js +0 -4
- package/dist/src/bundles/audio.js.map +0 -10
- package/dist/src/bundles/bounds.js +0 -4
- package/dist/src/bundles/bounds.js.map +0 -10
- package/dist/src/bundles/camera.js +0 -4
- package/dist/src/bundles/camera.js.map +0 -10
- package/dist/src/bundles/collision.js +0 -4
- package/dist/src/bundles/collision.js.map +0 -11
- package/dist/src/bundles/diagnostics.js +0 -5
- package/dist/src/bundles/diagnostics.js.map +0 -10
- package/dist/src/bundles/input.js +0 -4
- package/dist/src/bundles/input.js.map +0 -10
- package/dist/src/bundles/physics2D.js +0 -4
- package/dist/src/bundles/physics2D.js.map +0 -11
- package/dist/src/bundles/renderers/renderer2D.js +0 -4
- package/dist/src/bundles/renderers/renderer2D.js.map +0 -10
- package/dist/src/bundles/spatial-index.js +0 -4
- package/dist/src/bundles/spatial-index.js.map +0 -11
- package/dist/src/bundles/state-machine.js +0 -4
- package/dist/src/bundles/state-machine.js.map +0 -10
- package/dist/src/bundles/timers.js +0 -4
- package/dist/src/bundles/timers.js.map +0 -10
- package/dist/src/bundles/transform.js +0 -4
- package/dist/src/bundles/transform.js.map +0 -10
- package/dist/src/bundles/tween.js +0 -4
- package/dist/src/bundles/tween.js.map +0 -11
package/dist/entity-manager.d.ts
CHANGED
|
@@ -47,38 +47,42 @@ export default class EntityManager<ComponentTypes> {
|
|
|
47
47
|
* Called when a component is removed (explicit removal, entity destruction, or replacement).
|
|
48
48
|
* Later registrations replace earlier ones for the same component type.
|
|
49
49
|
* @param componentName The component type to register disposal for
|
|
50
|
-
* @param callback Function receiving the component value being disposed
|
|
50
|
+
* @param callback Function receiving the component value being disposed and the entity ID
|
|
51
51
|
*/
|
|
52
|
-
registerDispose<ComponentName extends keyof ComponentTypes>(componentName: ComponentName, callback: (
|
|
52
|
+
registerDispose<ComponentName extends keyof ComponentTypes>(componentName: ComponentName, callback: (ctx: {
|
|
53
|
+
value: ComponentTypes[ComponentName];
|
|
54
|
+
entityId: number;
|
|
55
|
+
}) => void): void;
|
|
53
56
|
/**
|
|
54
57
|
* Get all registered dispose callbacks.
|
|
55
|
-
* @internal Used by ECSpresso for
|
|
58
|
+
* @internal Used by ECSpresso for plugin installation
|
|
56
59
|
*/
|
|
57
|
-
getDisposeCallbacks(): Map<keyof ComponentTypes, (
|
|
60
|
+
getDisposeCallbacks(): Map<keyof ComponentTypes, (ctx: {
|
|
61
|
+
value: unknown;
|
|
62
|
+
entityId: number;
|
|
63
|
+
}) => void>;
|
|
58
64
|
/**
|
|
59
65
|
* Invoke the dispose callback for a component, if registered.
|
|
60
66
|
* Errors are caught and logged to prevent blocking removal.
|
|
61
67
|
*/
|
|
62
68
|
private invokeDispose;
|
|
63
|
-
|
|
64
|
-
private resolveEntityId;
|
|
65
|
-
addComponent<ComponentName extends keyof ComponentTypes>(entityOrId: number | Entity<ComponentTypes>, componentName: ComponentName, data: ComponentTypes[ComponentName]): this;
|
|
69
|
+
addComponent<ComponentName extends keyof ComponentTypes>(entityId: number, componentName: ComponentName, data: ComponentTypes[ComponentName]): this;
|
|
66
70
|
/**
|
|
67
71
|
* Add multiple components to an entity at once
|
|
68
|
-
* @param
|
|
72
|
+
* @param entityId Entity ID to add components to
|
|
69
73
|
* @param components Object with component names as keys and component data as values
|
|
70
74
|
*/
|
|
71
75
|
addComponents<T extends {
|
|
72
76
|
[K in keyof ComponentTypes]?: ComponentTypes[K];
|
|
73
|
-
}>(
|
|
74
|
-
removeComponent<ComponentName extends keyof ComponentTypes>(
|
|
77
|
+
}>(entityId: number, components: T & Record<Exclude<keyof T, keyof ComponentTypes>, never>): this;
|
|
78
|
+
removeComponent<ComponentName extends keyof ComponentTypes>(entityId: number, componentName: ComponentName): this;
|
|
75
79
|
getComponent<ComponentName extends keyof ComponentTypes>(entityId: number, componentName: ComponentName): ComponentTypes[ComponentName] | undefined;
|
|
76
80
|
getEntitiesWithQuery<WithComponents extends keyof ComponentTypes = never, WithoutComponents extends keyof ComponentTypes = never>(required?: ReadonlyArray<WithComponents>, excluded?: ReadonlyArray<WithoutComponents>, changed?: ReadonlyArray<keyof ComponentTypes>, changeThreshold?: number, parentHas?: ReadonlyArray<keyof ComponentTypes>): Array<FilteredEntity<ComponentTypes, WithComponents extends never ? never : WithComponents, WithoutComponents extends never ? never : WithoutComponents>>;
|
|
77
81
|
/**
|
|
78
82
|
* Check if an entity's direct parent has all specified components
|
|
79
83
|
*/
|
|
80
84
|
private parentHasComponents;
|
|
81
|
-
removeEntity(
|
|
85
|
+
removeEntity(entityId: number, options?: RemoveEntityOptions): boolean;
|
|
82
86
|
/**
|
|
83
87
|
* Internal method to remove a single entity without cascade logic
|
|
84
88
|
*/
|
|
@@ -90,14 +94,20 @@ export default class EntityManager<ComponentTypes> {
|
|
|
90
94
|
* @param handler Function receiving the new component value and the entity
|
|
91
95
|
* @returns Unsubscribe function to remove the callback
|
|
92
96
|
*/
|
|
93
|
-
onComponentAdded<ComponentName extends keyof ComponentTypes>(componentName: ComponentName, handler: (
|
|
97
|
+
onComponentAdded<ComponentName extends keyof ComponentTypes>(componentName: ComponentName, handler: (ctx: {
|
|
98
|
+
value: ComponentTypes[ComponentName];
|
|
99
|
+
entity: Entity<ComponentTypes>;
|
|
100
|
+
}) => void): () => void;
|
|
94
101
|
/**
|
|
95
102
|
* Register a callback when a specific component is removed from any entity
|
|
96
103
|
* @param componentName The component key
|
|
97
104
|
* @param handler Function receiving the old component value and the entity
|
|
98
105
|
* @returns Unsubscribe function to remove the callback
|
|
99
106
|
*/
|
|
100
|
-
onComponentRemoved<ComponentName extends keyof ComponentTypes>(componentName: ComponentName, handler: (
|
|
107
|
+
onComponentRemoved<ComponentName extends keyof ComponentTypes>(componentName: ComponentName, handler: (ctx: {
|
|
108
|
+
value: ComponentTypes[ComponentName];
|
|
109
|
+
entity: Entity<ComponentTypes>;
|
|
110
|
+
}) => void): () => void;
|
|
101
111
|
onAfterComponentAdded(hook: (entityId: number, componentName: keyof ComponentTypes) => void): () => void;
|
|
102
112
|
onAfterEntityMutated(hook: (entityId: number) => void): () => void;
|
|
103
113
|
onAfterComponentRemoved(hook: (entityId: number, componentName: keyof ComponentTypes) => void): () => void;
|
|
@@ -110,10 +120,10 @@ export default class EntityManager<ComponentTypes> {
|
|
|
110
120
|
get changeSeq(): number;
|
|
111
121
|
/**
|
|
112
122
|
* Mark a component as changed on an entity, stamping the next sequence number.
|
|
113
|
-
* @param
|
|
123
|
+
* @param entityId The entity ID
|
|
114
124
|
* @param componentName The component that changed
|
|
115
125
|
*/
|
|
116
|
-
markChanged<K extends keyof ComponentTypes>(
|
|
126
|
+
markChanged<K extends keyof ComponentTypes>(entityId: number, componentName: K): void;
|
|
117
127
|
/**
|
|
118
128
|
* Get the sequence number at which a component was last changed on an entity
|
|
119
129
|
* @param entityId The entity ID
|
|
@@ -123,89 +133,89 @@ export default class EntityManager<ComponentTypes> {
|
|
|
123
133
|
getChangeSeq<K extends keyof ComponentTypes>(entityId: number, componentName: K): number;
|
|
124
134
|
/**
|
|
125
135
|
* Create an entity as a child of another entity with initial components
|
|
126
|
-
* @param
|
|
136
|
+
* @param parentId The parent entity ID
|
|
127
137
|
* @param components Initial components to add
|
|
128
138
|
* @returns The created child entity
|
|
129
139
|
*/
|
|
130
140
|
spawnChild<T extends {
|
|
131
141
|
[K in keyof ComponentTypes]?: ComponentTypes[K];
|
|
132
|
-
}>(
|
|
142
|
+
}>(parentId: number, components: T & Record<Exclude<keyof T, keyof ComponentTypes>, never>): FilteredEntity<ComponentTypes, keyof T & keyof ComponentTypes>;
|
|
133
143
|
/**
|
|
134
144
|
* Set the parent of an entity
|
|
135
|
-
* @param
|
|
136
|
-
* @param
|
|
145
|
+
* @param childId The entity ID to set as a child
|
|
146
|
+
* @param parentId The entity ID to set as the parent
|
|
137
147
|
*/
|
|
138
|
-
setParent(
|
|
148
|
+
setParent(childId: number, parentId: number): this;
|
|
139
149
|
/**
|
|
140
150
|
* Remove the parent relationship for an entity (orphan it)
|
|
141
|
-
* @param
|
|
151
|
+
* @param childId The entity ID to orphan
|
|
142
152
|
* @returns true if a parent was removed, false if entity had no parent
|
|
143
153
|
*/
|
|
144
|
-
removeParent(
|
|
154
|
+
removeParent(childId: number): boolean;
|
|
145
155
|
/**
|
|
146
156
|
* Get the parent of an entity
|
|
147
|
-
* @param
|
|
157
|
+
* @param entityId The entity ID to get the parent of
|
|
148
158
|
* @returns The parent entity ID, or null if no parent
|
|
149
159
|
*/
|
|
150
|
-
getParent(
|
|
160
|
+
getParent(entityId: number): number | null;
|
|
151
161
|
/**
|
|
152
162
|
* Get all children of an entity in insertion order
|
|
153
|
-
* @param
|
|
163
|
+
* @param parentId The parent entity ID
|
|
154
164
|
* @returns Readonly array of child entity IDs
|
|
155
165
|
*/
|
|
156
|
-
getChildren(
|
|
166
|
+
getChildren(parentId: number): readonly number[];
|
|
157
167
|
/**
|
|
158
168
|
* Get a child at a specific index
|
|
159
|
-
* @param
|
|
169
|
+
* @param parentId The parent entity ID
|
|
160
170
|
* @param index The index of the child
|
|
161
171
|
* @returns The child entity ID, or null if index is out of bounds
|
|
162
172
|
*/
|
|
163
|
-
getChildAt(
|
|
173
|
+
getChildAt(parentId: number, index: number): number | null;
|
|
164
174
|
/**
|
|
165
175
|
* Get the index of a child within its parent's children list
|
|
166
|
-
* @param
|
|
167
|
-
* @param
|
|
176
|
+
* @param parentId The parent entity ID
|
|
177
|
+
* @param childId The child entity ID to find
|
|
168
178
|
* @returns The index of the child, or -1 if not found
|
|
169
179
|
*/
|
|
170
|
-
getChildIndex(
|
|
180
|
+
getChildIndex(parentId: number, childId: number): number;
|
|
171
181
|
/**
|
|
172
182
|
* Get all ancestors of an entity in order [parent, grandparent, ...]
|
|
173
|
-
* @param
|
|
183
|
+
* @param entityId The entity ID to get ancestors of
|
|
174
184
|
* @returns Readonly array of ancestor entity IDs
|
|
175
185
|
*/
|
|
176
|
-
getAncestors(
|
|
186
|
+
getAncestors(entityId: number): readonly number[];
|
|
177
187
|
/**
|
|
178
188
|
* Get all descendants of an entity in depth-first order
|
|
179
|
-
* @param
|
|
189
|
+
* @param entityId The entity ID to get descendants of
|
|
180
190
|
* @returns Readonly array of descendant entity IDs
|
|
181
191
|
*/
|
|
182
|
-
getDescendants(
|
|
192
|
+
getDescendants(entityId: number): readonly number[];
|
|
183
193
|
/**
|
|
184
194
|
* Get the root ancestor of an entity (topmost parent), or self if no parent
|
|
185
|
-
* @param
|
|
195
|
+
* @param entityId The entity ID to get the root of
|
|
186
196
|
* @returns The root entity ID
|
|
187
197
|
*/
|
|
188
|
-
getRoot(
|
|
198
|
+
getRoot(entityId: number): number;
|
|
189
199
|
/**
|
|
190
200
|
* Get siblings of an entity (other children of the same parent)
|
|
191
|
-
* @param
|
|
201
|
+
* @param entityId The entity ID to get siblings of
|
|
192
202
|
* @returns Readonly array of sibling entity IDs
|
|
193
203
|
*/
|
|
194
|
-
getSiblings(
|
|
204
|
+
getSiblings(entityId: number): readonly number[];
|
|
195
205
|
/**
|
|
196
206
|
* Check if an entity is a descendant of another entity
|
|
197
|
-
* @param
|
|
198
|
-
* @param
|
|
199
|
-
* @returns true if
|
|
207
|
+
* @param entityId The potential descendant ID
|
|
208
|
+
* @param ancestorId The potential ancestor ID
|
|
209
|
+
* @returns true if entityId is a descendant of ancestorId
|
|
200
210
|
*/
|
|
201
|
-
isDescendantOf(
|
|
211
|
+
isDescendantOf(entityId: number, ancestorId: number): boolean;
|
|
202
212
|
/**
|
|
203
213
|
* Check if an entity is an ancestor of another entity
|
|
204
|
-
* @param
|
|
205
|
-
* @param
|
|
206
|
-
* @returns true if
|
|
214
|
+
* @param entityId The potential ancestor ID
|
|
215
|
+
* @param descendantId The potential descendant ID
|
|
216
|
+
* @returns true if entityId is an ancestor of descendantId
|
|
207
217
|
*/
|
|
208
|
-
isAncestorOf(
|
|
218
|
+
isAncestorOf(entityId: number, descendantId: number): boolean;
|
|
209
219
|
/**
|
|
210
220
|
* Get all root entities (entities that have children but no parent)
|
|
211
221
|
* @returns Readonly array of root entity IDs
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ECSpresso from './ecspresso';
|
|
2
|
-
import { SystemBuilder } from './system-builder';
|
|
3
|
-
import
|
|
2
|
+
import { SystemBuilder, type ProcessContext } from './system-builder';
|
|
3
|
+
import { type Plugin, type BasePluginOptions, definePlugin } from './plugin';
|
|
4
4
|
export * from './types';
|
|
5
5
|
export * from './asset-types';
|
|
6
6
|
export * from './screen-types';
|
|
@@ -8,6 +8,7 @@ export * from './utils/math';
|
|
|
8
8
|
export type { ReactiveQueryDefinition } from './reactive-query-manager';
|
|
9
9
|
export { default as AssetManager, createAssetConfigurator } from './asset-manager';
|
|
10
10
|
export { default as ScreenManager, createScreenConfigurator } from './screen-manager';
|
|
11
|
-
export { SystemBuilder };
|
|
12
|
-
export {
|
|
11
|
+
export { SystemBuilder, type ProcessContext };
|
|
12
|
+
export { type Plugin, type BasePluginOptions, definePlugin };
|
|
13
|
+
export { directValue, type ResourceDirectValue } from './resource-manager';
|
|
13
14
|
export default ECSpresso;
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type ECSpresso from './ecspresso';
|
|
2
|
+
import type { SystemPhase } from './types';
|
|
3
|
+
import type { WorldConfig, EmptyConfig, MergeConfigs, AnyECSpresso, ConfigOf } from './type-utils';
|
|
4
|
+
/**
|
|
5
|
+
* Plugin interface for ECSpresso. A plugin is a plain object with an `install`
|
|
6
|
+
* function that configures a world directly, plus phantom properties for
|
|
7
|
+
* compile-time type extraction.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam Cfg - The WorldConfig this plugin provides (components, events, resources, etc.)
|
|
10
|
+
* @typeParam Requires - The WorldConfig this plugin requires from other plugins
|
|
11
|
+
*/
|
|
12
|
+
export interface Plugin<Cfg extends WorldConfig = EmptyConfig, Requires extends WorldConfig = EmptyConfig, Labels extends string = never, Groups extends string = never, AssetGroupNames extends string = never, ReactiveQueryNames extends string = never> {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly install: (world: ECSpresso<MergeConfigs<Cfg, Requires>>) => void;
|
|
15
|
+
readonly _cfg?: Cfg;
|
|
16
|
+
readonly _requires?: Requires;
|
|
17
|
+
readonly _labels?: Labels;
|
|
18
|
+
readonly _groups?: Groups;
|
|
19
|
+
readonly _assetGroupNames?: AssetGroupNames;
|
|
20
|
+
readonly _reactiveQueryNames?: ReactiveQueryNames;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Common configuration options shared by most plugins.
|
|
24
|
+
* Plugin-specific options interfaces extend this with additional fields.
|
|
25
|
+
*/
|
|
26
|
+
export interface BasePluginOptions<G extends string = string> {
|
|
27
|
+
/** System group name for all systems registered by this plugin */
|
|
28
|
+
systemGroup?: G;
|
|
29
|
+
/** Priority for the plugin's primary system (default varies per plugin) */
|
|
30
|
+
priority?: number;
|
|
31
|
+
/** Execution phase for the plugin's primary system */
|
|
32
|
+
phase?: SystemPhase;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Factory function to create a type-safe Plugin with phantom type parameters.
|
|
36
|
+
* The type assertion adds phantom types without runtime cost.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* // Option 1: Explicit config type param
|
|
41
|
+
* const myPlugin = definePlugin<WorldConfigFrom<MyComponents, MyEvents, MyResources>>({
|
|
42
|
+
* id: 'my-plugin',
|
|
43
|
+
* install(world) { ... },
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* // Option 2: Single world type param (extracts config automatically)
|
|
47
|
+
* type MyWorld = typeof ecs;
|
|
48
|
+
* const myPlugin = definePlugin<MyWorld>({
|
|
49
|
+
* id: 'my-plugin',
|
|
50
|
+
* install(world) { ... },
|
|
51
|
+
* });
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare function definePlugin<W extends AnyECSpresso, Requires extends WorldConfig = EmptyConfig, Labels extends string = never, Groups extends string = never, AssetGroupNames extends string = never, ReactiveQueryNames extends string = never>(config: {
|
|
55
|
+
id: string;
|
|
56
|
+
install: (world: W) => void;
|
|
57
|
+
}): Plugin<ConfigOf<W>, Requires, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
|
|
58
|
+
export declare function definePlugin<Cfg extends WorldConfig = EmptyConfig, Requires extends WorldConfig = EmptyConfig, Labels extends string = never, Groups extends string = never, AssetGroupNames extends string = never, ReactiveQueryNames extends string = never>(config: {
|
|
59
|
+
id: string;
|
|
60
|
+
install: (world: ECSpresso<MergeConfigs<Cfg, Requires>>) => void;
|
|
61
|
+
}): Plugin<Cfg, Requires, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Audio
|
|
2
|
+
* Audio Plugin for ECSpresso
|
|
3
3
|
*
|
|
4
4
|
* Web Audio API integration via Howler.js for sound effects and music playback.
|
|
5
5
|
* User-defined channels with type-safe volume control, hybrid resource + component API,
|
|
6
6
|
* and asset manager integration.
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
9
|
-
import type {
|
|
8
|
+
import { type Plugin, type BasePluginOptions } from 'ecspresso';
|
|
9
|
+
import type { AssetsOfWorld, AnyECSpresso, ChannelOfWorld } from 'ecspresso';
|
|
10
|
+
import type { WorldConfigFrom, EmptyConfig } from '../type-utils';
|
|
10
11
|
import type { Howl } from 'howler';
|
|
11
12
|
/**
|
|
12
13
|
* Configuration for a single audio channel.
|
|
@@ -56,7 +57,7 @@ export interface AudioSource<Ch extends string = string> {
|
|
|
56
57
|
_soundId: number;
|
|
57
58
|
}
|
|
58
59
|
/**
|
|
59
|
-
* Component types provided by the audio
|
|
60
|
+
* Component types provided by the audio plugin.
|
|
60
61
|
*/
|
|
61
62
|
export interface AudioComponentTypes<Ch extends string = string> {
|
|
62
63
|
audioSource: AudioSource<Ch>;
|
|
@@ -93,7 +94,7 @@ export interface SoundEndedEvent {
|
|
|
93
94
|
sound: string;
|
|
94
95
|
}
|
|
95
96
|
/**
|
|
96
|
-
* Event types provided by the audio
|
|
97
|
+
* Event types provided by the audio plugin.
|
|
97
98
|
*/
|
|
98
99
|
export interface AudioEventTypes<Ch extends string = string> {
|
|
99
100
|
playSound: PlaySoundEvent<Ch>;
|
|
@@ -157,23 +158,17 @@ export interface AudioState<Ch extends string = string> {
|
|
|
157
158
|
isMuted(): boolean;
|
|
158
159
|
}
|
|
159
160
|
/**
|
|
160
|
-
* Resource types provided by the audio
|
|
161
|
+
* Resource types provided by the audio plugin.
|
|
161
162
|
*/
|
|
162
163
|
export interface AudioResourceTypes<Ch extends string = string> {
|
|
163
164
|
audioState: AudioState<Ch>;
|
|
164
165
|
}
|
|
165
166
|
/**
|
|
166
|
-
* Configuration options for the audio
|
|
167
|
+
* Configuration options for the audio plugin.
|
|
167
168
|
*/
|
|
168
|
-
export interface
|
|
169
|
+
export interface AudioPluginOptions<Ch extends string, G extends string = 'audio'> extends BasePluginOptions<G> {
|
|
169
170
|
/** Channel definitions from defineAudioChannels */
|
|
170
171
|
channels: Readonly<Record<Ch, AudioChannelConfig>>;
|
|
171
|
-
/** System group name (default: 'audio') */
|
|
172
|
-
systemGroup?: G;
|
|
173
|
-
/** Priority for audio sync system (default: 0) */
|
|
174
|
-
priority?: number;
|
|
175
|
-
/** Execution phase (default: 'update') */
|
|
176
|
-
phase?: SystemPhase;
|
|
177
172
|
}
|
|
178
173
|
/**
|
|
179
174
|
* Create an audioSource component for entity-attached audio.
|
|
@@ -219,7 +214,7 @@ export declare function loadSound(src: string | string[], options?: {
|
|
|
219
214
|
preload?: boolean;
|
|
220
215
|
}): () => Promise<Howl>;
|
|
221
216
|
/**
|
|
222
|
-
* Create an audio
|
|
217
|
+
* Create an audio plugin for ECSpresso.
|
|
223
218
|
*
|
|
224
219
|
* Provides:
|
|
225
220
|
* - `audioState` resource for fire-and-forget SFX and music
|
|
@@ -240,7 +235,7 @@ export declare function loadSound(src: string | string[], options?: {
|
|
|
240
235
|
*
|
|
241
236
|
* const ecs = ECSpresso.create()
|
|
242
237
|
* .withAssets(a => a.add('explosion', loadSound('/sfx/boom.mp3')))
|
|
243
|
-
* .
|
|
238
|
+
* .withPlugin(createAudioPlugin({ channels }))
|
|
244
239
|
* .build();
|
|
245
240
|
*
|
|
246
241
|
* await ecs.initialize();
|
|
@@ -248,46 +243,31 @@ export declare function loadSound(src: string | string[], options?: {
|
|
|
248
243
|
* audio.play('explosion', { channel: 'sfx' });
|
|
249
244
|
* ```
|
|
250
245
|
*/
|
|
251
|
-
export declare function
|
|
252
|
-
type AnyECSpresso = import('ecspresso').default<any, any, any, any, any, any, any>;
|
|
246
|
+
export declare function createAudioPlugin<Ch extends string, G extends string = 'audio'>(options: AudioPluginOptions<Ch, G>): Plugin<WorldConfigFrom<AudioComponentTypes<Ch>, AudioEventTypes<Ch>, AudioResourceTypes<Ch>>, EmptyConfig, 'audio-sync', G, never, 'audio-sources'>;
|
|
253
247
|
/**
|
|
254
|
-
*
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
bundle: Bundle<AudioComponentTypes<Ch>, AudioEventTypes<Ch>, AudioResourceTypes<Ch>, {}, {}, 'audio-sync', G, never, 'audio-sources'>;
|
|
258
|
-
createAudioSource: (sound: keyof AssetsOfWorld<W> & string, channel: Ch, options?: {
|
|
259
|
-
volume?: number;
|
|
260
|
-
loop?: boolean;
|
|
261
|
-
autoRemove?: boolean;
|
|
262
|
-
}) => Pick<AudioComponentTypes<Ch>, 'audioSource'>;
|
|
263
|
-
loadSound: typeof loadSound;
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Create a typed audio kit that captures the world type W and channel type Ch.
|
|
267
|
-
*
|
|
268
|
-
* The returned `createAudioSource` validates sound keys against the world's
|
|
269
|
-
* asset types at compile time.
|
|
248
|
+
* Typed helpers for the audio plugin.
|
|
249
|
+
* Creates helpers that validate sound keys and channel names against the world type W.
|
|
250
|
+
* Call after .build() using typeof ecs.
|
|
270
251
|
*
|
|
271
252
|
* @template W - Concrete ECS world type (e.g. `typeof ecs`)
|
|
272
|
-
* @template Ch - Channel name union from defineAudioChannels
|
|
273
|
-
* @template G - System group name (default: 'audio')
|
|
274
|
-
* @param options - Bundle configuration including channel definitions
|
|
275
|
-
* @returns A kit object with bundle, createAudioSource, loadSound
|
|
276
253
|
*
|
|
277
254
|
* @example
|
|
278
255
|
* ```typescript
|
|
279
|
-
* const channels = defineAudioChannels({ sfx: { volume: 1 }, music: { volume: 0.7 } });
|
|
280
|
-
* type Ch = ChannelsOf<typeof channels>;
|
|
281
|
-
* const kit = createAudioKit<typeof ecs, Ch>({ channels });
|
|
282
|
-
*
|
|
283
256
|
* const ecs = ECSpresso.create()
|
|
284
|
-
* .
|
|
257
|
+
* .withPlugin(createAudioPlugin({ channels }))
|
|
285
258
|
* .withAssets(a => a.add('boom', loadSound('/sfx/boom.mp3')))
|
|
286
259
|
* .build();
|
|
287
260
|
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
261
|
+
* const { createAudioSource } = createAudioHelpers<typeof ecs>();
|
|
262
|
+
* // Type-safe: 'boom' must be a registered asset, 'sfx' a valid channel
|
|
263
|
+
* createAudioSource('boom', 'sfx');
|
|
290
264
|
* ```
|
|
291
265
|
*/
|
|
292
|
-
export
|
|
293
|
-
|
|
266
|
+
export interface AudioHelpers<W extends AnyECSpresso> {
|
|
267
|
+
createAudioSource: (sound: keyof AssetsOfWorld<W> & string, channel: ChannelOfWorld<W>, options?: {
|
|
268
|
+
volume?: number;
|
|
269
|
+
loop?: boolean;
|
|
270
|
+
autoRemove?: boolean;
|
|
271
|
+
}) => Pick<AudioComponentTypes<ChannelOfWorld<W>>, 'audioSource'>;
|
|
272
|
+
}
|
|
273
|
+
export declare function createAudioHelpers<W extends AnyECSpresso>(_world?: W): AudioHelpers<W>;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Bounds
|
|
2
|
+
* Bounds Plugin for ECSpresso
|
|
3
3
|
*
|
|
4
4
|
* Provides screen bounds enforcement for entities with transforms.
|
|
5
5
|
* Reads worldTransform for position checking; modifies localTransform for corrections.
|
|
6
6
|
* Supports destroy, clamp, and wrap behaviors.
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
9
|
-
import type {
|
|
10
|
-
import type {
|
|
8
|
+
import { type Plugin, type BasePluginOptions } from 'ecspresso';
|
|
9
|
+
import type { WorldConfigFrom } from '../type-utils';
|
|
10
|
+
import type { TransformWorldConfig } from './transform';
|
|
11
11
|
/**
|
|
12
12
|
* Component that marks an entity for destruction when outside bounds.
|
|
13
13
|
*/
|
|
@@ -30,14 +30,14 @@ export interface WrapAtBounds {
|
|
|
30
30
|
padding?: number;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
* Component types provided by the bounds
|
|
34
|
-
* Included automatically via `.
|
|
33
|
+
* Component types provided by the bounds plugin.
|
|
34
|
+
* Included automatically via `.withPlugin(createBoundsPlugin())`.
|
|
35
35
|
*
|
|
36
36
|
* @example
|
|
37
37
|
* ```typescript
|
|
38
38
|
* const ecs = ECSpresso.create()
|
|
39
|
-
* .
|
|
40
|
-
* .
|
|
39
|
+
* .withPlugin(createTransformPlugin())
|
|
40
|
+
* .withPlugin(createBoundsPlugin({ width: 800, height: 600 }))
|
|
41
41
|
* .withComponentTypes<{ sprite: Sprite }>()
|
|
42
42
|
* .build();
|
|
43
43
|
* ```
|
|
@@ -61,7 +61,7 @@ export interface BoundsRect {
|
|
|
61
61
|
height: number;
|
|
62
62
|
}
|
|
63
63
|
/**
|
|
64
|
-
* Resource types provided by the bounds
|
|
64
|
+
* Resource types provided by the bounds plugin.
|
|
65
65
|
*/
|
|
66
66
|
export interface BoundsResourceTypes {
|
|
67
67
|
bounds: BoundsRect;
|
|
@@ -76,25 +76,19 @@ export interface EntityOutOfBoundsEvent {
|
|
|
76
76
|
exitEdge: 'top' | 'bottom' | 'left' | 'right';
|
|
77
77
|
}
|
|
78
78
|
/**
|
|
79
|
-
* Event types provided by the bounds
|
|
79
|
+
* Event types provided by the bounds plugin.
|
|
80
80
|
*/
|
|
81
81
|
export interface BoundsEventTypes {
|
|
82
82
|
entityOutOfBounds: EntityOutOfBoundsEvent;
|
|
83
83
|
}
|
|
84
84
|
/**
|
|
85
|
-
* Configuration options for the bounds
|
|
85
|
+
* Configuration options for the bounds plugin.
|
|
86
86
|
*/
|
|
87
|
-
export interface
|
|
88
|
-
/** System group name (default: 'physics') */
|
|
89
|
-
systemGroup?: G;
|
|
90
|
-
/** Priority for bounds systems (default: 50) */
|
|
91
|
-
priority?: number;
|
|
87
|
+
export interface BoundsPluginOptions<G extends string = 'physics'> extends BasePluginOptions<G> {
|
|
92
88
|
/** Resource key for bounds rectangle (default: 'bounds') */
|
|
93
89
|
boundsResourceKey?: string;
|
|
94
90
|
/** Whether to auto-remove entities when out of bounds (default: true) */
|
|
95
91
|
autoRemove?: boolean;
|
|
96
|
-
/** Execution phase (default: 'postUpdate') */
|
|
97
|
-
phase?: SystemPhase;
|
|
98
92
|
}
|
|
99
93
|
/**
|
|
100
94
|
* Create a bounds rectangle resource.
|
|
@@ -158,11 +152,10 @@ export declare function createClampToBounds(margin?: number): Pick<BoundsCompone
|
|
|
158
152
|
* ```
|
|
159
153
|
*/
|
|
160
154
|
export declare function createWrapAtBounds(padding?: number): Pick<BoundsComponentTypes, 'wrapAtBounds'>;
|
|
161
|
-
type CombinedComponentTypes = BoundsComponentTypes & TransformComponentTypes;
|
|
162
155
|
/**
|
|
163
|
-
* Create a bounds
|
|
156
|
+
* Create a bounds plugin for ECSpresso.
|
|
164
157
|
*
|
|
165
|
-
* This
|
|
158
|
+
* This plugin provides:
|
|
166
159
|
* - Destroy out of bounds system - removes entities that exit bounds
|
|
167
160
|
* - Clamp to bounds system - constrains entities within bounds
|
|
168
161
|
* - Wrap at bounds system - wraps entities to opposite edge
|
|
@@ -176,8 +169,8 @@ type CombinedComponentTypes = BoundsComponentTypes & TransformComponentTypes;
|
|
|
176
169
|
* const ecs = ECSpresso
|
|
177
170
|
* .create<Components, Events, Resources>()
|
|
178
171
|
* .withResource('bounds', createBounds(800, 600))
|
|
179
|
-
* .
|
|
180
|
-
* .
|
|
172
|
+
* .withPlugin(createTransformPlugin())
|
|
173
|
+
* .withPlugin(createBoundsPlugin())
|
|
181
174
|
* .build();
|
|
182
175
|
*
|
|
183
176
|
* // Entity that gets destroyed when leaving screen
|
|
@@ -187,5 +180,4 @@ type CombinedComponentTypes = BoundsComponentTypes & TransformComponentTypes;
|
|
|
187
180
|
* });
|
|
188
181
|
* ```
|
|
189
182
|
*/
|
|
190
|
-
export declare function
|
|
191
|
-
export {};
|
|
183
|
+
export declare function createBoundsPlugin<ResourceTypes extends BoundsResourceTypes = BoundsResourceTypes, G extends string = 'physics'>(options?: BoundsPluginOptions<G>): Plugin<WorldConfigFrom<BoundsComponentTypes, BoundsEventTypes, ResourceTypes>, TransformWorldConfig, 'bounds-destroy' | 'bounds-clamp' | 'bounds-wrap', G>;
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Camera / Viewport
|
|
2
|
+
* Camera / Viewport Plugin for ECSpresso
|
|
3
3
|
*
|
|
4
4
|
* Provides a camera entity with world/screen coordinate conversion, smooth follow,
|
|
5
5
|
* trauma-based shake, bounds clamping, and logical viewport dimensions.
|
|
6
6
|
*
|
|
7
|
-
* This
|
|
7
|
+
* This plugin is renderer-agnostic. PixiJS or other renderer integration (applying
|
|
8
8
|
* cameraState to a container/stage transform) is the consumer's responsibility.
|
|
9
9
|
*
|
|
10
10
|
* Camera uses its own x/y/zoom/rotation rather than localTransform/worldTransform.
|
|
11
11
|
* It reads the target entity's worldTransform for follow, but doesn't participate
|
|
12
12
|
* in the transform hierarchy itself.
|
|
13
13
|
*/
|
|
14
|
-
import {
|
|
14
|
+
import { type Plugin } from 'ecspresso';
|
|
15
15
|
import type { SystemPhase } from 'ecspresso';
|
|
16
16
|
import type ECSpresso from 'ecspresso';
|
|
17
|
-
import type {
|
|
17
|
+
import type { WorldConfigFrom } from '../type-utils';
|
|
18
|
+
import type { TransformWorldConfig } from './transform';
|
|
18
19
|
export interface Camera {
|
|
19
20
|
x: number;
|
|
20
21
|
y: number;
|
|
@@ -48,7 +49,6 @@ export interface CameraComponentTypes {
|
|
|
48
49
|
cameraShake: CameraShake;
|
|
49
50
|
cameraBounds: CameraBounds;
|
|
50
51
|
}
|
|
51
|
-
type CombinedComponentTypes = CameraComponentTypes & TransformComponentTypes;
|
|
52
52
|
export interface CameraState {
|
|
53
53
|
x: number;
|
|
54
54
|
y: number;
|
|
@@ -63,7 +63,7 @@ export interface CameraState {
|
|
|
63
63
|
export interface CameraResourceTypes {
|
|
64
64
|
cameraState: CameraState;
|
|
65
65
|
}
|
|
66
|
-
export interface
|
|
66
|
+
export interface CameraPluginOptions<G extends string = 'camera'> {
|
|
67
67
|
viewportWidth?: number;
|
|
68
68
|
viewportHeight?: number;
|
|
69
69
|
systemGroup?: G;
|
|
@@ -76,7 +76,7 @@ export declare function createCamera(x?: number, y?: number, zoom?: number, rota
|
|
|
76
76
|
export declare function createCameraFollow(target: number, options?: Partial<Omit<CameraFollow, 'target'>>): Pick<CameraComponentTypes, 'cameraFollow'>;
|
|
77
77
|
export declare function createCameraShake(options?: Partial<CameraShake>): Pick<CameraComponentTypes, 'cameraShake'>;
|
|
78
78
|
export declare function createCameraBounds(minX: number, minY: number, maxX: number, maxY: number): Pick<CameraComponentTypes, 'cameraBounds'>;
|
|
79
|
-
export declare function addTrauma<
|
|
79
|
+
export declare function addTrauma<Cfg extends WorldConfigFrom<CameraComponentTypes, {}, CameraResourceTypes>>(ecs: ECSpresso<Cfg>, entityId: number, amount: number): void;
|
|
80
80
|
export declare function worldToScreen(worldX: number, worldY: number, state: CameraState): {
|
|
81
81
|
x: number;
|
|
82
82
|
y: number;
|
|
@@ -85,5 +85,4 @@ export declare function screenToWorld(screenX: number, screenY: number, state: C
|
|
|
85
85
|
x: number;
|
|
86
86
|
y: number;
|
|
87
87
|
};
|
|
88
|
-
export declare function
|
|
89
|
-
export {};
|
|
88
|
+
export declare function createCameraPlugin<G extends string = 'camera'>(options?: CameraPluginOptions<G>): Plugin<WorldConfigFrom<CameraComponentTypes, {}, CameraResourceTypes>, TransformWorldConfig, 'camera-follow' | 'camera-shake-update' | 'camera-bounds' | 'camera-state-sync', G>;
|