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
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 2D Renderer
|
|
2
|
+
* 2D Renderer Plugin for ECSpresso
|
|
3
3
|
*
|
|
4
|
-
* An opt-in PixiJS-based 2D rendering
|
|
5
|
-
* Import from 'ecspresso/
|
|
4
|
+
* An opt-in PixiJS-based 2D rendering plugin that automates scene graph wiring.
|
|
5
|
+
* Import from 'ecspresso/plugins/renderers/renderer2D'
|
|
6
6
|
*
|
|
7
|
-
* This
|
|
7
|
+
* This plugin includes transform propagation automatically.
|
|
8
8
|
*/
|
|
9
9
|
import type { Application, ApplicationOptions, Container, Sprite, Graphics } from 'pixi.js';
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
-
import { type
|
|
13
|
-
import type
|
|
10
|
+
import { type Plugin } from 'ecspresso';
|
|
11
|
+
import type { WorldConfigFrom, EmptyConfig } from '../../type-utils';
|
|
12
|
+
import { type LocalTransform, type WorldTransform, type TransformComponentTypes, type TransformPluginOptions } from 'ecspresso/plugins/transform';
|
|
13
|
+
import { type BoundsRect } from 'ecspresso/plugins/bounds';
|
|
14
|
+
import type { CameraResourceTypes } from 'ecspresso/plugins/camera';
|
|
14
15
|
export type { LocalTransform, WorldTransform, TransformComponentTypes };
|
|
15
16
|
export type { BoundsRect };
|
|
16
|
-
export { createTransform, createLocalTransform, createWorldTransform, DEFAULT_LOCAL_TRANSFORM, DEFAULT_WORLD_TRANSFORM } from 'ecspresso/
|
|
17
|
+
export { createTransform, createLocalTransform, createWorldTransform, DEFAULT_LOCAL_TRANSFORM, DEFAULT_WORLD_TRANSFORM } from 'ecspresso/plugins/transform';
|
|
17
18
|
/**
|
|
18
19
|
* Visibility and alpha component
|
|
19
20
|
*/
|
|
@@ -22,13 +23,13 @@ export interface Visible {
|
|
|
22
23
|
alpha?: number;
|
|
23
24
|
}
|
|
24
25
|
/**
|
|
25
|
-
* Aggregate component types for the 2D renderer
|
|
26
|
-
* Included automatically via `.
|
|
26
|
+
* Aggregate component types for the 2D renderer plugin.
|
|
27
|
+
* Included automatically via `.withPlugin(createRenderer2DPlugin({ ... }))`.
|
|
27
28
|
*
|
|
28
29
|
* @example
|
|
29
30
|
* ```typescript
|
|
30
31
|
* const ecs = ECSpresso.create()
|
|
31
|
-
* .
|
|
32
|
+
* .withPlugin(createRenderer2DPlugin({ ... }))
|
|
32
33
|
* .withComponentTypes<{ velocity: { x: number; y: number }; player: true }>()
|
|
33
34
|
* .build();
|
|
34
35
|
* ```
|
|
@@ -42,7 +43,7 @@ export interface Renderer2DComponentTypes extends TransformComponentTypes {
|
|
|
42
43
|
renderLayer: string;
|
|
43
44
|
}
|
|
44
45
|
/**
|
|
45
|
-
* Events emitted by the 2D renderer
|
|
46
|
+
* Events emitted by the 2D renderer plugin
|
|
46
47
|
*/
|
|
47
48
|
export interface Renderer2DEventTypes {
|
|
48
49
|
hierarchyChanged: {
|
|
@@ -52,7 +53,7 @@ export interface Renderer2DEventTypes {
|
|
|
52
53
|
};
|
|
53
54
|
}
|
|
54
55
|
/**
|
|
55
|
-
* Resources provided by the 2D renderer
|
|
56
|
+
* Resources provided by the 2D renderer plugin
|
|
56
57
|
*/
|
|
57
58
|
export interface Renderer2DResourceTypes {
|
|
58
59
|
pixiApp: Application;
|
|
@@ -82,21 +83,21 @@ export interface ViewportScaleResourceTypes {
|
|
|
82
83
|
/**
|
|
83
84
|
* Common options shared between both initialization modes
|
|
84
85
|
*/
|
|
85
|
-
interface
|
|
86
|
+
interface Renderer2DPluginCommonOptions<G extends string = 'renderer2d'> {
|
|
86
87
|
/** Optional custom root container (defaults to app.stage) */
|
|
87
88
|
rootContainer?: Container;
|
|
88
89
|
/** System group name (default: 'renderer2d') */
|
|
89
90
|
systemGroup?: G;
|
|
90
91
|
/** Priority for render sync system (default: 500) */
|
|
91
92
|
renderSyncPriority?: number;
|
|
92
|
-
/** Options for the included transform
|
|
93
|
-
transform?:
|
|
93
|
+
/** Options for the included transform plugin */
|
|
94
|
+
transform?: TransformPluginOptions;
|
|
94
95
|
/** When true, wires up pixiApp.ticker to drive ecs.update() automatically (default: true) */
|
|
95
96
|
startLoop?: boolean;
|
|
96
97
|
/** Ordered render layer names (back-to-front). Entities with a renderLayer component are placed in the corresponding container. */
|
|
97
98
|
renderLayers?: string[];
|
|
98
99
|
/** Automatically apply cameraState resource to rootContainer each frame.
|
|
99
|
-
* Requires the camera
|
|
100
|
+
* Requires the camera plugin to be installed. (default: false) */
|
|
100
101
|
camera?: boolean;
|
|
101
102
|
/** Enforce a logical design resolution with automatic aspect-ratio-aware scaling.
|
|
102
103
|
* When set, systems work in design-resolution coordinate space. */
|
|
@@ -105,37 +106,37 @@ interface Renderer2DBundleCommonOptions<G extends string = 'renderer2d'> {
|
|
|
105
106
|
/**
|
|
106
107
|
* Options when providing a pre-initialized PixiJS Application
|
|
107
108
|
*/
|
|
108
|
-
export interface
|
|
109
|
+
export interface Renderer2DPluginAppOptions<G extends string = 'renderer2d'> extends Renderer2DPluginCommonOptions<G> {
|
|
109
110
|
/** The PixiJS Application instance (already initialized) */
|
|
110
111
|
app: Application;
|
|
111
112
|
init?: never;
|
|
112
113
|
container?: never;
|
|
113
114
|
}
|
|
114
115
|
/**
|
|
115
|
-
* Options when letting the
|
|
116
|
+
* Options when letting the plugin create and manage the PixiJS Application
|
|
116
117
|
*/
|
|
117
|
-
export interface
|
|
118
|
+
export interface Renderer2DPluginManagedOptions<G extends string = 'renderer2d'> extends Renderer2DPluginCommonOptions<G> {
|
|
118
119
|
app?: never;
|
|
119
|
-
/** PixiJS ApplicationOptions -
|
|
120
|
+
/** PixiJS ApplicationOptions - plugin will create and initialize the Application */
|
|
120
121
|
init: Partial<ApplicationOptions>;
|
|
121
122
|
/** Container element to append the canvas to, or CSS selector string */
|
|
122
123
|
container?: HTMLElement | string;
|
|
123
124
|
}
|
|
124
125
|
/**
|
|
125
|
-
* Configuration options for the 2D renderer
|
|
126
|
+
* Configuration options for the 2D renderer plugin.
|
|
126
127
|
*
|
|
127
128
|
* Supports two modes:
|
|
128
129
|
* 1. **Pre-initialized**: Pass an already-initialized Application via `app`
|
|
129
|
-
* 2. **Managed**: Pass `init` options and the
|
|
130
|
+
* 2. **Managed**: Pass `init` options and the plugin creates the Application during `ecs.initialize()`
|
|
130
131
|
*
|
|
131
|
-
* This
|
|
132
|
+
* This plugin includes transform propagation automatically - no need to add createTransformPlugin() separately.
|
|
132
133
|
*
|
|
133
134
|
* @example Pre-initialized mode (full control)
|
|
134
135
|
* ```typescript
|
|
135
136
|
* const app = new Application();
|
|
136
137
|
* await app.init({ resizeTo: window });
|
|
137
138
|
* const ecs = ECSpresso.create()
|
|
138
|
-
* .
|
|
139
|
+
* .withPlugin(createRenderer2DPlugin({ app }))
|
|
139
140
|
* .withComponentTypes<{ player: true }>()
|
|
140
141
|
* .build();
|
|
141
142
|
* ```
|
|
@@ -143,7 +144,7 @@ export interface Renderer2DBundleManagedOptions<G extends string = 'renderer2d'>
|
|
|
143
144
|
* @example Managed mode (convenience)
|
|
144
145
|
* ```typescript
|
|
145
146
|
* const ecs = ECSpresso.create()
|
|
146
|
-
* .
|
|
147
|
+
* .withPlugin(createRenderer2DPlugin({
|
|
147
148
|
* init: { background: '#1099bb', resizeTo: window },
|
|
148
149
|
* container: document.body,
|
|
149
150
|
* }))
|
|
@@ -152,7 +153,7 @@ export interface Renderer2DBundleManagedOptions<G extends string = 'renderer2d'>
|
|
|
152
153
|
* await ecs.initialize(); // Application created here
|
|
153
154
|
* ```
|
|
154
155
|
*/
|
|
155
|
-
export type
|
|
156
|
+
export type Renderer2DPluginOptions<G extends string = 'renderer2d'> = Renderer2DPluginAppOptions<G> | Renderer2DPluginManagedOptions<G>;
|
|
156
157
|
interface PositionOption {
|
|
157
158
|
x?: number;
|
|
158
159
|
y?: number;
|
|
@@ -218,9 +219,9 @@ export declare function physicalToLogical(physicalX: number, physicalY: number,
|
|
|
218
219
|
y: number;
|
|
219
220
|
};
|
|
220
221
|
/**
|
|
221
|
-
* Create a 2D rendering
|
|
222
|
+
* Create a 2D rendering plugin for ECSpresso.
|
|
222
223
|
*
|
|
223
|
-
* This
|
|
224
|
+
* This plugin provides:
|
|
224
225
|
* - Transform propagation (localTransform -> worldTransform)
|
|
225
226
|
* - Render sync system (updates PixiJS objects from ECS components)
|
|
226
227
|
* - Scene graph management (mirrors ECS hierarchy in PixiJS scene graph)
|
|
@@ -231,14 +232,14 @@ export declare function physicalToLogical(physicalX: number, physicalY: number,
|
|
|
231
232
|
* await app.init({ resizeTo: window });
|
|
232
233
|
*
|
|
233
234
|
* const ecs = ECSpresso.create<GameComponents, {}, {}>()
|
|
234
|
-
* .
|
|
235
|
+
* .withPlugin(createRenderer2DPlugin({ app }))
|
|
235
236
|
* .build();
|
|
236
237
|
* ```
|
|
237
238
|
*
|
|
238
239
|
* @example Managed mode
|
|
239
240
|
* ```typescript
|
|
240
241
|
* const ecs = ECSpresso.create<GameComponents, {}, {}>()
|
|
241
|
-
* .
|
|
242
|
+
* .withPlugin(createRenderer2DPlugin({
|
|
242
243
|
* init: { background: '#1099bb', resizeTo: window },
|
|
243
244
|
* container: document.body,
|
|
244
245
|
* }))
|
|
@@ -248,14 +249,14 @@ export declare function physicalToLogical(physicalX: number, physicalY: number,
|
|
|
248
249
|
*/
|
|
249
250
|
type Renderer2DLabels = 'renderer2d-sync' | 'renderer2d-scene-graph' | 'renderer2d-camera-sync' | 'transform-propagation';
|
|
250
251
|
type Renderer2DReactiveQueryNames = 'renderer2d-sprites' | 'renderer2d-graphics' | 'renderer2d-containers';
|
|
251
|
-
export declare function
|
|
252
|
+
export declare function createRenderer2DPlugin<G extends string = 'renderer2d'>(options: Renderer2DPluginOptions<G> & {
|
|
252
253
|
screenScale: ScreenScaleOptions;
|
|
253
254
|
camera: true;
|
|
254
|
-
}):
|
|
255
|
-
export declare function
|
|
255
|
+
}): Plugin<WorldConfigFrom<Renderer2DComponentTypes, Renderer2DEventTypes, Renderer2DResourceTypes & ViewportScaleResourceTypes & CameraResourceTypes>, EmptyConfig, Renderer2DLabels, G, never, Renderer2DReactiveQueryNames>;
|
|
256
|
+
export declare function createRenderer2DPlugin<G extends string = 'renderer2d'>(options: Renderer2DPluginOptions<G> & {
|
|
256
257
|
screenScale: ScreenScaleOptions;
|
|
257
|
-
}):
|
|
258
|
-
export declare function
|
|
258
|
+
}): Plugin<WorldConfigFrom<Renderer2DComponentTypes, Renderer2DEventTypes, Renderer2DResourceTypes & ViewportScaleResourceTypes>, EmptyConfig, Renderer2DLabels, G, never, Renderer2DReactiveQueryNames>;
|
|
259
|
+
export declare function createRenderer2DPlugin<G extends string = 'renderer2d'>(options: Renderer2DPluginOptions<G> & {
|
|
259
260
|
camera: true;
|
|
260
|
-
}):
|
|
261
|
-
export declare function
|
|
261
|
+
}): Plugin<WorldConfigFrom<Renderer2DComponentTypes, Renderer2DEventTypes, Renderer2DResourceTypes & CameraResourceTypes>, EmptyConfig, Renderer2DLabels, G, never, Renderer2DReactiveQueryNames>;
|
|
262
|
+
export declare function createRenderer2DPlugin<G extends string = 'renderer2d'>(options: Renderer2DPluginOptions<G>): Plugin<WorldConfigFrom<Renderer2DComponentTypes, Renderer2DEventTypes, Renderer2DResourceTypes>, EmptyConfig, Renderer2DLabels, G, never, Renderer2DReactiveQueryNames>;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Spatial Index
|
|
2
|
+
* Spatial Index Plugin for ECSpresso
|
|
3
3
|
*
|
|
4
4
|
* Provides a uniform-grid spatial hash for broadphase collision detection
|
|
5
5
|
* and proximity queries. Replaces O(n²) brute-force with O(n·d) where
|
|
6
6
|
* d = local density.
|
|
7
7
|
*
|
|
8
8
|
* Standalone usage: queryRect / queryRadius for proximity queries.
|
|
9
|
-
* Automatic acceleration: collision and physics2D
|
|
9
|
+
* Automatic acceleration: collision and physics2D plugins detect the
|
|
10
10
|
* spatialIndex resource at runtime and use it for broadphase when present.
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
12
|
+
import { type Plugin } from 'ecspresso';
|
|
13
|
+
import type { WorldConfigFrom, EmptyConfig } from '../type-utils';
|
|
13
14
|
import type { TransformComponentTypes } from './transform';
|
|
14
15
|
import type { CollisionComponentTypes } from './collision';
|
|
15
16
|
import { type SpatialIndex } from '../utils/spatial-hash';
|
|
@@ -19,7 +20,7 @@ export interface SpatialIndexResourceTypes {
|
|
|
19
20
|
type SpatialIndexComponentTypes = TransformComponentTypes & Pick<CollisionComponentTypes<string>, 'aabbCollider' | 'circleCollider'>;
|
|
20
21
|
export type SpatialIndexPhase = 'fixedUpdate' | 'postUpdate';
|
|
21
22
|
type SpatialIndexLabel = `spatial-index-rebuild-${SpatialIndexPhase}`;
|
|
22
|
-
export interface
|
|
23
|
+
export interface SpatialIndexPluginOptions<G extends string = 'spatialIndex'> {
|
|
23
24
|
/** Cell size for the spatial hash grid (default: 64) */
|
|
24
25
|
cellSize?: number;
|
|
25
26
|
/** System group name (default: 'spatialIndex') */
|
|
@@ -30,10 +31,10 @@ export interface SpatialIndexBundleOptions<G extends string = 'spatialIndex'> {
|
|
|
30
31
|
phases?: ReadonlyArray<SpatialIndexPhase>;
|
|
31
32
|
}
|
|
32
33
|
/**
|
|
33
|
-
* Create a spatial index
|
|
34
|
+
* Create a spatial index plugin for ECSpresso.
|
|
34
35
|
*
|
|
35
36
|
* Provides a uniform-grid spatial hash that accelerates collision detection.
|
|
36
|
-
* When installed alongside the collision or physics2D
|
|
37
|
+
* When installed alongside the collision or physics2D plugins, they
|
|
37
38
|
* automatically use the spatial index for broadphase instead of O(n²)
|
|
38
39
|
* brute-force.
|
|
39
40
|
*
|
|
@@ -43,9 +44,9 @@ export interface SpatialIndexBundleOptions<G extends string = 'spatialIndex'> {
|
|
|
43
44
|
* @example
|
|
44
45
|
* ```typescript
|
|
45
46
|
* const ecs = ECSpresso.create()
|
|
46
|
-
* .
|
|
47
|
-
* .
|
|
48
|
-
* .
|
|
47
|
+
* .withPlugin(createTransformPlugin())
|
|
48
|
+
* .withPlugin(createCollisionPlugin({ layers }))
|
|
49
|
+
* .withPlugin(createSpatialIndexPlugin({ cellSize: 128 }))
|
|
49
50
|
* .build();
|
|
50
51
|
*
|
|
51
52
|
* // Proximity query in a system:
|
|
@@ -53,5 +54,5 @@ export interface SpatialIndexBundleOptions<G extends string = 'spatialIndex'> {
|
|
|
53
54
|
* const nearby = si.queryRadius(playerX, playerY, 200);
|
|
54
55
|
* ```
|
|
55
56
|
*/
|
|
56
|
-
export declare function
|
|
57
|
+
export declare function createSpatialIndexPlugin<G extends string = 'spatialIndex'>(options?: SpatialIndexPluginOptions<G>): Plugin<WorldConfigFrom<SpatialIndexComponentTypes, {}, SpatialIndexResourceTypes>, EmptyConfig, SpatialIndexLabel, G>;
|
|
57
58
|
export {};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sprite Animation Plugin for ECSpresso
|
|
3
|
+
*
|
|
4
|
+
* ECS-native frame-based sprite animation. Advances through spritesheet frames,
|
|
5
|
+
* handles loop modes (once, loop, pingPong), publishes completion events, and
|
|
6
|
+
* syncs the current frame's texture to the PixiJS Sprite via structural access.
|
|
7
|
+
*
|
|
8
|
+
* Renderer2D is a required dependency — the `sprite` component comes from that plugin.
|
|
9
|
+
* This plugin declares only `spriteAnimation` as its component type.
|
|
10
|
+
*/
|
|
11
|
+
import { type Plugin, type BasePluginOptions } from 'ecspresso';
|
|
12
|
+
import type { BaseWorld } from 'ecspresso';
|
|
13
|
+
import type { WorldConfigFrom, EmptyConfig } from '../type-utils';
|
|
14
|
+
/** BaseWorld narrowed to sprite-animation components for typed access in helpers. */
|
|
15
|
+
type SpriteAnimationWorld = BaseWorld<SpriteAnimationComponentTypes>;
|
|
16
|
+
export type AnimationLoopMode = 'once' | 'loop' | 'pingPong';
|
|
17
|
+
/**
|
|
18
|
+
* A single animation clip: an ordered sequence of texture frames with timing.
|
|
19
|
+
* Immutable and shared across entities.
|
|
20
|
+
*/
|
|
21
|
+
export interface SpriteAnimationClip {
|
|
22
|
+
readonly frames: readonly unknown[];
|
|
23
|
+
readonly frameDuration: number;
|
|
24
|
+
readonly frameDurations: readonly number[] | null;
|
|
25
|
+
readonly loop: AnimationLoopMode;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Input format for defining a clip. Accepts either uniform or per-frame timing.
|
|
29
|
+
*/
|
|
30
|
+
export interface SpriteAnimationClipInput {
|
|
31
|
+
/** Array of PixiJS Texture objects */
|
|
32
|
+
frames: readonly unknown[];
|
|
33
|
+
/** Uniform seconds-per-frame (used when frameDurations is not provided) */
|
|
34
|
+
frameDuration?: number;
|
|
35
|
+
/** Per-frame durations in seconds (overrides frameDuration) */
|
|
36
|
+
frameDurations?: readonly number[];
|
|
37
|
+
/** Loop mode (default: 'loop') */
|
|
38
|
+
loop?: AnimationLoopMode;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A named collection of animation clips. Immutable and shared across entities.
|
|
42
|
+
* Parameterized by A (animation name union) for compile-time validation.
|
|
43
|
+
*/
|
|
44
|
+
export interface SpriteAnimationSet<A extends string = string> {
|
|
45
|
+
readonly id: string;
|
|
46
|
+
readonly clips: {
|
|
47
|
+
readonly [K in A]: SpriteAnimationClip;
|
|
48
|
+
};
|
|
49
|
+
readonly defaultClip: A;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Per-entity runtime animation state.
|
|
53
|
+
*/
|
|
54
|
+
export interface SpriteAnimation<A extends string = string> {
|
|
55
|
+
readonly set: SpriteAnimationSet<A>;
|
|
56
|
+
current: A;
|
|
57
|
+
currentFrame: number;
|
|
58
|
+
elapsed: number;
|
|
59
|
+
playing: boolean;
|
|
60
|
+
speed: number;
|
|
61
|
+
direction: 1 | -1;
|
|
62
|
+
totalLoops: number;
|
|
63
|
+
completedLoops: number;
|
|
64
|
+
justFinished: boolean;
|
|
65
|
+
onComplete?: (data: SpriteAnimationEventData) => void;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Component types provided by the sprite animation plugin.
|
|
69
|
+
*/
|
|
70
|
+
export interface SpriteAnimationComponentTypes<A extends string = string> {
|
|
71
|
+
spriteAnimation: SpriteAnimation<A>;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Data published when an animation completes.
|
|
75
|
+
*/
|
|
76
|
+
export interface SpriteAnimationEventData {
|
|
77
|
+
entityId: number;
|
|
78
|
+
animation: string;
|
|
79
|
+
}
|
|
80
|
+
export interface SpriteAnimationPluginOptions<G extends string = 'spriteAnimation'> extends BasePluginOptions<G> {
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Define a single-clip animation set named 'default'.
|
|
84
|
+
* For simple use cases like spinning coins, pulsing effects, etc.
|
|
85
|
+
*
|
|
86
|
+
* @param id Unique identifier for this animation set
|
|
87
|
+
* @param clip Clip definition
|
|
88
|
+
* @returns A frozen SpriteAnimationSet with one clip named 'default'
|
|
89
|
+
*/
|
|
90
|
+
export declare function defineSpriteAnimation(id: string, clip: SpriteAnimationClipInput): SpriteAnimationSet<'default'>;
|
|
91
|
+
/**
|
|
92
|
+
* Define a multi-clip animation set with named animations.
|
|
93
|
+
* Animation names are inferred from the keys of the clips object.
|
|
94
|
+
*
|
|
95
|
+
* @param id Unique identifier for this animation set
|
|
96
|
+
* @param clips Object mapping animation names to clip definitions
|
|
97
|
+
* @param options Optional configuration (defaultClip)
|
|
98
|
+
* @returns A frozen SpriteAnimationSet with inferred animation name union
|
|
99
|
+
*/
|
|
100
|
+
export declare function defineSpriteAnimations<A extends string>(id: string, clips: Record<A, SpriteAnimationClipInput>, options?: {
|
|
101
|
+
defaultClip?: NoInfer<A>;
|
|
102
|
+
}): SpriteAnimationSet<A>;
|
|
103
|
+
/**
|
|
104
|
+
* Create a spriteAnimation component from an animation set.
|
|
105
|
+
*
|
|
106
|
+
* @param set The animation set to use
|
|
107
|
+
* @param options Optional configuration (initial clip, speed, onComplete event)
|
|
108
|
+
* @returns Component object suitable for spreading into spawn()
|
|
109
|
+
*/
|
|
110
|
+
export declare function createSpriteAnimation<A extends string>(set: SpriteAnimationSet<A>, options?: {
|
|
111
|
+
initial?: A;
|
|
112
|
+
speed?: number;
|
|
113
|
+
totalLoops?: number;
|
|
114
|
+
onComplete?: (data: SpriteAnimationEventData) => void;
|
|
115
|
+
}): Pick<SpriteAnimationComponentTypes<A>, 'spriteAnimation'>;
|
|
116
|
+
/**
|
|
117
|
+
* Switch an entity's current animation at runtime.
|
|
118
|
+
* Resets state if switching to a different animation (or restart=true).
|
|
119
|
+
*
|
|
120
|
+
* @returns false if entity has no spriteAnimation or animation name doesn't exist
|
|
121
|
+
*/
|
|
122
|
+
export declare function playAnimation(ecs: SpriteAnimationWorld, entityId: number, animation: string, options?: {
|
|
123
|
+
restart?: boolean;
|
|
124
|
+
speed?: number;
|
|
125
|
+
}): boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Pause an entity's animation.
|
|
128
|
+
*
|
|
129
|
+
* @returns false if entity has no spriteAnimation
|
|
130
|
+
*/
|
|
131
|
+
export declare function stopAnimation(ecs: SpriteAnimationWorld, entityId: number): boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Resume a paused animation.
|
|
134
|
+
*
|
|
135
|
+
* @returns false if entity has no spriteAnimation
|
|
136
|
+
*/
|
|
137
|
+
export declare function resumeAnimation(ecs: SpriteAnimationWorld, entityId: number): boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Create a sprite animation plugin for ECSpresso.
|
|
140
|
+
*
|
|
141
|
+
* Provides:
|
|
142
|
+
* - Frame-based animation system processing spriteAnimation components
|
|
143
|
+
* - Loop modes: once, loop, pingPong
|
|
144
|
+
* - justFinished one-frame flag for completion detection
|
|
145
|
+
* - onComplete event publishing
|
|
146
|
+
* - Sprite texture sync via structural cross-plugin access
|
|
147
|
+
* - Change detection via markChanged
|
|
148
|
+
*/
|
|
149
|
+
export declare function createSpriteAnimationPlugin<G extends string = 'spriteAnimation'>(options?: SpriteAnimationPluginOptions<G>): Plugin<WorldConfigFrom<SpriteAnimationComponentTypes>, EmptyConfig, 'sprite-animation-update', G>;
|
|
150
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* State Machine
|
|
2
|
+
* State Machine Plugin for ECSpresso
|
|
3
3
|
*
|
|
4
4
|
* Provides ECS-native finite state machines with guard-based transitions,
|
|
5
5
|
* event-driven transitions, and lifecycle hooks (onEnter, onExit, onUpdate).
|
|
@@ -7,55 +7,49 @@
|
|
|
7
7
|
* Each entity gets a `stateMachine` component referencing a shared definition.
|
|
8
8
|
* One system processes all state machine entities each tick.
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
11
|
-
import type {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* allowing users to annotate hooks with their concrete ECSpresso type.
|
|
16
|
-
*/
|
|
17
|
-
export interface StateMachineWorld {
|
|
18
|
-
entityManager: {
|
|
19
|
-
getComponent(entityId: number, componentName: string): unknown | undefined;
|
|
20
|
-
};
|
|
21
|
-
eventBus: {
|
|
22
|
-
publish(eventType: string, data: unknown): void;
|
|
23
|
-
};
|
|
24
|
-
spawn(components: Record<string, unknown>): {
|
|
25
|
-
id: number;
|
|
26
|
-
};
|
|
27
|
-
removeEntity(entityOrId: number): boolean;
|
|
28
|
-
hasComponent(entityId: number, componentName: string): boolean;
|
|
29
|
-
getResource(key: string): unknown;
|
|
30
|
-
hasResource(key: string): boolean;
|
|
31
|
-
markChanged(entityId: number, componentName: string): void;
|
|
32
|
-
commands: {
|
|
33
|
-
spawn(components: Record<string, unknown>): void;
|
|
34
|
-
removeEntity(entityId: number): void;
|
|
35
|
-
};
|
|
36
|
-
}
|
|
10
|
+
import { type Plugin, type BasePluginOptions } from 'ecspresso';
|
|
11
|
+
import type { BaseWorld } from 'ecspresso';
|
|
12
|
+
import type { WorldConfigFrom, EmptyConfig } from '../type-utils';
|
|
13
|
+
/** BaseWorld narrowed to state-machine components for typed access in helpers. */
|
|
14
|
+
type StateMachineWorld = BaseWorld<StateMachineComponentTypes>;
|
|
37
15
|
/**
|
|
38
16
|
* Configuration for a single state in a state machine definition.
|
|
39
17
|
*
|
|
40
18
|
* @template S - Union of state name strings
|
|
41
19
|
* @template W - World interface type for hooks/guards (default: StateMachineWorld)
|
|
42
20
|
*/
|
|
43
|
-
export interface StateConfig<S extends string, W extends
|
|
21
|
+
export interface StateConfig<S extends string, W extends BaseWorld<StateMachineComponentTypes> = StateMachineWorld> {
|
|
44
22
|
/** Called when entering this state */
|
|
45
|
-
onEnter?(
|
|
23
|
+
onEnter?(ctx: {
|
|
24
|
+
ecs: W;
|
|
25
|
+
entityId: number;
|
|
26
|
+
}): void;
|
|
46
27
|
/** Called when exiting this state */
|
|
47
|
-
onExit?(
|
|
28
|
+
onExit?(ctx: {
|
|
29
|
+
ecs: W;
|
|
30
|
+
entityId: number;
|
|
31
|
+
}): void;
|
|
48
32
|
/** Called each tick while in this state */
|
|
49
|
-
onUpdate?(
|
|
33
|
+
onUpdate?(ctx: {
|
|
34
|
+
ecs: W;
|
|
35
|
+
entityId: number;
|
|
36
|
+
dt: number;
|
|
37
|
+
}): void;
|
|
50
38
|
/** Guard-based transitions evaluated each tick. First passing guard wins. */
|
|
51
39
|
transitions?: ReadonlyArray<{
|
|
52
40
|
target: S;
|
|
53
|
-
guard(
|
|
41
|
+
guard(ctx: {
|
|
42
|
+
ecs: W;
|
|
43
|
+
entityId: number;
|
|
44
|
+
}): boolean;
|
|
54
45
|
}>;
|
|
55
46
|
/** Event-based transition map: eventName → target state or guarded transition */
|
|
56
47
|
on?: Record<string, S | {
|
|
57
48
|
target: S;
|
|
58
|
-
guard(
|
|
49
|
+
guard(ctx: {
|
|
50
|
+
ecs: W;
|
|
51
|
+
entityId: number;
|
|
52
|
+
}): boolean;
|
|
59
53
|
}>;
|
|
60
54
|
}
|
|
61
55
|
/**
|
|
@@ -82,7 +76,7 @@ export interface StateMachine<S extends string = string> {
|
|
|
82
76
|
stateTime: number;
|
|
83
77
|
}
|
|
84
78
|
/**
|
|
85
|
-
* Component types provided by the state machine
|
|
79
|
+
* Component types provided by the state machine plugin.
|
|
86
80
|
*
|
|
87
81
|
* @template S - Union of state name strings (default: string)
|
|
88
82
|
*/
|
|
@@ -101,7 +95,7 @@ export interface StateTransitionEvent<S extends string = string> {
|
|
|
101
95
|
definitionId: string;
|
|
102
96
|
}
|
|
103
97
|
/**
|
|
104
|
-
* Event types provided by the state machine
|
|
98
|
+
* Event types provided by the state machine plugin.
|
|
105
99
|
*
|
|
106
100
|
* @template S - Union of state name strings (default: string)
|
|
107
101
|
*/
|
|
@@ -120,15 +114,9 @@ export interface StateMachineEventTypes<S extends string = string> {
|
|
|
120
114
|
*/
|
|
121
115
|
export type StatesOf<D> = D extends StateMachineDefinition<infer S> ? S : never;
|
|
122
116
|
/**
|
|
123
|
-
* Configuration options for the state machine
|
|
117
|
+
* Configuration options for the state machine plugin.
|
|
124
118
|
*/
|
|
125
|
-
export interface
|
|
126
|
-
/** System group name (default: 'stateMachine') */
|
|
127
|
-
systemGroup?: G;
|
|
128
|
-
/** Priority for state machine system (default: 0) */
|
|
129
|
-
priority?: number;
|
|
130
|
-
/** Execution phase (default: 'update') */
|
|
131
|
-
phase?: SystemPhase;
|
|
119
|
+
export interface StateMachinePluginOptions<G extends string = 'stateMachine'> extends BasePluginOptions<G> {
|
|
132
120
|
}
|
|
133
121
|
/**
|
|
134
122
|
* Define a state machine with type-safe state names.
|
|
@@ -144,11 +132,11 @@ export interface StateMachineBundleOptions<G extends string = 'stateMachine'> {
|
|
|
144
132
|
* initial: 'idle',
|
|
145
133
|
* states: {
|
|
146
134
|
* idle: {
|
|
147
|
-
* onEnter: (ecs,
|
|
148
|
-
* transitions: [{ target: 'chase', guard: (ecs,
|
|
135
|
+
* onEnter: ({ ecs, entityId }) => { ... },
|
|
136
|
+
* transitions: [{ target: 'chase', guard: ({ ecs, entityId }) => playerNearby(ecs, entityId) }],
|
|
149
137
|
* },
|
|
150
138
|
* chase: {
|
|
151
|
-
* onUpdate: (ecs,
|
|
139
|
+
* onUpdate: ({ ecs, entityId, dt }) => { ... },
|
|
152
140
|
* on: { playerLost: 'idle' },
|
|
153
141
|
* },
|
|
154
142
|
* },
|
|
@@ -206,62 +194,19 @@ export declare function sendEvent(ecs: StateMachineWorld, entityId: number, even
|
|
|
206
194
|
*/
|
|
207
195
|
export declare function getStateMachineState(ecs: StateMachineWorld, entityId: number): string | undefined;
|
|
208
196
|
/**
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
* @template W - Concrete ECS world type
|
|
197
|
+
* Typed helpers for the state machine plugin.
|
|
198
|
+
* Creates helpers that validate hook parameters against the world type W.
|
|
199
|
+
* Call after .build() using typeof ecs.
|
|
213
200
|
*/
|
|
214
|
-
export interface
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}) => StateMachineDefinition<DS>;
|
|
220
|
-
createStateMachine: <DS extends S>(definition: StateMachineDefinition<DS>, options?: {
|
|
221
|
-
initial?: DS;
|
|
222
|
-
}) => Pick<StateMachineComponentTypes<S>, 'stateMachine'>;
|
|
201
|
+
export interface StateMachineHelpers<W extends BaseWorld<StateMachineComponentTypes>> {
|
|
202
|
+
defineStateMachine: <S extends string>(id: string, config: {
|
|
203
|
+
initial: NoInfer<S>;
|
|
204
|
+
states: Record<S, StateConfig<NoInfer<S>, W>>;
|
|
205
|
+
}) => StateMachineDefinition<S>;
|
|
223
206
|
}
|
|
207
|
+
export declare function createStateMachineHelpers<W extends BaseWorld<StateMachineComponentTypes> = StateMachineWorld>(_world?: W): StateMachineHelpers<W>;
|
|
224
208
|
/**
|
|
225
|
-
* Create a
|
|
226
|
-
*
|
|
227
|
-
* Hooks and guards in definitions created via the kit's `defineStateMachine`
|
|
228
|
-
* contextually receive W as their `ecs` parameter — no manual annotations needed.
|
|
229
|
-
*
|
|
230
|
-
* @template W - Concrete ECS world type
|
|
231
|
-
* @param options - Optional bundle configuration (same as createStateMachineBundle)
|
|
232
|
-
* @returns A kit object with bundle, defineStateMachine, createStateMachine, transitionTo, sendEvent, getStateMachineState
|
|
233
|
-
*
|
|
234
|
-
* @example
|
|
235
|
-
* ```typescript
|
|
236
|
-
* const ecs = ECSpresso.create()
|
|
237
|
-
* .withBundle(createStateMachineBundle())
|
|
238
|
-
* .withComponentTypes<{ enemy: true }>()
|
|
239
|
-
* .build();
|
|
240
|
-
*
|
|
241
|
-
* type ECS = typeof ecs;
|
|
242
|
-
* const { bundle, defineStateMachine, createStateMachine } =
|
|
243
|
-
* createStateMachineKit<ECS>();
|
|
244
|
-
*
|
|
245
|
-
* const enemyFSM = defineStateMachine('enemy', {
|
|
246
|
-
* initial: 'patrol',
|
|
247
|
-
* states: {
|
|
248
|
-
* patrol: {
|
|
249
|
-
* onEnter(ecs, entityId) {
|
|
250
|
-
* ecs.getResource('bounds'); // fully typed
|
|
251
|
-
* },
|
|
252
|
-
* transitions: [{
|
|
253
|
-
* target: 'chase',
|
|
254
|
-
* guard: (ecs, entityId) => distanceToPlayer(ecs, entityId) < 180,
|
|
255
|
-
* }],
|
|
256
|
-
* },
|
|
257
|
-
* chase: {},
|
|
258
|
-
* },
|
|
259
|
-
* });
|
|
260
|
-
* ```
|
|
261
|
-
*/
|
|
262
|
-
export declare function createStateMachineKit<W extends StateMachineWorld = StateMachineWorld, S extends string = string>(options?: StateMachineBundleOptions): StateMachineKit<W, S>;
|
|
263
|
-
/**
|
|
264
|
-
* Create a state machine bundle for ECSpresso.
|
|
209
|
+
* Create a state machine plugin for ECSpresso.
|
|
265
210
|
*
|
|
266
211
|
* Provides:
|
|
267
212
|
* - Lifecycle hooks (onEnter, onExit, onUpdate) per state
|
|
@@ -273,17 +218,17 @@ export declare function createStateMachineKit<W extends StateMachineWorld = Stat
|
|
|
273
218
|
* @example
|
|
274
219
|
* ```typescript
|
|
275
220
|
* const ecs = ECSpresso.create()
|
|
276
|
-
* .
|
|
221
|
+
* .withPlugin(createStateMachinePlugin())
|
|
277
222
|
* .build();
|
|
278
223
|
*
|
|
279
224
|
* const fsm = defineStateMachine('enemy', {
|
|
280
225
|
* initial: 'idle',
|
|
281
226
|
* states: {
|
|
282
227
|
* idle: {
|
|
283
|
-
* transitions: [{ target: 'chase', guard: (ecs,
|
|
228
|
+
* transitions: [{ target: 'chase', guard: ({ ecs, entityId }) => playerNearby(ecs, entityId) }],
|
|
284
229
|
* },
|
|
285
230
|
* chase: {
|
|
286
|
-
* onUpdate: (ecs,
|
|
231
|
+
* onUpdate: ({ ecs, entityId, dt }) => moveTowardPlayer(ecs, entityId, dt),
|
|
287
232
|
* on: { playerLost: 'idle' },
|
|
288
233
|
* },
|
|
289
234
|
* },
|
|
@@ -295,4 +240,5 @@ export declare function createStateMachineKit<W extends StateMachineWorld = Stat
|
|
|
295
240
|
* });
|
|
296
241
|
* ```
|
|
297
242
|
*/
|
|
298
|
-
export declare function
|
|
243
|
+
export declare function createStateMachinePlugin<S extends string = string, G extends string = 'stateMachine'>(options?: StateMachinePluginOptions<G>): Plugin<WorldConfigFrom<StateMachineComponentTypes<S>, StateMachineEventTypes<S>>, EmptyConfig, 'state-machine-update', G>;
|
|
244
|
+
export {};
|