@moku-labs/game 0.0.1 → 0.0.2
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 +424 -37
- package/dist/assets.d.mts +161 -0
- package/dist/assets.mjs +4729 -0
- package/dist/component-DGg5DqKK.mjs +44 -0
- package/dist/control.d.mts +162 -0
- package/dist/control.mjs +758 -0
- package/dist/define-sFoO3y6X.d.mts +263 -0
- package/dist/headless-CvamCUcR.mjs +186 -0
- package/dist/headless-KaSWcd0s.d.mts +181 -0
- package/dist/index.d.mts +1204 -50
- package/dist/index.mjs +20978 -2010
- package/dist/inspect.d.mts +109 -0
- package/dist/inspect.mjs +519 -0
- package/dist/jsx-dev-runtime.d.mts +2 -0
- package/dist/jsx-dev-runtime.mjs +2 -0
- package/dist/jsx-runtime.d.mts +2 -0
- package/dist/jsx-runtime.mjs +2 -0
- package/dist/memory-CvgdnsQO.mjs +259 -0
- package/dist/registry-DlpRCibU.mjs +384 -0
- package/dist/runtime-DRlwxkIv.mjs +182 -0
- package/dist/runtime-DiOTkDZz.d.mts +77 -0
- package/dist/session-DmAxY6Ll.mjs +145 -0
- package/dist/testing.d.mts +23 -111
- package/dist/testing.mjs +12 -289
- package/dist/types-BxkNNYul.d.mts +2840 -0
- package/dist/types-CTPS9GBu.d.mts +742 -0
- package/dist/types-DD-QrG_z.d.mts +588 -0
- package/dist/types-DWILGrPn.d.mts +622 -0
- package/dist/types-DYLnSgMI.d.mts +570 -0
- package/dist/types-JNc_UQBo.d.mts +2896 -0
- package/dist/types-yg_ywtT-.d.mts +1859 -0
- package/dist/visual-BDUHSRvf.mjs +734 -0
- package/package.json +26 -4
- package/dist/registry-DWV5C0Mf.mjs +0 -666
- package/dist/types-BfsmUzLC.d.mts +0 -1908
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,191 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { $ as PauseReason, A as Config$4, B as types_d_exports$8, C as SceneIdOf, D as Hint, E as GuideOptions, F as Config$3, G as SaveUnreadableError, J as RngApi, L as Json, N as types_d_exports$12, R as Root, T as Descriptor, V as Patch, X as Api$2, Z as Config$2, _ as DefineNode, a as GameTypes, at as State, c as TextStylesOf, ct as Events, d as exit, et as State$2, f as slot, h as FeatureDescription, i as FeaturePlugin, j as State$4, k as Api$3, l as types_d_exports$4, m as type, n as BundlesOf, nt as Api, ot as types_d_exports$3, p as to, q as StoreApi, r as Config$1, rt as Config, s as State$1, st as Config$5, t as Api$1, tt as types_d_exports$7, u as defineFlow, z as State$3 } from "./types-JNc_UQBo.mjs";
|
|
2
|
+
import { A as ComponentHandle, B as SystemDefinition, C as ProjectionSpec, F as Mut, I as Narrowed, M as ComponentValue, R as QueryTerm, S as ProjectionMotion, V as TagType, a as types_d_exports$9, d as Config$7, f as State$6, g as Ease, h as DescriptionNode, i as State$5, j as ComponentType, k as AnyComponentValue, l as ViewportSize, n as Config$6, p as types_d_exports$14, t as Api$4, u as Api$5, x as NumericFields, z as ResourceType } from "./types-BxkNNYul.mjs";
|
|
3
|
+
import { a as DefineBundles, c as LoadReason, d as Tier, i as Config$8, n as BundleMap, p as types_d_exports$1, r as BundleSpec, s as LoadBundles, t as Api$6, u as State$7 } from "./types-DWILGrPn.mjs";
|
|
4
|
+
import { A as Transform, B as types_d_exports$5, C as NineSliceValue, D as Sprite, E as ShapeValue, H as InputApi, I as I18nApi, L as Message, M as sprite, N as Argument, O as SpriteOptions, P as Config$9, R as State$8, S as NineSlice, T as Shape, U as State$9, V as Config$10, W as types_d_exports$6, _ as Style, b as defineComponent, d as popup, f as defineTokens, g as ResolvedStyle, h as IsFlags, j as TransformValue, k as SpriteValue, l as Box, p as IntrinsicElementsFor, s as PopupComponent, u as LocalWrite, w as Parent, x as Display, y as WhenFlags, z as TypedTr } from "./types-yg_ywtT-.mjs";
|
|
5
|
+
import { a as Config$11, c as TextApi, d as TextValue, f as types_d_exports$11, i as types_d_exports$13, l as TextStyleInput, n as State$11, o as Point, r as UiApi, s as State$10, t as Config$12, u as TextStyles } from "./types-DD-QrG_z.mjs";
|
|
6
|
+
import { a as Config$13, c as SlotValues, d as types_d_exports, f as ExternalPlayer, g as Step, h as SfxDescriptor, i as BuildTools, l as State$12, m as PlayDescriptor, n as AnimationDefinition, o as MotionKeyframe, p as HapticDescriptor, r as AnimationSpec, s as SlotTags, t as AnimApi, u as Target } from "./types-CTPS9GBu.mjs";
|
|
7
|
+
import { c as AnySceneProjection, d as SceneDefinition, f as SceneSpec, h as types_d_exports$10, i as MusicOptions, l as DefineScene, m as State$14, n as Config$14, o as State$13, p as ScenesApi, r as MusicDescriptor, s as types_d_exports$2, t as AudioApi, u as LayerMap } from "./types-DYLnSgMI.mjs";
|
|
2
8
|
|
|
9
|
+
//#region src/plugins/text/components.d.ts
|
|
10
|
+
/**
|
|
11
|
+
* Words on the screen: a string or a message, the style it is drawn in, and the string `text`
|
|
12
|
+
* resolved out of it. A game writes `content`, `style`, `bind` and `anchor`; `resolved` is
|
|
13
|
+
* engine-owned and `ui` and the tests read it.
|
|
14
|
+
*/
|
|
15
|
+
declare const Text: ComponentType<TextValue>;
|
|
16
|
+
/**
|
|
17
|
+
* What `label` takes: the two things every label needs, and the anchor that has a default.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const options: LabelOptions = { text: "+5", style: "board.float", at: { x: 90, y: 180 } };
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
type LabelOptions = {
|
|
25
|
+
text: string | Message;
|
|
26
|
+
style: string;
|
|
27
|
+
at: Point;
|
|
28
|
+
anchor?: Point;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Bundles the two components a label needs, so a projection `view` reads as one line. The anchor
|
|
32
|
+
* is the point of the block that sits on the transform.
|
|
33
|
+
*
|
|
34
|
+
* @param options - The text, its style, where it sits, and which point of it sits there.
|
|
35
|
+
* @returns The `Text` and the `Transform` value, in that order.
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* label({ text: "+5", style: "board.float", at: { x: 90, y: 180 } });
|
|
39
|
+
* // [Text({ content: "+5", style: "board.float", bind: undefined,
|
|
40
|
+
* // anchor: { x: 0.5, y: 0.5 }, resolved: "" }),
|
|
41
|
+
* // Transform({ x: 90, y: 180, rotation: 0, scale: 1 })]
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
declare function label(options: LabelOptions): [ComponentValue<TextValue>, ComponentValue<TransformValue>];
|
|
45
|
+
/**
|
|
46
|
+
* Declares the text styles of a feature. The result goes under the `textStyles` key of the
|
|
47
|
+
* feature description, and `text` reads it in `onStart`.
|
|
48
|
+
*
|
|
49
|
+
* @param map - Style name to what that style looks like.
|
|
50
|
+
* @returns The registration a feature carries.
|
|
51
|
+
* @throws {Error} When a style names a wrap that is not a width and not `"none"`.
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* defineTextStyles({ "hud.digits": { font: "ui.font-digits", size: 40, fill: 0xffe082 } });
|
|
55
|
+
* // { kind: "textStyles", map: { "hud.digits": { font: "ui.font-digits", bold: undefined,
|
|
56
|
+
* // italic: undefined, size: 40, fill: 0xffe082, stroke: 0x000000, strokeWidth: 0,
|
|
57
|
+
* // letterSpacing: 0, align: "left", wrap: "none", digits: false, shadow: undefined } } }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
declare function defineTextStyles(map: Record<string, TextStyleInput>): TextStyles;
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/plugins/world/projection/define.d.ts
|
|
63
|
+
/**
|
|
64
|
+
* Types a projection: keyed items of the model turned into entities. `Item` is inferred from the
|
|
65
|
+
* return of `from` and reaches `key`, `view` and every motion hook; `layer` and `lift` stay
|
|
66
|
+
* literal, so `defineScene` can check them against the layers of the scene.
|
|
67
|
+
*
|
|
68
|
+
* @param spec - Name, layer, optional lift layer, `from`, `key`, `view` and the motion hooks.
|
|
69
|
+
* @returns The same spec, typed.
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* const boardItems = projection({
|
|
73
|
+
* name: "board.items",
|
|
74
|
+
* layer: "items",
|
|
75
|
+
* from: (player: { items: { id: string }[] }) => player.items,
|
|
76
|
+
* key: item => item.id,
|
|
77
|
+
* view: () => []
|
|
78
|
+
* });
|
|
79
|
+
* boardItems.layer; // "items", the literal type, not string
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
declare function projection<const LayerName extends string, const LiftName extends string, Item, Player = Json, Session = Json>(spec: ProjectionSpec<Item, LayerName, LiftName, Player, Session>): ProjectionSpec<Item, LayerName, LiftName, Player, Session>;
|
|
83
|
+
/**
|
|
84
|
+
* The projection helper bound to one game's `player` and `session`.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* const bound: ProjectionFor<{ coins: number }, {}> = projection;
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
type ProjectionFor<Player, Session> = <const LayerName extends string, const LiftName extends string, Item>(spec: ProjectionSpec<Item, LayerName, LiftName, Player, Session>) => ProjectionSpec<Item, LayerName, LiftName, Player, Session>;
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/plugins/anim/index.d.ts
|
|
94
|
+
/**
|
|
95
|
+
* Anim plugin: `app.anim.play(animation, slots)`, `app.anim.finishAll()`,
|
|
96
|
+
* `app.anim.setReducedMotion(on)`.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* // Animation is text: a module next to the feature, played by a node or by a test.
|
|
101
|
+
* const coinsFly = defineAnimation("hud.coinsFly", {
|
|
102
|
+
* slots: { from: type<Target>(), to: type<Target>() },
|
|
103
|
+
* build: ({ from, to }, { at }) =>
|
|
104
|
+
* sequence(
|
|
105
|
+
* tween(from, Transform, { x: at(to).x, y: at(to).y }, { ms: 600, ease: "inCubic" }),
|
|
106
|
+
* mark("landed")
|
|
107
|
+
* )
|
|
108
|
+
* });
|
|
109
|
+
*
|
|
110
|
+
* const app = createApp({ plugins: [...screen, animPlugin, hudFeature] });
|
|
111
|
+
*
|
|
112
|
+
* app.anim.play(coinsFly, { from: purse, to: counter }).marks(); // []: the first frame is next
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
declare const animPlugin: import("@moku-labs/core").PluginInstance<"anim", Config$13, State$12, AnimApi, {
|
|
116
|
+
"anim:mark": {
|
|
117
|
+
animation: string;
|
|
118
|
+
mark: string;
|
|
119
|
+
};
|
|
120
|
+
"anim:finished": {
|
|
121
|
+
animation: string;
|
|
122
|
+
};
|
|
123
|
+
}> & Record<never, never>;
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/plugins/assets/index.d.ts
|
|
126
|
+
/**
|
|
127
|
+
* Assets plugin: `app.assets.load(bundle)`, `app.assets.texture(key)`, `app.assets.usage()`.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* // A game names its manifest; the graph decides from there what is loaded and when.
|
|
132
|
+
* const app = createApp({
|
|
133
|
+
* plugins: [...screen, boardFeature],
|
|
134
|
+
* pluginConfigs: { assets: { manifest: "/assets/manifest.json", textureBudgetMb: 192 } }
|
|
135
|
+
* });
|
|
136
|
+
*
|
|
137
|
+
* await app.start();
|
|
138
|
+
* app.assets.usage().textureMb; // 0.188, the boot tier
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
declare const assetsPlugin: import("@moku-labs/core").PluginInstance<"assets", Config$8, State$7, Api$6, {
|
|
142
|
+
"assets:bundle-loaded": {
|
|
143
|
+
bundle: string;
|
|
144
|
+
tier: Tier;
|
|
145
|
+
mb: number;
|
|
146
|
+
reason: LoadReason;
|
|
147
|
+
};
|
|
148
|
+
"assets:bundle-progress": {
|
|
149
|
+
bundle: string;
|
|
150
|
+
loaded: number;
|
|
151
|
+
total: number;
|
|
152
|
+
};
|
|
153
|
+
"assets:bundle-unloaded": {
|
|
154
|
+
bundle: string;
|
|
155
|
+
tier: Tier;
|
|
156
|
+
mb: number;
|
|
157
|
+
reason: "budget" | "request";
|
|
158
|
+
keys: readonly string[];
|
|
159
|
+
};
|
|
160
|
+
}> & Record<never, never>;
|
|
161
|
+
//#endregion
|
|
162
|
+
//#region src/plugins/audio/index.d.ts
|
|
163
|
+
/**
|
|
164
|
+
* Audio plugin: `app.audio`, the handlers of the effect kinds `sfx` and `music`, and the three
|
|
165
|
+
* buses a game drives from its player state.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* // A game composes it next to the screen set and points it at the player's settings.
|
|
170
|
+
* createApp({
|
|
171
|
+
* plugins: [...screen, audioPlugin, settingsFeature],
|
|
172
|
+
* pluginConfigs: { audio: { volumes: player => player.settings.audio } }
|
|
173
|
+
* });
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
declare const audioPlugin: import("@moku-labs/core").PluginInstance<"audio", Config$14, State$13, AudioApi, {}> & Record<never, never>;
|
|
177
|
+
//#endregion
|
|
3
178
|
//#region src/plugins/clock/index.d.ts
|
|
4
179
|
/**
|
|
5
180
|
* Clock plugin: `app.clock.now()`, `app.clock.scheduleAt(moment)`, `app.clock.onElapsed(fn)`.
|
|
6
181
|
*
|
|
7
182
|
* @example
|
|
8
183
|
* ```ts
|
|
9
|
-
*
|
|
184
|
+
* // A game plugin that needs trusted time declares the dependency and asks for the API.
|
|
185
|
+
* const energyPlugin = createPlugin("energy", {
|
|
186
|
+
* depends: [clockPlugin],
|
|
187
|
+
* api: ctx => ({ fullAt: (missing: number) => ctx.require(clockPlugin).now() + missing * 60_000 })
|
|
188
|
+
* });
|
|
10
189
|
* ```
|
|
11
190
|
*/
|
|
12
191
|
declare const clockPlugin: import("@moku-labs/core").PluginInstance<"clock", Config, State, Api, {}> & Record<never, never>;
|
|
@@ -17,7 +196,13 @@ declare const clockPlugin: import("@moku-labs/core").PluginInstance<"clock", Con
|
|
|
17
196
|
*
|
|
18
197
|
* @example
|
|
19
198
|
* ```ts
|
|
20
|
-
*
|
|
199
|
+
* // The game starts the graph itself: an awaited loop in onStart would never let start() resolve.
|
|
200
|
+
* createApp({
|
|
201
|
+
* pluginConfigs: { flow: { mainFlow, safeNode: "home" } },
|
|
202
|
+
* onStart: ctx => {
|
|
203
|
+
* ctx.flow.run().catch(showFatal);
|
|
204
|
+
* }
|
|
205
|
+
* });
|
|
21
206
|
* ```
|
|
22
207
|
*/
|
|
23
208
|
declare const flowPlugin: import("@moku-labs/core").PluginInstance<"flow", Config$1, State$1, Api$1, {
|
|
@@ -46,13 +231,59 @@ declare const flowPlugin: import("@moku-labs/core").PluginInstance<"flow", Confi
|
|
|
46
231
|
};
|
|
47
232
|
}> & Record<never, never>;
|
|
48
233
|
//#endregion
|
|
234
|
+
//#region src/plugins/i18n/index.d.ts
|
|
235
|
+
/**
|
|
236
|
+
* I18n plugin: `app.i18n.format(tr("hud.orders", { n: 3 }))`, and `tr` for the game.
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```ts
|
|
240
|
+
* // A feature ships its compiled modules; the settings screen switches between them.
|
|
241
|
+
* export const hudFeature = defineFeature("hud", {
|
|
242
|
+
* projections: [hud],
|
|
243
|
+
* strings: { ru: ruStrings, en: () => import("./generated/strings.en") }
|
|
244
|
+
* });
|
|
245
|
+
*
|
|
246
|
+
* await app.i18n.setLocale("en"); // text re-resolves every message on i18n:locale-changed
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
declare const i18nPlugin: import("@moku-labs/core").PluginInstance<"i18n", Config$9, State$8, I18nApi, {
|
|
250
|
+
"i18n:locale-changed": {
|
|
251
|
+
locale: string;
|
|
252
|
+
};
|
|
253
|
+
}> & Record<never, never>;
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region src/plugins/input/index.d.ts
|
|
256
|
+
/**
|
|
257
|
+
* Input plugin: `app.input.tap(target)`, `app.input.drag(from, to)`.
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```ts
|
|
261
|
+
* // A view declares its behaviour; the engine owns the drag and the way home.
|
|
262
|
+
* const boardItems = projection({
|
|
263
|
+
* name: "board.items",
|
|
264
|
+
* layer: "items",
|
|
265
|
+
* from: (player: Player) => player.items,
|
|
266
|
+
* key: (item: Item) => item.id,
|
|
267
|
+
* view: (item: Item) => [
|
|
268
|
+
* Draggable({ payload: { from: item.cell } }),
|
|
269
|
+
* DropTarget({ intent: "merge", payload: { to: item.cell } })
|
|
270
|
+
* ]
|
|
271
|
+
* });
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
declare const inputPlugin: import("@moku-labs/core").PluginInstance<"input", Config$10, State$9, InputApi, {}> & Record<never, never>;
|
|
275
|
+
//#endregion
|
|
49
276
|
//#region src/plugins/lifecycle/index.d.ts
|
|
50
277
|
/**
|
|
51
278
|
* Lifecycle plugin: `app.lifecycle.push(reason)`, `app.lifecycle.pop(reason)`.
|
|
52
279
|
*
|
|
53
280
|
* @example
|
|
54
281
|
* ```ts
|
|
55
|
-
*
|
|
282
|
+
* // A game plugin that reacts to the pause declares the dependency and hooks the event.
|
|
283
|
+
* const musicPlugin = createPlugin("music", {
|
|
284
|
+
* depends: [lifecyclePlugin],
|
|
285
|
+
* hooks: () => ({ "lifecycle:changed": ({ paused }) => music.setMuted(paused) })
|
|
286
|
+
* });
|
|
56
287
|
* ```
|
|
57
288
|
*/
|
|
58
289
|
declare const lifecyclePlugin: import("@moku-labs/core").PluginInstance<"lifecycle", Config$2, State$2, Api$2, {
|
|
@@ -71,7 +302,13 @@ declare const lifecyclePlugin: import("@moku-labs/core").PluginInstance<"lifecyc
|
|
|
71
302
|
*
|
|
72
303
|
* @example
|
|
73
304
|
* ```ts
|
|
74
|
-
*
|
|
305
|
+
* // A game plugin that draws from committed state declares the dependency and reads the snapshot.
|
|
306
|
+
* const hudPlugin = createPlugin("hud", {
|
|
307
|
+
* depends: [modelPlugin],
|
|
308
|
+
* hooks: ctx => ({
|
|
309
|
+
* "model:committed": () => drawCoins(ctx.require(modelPlugin).store.snapshot().player)
|
|
310
|
+
* })
|
|
311
|
+
* });
|
|
75
312
|
* ```
|
|
76
313
|
*/
|
|
77
314
|
declare const modelPlugin: import("@moku-labs/core").PluginInstance<"model", Config$3, State$3, {
|
|
@@ -84,17 +321,132 @@ declare const modelPlugin: import("@moku-labs/core").PluginInstance<"model", Con
|
|
|
84
321
|
};
|
|
85
322
|
}> & Record<never, never>;
|
|
86
323
|
//#endregion
|
|
324
|
+
//#region src/plugins/renderer/index.d.ts
|
|
325
|
+
/**
|
|
326
|
+
* Renderer plugin: `app.renderer.host.ready()`, `app.renderer.viewport.size()`,
|
|
327
|
+
* `app.renderer.sync.hitTest(...)`.
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```ts
|
|
331
|
+
* // A game with a screen names the element the canvas goes into. Nothing else is configured.
|
|
332
|
+
* const app = createApp({
|
|
333
|
+
* plugins: [...screen, boardFeature],
|
|
334
|
+
* pluginConfigs: { renderer: { mount: "#game" } }
|
|
335
|
+
* });
|
|
336
|
+
*
|
|
337
|
+
* await app.start();
|
|
338
|
+
* app.renderer.host.kind(); // "webgpu" in Chrome, "webgl" on an older device
|
|
339
|
+
* ```
|
|
340
|
+
*/
|
|
341
|
+
declare const rendererPlugin: import("@moku-labs/core").PluginInstance<"renderer", Config$6, State$5, Api$4, {
|
|
342
|
+
"renderer:device-lost": {
|
|
343
|
+
kind: "webgpu" | "webgl";
|
|
344
|
+
reason: string;
|
|
345
|
+
};
|
|
346
|
+
}> & Record<never, never>;
|
|
347
|
+
//#endregion
|
|
348
|
+
//#region src/plugins/scenes/index.d.ts
|
|
349
|
+
/**
|
|
350
|
+
* Scenes plugin: `app.scenes.current()`, and `defineScene` for the game.
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* ```ts
|
|
354
|
+
* // features/board/view/scene.ts, and the node that shows it.
|
|
355
|
+
* export const boardScene = defineScene("board", {
|
|
356
|
+
* bundle: "board",
|
|
357
|
+
* layers: { cells: {}, items: { sort: "y" }, lifted: {} },
|
|
358
|
+
* projections: [boardCells, boardItems]
|
|
359
|
+
* });
|
|
360
|
+
*
|
|
361
|
+
* export const awaitIntent = defineNode({ scene: "board", rest: true, outcomes: { merge: type() } });
|
|
362
|
+
* ```
|
|
363
|
+
*/
|
|
364
|
+
declare const scenesPlugin: import("@moku-labs/core").PluginInstance<"scenes", Record<string, never>, State$14, ScenesApi, {
|
|
365
|
+
"scenes:changed": {
|
|
366
|
+
from: string | undefined;
|
|
367
|
+
to: string;
|
|
368
|
+
music: string | undefined;
|
|
369
|
+
};
|
|
370
|
+
}> & Record<never, never>;
|
|
371
|
+
//#endregion
|
|
372
|
+
//#region src/plugins/text/index.d.ts
|
|
373
|
+
/**
|
|
374
|
+
* Text plugin: `app.text.measure(...)`, the `Text` component and the helpers `label` and
|
|
375
|
+
* `defineTextStyles` a game writes.
|
|
376
|
+
*
|
|
377
|
+
* @example
|
|
378
|
+
* ```ts
|
|
379
|
+
* // A feature brings its styles; a projection puts a label over an item.
|
|
380
|
+
* export const hudStyles = defineTextStyles({
|
|
381
|
+
* "hud.digits": { font: "ui.font-digits", size: 40, fill: 0xffe082, digits: true }
|
|
382
|
+
* });
|
|
383
|
+
*
|
|
384
|
+
* const app = createApp({ plugins: [...screen, hudFeature] });
|
|
385
|
+
*
|
|
386
|
+
* app.text.styles(); // ["body", "digits", "hud.digits"]
|
|
387
|
+
* ```
|
|
388
|
+
*/
|
|
389
|
+
declare const textPlugin: import("@moku-labs/core").PluginInstance<"text", Config$11, State$10, TextApi, {}> & Record<never, never>;
|
|
390
|
+
//#endregion
|
|
87
391
|
//#region src/plugins/time/index.d.ts
|
|
88
392
|
/**
|
|
89
393
|
* Time plugin: `app.time.onFrame(phase, fn)`, `app.time.step(dt)`.
|
|
90
394
|
*
|
|
91
395
|
* @example
|
|
92
396
|
* ```ts
|
|
93
|
-
*
|
|
397
|
+
* // A game plugin with frame work declares the dependency and registers a callback on start.
|
|
398
|
+
* const sparklePlugin = createPlugin("sparkle", {
|
|
399
|
+
* depends: [timePlugin],
|
|
400
|
+
* onStart: ctx => void ctx.require(timePlugin).onFrame("animate", time => advance(time.delta))
|
|
401
|
+
* });
|
|
94
402
|
* ```
|
|
95
403
|
*/
|
|
96
404
|
declare const timePlugin: import("@moku-labs/core").PluginInstance<"time", Config$4, State$4, Api$3, {}> & Record<never, never>;
|
|
97
405
|
//#endregion
|
|
406
|
+
//#region src/plugins/ui/index.d.ts
|
|
407
|
+
/**
|
|
408
|
+
* Ui plugin: `app.ui.tree()`, `app.ui.find(...)`, `app.ui.lint()`, the components `Box` and
|
|
409
|
+
* `LocalWrite`, and the helpers `defineComponent`, `defineStyle`, `defineTokens` and `popup`.
|
|
410
|
+
*
|
|
411
|
+
* @example
|
|
412
|
+
* ```ts
|
|
413
|
+
* // A headless test reads the HUD and taps the button the popup opened.
|
|
414
|
+
* const app = createApp({ plugins: [...screen, uiPlugin, hudFeature] });
|
|
415
|
+
*
|
|
416
|
+
* app.ui.tree().type; // "row"
|
|
417
|
+
* app.input.tap(app.ui.find("claim") ?? 0);
|
|
418
|
+
* ```
|
|
419
|
+
*/
|
|
420
|
+
declare const uiPlugin: import("@moku-labs/core").PluginInstance<"ui", Config$12, State$11, UiApi, {}> & Record<never, never>;
|
|
421
|
+
//#endregion
|
|
422
|
+
//#region src/plugins/world/index.d.ts
|
|
423
|
+
/**
|
|
424
|
+
* World plugin: `app.world.ecs.query(...)`, `app.world.projection.mount(...)`.
|
|
425
|
+
*
|
|
426
|
+
* @example
|
|
427
|
+
* ```ts
|
|
428
|
+
* // A test drives the screen without a browser: mount, commit, step frames.
|
|
429
|
+
* const app = createApp({ plugins: [worldPlugin, boardFeature] });
|
|
430
|
+
*
|
|
431
|
+
* app.world.projection.setLayers([{ name: "items", sort: "y" }]);
|
|
432
|
+
* app.world.projection.mount(["board.items"], { kind: "plugin", name: "test" });
|
|
433
|
+
* app.world.projection.entityOf("board.items", "i7"); // 1048576
|
|
434
|
+
* ```
|
|
435
|
+
*/
|
|
436
|
+
declare const worldPlugin: import("@moku-labs/core").PluginInstance<"world", Config$7, State$6, Api$5, {
|
|
437
|
+
"world:reconciled": {
|
|
438
|
+
mode: "play" | "direct";
|
|
439
|
+
projections: number;
|
|
440
|
+
entered: number;
|
|
441
|
+
changed: number;
|
|
442
|
+
exited: number;
|
|
443
|
+
revived: number;
|
|
444
|
+
queued: number;
|
|
445
|
+
hintsRouted: number;
|
|
446
|
+
hintsDropped: number;
|
|
447
|
+
};
|
|
448
|
+
}> & Record<never, never>;
|
|
449
|
+
//#endregion
|
|
98
450
|
//#region src/plugins/flow/feature.d.ts
|
|
99
451
|
/**
|
|
100
452
|
* Turns a feature description into a plugin that registers it with `flow.features` in `onInit`.
|
|
@@ -107,10 +459,12 @@ declare const timePlugin: import("@moku-labs/core").PluginInstance<"time", Confi
|
|
|
107
459
|
* @throws {Error} When the name is reserved or belongs to an engine plugin.
|
|
108
460
|
* @example
|
|
109
461
|
* ```ts
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
462
|
+
* // The reward popup is a feature: the main flow only declares slot("afterOrder").
|
|
463
|
+
* export const rewardFeature = defineFeature("reward", {
|
|
464
|
+
* flows: [rewardFlow],
|
|
465
|
+
* contribute: { afterOrder: { flow: rewardFlow, order: 10 } }
|
|
113
466
|
* });
|
|
467
|
+
* createApp({ plugins: [rewardFeature] }); // a headless test passes rewardFeature.logicOnly
|
|
114
468
|
* ```
|
|
115
469
|
*/
|
|
116
470
|
declare function defineFeature(name: string, description: FeatureDescription): FeaturePlugin;
|
|
@@ -125,7 +479,9 @@ declare function defineFeature(name: string, description: FeatureDescription): F
|
|
|
125
479
|
* @returns The hint as plain data.
|
|
126
480
|
* @example
|
|
127
481
|
* ```ts
|
|
482
|
+
* // Inside a node body: sparkle on the merged cell, shown once the edge has committed.
|
|
128
483
|
* fx.emit(hint("sparkle", { cell: "c3" }));
|
|
484
|
+
* // hint("sparkle", { cell: "c3" }) is { kind: "sparkle", payload: { cell: "c3" }, hint: true }
|
|
129
485
|
* ```
|
|
130
486
|
*/
|
|
131
487
|
declare function hint(kind: string, payload?: Json): Hint;
|
|
@@ -138,74 +494,753 @@ declare function hint(kind: string, payload?: Json): Hint;
|
|
|
138
494
|
* @returns The descriptor a node awaits.
|
|
139
495
|
* @example
|
|
140
496
|
* ```ts
|
|
141
|
-
*
|
|
497
|
+
* // Inside a node body, after the rules changed a timer: ask for the next `elapsed`.
|
|
498
|
+
* await fx(schedule(1_790_000_060_000)); // payload: { moment: 1790000060000 }
|
|
499
|
+
* await fx(schedule(undefined)); // payload: {}, the pending timer is cancelled
|
|
142
500
|
* ```
|
|
143
501
|
*/
|
|
144
502
|
declare function schedule(moment: number | undefined): Descriptor;
|
|
145
503
|
/**
|
|
146
504
|
* Creates the tutorial descriptor: it narrows the gate to one answer until the node exits. Its
|
|
147
|
-
* visual part (highlight, hand, text) is
|
|
148
|
-
* a
|
|
505
|
+
* visual part (`target`, highlight, hand, text) is drawn by `ui`, which dims the screen and cuts
|
|
506
|
+
* a hole over the target element. The highlight list and the target are copied, so a later change
|
|
507
|
+
* of the caller's objects cannot reach the descriptor.
|
|
149
508
|
*
|
|
150
509
|
* @param options - The allowed answer and the visual hints.
|
|
151
510
|
* @returns The descriptor a node awaits.
|
|
152
511
|
* @example
|
|
153
512
|
* ```ts
|
|
154
|
-
*
|
|
513
|
+
* // A tutorial node: the popup lists two intents, the guide lets only "ok" through.
|
|
514
|
+
* await fx(guide({ allow: { intent: "ok" }, target: { projection: "hud", key: "play" } }));
|
|
515
|
+
* await fx({ kind: "popup", answers: ["ok", "cancel"] });
|
|
516
|
+
* // app.flow.gate.answer({ intent: "cancel" }) is false until the node exits
|
|
155
517
|
* ```
|
|
156
518
|
*/
|
|
157
519
|
declare function guide(options: GuideOptions): Descriptor;
|
|
158
520
|
//#endregion
|
|
159
|
-
//#region src/
|
|
521
|
+
//#region src/plugins/world/ecs/define.d.ts
|
|
160
522
|
/**
|
|
161
|
-
*
|
|
523
|
+
* Declares a component type. The defaults give the TypeScript type, the JSON shape and the
|
|
524
|
+
* inspector schema; the name is the storage key and the key of `motion.change`.
|
|
525
|
+
*
|
|
526
|
+
* @param name - Storage name, unique per world.
|
|
527
|
+
* @param defaults - Every field with its default value. Plain JSON only.
|
|
528
|
+
* @param options - The fields a plugin owns: a projection view neither writes nor corrects them.
|
|
529
|
+
* @param options.owned - Names of the owned fields.
|
|
530
|
+
* @returns A callable component type.
|
|
531
|
+
* @example
|
|
532
|
+
* ```ts
|
|
533
|
+
* const Item = component("Item", { kind: "", level: 1 });
|
|
534
|
+
* Item({ level: 2 }); // { type: Item, value: { kind: "", level: 2 } }
|
|
535
|
+
* Item({ level: 2 }).type.componentName; // "Item", the storage key
|
|
536
|
+
*
|
|
537
|
+
* // A caption whose drawn string is written by the plugin that draws it.
|
|
538
|
+
* const Caption = component("Caption", { text: "", shown: "" }, { owned: ["shown"] });
|
|
539
|
+
* Caption.owned; // ["shown"]
|
|
540
|
+
* ```
|
|
162
541
|
*/
|
|
542
|
+
declare function component<Value extends object>(name: string, defaults: Value, options?: {
|
|
543
|
+
owned?: ReadonlyArray<keyof Value & string>;
|
|
544
|
+
}): ComponentType<Value>;
|
|
163
545
|
/**
|
|
164
|
-
*
|
|
546
|
+
* Declares a tag: a component with no data, stored as `true`.
|
|
165
547
|
*
|
|
548
|
+
* @param name - Storage name, unique per world.
|
|
549
|
+
* @returns A callable tag type.
|
|
166
550
|
* @example
|
|
167
551
|
* ```ts
|
|
168
|
-
* const
|
|
552
|
+
* const Held = tag("Held");
|
|
553
|
+
* Held(); // { type: Held, value: true }
|
|
554
|
+
* Held().type.componentName; // "Held"
|
|
169
555
|
* ```
|
|
170
556
|
*/
|
|
171
|
-
|
|
557
|
+
declare function tag(name: string): TagType;
|
|
172
558
|
/**
|
|
173
|
-
*
|
|
559
|
+
* Declares a resource: one mutable object per world, created from a deep clone of the defaults
|
|
560
|
+
* on first read.
|
|
174
561
|
*
|
|
175
|
-
* @param
|
|
176
|
-
* @param
|
|
177
|
-
* @
|
|
562
|
+
* @param name - Storage name, unique per world.
|
|
563
|
+
* @param defaults - The value a fresh world starts with.
|
|
564
|
+
* @returns The resource type.
|
|
178
565
|
* @example
|
|
179
566
|
* ```ts
|
|
180
|
-
*
|
|
567
|
+
* const Pointer = resource("Pointer", { x: 0, y: 0, down: false });
|
|
568
|
+
* Pointer.defaults; // { x: 0, y: 0, down: false }
|
|
181
569
|
* ```
|
|
182
570
|
*/
|
|
183
|
-
declare function
|
|
571
|
+
declare function resource<Value extends object>(name: string, defaults: Value): ResourceType<Value>;
|
|
184
572
|
/**
|
|
185
|
-
*
|
|
186
|
-
*
|
|
573
|
+
* Marks a query term as written. The only effect is change detection: every entity the query
|
|
574
|
+
* yields is marked changed for this component.
|
|
187
575
|
*
|
|
188
|
-
* @param
|
|
189
|
-
* @
|
|
190
|
-
* @returns Resolves when the disposer has finished.
|
|
576
|
+
* @param componentType - The component the system writes.
|
|
577
|
+
* @returns The marked term.
|
|
191
578
|
* @example
|
|
192
579
|
* ```ts
|
|
193
|
-
*
|
|
580
|
+
* const Transform = component("Transform", { x: 0, y: 0 });
|
|
581
|
+
* mut(Transform).kind; // "mut"
|
|
194
582
|
* ```
|
|
195
583
|
*/
|
|
196
|
-
declare function
|
|
584
|
+
declare function mut<Value extends object>(componentType: ComponentHandle<Value>): Mut<Value>;
|
|
197
585
|
/**
|
|
198
|
-
*
|
|
586
|
+
* Types a system definition. It returns the same plain object; the work is the type, which reads
|
|
587
|
+
* the query tuple and types the first argument of `run`.
|
|
199
588
|
*
|
|
589
|
+
* @param definition - Name, phase, query and the run function.
|
|
590
|
+
* @returns The same definition, typed.
|
|
200
591
|
* @example
|
|
201
592
|
* ```ts
|
|
202
|
-
*
|
|
593
|
+
* const Transform = component("Transform", { x: 0, y: 0 });
|
|
594
|
+
* const drift = system({
|
|
595
|
+
* name: "drift",
|
|
596
|
+
* phase: "animate",
|
|
597
|
+
* query: [mut(Transform)],
|
|
598
|
+
* run: entities => {
|
|
599
|
+
* for (const [, transform] of entities) transform.x += 1;
|
|
600
|
+
* }
|
|
601
|
+
* });
|
|
602
|
+
* drift.phase; // "animate"
|
|
203
603
|
* ```
|
|
204
604
|
*/
|
|
205
|
-
declare const
|
|
206
|
-
|
|
207
|
-
|
|
605
|
+
declare function system<const Terms extends readonly QueryTerm[]>(definition: SystemDefinition<Terms>): SystemDefinition<Terms>;
|
|
606
|
+
/**
|
|
607
|
+
* The layer a view is drawn in. Written only by the projection; a `view` that returns it is
|
|
608
|
+
* logged and the value ignored.
|
|
609
|
+
*/
|
|
610
|
+
declare const Layer: ComponentType<{
|
|
611
|
+
name: string;
|
|
612
|
+
}>;
|
|
613
|
+
/**
|
|
614
|
+
* Explicit draw order inside a layer sorted by `"order"`.
|
|
615
|
+
*/
|
|
616
|
+
declare const Order: ComponentType<{
|
|
617
|
+
value: number;
|
|
618
|
+
}>;
|
|
619
|
+
/**
|
|
620
|
+
* The view is in the despawn queue: still drawn, never hit-tested.
|
|
621
|
+
*/
|
|
622
|
+
declare const Exiting: TagType;
|
|
623
|
+
/**
|
|
624
|
+
* The element description of a screen: a projection whose `view` returns one node gets it wrapped
|
|
625
|
+
* as this component, and `ui` reconciles the node into child entities. The node is a foreign
|
|
626
|
+
* object, so the world diffs it by identity and `snapshot()` leaves it out.
|
|
627
|
+
*/
|
|
628
|
+
declare const Tree: ComponentType<{
|
|
629
|
+
node: DescriptionNode;
|
|
630
|
+
}>;
|
|
631
|
+
//#endregion
|
|
632
|
+
//#region src/plugins/input/components.d.ts
|
|
633
|
+
/**
|
|
634
|
+
* A gesture that names an intent. `payload` is a plain JSON object of model keys, never an
|
|
635
|
+
* entity id: the flow graph reads it as the payload of the answer.
|
|
636
|
+
*
|
|
637
|
+
* @example
|
|
638
|
+
* ```ts
|
|
639
|
+
* const value: IntentValue = { intent: "merge", payload: { to: "c3" } };
|
|
640
|
+
* ```
|
|
641
|
+
*/
|
|
642
|
+
type IntentValue = {
|
|
643
|
+
intent: string;
|
|
644
|
+
payload: Json;
|
|
645
|
+
};
|
|
646
|
+
/**
|
|
647
|
+
* A view that can be carried. It names no intent: the drop target does.
|
|
648
|
+
*
|
|
649
|
+
* @example
|
|
650
|
+
* ```ts
|
|
651
|
+
* const value: CarryValue = { payload: { from: "c2" } };
|
|
652
|
+
* ```
|
|
653
|
+
*/
|
|
654
|
+
type CarryValue = {
|
|
655
|
+
payload: Json;
|
|
208
656
|
};
|
|
657
|
+
/**
|
|
658
|
+
* Where the one pointer is, in reference units. `justPressed` and `justReleased` are true for
|
|
659
|
+
* exactly one frame.
|
|
660
|
+
*
|
|
661
|
+
* @example
|
|
662
|
+
* ```ts
|
|
663
|
+
* const value: PointerValue = {
|
|
664
|
+
* x: 540, y: 960, down: true, justPressed: false, justReleased: false
|
|
665
|
+
* };
|
|
666
|
+
* ```
|
|
667
|
+
*/
|
|
668
|
+
type PointerValue = {
|
|
669
|
+
x: number;
|
|
670
|
+
y: number;
|
|
671
|
+
down: boolean;
|
|
672
|
+
justPressed: boolean;
|
|
673
|
+
justReleased: boolean;
|
|
674
|
+
};
|
|
675
|
+
/**
|
|
676
|
+
* A tap on this view answers `{ intent, payload }`.
|
|
677
|
+
*/
|
|
678
|
+
declare const Tappable: ComponentType<IntentValue>;
|
|
679
|
+
/**
|
|
680
|
+
* A long press on this view answers `{ intent, payload }`.
|
|
681
|
+
*/
|
|
682
|
+
declare const Pressable: ComponentType<IntentValue>;
|
|
683
|
+
/**
|
|
684
|
+
* This view can be carried by the finger. It names no intent; the drop target does.
|
|
685
|
+
*/
|
|
686
|
+
declare const Draggable: ComponentType<CarryValue>;
|
|
687
|
+
/**
|
|
688
|
+
* A drop on this view answers THIS intent, with the carried payload merged under it.
|
|
689
|
+
*/
|
|
690
|
+
declare const DropTarget: ComponentType<IntentValue>;
|
|
691
|
+
/**
|
|
692
|
+
* A swipe on this view answers `{ intent, payload: { ...payload, direction } }`.
|
|
693
|
+
*/
|
|
694
|
+
declare const Swipeable: ComponentType<IntentValue>;
|
|
695
|
+
/**
|
|
696
|
+
* Takes a press without naming a gesture: the hit test accepts a view that carries only this tag,
|
|
697
|
+
* and a tap on it runs the `onTap` listeners and answers nothing. `ui` tags the buttons that
|
|
698
|
+
* write local state and name no intent.
|
|
699
|
+
*/
|
|
700
|
+
declare const Touchable: TagType;
|
|
701
|
+
/**
|
|
702
|
+
* On the carried view, from grab to release.
|
|
703
|
+
*/
|
|
704
|
+
declare const Held: TagType;
|
|
705
|
+
/**
|
|
706
|
+
* On the topmost drop target under the finger during a drag. At most one, never the held view.
|
|
707
|
+
*/
|
|
708
|
+
declare const Hovered: TagType;
|
|
709
|
+
/**
|
|
710
|
+
* On the pressed view, from pointer down until a tap, a long press, a grab, a swipe or a cancel.
|
|
711
|
+
*/
|
|
712
|
+
declare const Pressed: TagType;
|
|
713
|
+
/**
|
|
714
|
+
* On the topmost view a press would take, while a mouse or a pen moves over it with no press. At
|
|
715
|
+
* most one view carries it, and a touch never hovers. A touch sample, a pointer cancel, the pointer
|
|
716
|
+
* leaving the canvas and a paused world take it away. `ui` reads it as `is.hover`. It is not
|
|
717
|
+
* `Hovered`, which marks the drop target under a drag.
|
|
718
|
+
*/
|
|
719
|
+
declare const PointerOver: TagType;
|
|
720
|
+
/**
|
|
721
|
+
* Where the one pointer is, in reference units. Written once per frame by the frame step.
|
|
722
|
+
*/
|
|
723
|
+
declare const Pointer: ResourceType<PointerValue>;
|
|
724
|
+
//#endregion
|
|
725
|
+
//#region src/plugins/assets/bundles.d.ts
|
|
726
|
+
/**
|
|
727
|
+
* Declares the bundles of one feature. The map is copied, so a later change of the caller's
|
|
728
|
+
* object cannot reach the scanner or the plugin. `defineGame` returns this helper typed by the
|
|
729
|
+
* game's `BundleKey`, so a name the scanner never saw does not compile.
|
|
730
|
+
*
|
|
731
|
+
* @param map - Bundle name to its tier and, when it is a split bundle, its globs.
|
|
732
|
+
* @returns The bundle map as plain data.
|
|
733
|
+
* @example
|
|
734
|
+
* ```ts
|
|
735
|
+
* // features/board/assets.ts of a game: the board is a scene bundle, the chains load on demand.
|
|
736
|
+
* export const boardAssets = defineBundles({
|
|
737
|
+
* board: { tier: "scene" },
|
|
738
|
+
* "board.chains": { tier: "lazy", files: ["chains/*.png"] }
|
|
739
|
+
* });
|
|
740
|
+
* ```
|
|
741
|
+
*/
|
|
742
|
+
declare function defineBundles<Key extends string>(map: Partial<Record<Key, BundleSpec>>): BundleMap<Key>;
|
|
743
|
+
/**
|
|
744
|
+
* Creates the awaited effect that loads one or more bundles. The handler of the kind `"load"` is
|
|
745
|
+
* registered by this plugin and runs in fast mode too, so a fast walk really loads.
|
|
746
|
+
*
|
|
747
|
+
* @param bundle - One bundle name, or a list of them in load order.
|
|
748
|
+
* @returns The descriptor a loading node awaits.
|
|
749
|
+
* @example
|
|
750
|
+
* ```ts
|
|
751
|
+
* // A loading node of a game: one bundle per turn, so the screen can draw progress.
|
|
752
|
+
* await fx(load("board.chains")); // { loaded: ["board.chains"], mb: 1.25 }
|
|
753
|
+
* await fx(load(["board", "ui"])); // both, in that order
|
|
754
|
+
* ```
|
|
755
|
+
*/
|
|
756
|
+
declare function load(bundle: string | readonly string[]): Descriptor;
|
|
757
|
+
//#endregion
|
|
758
|
+
//#region src/plugins/scenes/define.d.ts
|
|
759
|
+
/**
|
|
760
|
+
* Declares a scene: a bundle, named layers in draw order, the projections it mounts and optional
|
|
761
|
+
* music. A layer `ui` is appended for the HUD and the popups unless the scene declares one. The
|
|
762
|
+
* layer names come from the keys of `layers` and that `ui`, so a projection whose `layer` or
|
|
763
|
+
* `lift` is not among them does not compile — and throws here for a caller without types.
|
|
764
|
+
*
|
|
765
|
+
* @param id - Id of the scene. A node names it with `defineNode({ scene: id })`.
|
|
766
|
+
* @param scene - The bundle, the layers, the projections and the optional music key.
|
|
767
|
+
* @returns The scene as frozen data, ready for the `scenes` key of a feature.
|
|
768
|
+
* @throws {Error} For an integer-like layer name, and for a `layer` or `lift` that is not declared.
|
|
769
|
+
* @example
|
|
770
|
+
* ```ts
|
|
771
|
+
* // features/board/view/scene.ts of a game.
|
|
772
|
+
* export const boardScene = defineScene("board", {
|
|
773
|
+
* bundle: "board",
|
|
774
|
+
* layers: { background: {}, cells: {}, items: { sort: "y" }, lifted: {} },
|
|
775
|
+
* projections: [boardCells, boardItems]
|
|
776
|
+
* });
|
|
777
|
+
*
|
|
778
|
+
* boardScene.layers[2]; // { name: "items", sort: "y" }
|
|
779
|
+
* boardScene.layers[4]; // { name: "ui", sort: "none" }, appended for the HUD
|
|
780
|
+
* ```
|
|
781
|
+
*/
|
|
782
|
+
declare function defineScene<Layers extends LayerMap, const Projections extends readonly AnySceneProjection[]>(id: string, scene: SceneSpec<Layers, Projections, string, string>): SceneDefinition;
|
|
783
|
+
//#endregion
|
|
784
|
+
//#region src/plugins/anim/components.d.ts
|
|
785
|
+
/**
|
|
786
|
+
* How many tracks and running timelines name this entity. Written by `anim` while something
|
|
787
|
+
* moves and removed at zero; the inspector and `ui.lint` read it, `anim` itself never does.
|
|
788
|
+
*/
|
|
789
|
+
declare const Animation: ComponentType<{
|
|
790
|
+
playing: number;
|
|
791
|
+
}>;
|
|
792
|
+
//#endregion
|
|
793
|
+
//#region src/plugins/anim/motion.d.ts
|
|
794
|
+
/**
|
|
795
|
+
* The display components a pure `defineMotion` can name. A hook has no context, so it can only
|
|
796
|
+
* reach the components `anim` itself imports: the four of `renderer` that carry numeric fields.
|
|
797
|
+
*
|
|
798
|
+
* @example
|
|
799
|
+
* ```ts
|
|
800
|
+
* type Fields = MotionComponents["Transform"]; // { x: number; y: number; rotation: number; scale: number }
|
|
801
|
+
* ```
|
|
802
|
+
*/
|
|
803
|
+
type MotionComponents = {
|
|
804
|
+
Transform: TransformValue;
|
|
805
|
+
Sprite: SpriteValue;
|
|
806
|
+
NineSlice: NineSliceValue;
|
|
807
|
+
Shape: ShapeValue;
|
|
808
|
+
};
|
|
809
|
+
/**
|
|
810
|
+
* One named pose: the numeric fields it gives each component it names.
|
|
811
|
+
*
|
|
812
|
+
* @example
|
|
813
|
+
* ```ts
|
|
814
|
+
* const hidden: MotionState = { Transform: { scale: 0.8 }, Shape: { alpha: 0 } };
|
|
815
|
+
* ```
|
|
816
|
+
*/
|
|
817
|
+
type MotionState = { readonly [Name in keyof MotionComponents]?: Readonly<Partial<NumericFields<MotionComponents[Name]>>> };
|
|
818
|
+
/**
|
|
819
|
+
* What `defineMotion` is given: the named poses, the keyframe tracks, how long the way takes, and
|
|
820
|
+
* which hooks to build. `on.enter` and `on.exit` name a state or a track. For a track,
|
|
821
|
+
* `transition.ms` is the whole walk and each segment eases by its key, not by `transition.ease`.
|
|
822
|
+
*
|
|
823
|
+
* `loop.track` names a keyframe track that plays from the moment the element enters, forever,
|
|
824
|
+
* added over whatever else moves it: one cycle is `loop.ms` (default `transition.ms`), every
|
|
825
|
+
* Transform key is an offset from rest, and the last key repeats the first one. It is not part of
|
|
826
|
+
* the motion `enter` returns.
|
|
827
|
+
*
|
|
828
|
+
* @example
|
|
829
|
+
* ```ts
|
|
830
|
+
* const spec: MotionSpec = {
|
|
831
|
+
* states: { hidden: { Transform: { scale: 0.8 } } },
|
|
832
|
+
* keyframes: { dropIn: [{ at: 0, Transform: { dy: -780, scale: 0.8 } }, { at: 0.42, Transform: { dy: 14 } }] },
|
|
833
|
+
* transition: { ms: 1000 },
|
|
834
|
+
* on: { enter: "dropIn", exit: "hidden", change: ["Transform"] }
|
|
835
|
+
* };
|
|
836
|
+
* // An order card pops in over 250 ms and sways on its pin, one swing every 2400 ms.
|
|
837
|
+
* const orderCard: MotionSpec = {
|
|
838
|
+
* states: { small: { Transform: { scale: 0.8 } } },
|
|
839
|
+
* keyframes: { sway: [{ at: 0, Transform: { rotation: 0 } }, { at: 0.5, Transform: { rotation: 0.03 } }, { at: 1, Transform: { rotation: 0 } }] },
|
|
840
|
+
* transition: { ms: 250 },
|
|
841
|
+
* loop: { track: "sway", ms: 2400 },
|
|
842
|
+
* on: { enter: "small" }
|
|
843
|
+
* };
|
|
844
|
+
* ```
|
|
845
|
+
*/
|
|
846
|
+
type MotionSpec = {
|
|
847
|
+
readonly states?: Readonly<Record<string, MotionState>>;
|
|
848
|
+
readonly keyframes?: Readonly<Record<string, readonly MotionKeyframe[]>>;
|
|
849
|
+
readonly transition?: {
|
|
850
|
+
readonly ms?: number;
|
|
851
|
+
readonly ease?: Ease;
|
|
852
|
+
};
|
|
853
|
+
readonly loop?: {
|
|
854
|
+
readonly track: string;
|
|
855
|
+
readonly ms?: number;
|
|
856
|
+
};
|
|
857
|
+
readonly on: {
|
|
858
|
+
readonly enter?: string;
|
|
859
|
+
readonly exit?: string;
|
|
860
|
+
readonly change?: readonly (keyof MotionComponents & string)[];
|
|
861
|
+
};
|
|
862
|
+
};
|
|
863
|
+
/**
|
|
864
|
+
* Builds the projection motion hooks of an element from named poses and keyframe tracks. The
|
|
865
|
+
* transition is resolved and every name is checked here, at definition time, so every track it
|
|
866
|
+
* starts carries a concrete duration and a wrong name fails where it is written. A `loop` builds
|
|
867
|
+
* the `loop` hook: `world` and `ui` play it wherever they play `enter`, so a projection view loops
|
|
868
|
+
* once it entered with motion, never after a direct reconcile, and `ui` swaps it when the motion
|
|
869
|
+
* prop of an element changes. One cycle of the loop is `loop.ms`, or `transition.ms` when it is
|
|
870
|
+
* left out.
|
|
871
|
+
*
|
|
872
|
+
* @param spec - The named poses, the keyframe tracks, the transition, the loop and the hooks to
|
|
873
|
+
* build.
|
|
874
|
+
* @returns The `enter`, `loop`, `exit` and `change` hooks. `settle` is left out: the default of
|
|
875
|
+
* `world` applies.
|
|
876
|
+
* @throws {Error} When a track is invalid, a name is both a state and a track, `on` names
|
|
877
|
+
* neither, `loop.track` names no track, `loop.ms` is not a finite number above 0, or the loop
|
|
878
|
+
* ends somewhere else than it starts.
|
|
879
|
+
* @example
|
|
880
|
+
* ```ts
|
|
881
|
+
* const buttonMotion = defineMotion({
|
|
882
|
+
* states: { hidden: { Transform: { scale: 0.8 }, Shape: { alpha: 0 } } },
|
|
883
|
+
* transition: { ms: 150, ease: "out" },
|
|
884
|
+
* on: { enter: "hidden", exit: "hidden", change: ["Transform"] }
|
|
885
|
+
* });
|
|
886
|
+
* buttonMotion.settle; // undefined
|
|
887
|
+
* ```
|
|
888
|
+
*/
|
|
889
|
+
declare function defineMotion(spec: MotionSpec): ProjectionMotion<unknown>;
|
|
890
|
+
//#endregion
|
|
891
|
+
//#region src/plugins/anim/timeline/steps.d.ts
|
|
892
|
+
/**
|
|
893
|
+
* Runs the steps one after another. The remainder past a step's end reaches the next step in the
|
|
894
|
+
* same frame, so the tree takes exactly the sum of its durations.
|
|
895
|
+
*
|
|
896
|
+
* @param steps - The steps, in order.
|
|
897
|
+
* @returns The sequence step.
|
|
898
|
+
* @example
|
|
899
|
+
* ```ts
|
|
900
|
+
* sequence(wait(100), mark("done"));
|
|
901
|
+
* // { kind: "sequence", steps: [{ kind: "wait", ms: 100 }, { kind: "mark", name: "done" }] }
|
|
902
|
+
* ```
|
|
903
|
+
*/
|
|
904
|
+
declare function sequence(...steps: readonly Step[]): Step;
|
|
905
|
+
/**
|
|
906
|
+
* Runs every step at once and ends with the longest one.
|
|
907
|
+
*
|
|
908
|
+
* @param steps - The steps.
|
|
909
|
+
* @returns The parallel step.
|
|
910
|
+
* @example
|
|
911
|
+
* ```ts
|
|
912
|
+
* parallel(wait(100), wait(300)); // ends after 300 ms
|
|
913
|
+
* ```
|
|
914
|
+
*/
|
|
915
|
+
declare function parallel(...steps: readonly Step[]): Step;
|
|
916
|
+
/**
|
|
917
|
+
* Builds one step per item and starts each one `staggerMs` later than the one before. The build
|
|
918
|
+
* function runs here, so no function survives in the data.
|
|
919
|
+
*
|
|
920
|
+
* @param items - What to build a step for.
|
|
921
|
+
* @param staggerMs - Delay between two neighbouring items, in game milliseconds.
|
|
922
|
+
* @param build - Builds the step of one item.
|
|
923
|
+
* @returns The parallel of delayed sequences.
|
|
924
|
+
* @example
|
|
925
|
+
* ```ts
|
|
926
|
+
* stagger(["a", "b"], 60, item => mark(item));
|
|
927
|
+
* // parallel(sequence(wait(0), mark("a")), sequence(wait(60), mark("b")))
|
|
928
|
+
* ```
|
|
929
|
+
*/
|
|
930
|
+
declare function stagger<Item>(items: readonly Item[], staggerMs: number, build: (item: Item, index: number) => Step): Step;
|
|
931
|
+
/**
|
|
932
|
+
* Holds still for a while.
|
|
933
|
+
*
|
|
934
|
+
* @param durationMs - How long to wait, in game milliseconds.
|
|
935
|
+
* @returns The wait step.
|
|
936
|
+
* @example
|
|
937
|
+
* ```ts
|
|
938
|
+
* wait(120); // { kind: "wait", ms: 120 }
|
|
939
|
+
* ```
|
|
940
|
+
*/
|
|
941
|
+
declare function wait(durationMs: number): Step;
|
|
942
|
+
/**
|
|
943
|
+
* Names a point in the choreography. Reaching it emits `anim:mark`, calls the `onMark` listeners
|
|
944
|
+
* and appends the name to `marks()`. It is the only way out of a timeline.
|
|
945
|
+
*
|
|
946
|
+
* @param name - Name of the mark.
|
|
947
|
+
* @returns The mark step.
|
|
948
|
+
* @example
|
|
949
|
+
* ```ts
|
|
950
|
+
* mark("landed"); // { kind: "mark", name: "landed" }
|
|
951
|
+
* ```
|
|
952
|
+
*/
|
|
953
|
+
declare function mark(name: string): Step;
|
|
954
|
+
/**
|
|
955
|
+
* Moves the numeric fields of one component of one target to an exact target value. The component
|
|
956
|
+
* is any handle `world.ecs` takes, so the kit's `Sprite` and `NineSlice` of `defineGame` pass as
|
|
957
|
+
* they are.
|
|
958
|
+
*
|
|
959
|
+
* By default the fields are local: they are written into the target's own `Transform`. With
|
|
960
|
+
* `space: "root"` the `x`, `y`, `rotation` and `scale` of a `Transform` are a root pose, the space
|
|
961
|
+
* `at()` answers in, and are turned into the space of the target's `Parent` when the track starts.
|
|
962
|
+
* That aims a hosted view, such as a board item inside the board slot, at another element. A
|
|
963
|
+
* field the step does not name stays where it is, so under a turned parent name `x` and `y`
|
|
964
|
+
* together. A target without a parent, and a component other than `Transform`, move as in the
|
|
965
|
+
* local space.
|
|
966
|
+
*
|
|
967
|
+
* @param target - The projection key or the entity to animate.
|
|
968
|
+
* @param component - The component to animate.
|
|
969
|
+
* @param to - The numeric target fields.
|
|
970
|
+
* @param options - Duration, easing, delay, the additive flag and the space of the fields.
|
|
971
|
+
* @param options.ms - Duration in game milliseconds.
|
|
972
|
+
* @param options.ease - Easing curve; `"out"` when omitted.
|
|
973
|
+
* @param options.delayMs - How long the track waits before it reads its start values.
|
|
974
|
+
* @param options.additive - `true` adds an offset instead of owning the fields.
|
|
975
|
+
* @param options.space - `"root"` reads the `Transform` fields as a root pose; `"local"` when
|
|
976
|
+
* omitted.
|
|
977
|
+
* @returns The tween step.
|
|
978
|
+
* @example
|
|
979
|
+
* ```ts
|
|
980
|
+
* // An order is delivered: the board item flies out of the scaled board slot onto the order card.
|
|
981
|
+
* const deliverFly = defineAnimation("orders.deliverFly", {
|
|
982
|
+
* slots: { item: type<Target>(), card: type<Target>() },
|
|
983
|
+
* build: ({ item, card }, { at }) =>
|
|
984
|
+
* tween(item, Transform, { x: at(card).x, y: at(card).y, scale: at(card).scale }, {
|
|
985
|
+
* ms: 400, ease: "inCubic", space: "root"
|
|
986
|
+
* })
|
|
987
|
+
* });
|
|
988
|
+
* app.anim.play(deliverFly, {
|
|
989
|
+
* item: { projection: "board.items", key: "i1" },
|
|
990
|
+
* card: { projection: "hud", key: "card0" }
|
|
991
|
+
* });
|
|
992
|
+
* // 400 ms later the item covers the card at the card's size; its Transform stays slot-local
|
|
993
|
+
* ```
|
|
994
|
+
*/
|
|
995
|
+
declare function tween<Value extends object>(target: Target, component: ComponentHandle<Value>, to: Partial<NumericFields<Value>>, options: {
|
|
996
|
+
ms: number;
|
|
997
|
+
ease?: Ease;
|
|
998
|
+
delayMs?: number;
|
|
999
|
+
additive?: boolean;
|
|
1000
|
+
space?: "local" | "root";
|
|
1001
|
+
}): Step;
|
|
1002
|
+
/**
|
|
1003
|
+
* Writes a component patch at once. Any field may be written, not only the numeric ones. The
|
|
1004
|
+
* component is any handle `world.ecs` takes, the kit's `Sprite` and `NineSlice` included.
|
|
1005
|
+
*
|
|
1006
|
+
* @param target - The projection key or the entity to write.
|
|
1007
|
+
* @param component - The component to write.
|
|
1008
|
+
* @param patch - The fields to overwrite.
|
|
1009
|
+
* @returns The set step.
|
|
1010
|
+
* @example
|
|
1011
|
+
* ```ts
|
|
1012
|
+
* set({ projection: "hud", key: "coins" }, Sprite, { texture: "hud.coin-gold" });
|
|
1013
|
+
* // { kind: "set", patch: { texture: "hud.coin-gold" }, ... }
|
|
1014
|
+
* ```
|
|
1015
|
+
*/
|
|
1016
|
+
declare function set<Value extends object>(target: Target, component: ComponentHandle<Value>, patch: Partial<Value>): Step;
|
|
1017
|
+
/**
|
|
1018
|
+
* Plays a frame sprite: one texture key of the list per frame of `fps`, written into `Sprite`.
|
|
1019
|
+
*
|
|
1020
|
+
* @param target - The projection key or the entity to animate.
|
|
1021
|
+
* @param options - The keys, the frame rate and whether the list repeats.
|
|
1022
|
+
* @param options.keys - The texture keys, in play order.
|
|
1023
|
+
* @param options.fps - Frames per second of the list.
|
|
1024
|
+
* @param options.loop - `true` repeats the list until the step is finished.
|
|
1025
|
+
* @returns The frames step.
|
|
1026
|
+
* @example
|
|
1027
|
+
* ```ts
|
|
1028
|
+
* frames({ projection: "board", key: "c3" }, { keys: ["fx.pop-1", "fx.pop-2"], fps: 12 });
|
|
1029
|
+
* // { kind: "frames", keys: ["fx.pop-1", "fx.pop-2"], fps: 12, loop: false, ... }
|
|
1030
|
+
* ```
|
|
1031
|
+
*/
|
|
1032
|
+
declare function frames(target: Target, options: {
|
|
1033
|
+
keys: readonly string[];
|
|
1034
|
+
fps: number;
|
|
1035
|
+
loop?: boolean;
|
|
1036
|
+
}): Step;
|
|
1037
|
+
/**
|
|
1038
|
+
* Makes a temporary entity when the step is reached: a flying coin, a toast sign, a sparkle. The
|
|
1039
|
+
* entity is owned by `anim`, drawn in `layer` at `order`, and despawned when the timeline ends, is
|
|
1040
|
+
* finished or is cancelled. Later steps of the same timeline aim at it with `spawned(id)`.
|
|
1041
|
+
*
|
|
1042
|
+
* @param id - Name of the entity inside this timeline; one timeline spawns each id once.
|
|
1043
|
+
* @param components - The component values the entity starts with, as `world.ecs.spawn` takes.
|
|
1044
|
+
* @param options - Where the entity is drawn.
|
|
1045
|
+
* @param options.layer - The layer; `"ui"` when omitted.
|
|
1046
|
+
* @param options.order - The draw order inside the layer; `0` when omitted.
|
|
1047
|
+
* @returns The spawn step.
|
|
1048
|
+
* @example
|
|
1049
|
+
* ```ts
|
|
1050
|
+
* spawn("coin1", [Sprite({ texture: "ui.icon-coin" }), Transform({ x: 540, y: 900 })], { order: 50 });
|
|
1051
|
+
* // { kind: "spawn", id: "coin1", components: [...], layer: "ui", order: 50 }
|
|
1052
|
+
* ```
|
|
1053
|
+
*/
|
|
1054
|
+
declare function spawn(id: string, components: readonly AnyComponentValue[], options?: {
|
|
1055
|
+
layer?: string;
|
|
1056
|
+
order?: number;
|
|
1057
|
+
}): Step;
|
|
1058
|
+
/**
|
|
1059
|
+
* Aims a later step at the entity a `spawn` step of the same timeline made. Before that step is
|
|
1060
|
+
* reached nothing answers the id, so a step aimed at it ends silently.
|
|
1061
|
+
*
|
|
1062
|
+
* @param id - The id the `spawn` step was given.
|
|
1063
|
+
* @returns The target.
|
|
1064
|
+
* @example
|
|
1065
|
+
* ```ts
|
|
1066
|
+
* tween(spawned("coin1"), Transform, { x: 40, y: 120 }, { ms: 600, ease: "inCubic" });
|
|
1067
|
+
* // { kind: "tween", target: { spawned: "coin1" }, ... }
|
|
1068
|
+
* ```
|
|
1069
|
+
*/
|
|
1070
|
+
declare function spawned(id: string): {
|
|
1071
|
+
spawned: string;
|
|
1072
|
+
};
|
|
1073
|
+
/**
|
|
1074
|
+
* A sound. `anim` owns the descriptor because it sits below `audio`; `audio` owns the handler,
|
|
1075
|
+
* and a game without `audio` plays nothing and hears no error.
|
|
1076
|
+
*
|
|
1077
|
+
* @param key - Asset key of the sound.
|
|
1078
|
+
* @param options - The bus to play it on.
|
|
1079
|
+
* @param options.bus - `"sfx"` when omitted.
|
|
1080
|
+
* @returns The descriptor, usable as a timeline step and as `fx(...)` in a node.
|
|
1081
|
+
* @example
|
|
1082
|
+
* ```ts
|
|
1083
|
+
* sfx("board.merge"); // { kind: "sfx", payload: { key: "board.merge", bus: "sfx" }, cosmetic: true }
|
|
1084
|
+
* ```
|
|
1085
|
+
*/
|
|
1086
|
+
declare function sfx(key: string, options?: {
|
|
1087
|
+
bus?: string;
|
|
1088
|
+
}): SfxDescriptor;
|
|
1089
|
+
/**
|
|
1090
|
+
* A haptic tick. `platform` owns the handler; a device without one stays still.
|
|
1091
|
+
*
|
|
1092
|
+
* @param kind - Which tick to play, for example `"light"`.
|
|
1093
|
+
* @returns The descriptor, usable as a timeline step and as `fx(...)` in a node.
|
|
1094
|
+
* @example
|
|
1095
|
+
* ```ts
|
|
1096
|
+
* haptic("light"); // { kind: "haptic", payload: { kind: "light" }, cosmetic: true }
|
|
1097
|
+
* ```
|
|
1098
|
+
*/
|
|
1099
|
+
declare function haptic(kind: string): HapticDescriptor;
|
|
1100
|
+
/**
|
|
1101
|
+
* Reserved for Spine and the other external players. It throws until one arrives, so nobody
|
|
1102
|
+
* builds a choreography on a door that is not open yet.
|
|
1103
|
+
*
|
|
1104
|
+
* @param _player - The player that would run the clip.
|
|
1105
|
+
* @param _clip - Name of the clip.
|
|
1106
|
+
* @throws {Error} Always.
|
|
1107
|
+
* @example
|
|
1108
|
+
* ```ts
|
|
1109
|
+
* external(spine, "idle"); // throws: External players arrive with Spine.
|
|
1110
|
+
* ```
|
|
1111
|
+
*/
|
|
1112
|
+
declare function external(_player: ExternalPlayer, _clip: string): never;
|
|
1113
|
+
/**
|
|
1114
|
+
* Nests one animation inside another. The nested tree is built here, so its marks are reported
|
|
1115
|
+
* under the nested id and no function survives in the data. Pass the outer `tools` when the
|
|
1116
|
+
* nested `build` reads `at`.
|
|
1117
|
+
*
|
|
1118
|
+
* @param animation - The animation to nest.
|
|
1119
|
+
* @param slots - One target, or a list of targets, per slot of the nested animation.
|
|
1120
|
+
* @param tools - The build tools of the outer animation; without them `at` is the identity pose.
|
|
1121
|
+
* @returns The use step.
|
|
1122
|
+
* @example
|
|
1123
|
+
* ```ts
|
|
1124
|
+
* use(popCard, { card: { projection: "hud", key: "order" } });
|
|
1125
|
+
* // { kind: "use", id: "hud.popCard", step: { kind: "sequence", ... } }
|
|
1126
|
+
* ```
|
|
1127
|
+
*/
|
|
1128
|
+
declare function use<Tags extends SlotTags>(animation: AnimationDefinition<Tags>, slots: SlotValues<Tags>, tools?: BuildTools): Step;
|
|
1129
|
+
/**
|
|
1130
|
+
* The effect descriptor a node awaits to play a choreography. The payload names the animation,
|
|
1131
|
+
* so the handler resolves the definition from the registry the features filled.
|
|
1132
|
+
*
|
|
1133
|
+
* @param animation - The animation to play.
|
|
1134
|
+
* @param slots - One target, or a list of targets, per slot.
|
|
1135
|
+
* @returns The descriptor, cosmetic, so a failing build never breaks the node.
|
|
1136
|
+
* @example
|
|
1137
|
+
* ```ts
|
|
1138
|
+
* play(coinsFly, { from: { projection: "hud", key: "purse" } });
|
|
1139
|
+
* // { kind: "play", payload: { animation: "hud.coinsFly", slots: { from: { ... } } }, cosmetic: true }
|
|
1140
|
+
* ```
|
|
1141
|
+
*/
|
|
1142
|
+
declare function play<Tags extends SlotTags>(animation: AnimationDefinition<Tags>, slots: SlotValues<Tags>): PlayDescriptor;
|
|
1143
|
+
/**
|
|
1144
|
+
* Declares one animation: an id, the slots it takes and the pure function that builds its step
|
|
1145
|
+
* tree. `build` runs once per play, so the same animation may play twice at once.
|
|
1146
|
+
*
|
|
1147
|
+
* @param id - Animation id, unique across the features of a game.
|
|
1148
|
+
* @param spec - The slots and the build function.
|
|
1149
|
+
* @returns The animation as frozen plain data.
|
|
1150
|
+
* @example
|
|
1151
|
+
* ```ts
|
|
1152
|
+
* const coinsFly = defineAnimation("hud.coinsFly", {
|
|
1153
|
+
* slots: { from: type<Target>() },
|
|
1154
|
+
* build: ({ from }) => tween(from, Transform, { scale: 0.4 }, { ms: 600 })
|
|
1155
|
+
* });
|
|
1156
|
+
* coinsFly.id; // "hud.coinsFly"
|
|
1157
|
+
* ```
|
|
1158
|
+
*/
|
|
1159
|
+
declare function defineAnimation<Tags extends SlotTags>(id: string, spec: AnimationSpec<Tags>): AnimationDefinition<Tags>;
|
|
1160
|
+
//#endregion
|
|
1161
|
+
//#region src/plugins/i18n/tr.d.ts
|
|
1162
|
+
/**
|
|
1163
|
+
* Builds a message. The result is frozen and the parameters are copied, so the caller's object
|
|
1164
|
+
* stays its own and nothing downstream can rewrite a label in place.
|
|
1165
|
+
*
|
|
1166
|
+
* @param key - The message key, one of the keys `compileStrings` generated.
|
|
1167
|
+
* @param params - The parameters the message declares. An element parameter is kept as it is.
|
|
1168
|
+
* @returns The message, frozen.
|
|
1169
|
+
* @example
|
|
1170
|
+
* ```ts
|
|
1171
|
+
* tr("hud.orders", { n: 3 }); // { key: "hud.orders", params: { n: 3 } }
|
|
1172
|
+
* tr("orders.complete"); // { key: "orders.complete" }
|
|
1173
|
+
* ```
|
|
1174
|
+
*/
|
|
1175
|
+
declare function tr(key: string, params?: Record<string, Argument>): Message;
|
|
1176
|
+
//#endregion
|
|
1177
|
+
//#region src/plugins/ui/styles/define.d.ts
|
|
1178
|
+
/**
|
|
1179
|
+
* Declares one style. The work is the type: a field outside the vocabulary, or a value outside
|
|
1180
|
+
* its union, is an error where the style is written, not where it is used.
|
|
1181
|
+
*
|
|
1182
|
+
* @param style - The style, with its `is` and `when` variants.
|
|
1183
|
+
* @returns The same object, frozen.
|
|
1184
|
+
* @example
|
|
1185
|
+
* ```ts
|
|
1186
|
+
* defineStyle({ direction: "row", gap: 12 }).gap; // 12
|
|
1187
|
+
* ```
|
|
1188
|
+
*/
|
|
1189
|
+
declare function defineStyle<const Given extends Style>(style: Given): Readonly<Given>;
|
|
1190
|
+
//#endregion
|
|
1191
|
+
//#region src/plugins/ui/styles/resolve.d.ts
|
|
1192
|
+
/**
|
|
1193
|
+
* The flags one element is resolved against: the viewport flags of the frame plus its own state.
|
|
1194
|
+
*
|
|
1195
|
+
* @example
|
|
1196
|
+
* ```ts
|
|
1197
|
+
* const flags: StyleFlags = {
|
|
1198
|
+
* portrait: true, landscape: false, tall: false, wide: false,
|
|
1199
|
+
* pressed: false, hover: false, focus: false, disabled: false, active: true, selected: false,
|
|
1200
|
+
* covered: false
|
|
1201
|
+
* };
|
|
1202
|
+
* ```
|
|
1203
|
+
*/
|
|
1204
|
+
type StyleFlags = WhenFlags & IsFlags;
|
|
1205
|
+
/**
|
|
1206
|
+
* Resolves one style against the flags of the frame and the viewport.
|
|
1207
|
+
*
|
|
1208
|
+
* @param style - The style a game wrote, or nothing.
|
|
1209
|
+
* @param flags - The four viewport flags and the seven state flags. While `disabled` is true the
|
|
1210
|
+
* `hover` and `pressed` variants are skipped.
|
|
1211
|
+
* @param viewport - What `renderer.viewport.size()` answered, for the safe-area tokens.
|
|
1212
|
+
* @returns The frozen style the layout and the visual are written from.
|
|
1213
|
+
* @example
|
|
1214
|
+
* ```ts
|
|
1215
|
+
* resolve(
|
|
1216
|
+
* { gap: 8, is: { pressed: { gap: 4 } } },
|
|
1217
|
+
* { portrait: true, landscape: false, tall: false, wide: false,
|
|
1218
|
+
* pressed: true, hover: false, focus: false, disabled: false, active: false, selected: false,
|
|
1219
|
+
* covered: false },
|
|
1220
|
+
* { width: 1080, height: 1920, scale: 1, orientation: "portrait",
|
|
1221
|
+
* safeArea: { top: 0, right: 0, bottom: 0, left: 0 } }
|
|
1222
|
+
* ).gap; // 4
|
|
1223
|
+
* ```
|
|
1224
|
+
*/
|
|
1225
|
+
declare function resolve(style: Style | undefined, flags: StyleFlags, viewport: ViewportSize): ResolvedStyle;
|
|
1226
|
+
//#endregion
|
|
1227
|
+
//#region src/plugins/audio/descriptors.d.ts
|
|
1228
|
+
/**
|
|
1229
|
+
* Creates the awaited effect that switches the music track. The same key as the one playing does
|
|
1230
|
+
* nothing, and `null` fades the current track out. An absent `fadeMs` leaves the key out of the
|
|
1231
|
+
* payload, so the descriptor stays plain JSON and the plugin's `musicFadeMs` decides at play time.
|
|
1232
|
+
*
|
|
1233
|
+
* @param key - Asset key of an `.mp3`, or `null` to stop the music.
|
|
1234
|
+
* @param options - `fadeMs` overrides the configured cross-fade for this switch.
|
|
1235
|
+
* @returns The descriptor a node awaits, frozen.
|
|
1236
|
+
* @example
|
|
1237
|
+
* ```ts
|
|
1238
|
+
* // A node of a game: the menu goes quiet before the ending cinematic starts.
|
|
1239
|
+
* await fx(music(null, { fadeMs: 1500 }));
|
|
1240
|
+
* // music("board.theme") is { kind: "music", payload: { key: "board.theme" }, cosmetic: true }
|
|
1241
|
+
* ```
|
|
1242
|
+
*/
|
|
1243
|
+
declare function music(key: string | null, options?: MusicOptions): Descriptor;
|
|
209
1244
|
//#endregion
|
|
210
1245
|
//#region src/index.d.ts
|
|
211
1246
|
/**
|
|
@@ -213,7 +1248,11 @@ declare const teardown: {
|
|
|
213
1248
|
*
|
|
214
1249
|
* @example
|
|
215
1250
|
* ```ts
|
|
216
|
-
*
|
|
1251
|
+
* // The entry point of a game. The graph is started by the game, never by the plugin.
|
|
1252
|
+
* const app = createApp({
|
|
1253
|
+
* pluginConfigs: { flow: { mainFlow, safeNode: "home" } },
|
|
1254
|
+
* onStart: ctx => void ctx.flow.run().catch(error => ctx.log.error("game: failed", { error }))
|
|
1255
|
+
* });
|
|
217
1256
|
* ```
|
|
218
1257
|
*/
|
|
219
1258
|
declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs/core").AnyPluginInstance[] = readonly []>(options?: import("@moku-labs/core").CreateAppOptions<Config$5, Events, (import("@moku-labs/core").PluginInstance<"time", Config$4, State$4, Api$3, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"lifecycle", Config$2, State$2, Api$2, {
|
|
@@ -302,26 +1341,141 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
|
|
|
302
1341
|
*
|
|
303
1342
|
* @example
|
|
304
1343
|
* ```ts
|
|
305
|
-
*
|
|
1344
|
+
* // A game plugin that writes every edge of the graph to the log.
|
|
1345
|
+
* export const edgeLog = createPlugin("edgeLog", {
|
|
1346
|
+
* depends: [flowPlugin],
|
|
1347
|
+
* hooks: ctx => ({ "flow:edge": ({ node, outcome }) => ctx.log.info("edge", { node, outcome }) })
|
|
1348
|
+
* });
|
|
306
1349
|
* ```
|
|
307
1350
|
*/
|
|
308
1351
|
declare const createPlugin: import("@moku-labs/core").BoundCreatePluginFunction<Config$5, Events, import("@moku-labs/core").CoreApisFromTuple<[import("@moku-labs/core").CorePluginInstance<"log", import("@moku-labs/common/browser").LogConfig, import("@moku-labs/common/browser").LogState, import("@moku-labs/common/browser").LogApi>, import("@moku-labs/core").CorePluginInstance<"env", import("@moku-labs/common/browser").EnvConfig, import("@moku-labs/common/browser").EnvState, import("@moku-labs/common/browser").EnvApi>]>>;
|
|
309
1352
|
/**
|
|
310
|
-
* Binds the authoring helpers to the types of one game: "createApp for a game".
|
|
311
|
-
*
|
|
312
|
-
*
|
|
1353
|
+
* Binds the authoring helpers to the types of one game: "createApp for a game". Each plugin binds
|
|
1354
|
+
* its own helpers (`flowFor`, `projectionFor`, `componentsFor`, `bundlesFor`, `scenesFor`); this
|
|
1355
|
+
* only spreads them, so the kit's type is inferred and never written by hand. At run time these
|
|
1356
|
+
* are the same functions and component objects the plugins export.
|
|
313
1357
|
*
|
|
314
|
-
* @returns The helpers typed with the game's `player` and `
|
|
1358
|
+
* @returns The helpers typed with the game's `player`, `session`, `assets`, `bundles` and `strings`.
|
|
315
1359
|
* @example
|
|
316
1360
|
* ```ts
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
* session: Session;
|
|
320
|
-
* assets: AssetKey;
|
|
321
|
-
* strings: StringTable;
|
|
322
|
-
* }>();
|
|
1361
|
+
* // kit.ts of a game: bound once, imported by every node, flow and view file.
|
|
1362
|
+
* export const { defineNode, defineFlow, defineFeature, projection, sprite, Sprite, defineBundles, load, defineScene } =
|
|
1363
|
+
* defineGame<{ player: Player; session: Session; assets: AssetKey; bundles: BundleKey; strings: StringTable }>();
|
|
323
1364
|
* ```
|
|
324
1365
|
*/
|
|
325
|
-
declare function defineGame<Types extends GameTypes>():
|
|
1366
|
+
declare function defineGame<Types extends GameTypes>(): {
|
|
1367
|
+
music: MusicDescriptor<Types["assets"]>;
|
|
1368
|
+
defineComponent: typeof defineComponent;
|
|
1369
|
+
defineStyle: <const Given extends Style<Types["assets"]>>(style: Given) => Readonly<Given>;
|
|
1370
|
+
defineTokens: typeof defineTokens;
|
|
1371
|
+
popup: <Properties extends object, Local extends object>(component: PopupComponent<Properties, Local>, props: Properties, options?: {
|
|
1372
|
+
over?: string;
|
|
1373
|
+
}) => Descriptor;
|
|
1374
|
+
intrinsics: IntrinsicElementsFor<Types["assets"], TextStylesOf<Types>, Extract<keyof Types["strings"], string>>;
|
|
1375
|
+
label: (options: Omit<LabelOptions, "style"> & {
|
|
1376
|
+
style: TextStylesOf<Types>;
|
|
1377
|
+
}) => ReturnType<typeof label>;
|
|
1378
|
+
defineTextStyles: (map: Record<string, Omit<TextStyleInput, "bold" | "font" | "italic"> & {
|
|
1379
|
+
font: Types["assets"];
|
|
1380
|
+
} & {
|
|
1381
|
+
bold?: Types["assets"];
|
|
1382
|
+
italic?: Types["assets"];
|
|
1383
|
+
}>) => TextStyles;
|
|
1384
|
+
tr: TypedTr<Types["strings"]>;
|
|
1385
|
+
defineAnimation: typeof defineAnimation;
|
|
1386
|
+
frames: (target: Target, options: {
|
|
1387
|
+
keys: readonly Types["assets"][];
|
|
1388
|
+
fps: number;
|
|
1389
|
+
loop?: boolean;
|
|
1390
|
+
}) => Step;
|
|
1391
|
+
sfx: (key: Types["assets"], options?: {
|
|
1392
|
+
bus?: string;
|
|
1393
|
+
}) => SfxDescriptor;
|
|
1394
|
+
play: typeof play;
|
|
1395
|
+
defineScene: DefineScene<Types["assets"], BundlesOf<Types>>;
|
|
1396
|
+
defineBundles: DefineBundles<BundlesOf<Types>>;
|
|
1397
|
+
load: LoadBundles<BundlesOf<Types>>;
|
|
1398
|
+
sprite: (options: Omit<SpriteOptions, "texture"> & {
|
|
1399
|
+
texture: Types["assets"];
|
|
1400
|
+
}) => ReturnType<typeof sprite>;
|
|
1401
|
+
Sprite: Narrowed<SpriteValue, Partial<Omit<SpriteValue, "texture">> & {
|
|
1402
|
+
texture?: Types["assets"];
|
|
1403
|
+
}>;
|
|
1404
|
+
NineSlice: Narrowed<NineSliceValue, Partial<Omit<NineSliceValue, "texture">> & {
|
|
1405
|
+
texture?: Types["assets"];
|
|
1406
|
+
}>;
|
|
1407
|
+
projection: ProjectionFor<Types["player"], Types["session"]>;
|
|
1408
|
+
defineNode: DefineNode<{
|
|
1409
|
+
player: Types["player"];
|
|
1410
|
+
session: Types["session"];
|
|
1411
|
+
scenes: SceneIdOf<Types>;
|
|
1412
|
+
}>;
|
|
1413
|
+
defineFlow: typeof defineFlow;
|
|
1414
|
+
defineFeature: (name: string, description: FeatureDescription) => FeaturePlugin;
|
|
1415
|
+
};
|
|
1416
|
+
/**
|
|
1417
|
+
* The screen plugins, in dependency order. A game with a screen spreads them into `plugins`;
|
|
1418
|
+
* a headless test leaves them out. V2: `world`, `renderer`, `input`, `assets`, `scenes`. V3 appends `anim`, `i18n`, `text`, `ui`; `audio` stays opt-in: `[...screen, audioPlugin]`.
|
|
1419
|
+
*
|
|
1420
|
+
* @example
|
|
1421
|
+
* ```ts
|
|
1422
|
+
* createApp({ plugins: [...screen, boardFeature], pluginConfigs: { renderer: { mount: "#game" } } });
|
|
1423
|
+
* ```
|
|
1424
|
+
*/
|
|
1425
|
+
declare const screen: readonly [import("@moku-labs/core").PluginInstance<"world", Config$7, State$6, Api$5, {
|
|
1426
|
+
"world:reconciled": {
|
|
1427
|
+
mode: "play" | "direct";
|
|
1428
|
+
projections: number;
|
|
1429
|
+
entered: number;
|
|
1430
|
+
changed: number;
|
|
1431
|
+
exited: number;
|
|
1432
|
+
revived: number;
|
|
1433
|
+
queued: number;
|
|
1434
|
+
hintsRouted: number;
|
|
1435
|
+
hintsDropped: number;
|
|
1436
|
+
};
|
|
1437
|
+
}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"renderer", Config$6, State$5, Api$4, {
|
|
1438
|
+
"renderer:device-lost": {
|
|
1439
|
+
kind: "webgpu" | "webgl";
|
|
1440
|
+
reason: string;
|
|
1441
|
+
};
|
|
1442
|
+
}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"input", Config$10, State$9, InputApi, {}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"assets", Config$8, State$7, Api$6, {
|
|
1443
|
+
"assets:bundle-loaded": {
|
|
1444
|
+
bundle: string;
|
|
1445
|
+
tier: Tier;
|
|
1446
|
+
mb: number;
|
|
1447
|
+
reason: LoadReason;
|
|
1448
|
+
};
|
|
1449
|
+
"assets:bundle-progress": {
|
|
1450
|
+
bundle: string;
|
|
1451
|
+
loaded: number;
|
|
1452
|
+
total: number;
|
|
1453
|
+
};
|
|
1454
|
+
"assets:bundle-unloaded": {
|
|
1455
|
+
bundle: string;
|
|
1456
|
+
tier: Tier;
|
|
1457
|
+
mb: number;
|
|
1458
|
+
reason: "budget" | "request";
|
|
1459
|
+
keys: readonly string[];
|
|
1460
|
+
};
|
|
1461
|
+
}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"scenes", Record<string, never>, State$14, ScenesApi, {
|
|
1462
|
+
"scenes:changed": {
|
|
1463
|
+
from: string | undefined;
|
|
1464
|
+
to: string;
|
|
1465
|
+
music: string | undefined;
|
|
1466
|
+
};
|
|
1467
|
+
}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"anim", Config$13, State$12, AnimApi, {
|
|
1468
|
+
"anim:mark": {
|
|
1469
|
+
animation: string;
|
|
1470
|
+
mark: string;
|
|
1471
|
+
};
|
|
1472
|
+
"anim:finished": {
|
|
1473
|
+
animation: string;
|
|
1474
|
+
};
|
|
1475
|
+
}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"i18n", Config$9, State$8, I18nApi, {
|
|
1476
|
+
"i18n:locale-changed": {
|
|
1477
|
+
locale: string;
|
|
1478
|
+
};
|
|
1479
|
+
}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"text", Config$11, State$10, TextApi, {}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"ui", Config$12, State$11, UiApi, {}> & Record<never, never>];
|
|
326
1480
|
//#endregion
|
|
327
|
-
export { types_d_exports as
|
|
1481
|
+
export { types_d_exports as Anim, Animation, types_d_exports$1 as Assets, types_d_exports$2 as Audio, Box, types_d_exports$3 as Clock, type DescriptionNode, Display, Draggable, DropTarget, Exiting, types_d_exports$4 as Flow, Held, Hovered, types_d_exports$5 as I18n, types_d_exports$6 as Input, Layer, types_d_exports$7 as Lifecycle, LocalWrite, types_d_exports$8 as Model, NineSlice, Order, Parent, Pointer, PointerOver, Pressable, Pressed, types_d_exports$9 as Renderer, SaveUnreadableError, types_d_exports$10 as Scenes, Shape, Sprite, Swipeable, Tappable, Text, types_d_exports$11 as TextTypes, types_d_exports$12 as Time, Touchable, Transform, Tree, types_d_exports$13 as Ui, types_d_exports$14 as World, animPlugin, assetsPlugin, audioPlugin, clockPlugin, component, createApp, createPlugin, defineAnimation, defineBundles, defineComponent, defineFeature, defineGame, defineMotion, defineScene, defineStyle, defineTextStyles, defineTokens, exit, external, flowPlugin, frames, guide, haptic, hint, i18nPlugin, inputPlugin, label, lifecyclePlugin, load, mark, modelPlugin, music, mut, parallel, play, popup, projection, rendererPlugin, resolve, resource, scenesPlugin, schedule, screen, sequence, set, sfx, slot, spawn, spawned, sprite, stagger, system, tag, textPlugin, timePlugin, to, tr, tween, type, uiPlugin, use, wait, worldPlugin };
|