@moku-labs/game 0.14.11 → 0.14.13

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.
Files changed (56) hide show
  1. package/README.md +13 -12
  2. package/dist/app/page.d.mts +8 -3
  3. package/dist/app/page.mjs +57 -12
  4. package/dist/app/system.d.mts +5 -3
  5. package/dist/app/system.mjs +2 -0
  6. package/dist/app.d.mts +15 -7
  7. package/dist/app.mjs +131 -27
  8. package/dist/{assets-BrKSg1O6.mjs → assets-CEMfBogh.mjs} +471 -120
  9. package/dist/assets.d.mts +30 -13
  10. package/dist/assets.mjs +1 -1
  11. package/dist/cli.d.mts +105 -8
  12. package/dist/cli.mjs +1036 -128
  13. package/dist/{commands-d5Zlh9hf.d.mts → commands-DAETmK86.d.mts} +43 -7
  14. package/dist/{config-CdARrrhU.mjs → config-B87aFTW-.mjs} +25 -4
  15. package/dist/control.d.mts +130 -17
  16. package/dist/control.mjs +4 -4
  17. package/dist/{define-BN15lAWb.d.mts → define-BASd9ZUh.d.mts} +32 -4
  18. package/dist/dev-DbHgx-R-.mjs +89 -0
  19. package/dist/{fake-MpzwZhIZ.mjs → fake-6mazmHK3.mjs} +20 -2
  20. package/dist/features-DowEilZm.mjs +266 -0
  21. package/dist/{headless-CrhefcLu.d.mts → headless-cFveciuY.d.mts} +1 -1
  22. package/dist/hot.d.mts +4 -2
  23. package/dist/hot.mjs +7 -4
  24. package/dist/{index-0GIP3tgm.d.mts → index-DedbED3T.d.mts} +317 -69
  25. package/dist/index.d.mts +5 -6
  26. package/dist/index.mjs +3 -3
  27. package/dist/inspect.d.mts +12 -7
  28. package/dist/inspect.mjs +2 -2
  29. package/dist/jsx-dev-runtime.d.mts +1 -1
  30. package/dist/jsx-runtime.d.mts +1 -1
  31. package/dist/lint.d.mts +8 -3
  32. package/dist/lint.mjs +432 -20
  33. package/dist/project.d.mts +15 -1
  34. package/dist/project.mjs +1 -1
  35. package/dist/{run-Bf2hKyjZ.mjs → run-BbipFRc6.mjs} +250 -51
  36. package/dist/{runtime-aLkoeoGj.d.mts → runtime-DoSlRx8X.d.mts} +1 -1
  37. package/dist/{session-DgukhR_7.mjs → session-CeKgO2hy.mjs} +30 -2
  38. package/dist/{sources-Duzj6lhV.mjs → sources-Cdvb0rOS.mjs} +33 -6
  39. package/dist/{src-Do697seR.mjs → src-BEbJ_sSx.mjs} +29154 -11121
  40. package/dist/testing.d.mts +119 -14
  41. package/dist/testing.mjs +97 -7
  42. package/dist/{types-BZa187kz.d.mts → types-7GXcXxxv.d.mts} +196 -242
  43. package/dist/{types-BT9S_Lo2.d.mts → types-BGcda5Le.d.mts} +4464 -735
  44. package/dist/{types-yiHtzg1Y.d.mts → types-C73hbmxi.d.mts} +129 -17
  45. package/dist/{types-Bc9AvZVO.d.mts → types-DngFQJro.d.mts} +43 -5
  46. package/dist/{types-kNiV7iFj.d.mts → types-GHE4J5Uf.d.mts} +1027 -192
  47. package/dist/{visual-dMW8iqAE.mjs → visual-2m4wJL_z.mjs} +111 -7
  48. package/dist/visual-_XhoGeIC.d.mts +345 -0
  49. package/dist/visual.d.mts +1 -332
  50. package/dist/visual.mjs +130 -20
  51. package/dist/{watch-CWI_on4T.mjs → watch-BEdrp80i.mjs} +149 -30
  52. package/llms.txt +103 -51
  53. package/package.json +8 -6
  54. package/dist/dev-Cc50Dk7H.mjs +0 -47
  55. package/dist/memory-DR1ibF_s.d.mts +0 -50
  56. package/dist/types-DMoi447V.d.mts +0 -656
@@ -1,7 +1,6 @@
1
- import { $ as DescriptionNode, A as Api$6, B as ComponentType, Et as FeatureDescription, Ft as SceneIdOf, G as Mut, Gt as State$2, J as QueryTerm, Jt as Config$5, K as Narrowed, Lt as Descriptor, N as State$8, Qt as State$5, R as ComponentHandle, Rt as GuideOptions, Sn as Require, Ut as Config$2, V as ComponentValue, Vt as Api$1, X as SystemDefinition, Xt as Json, Y as ResourceType, Z as TagType, Zt as Root, _n as State$7, a as Config$1, at as NumericFields, bn as Config$9, c as LoadBundles, d as State$1, dn as Events, dt as Api$2, en as Patch, et as Ease, f as Tier, fn as PauseReason, ft as BundlesOf, g as Config$6, gn as Config$7, gt as GameTypes, h as Api$4, hn as Api$5, ht as FeaturePlugin, i as BundleSpec, j as Config$8, k as ViewportSize, kt as DefineNode, l as LoadReason, ln as Api$3, mt as EmitterIdOf, o as DefineBundles, on as StoreApi, ot as ProjectionMotion, pn as State$4, pt as Config$3, r as BundleMap, sn as RngApi, st as ProjectionSpec, t as Api, un as Config$4, vt as State$3, x as State$6, xn as Events$1, xt as defineFlow, yt as TextStylesOf, zt as Hint } from "./types-BT9S_Lo2.mjs";
2
- import { A as SfxDescriptor, C as Config$10, D as Target, E as State$9, N as defineAnimation, S as AnimPlayerValue, T as MotionKeyframe, _ as SceneSpec, a as AudioApi, c as MusicDescriptor, d as State$10, g as SceneDefinition, h as LayerMap, j as Step, k as HapticKind, l as MusicOptions, m as DefineScene, n as State$12, p as AnySceneProjection, r as UiApi, s as Config$11, t as Config$12, v as ScenesApi, w as FramesValue, x as AnimApi, y as State$11, z as play } from "./types-kNiV7iFj.mjs";
3
- import { _ as NoiseValue, c as EmitterValue, d as ColorMatrixValue, f as DisplacementValue, g as GlowValue, h as FilterValueOf, i as State$13, l as AlphaValue, m as FilterSpec, n as EffectsApi, o as EmitterConfig, p as FilterComponent, s as EmitterDefinition, t as Config$13, u as BlurValue, v as OutlineValue, y as UniformDeclaration } from "./types-DMoi447V.mjs";
4
- import { A as InputApi, B as SpriteOptions, E as TextValue, F as NineSliceValue, G as Argument, J as IntlKit, K as Config$14, O as defineComponent, Q as TypedTr, R as ShapeValue, S as TextBind, T as TextStyles, U as TransformValue, V as SpriteValue, W as sprite, X as Part, Y as Message, Z as State$14, _ as Config$16, b as State$16, et as IsFlags, f as defineTokens, g as BindOptions, h as BindField, it as WhenFlags, j as State$15, k as Config$15, nt as Style, p as IntrinsicElementsFor, q as I18nApi, s as PopupComponent, tt as ResolvedStyle, v as CountdownValue, w as TextStyleInput, x as TextApi, y as Point } from "./types-BZa187kz.mjs";
1
+ import { An as defineFlow, Ar as Api$5, Bn as DefineNode, Br as Require, Bt as Config$8, C as State$7, Cn as EmitterIdOf, Dn as State$3, Dr as PauseReason, E as Config$6, Er as Events, Et as NineSliceValue, Fn as FeatureDescription, Fr as ThermalReading, H as FrameRing, Ht as State$9, In as FeaturePlugin, It as TransformValue, Jn as Descriptor, Kn as SceneIdOf, Ln as FeatureTree, Lt as sprite, N as State$6, Nr as RateChange, Nt as SpriteOptions, On as TextStylesOf, Or as State$4, Ot as OverlayValue, Pr as State$8, Pt as SpriteValue, Qn as Hint, Rr as Config$9, S as ScenesApi, Sn as Config$3, Sr as RngApi, T as Api$4, Tn as HudKeysOf, Tr as Config$4, V as FrameRecord, Xn as EffectOptions, Xt as ComponentValue, Yn as Effect, Yt as ComponentType, Zn as GuideOptions, _ as DefineScene, a as Config$1, an as SystemFor, ar as State$2, b as SceneDefinition, bn as Api$2, bt as ViewportSize, c as LoadBundles, cn as DescriptionNode, cr as Config$5, dr as Root, en as Mut, er as Answer, f as State$1, fr as State$5, g as AnySceneProjection, gn as ReducedMotion, hn as ProjectionSpec, i as BundleSpec, in as SystemDefinition, jr as Config$7, jt as ShapeValue, l as LoadReason, ln as Ease, mn as ProjectionMotion, mr as Patch, nn as QueryTerm, o as DefineBundles, on as TagType, p as Tier, pn as NumericFields, qt as ComponentHandle, r as BundleMap, rn as ResourceType, rr as Config$2, t as Api, tn as Narrowed, tr as Api$1, u as LoadResult, ur as Json, wn as GameTypes, wr as Api$3, wt as HudPartValue, x as SceneSpec, xn as BundlesOf, xr as StoreApi, y as LayerMap, zr as Events$1, zt as Api$6 } from "./types-BGcda5Le.mjs";
2
+ import { A as GlowValue, B as Target, C as BlurValue, D as FilterComponent, F as AnimPlayerValue, H as HapticKind, I as Config$10, K as defineAnimation, L as FramesValue, M as OutlineValue, N as UniformDeclaration, O as FilterSpec, P as AnimApi, Q as play, R as MotionKeyframe, S as AlphaValue, T as DisplacementValue, U as SfxDescriptor, W as Step, _ as State$12, a as AudioApi, b as EmitterDefinition, c as MusicDescriptor, ct as OverlayApi, d as State$11, f as VolumesFor, h as EffectsApi, j as NoiseValue, k as FilterValueOf, l as MusicOptions, m as Config$12, n as State$13, r as UiApi, s as Config$11, t as Config$13, w as ColorMatrixValue, x as EmitterValue, y as EmitterConfig, z as State$10 } from "./types-GHE4J5Uf.mjs";
3
+ import { A as Config$15, B as State$14, C as TextBind, D as TextValue, E as TextStyles, F as Config$14, G as IsFlags, H as TextKey, I as I18nApi, K as ResolvedStyle, L as IntlKit, M as State$15, P as Argument, R as Message, S as TextApi, T as TextStyleInput, U as TypedTr, Y as WhenFlags, _ as BindOptions, b as Point, g as BindField, j as InputApi, k as defineComponent, m as IntrinsicElementsFor, p as defineTokens, q as Style, s as PopupComponent, v as Config$16, x as State$16, y as CountdownValue, z as Part } from "./types-7GXcXxxv.mjs";
5
4
  import { Log } from "@moku-labs/common/browser";
6
5
  import { PluginCtx } from "@moku-labs/core";
7
6
 
@@ -151,7 +150,7 @@ type ProjectionFor<Player, Session> = <const LayerName extends string, const Lif
151
150
  * app.anim.play(coinsFly, { from: purse, to: counter }).marks(); // []: the first frame is next
152
151
  * ```
153
152
  */
154
- declare const animPlugin: import("@moku-labs/core").PluginInstance<"anim", Config$10, State$9, AnimApi, {
153
+ declare const animPlugin: import("@moku-labs/core").PluginInstance<"anim", Config$10, State$10, AnimApi, {
155
154
  "anim:mark": {
156
155
  animation: string;
157
156
  mark: string;
@@ -193,7 +192,7 @@ declare const assetsPlugin: import("@moku-labs/core").PluginInstance<"assets", C
193
192
  bundle: string;
194
193
  tier: Tier;
195
194
  mb: number;
196
- reason: "budget" | "request";
195
+ reason: "budget" | "request" | "leave";
197
196
  keys: readonly string[];
198
197
  };
199
198
  "assets:replaced": {
@@ -210,13 +209,14 @@ declare const assetsPlugin: import("@moku-labs/core").PluginInstance<"assets", C
210
209
  * @example
211
210
  * ```ts
212
211
  * // A game composes it next to the screen set and points it at the player's settings.
212
+ * // `volumes` comes from the game's `defineGame` kit, so `player` is the game's Player.
213
213
  * createApp({
214
214
  * plugins: [...screen, audioPlugin, settingsFeature],
215
- * pluginConfigs: { audio: { volumes: player => player.settings.audio } }
215
+ * pluginConfigs: { audio: { volumes: volumes(player => player.settings.audio) } }
216
216
  * });
217
217
  * ```
218
218
  */
219
- declare const audioPlugin: import("@moku-labs/core").PluginInstance<"audio", Config$11, State$10, AudioApi, {}> & Record<never, never>;
219
+ declare const audioPlugin: import("@moku-labs/core").PluginInstance<"audio", Config$11, State$11, AudioApi, {}> & Record<never, never>;
220
220
  //#endregion
221
221
  //#region src/plugins/clock/index.d.ts
222
222
  /**
@@ -233,10 +233,24 @@ declare const audioPlugin: import("@moku-labs/core").PluginInstance<"audio", Con
233
233
  */
234
234
  declare const clockPlugin: import("@moku-labs/core").PluginInstance<"clock", Config$2, State$2, Api$1, {}> & Record<never, never>;
235
235
  //#endregion
236
+ //#region src/plugins/debug/index.d.ts
237
+ /**
238
+ * Debug plugin: `app.debug.overlay.open()`, `close()`, `toggle()`, `isOpen()`.
239
+ *
240
+ * @example
241
+ * ```ts
242
+ * app.debug.overlay.open({ mode: "pill" }); // true on a debug build, false on the store build
243
+ * ```
244
+ */
245
+ declare const debugPlugin: import("@moku-labs/core").PluginInstance<"debug", Record<string, never>, Record<string, never>, {
246
+ overlay: OverlayApi;
247
+ }, {}> & Record<never, never>;
248
+ //#endregion
236
249
  //#region src/plugins/effects/index.d.ts
237
250
  /**
238
- * Effects plugin: `app.effects.stats()`; the `Emitter` component and every filter component do
239
- * the rest as data on entities.
251
+ * Effects plugin: `app.effects.stats()` and the switches of a debug build,
252
+ * `app.effects.diagnostics`; the `Emitter` component and every filter component do the rest as
253
+ * data on entities.
240
254
  *
241
255
  * @example
242
256
  * ```ts
@@ -248,7 +262,7 @@ declare const clockPlugin: import("@moku-labs/core").PluginInstance<"clock", Con
248
262
  * app.effects.stats(); // { particles: 0, emitters: 0, filters: 0, renderPasses: 0 }: nothing runs before start
249
263
  * ```
250
264
  */
251
- declare const effectsPlugin: import("@moku-labs/core").PluginInstance<"effects", Config$13, State$13, EffectsApi, {}> & Record<never, never>;
265
+ declare const effectsPlugin: import("@moku-labs/core").PluginInstance<"effects", Config$12, State$12, EffectsApi, {}> & Record<never, never>;
252
266
  //#endregion
253
267
  //#region src/plugins/flow/index.d.ts
254
268
  /**
@@ -304,6 +318,12 @@ declare const flowPlugin: import("@moku-labs/core").PluginInstance<"flow", Confi
304
318
  * });
305
319
  *
306
320
  * await app.i18n.setLocale("en"); // text re-resolves every message on i18n:locale-changed
321
+ *
322
+ * // A sub-feature registers its own modules lazily: they arrive with the bundle "ep01".
323
+ * export const ep01Feature = defineFeature("ep01", {
324
+ * strings: { en: () => import("@generated/strings.ep01.en") }
325
+ * });
326
+ * await app.assets.load("ep01"); // resolves after strings.ep01 of the loaded locales arrived
307
327
  * ```
308
328
  */
309
329
  declare const i18nPlugin: import("@moku-labs/core").PluginInstance<"i18n", Config$14, State$14, I18nApi, {
@@ -568,9 +588,17 @@ declare const rendererPlugin: import("@moku-labs/core").PluginInstance<"renderer
568
588
  * });
569
589
  *
570
590
  * export const awaitIntent = defineNode({ scene: "board", rest: true, outcomes: { merge: type() } });
591
+ *
592
+ * // A scene whose art depends on the session: mounted once "location" and the episode are in.
593
+ * export const wardScene = defineScene("ward", {
594
+ * bundle: "location",
595
+ * bundles: ({ session }) => [session.episode],
596
+ * layers: { room: {} },
597
+ * projections: [wardRoom]
598
+ * });
571
599
  * ```
572
600
  */
573
- declare const scenesPlugin: import("@moku-labs/core").PluginInstance<"scenes", Record<string, never>, State$11, ScenesApi, {
601
+ declare const scenesPlugin: import("@moku-labs/core").PluginInstance<"scenes", Record<string, never>, State$7, ScenesApi, {
574
602
  "scenes:changed": {
575
603
  from: string | undefined;
576
604
  to: string;
@@ -610,13 +638,16 @@ declare const textPlugin: import("@moku-labs/core").PluginInstance<"text", Confi
610
638
  * });
611
639
  * ```
612
640
  */
613
- declare const timePlugin: import("@moku-labs/core").PluginInstance<"time", Config$7, State$7, Api$5, {}> & Record<never, never>;
641
+ declare const timePlugin: import("@moku-labs/core").PluginInstance<"time", Config$7, State$8, Api$5, {
642
+ "time:thermal": ThermalReading;
643
+ "time:rate": RateChange;
644
+ }> & Record<never, never>;
614
645
  //#endregion
615
646
  //#region src/plugins/ui/index.d.ts
616
647
  /**
617
648
  * Ui plugin: `app.ui.tree()`, `app.ui.find(...)`, `app.ui.lint()`, `app.ui.fill(...)`, the
618
- * text field `<input local>`, the components `Box` and
619
- * `LocalWrite`, and the helpers `defineComponent`, `defineStyle`, `defineTokens` and `popup`.
649
+ * text field `<input local>`, the components `Box`, `LocalWrite` and
650
+ * `DebugTrigger`, and the helpers `defineComponent`, `defineStyle`, `defineTokens` and `popup`.
620
651
  *
621
652
  * @example
622
653
  * ```ts
@@ -627,7 +658,7 @@ declare const timePlugin: import("@moku-labs/core").PluginInstance<"time", Confi
627
658
  * app.input.tap(app.ui.find("claim") ?? 0);
628
659
  * ```
629
660
  */
630
- declare const uiPlugin: import("@moku-labs/core").PluginInstance<"ui", Config$12, State$12, UiApi, {}> & Record<never, never>;
661
+ declare const uiPlugin: import("@moku-labs/core").PluginInstance<"ui", Config$13, State$13, UiApi, {}> & Record<never, never>;
631
662
  //#endregion
632
663
  //#region src/plugins/world/index.d.ts
633
664
  /**
@@ -643,7 +674,7 @@ declare const uiPlugin: import("@moku-labs/core").PluginInstance<"ui", Config$12
643
674
  * app.world.projection.entityOf("board.items", "i7"); // 1048576
644
675
  * ```
645
676
  */
646
- declare const worldPlugin: import("@moku-labs/core").PluginInstance<"world", Config$8, State$8, Api$6, {
677
+ declare const worldPlugin: import("@moku-labs/core").PluginInstance<"world", Config$8, State$9, Api$6, {
647
678
  "world:reconciled": {
648
679
  mode: "play" | "direct";
649
680
  projections: number;
@@ -661,12 +692,15 @@ declare const worldPlugin: import("@moku-labs/core").PluginInstance<"world", Con
661
692
  /**
662
693
  * Turns a feature description into a plugin that registers it with `flow.features` in `onInit`.
663
694
  * Throws for a name that is reserved or already a plugin. The plugin carries `logicOnly`: the
664
- * same plugin built from the V1 keys of the description, for headless tests.
695
+ * same plugin built from the V1 keys of the description, for headless tests. A feature that
696
+ * declares `features` is a parent: its `onInit` throws when one of them is not composed. The
697
+ * plugin carries them in `features`, its `logicOnly` carries their `logicOnly`.
665
698
  *
666
699
  * @param name - Feature name. Shares the namespace with plugin names.
667
- * @param description - What the feature brings: nodes, flows, slot contributions.
700
+ * @param description - What the feature brings: nodes, flows, slot contributions, sub-features.
668
701
  * @returns The feature plugin, with its `logicOnly` twin.
669
- * @throws {Error} When the name is reserved or belongs to an engine plugin.
702
+ * @throws {Error} When the name is reserved or belongs to an engine plugin, and for an entry of
703
+ * `features` that `defineFeature` did not make.
670
704
  * @example
671
705
  * ```ts
672
706
  * // The reward popup is a feature: the main flow only declares slot("afterOrder").
@@ -674,10 +708,31 @@ declare const worldPlugin: import("@moku-labs/core").PluginInstance<"world", Con
674
708
  * flows: [rewardFlow],
675
709
  * contribute: { afterOrder: { flow: rewardFlow, order: 10 } }
676
710
  * });
677
- * createApp({ plugins: [rewardFeature] }); // a headless test passes rewardFeature.logicOnly
711
+ * // features/episodes/index.ts: a parent declares its sub-features, each a feature of its own.
712
+ * export const episodesFeature = defineFeature("episodes", { features: [kitFeature, ep01Feature] });
713
+ * episodesFeature.features.map(child => child.name); // ["kit", "ep01"]
678
714
  * ```
679
715
  */
680
716
  declare function defineFeature(name: string, description: FeatureDescription): FeaturePlugin;
717
+ /**
718
+ * Turns a list of features into the flat plugin list `createApp` takes: every feature followed by
719
+ * its sub-features, depth-first, in declaration order. `defineGameApp` does it for `features` and
720
+ * `headless.features`; a raw `createApp` calls it. A `logicOnly` tree flattens the same way. A
721
+ * flat list comes back unchanged.
722
+ *
723
+ * @param list - Features as the game lists them: full plugins, or their `logicOnly`.
724
+ * @returns A new array; the input is not touched.
725
+ * @throws {Error} When an entry at any depth is not a feature: a cast, or a plugin that
726
+ * `defineFeature` did not make.
727
+ * @example
728
+ * ```ts
729
+ * // A test composes the game without defineGameApp: the parent first, then its sub-features.
730
+ * const plugins = flattenFeatures([homeFeature, episodesFeature]);
731
+ * plugins.map(plugin => plugin.name); // ["home", "episodes", "kit", "ep01", "ep02"]
732
+ * createApp({ plugins: [...screen, ...plugins], pluginConfigs: { flow: { mainFlow } } });
733
+ * ```
734
+ */
735
+ declare function flattenFeatures(list: readonly FeatureTree[]): FeatureTree[];
681
736
  //#endregion
682
737
  //#region src/plugins/flow/fx/descriptors.d.ts
683
738
  /**
@@ -709,7 +764,7 @@ declare function hint(kind: string, payload?: Json): Hint;
709
764
  * await fx(schedule(undefined)); // payload: {}, the pending timer is cancelled
710
765
  * ```
711
766
  */
712
- declare function schedule(moment: number | undefined): Descriptor;
767
+ declare function schedule(moment: number | undefined): Descriptor<void>;
713
768
  /**
714
769
  * Creates the tutorial descriptor: it narrows the gate to one answer until the node exits. Its
715
770
  * visual part (`target`, highlight, hand, text) is drawn by `ui`, which dims the screen and cuts
@@ -726,7 +781,55 @@ declare function schedule(moment: number | undefined): Descriptor;
726
781
  * // app.flow.gate.answer({ intent: "cancel" }) is false until the node exits
727
782
  * ```
728
783
  */
729
- declare function guide(options: GuideOptions): Descriptor;
784
+ declare function guide(options: GuideOptions): Descriptor<void>;
785
+ //#endregion
786
+ //#region src/plugins/flow/fx/effect.d.ts
787
+ /**
788
+ * Declares an effect whose handler runs in a fast walk too: `await fx(effect(payload))` resolves
789
+ * `Result`. `fast: "run"` is the promise of the effect's owner: its handler is registered with
790
+ * `runInFast` and in every app that awaits the effect, the headless app of the tests included. An
791
+ * app with no handler for the kind still resolves `undefined`, which this type does not show.
792
+ *
793
+ * @param kind - The effect kind, as `fx.handle` and the journal name it.
794
+ * @param options - How it behaves.
795
+ * @param options.fast - `"run"`: the handler also runs in a fast walk.
796
+ * @param options.cosmetic - Not set or `false`: a cosmetic effect may resolve `undefined`.
797
+ * @returns The descriptor constructor with `kind` and `handle`.
798
+ * @example
799
+ * ```ts
800
+ * // shared/effects.ts of a game: the page read, typed once.
801
+ * export const envRead = defineEffect<{ notice: boolean }, { reducedMotion: boolean; saveFallback: boolean }>(
802
+ * "view-env.read",
803
+ * { fast: "run" }
804
+ * );
805
+ * // In a node: no guard any more.
806
+ * const env = await fx(envRead({ notice: true })); // { reducedMotion: false, saveFallback: true }
807
+ * // In the plugin that owns it, at its start:
808
+ * const off = envRead.handle(ctx.require(flowPlugin).fx, payload => readPage(payload.notice));
809
+ * ```
810
+ */
811
+ declare function defineEffect<Payload extends Json | void, Result>(kind: string, options: {
812
+ fast: "run";
813
+ cosmetic?: false;
814
+ }): Effect<Payload, Result, Result>;
815
+ /**
816
+ * Declares an effect that may resolve `undefined`: `await fx(effect(payload))` resolves
817
+ * `Result | undefined`, because a fast walk skips its handler, or a cosmetic effect whose handler
818
+ * failed resolves `undefined`.
819
+ *
820
+ * @param kind - The effect kind, as `fx.handle` and the journal name it.
821
+ * @param options - How it behaves.
822
+ * @param options.fast - `"skip"` (the default): the handler does not run in a fast walk.
823
+ * @param options.cosmetic - `true`: a handler error never reaches the node.
824
+ * @returns The descriptor constructor with `kind` and `handle`.
825
+ * @example
826
+ * ```ts
827
+ * // shared/effects.ts of a game: a confetti burst, nothing a fast walk needs.
828
+ * export const confetti = defineEffect<{ cell: string }, void>("board.confetti", { cosmetic: true });
829
+ * confetti({ cell: "c3" }); // { kind: "board.confetti", payload: { cell: "c3" }, cosmetic: true }
830
+ * ```
831
+ */
832
+ declare function defineEffect<Payload extends Json | void, Result>(kind: string, options?: EffectOptions): Effect<Payload, Result, Result | undefined>;
730
833
  //#endregion
731
834
  //#region src/plugins/world/ecs/define.d.ts
732
835
  /**
@@ -842,6 +945,53 @@ declare const Exiting: TagType;
842
945
  declare const Tree: ComponentType<{
843
946
  node: DescriptionNode;
844
947
  }>;
948
+ /**
949
+ * The moment of the frame on the game's clock: `clock.now()`, read by `world` once at the start of
950
+ * every frame (before the systems of `input`) and once when the world starts, headless too. It is
951
+ * the moment a node gets as `now`, so a fake clock makes it exact in tests. A system that shows
952
+ * time reads it and writes its component only when its picture changes; with `renderer.onDemand`
953
+ * that is when a frame is drawn. A write by a system is overwritten at the next frame. `0` only
954
+ * before the world started, and after `ecs.clear()` until the next frame. `"Now"` is an engine
955
+ * resource name: a game resource of that name is refused.
956
+ *
957
+ * @example
958
+ * ```ts
959
+ * // A toast shows the seconds left of its energy timer: it is written once a second, not every frame.
960
+ * const toastTime = system({
961
+ * name: "shared.toastTime",
962
+ * phase: "animate",
963
+ * query: [ToastTime],
964
+ * run: (rows, { world, res }) => {
965
+ * const { now } = res(Now); // 1_790_000_016_000: the fake clock of the test stands there
966
+ * for (const [entity, time] of rows) {
967
+ * const left = Math.max(0, time.until - now);
968
+ * if (Math.ceil(left / 1000) !== Math.ceil(time.left / 1000)) world.set(entity, ToastTime, { left });
969
+ * }
970
+ * }
971
+ * });
972
+ * app.world.ecs.resource(Now).now; // 1_790_000_016_000
973
+ * ```
974
+ */
975
+ declare const Now: ResourceType<{
976
+ now: number;
977
+ }>;
978
+ //#endregion
979
+ //#region src/plugins/renderer/monitor/ring.d.ts
980
+ /**
981
+ * One slot of the ring as a plain record, `age` 0 the newest frame; `undefined` beyond the frames held. Allocates: for
982
+ * tests and tools, never per frame. A root export.
983
+ *
984
+ * @param ring - The ring of `monitor.frames()`.
985
+ * @param age - Frames back from the newest.
986
+ * @returns The record, or `undefined`.
987
+ * @example
988
+ * ```ts
989
+ * // A test of a debug build checks the frame that a sheet opened in.
990
+ * frameAt(app.renderer.monitor.frames(), 0)?.passes; // 3
991
+ * frameAt(app.renderer.monitor.frames(), 5000); // undefined: the ring holds 1024
992
+ * ```
993
+ */
994
+ declare function frameAt(ring: FrameRing, age: number): FrameRecord | undefined;
845
995
  //#endregion
846
996
  //#region src/plugins/input/components.d.ts
847
997
  /**
@@ -860,25 +1010,38 @@ type IntentValue = {
860
1010
  /**
861
1011
  * A view that can be carried. It names no intent: the drop target does. `carry` lists the
862
1012
  * projection keys of views of the same projection that ride along on top of it, such as the cards
863
- * that lie on a solitaire card.
1013
+ * that lie on a solitaire card. `aim` is a point of the view in its own units, the units of its
1014
+ * hit box: with it the hover and the drop look the target up under that point of the view in the
1015
+ * hand, not under the finger. Absent, the default, or `null`, it looks under the finger; a
1016
+ * projection takes an aim away by not giving it. Absent by default, so a view without an aim is
1017
+ * stored and serialised exactly as before the aim existed.
864
1018
  *
865
1019
  * @example
866
1020
  * ```ts
867
1021
  * const value: CarryValue = { payload: { from: "c7" }, carry: ["c8", "c9"] };
1022
+ * // A board item whose picture is lifted above the finger: the drop goes to the cell under the picture.
1023
+ * const lifted: CarryValue = { payload: { from: "c7" }, carry: [], aim: { x: 25, y: 12 } };
868
1024
  * ```
869
1025
  */
870
1026
  type CarryValue = {
871
1027
  payload: Json;
872
- carry: readonly string[];
1028
+ carry: readonly string[]; /** A point of the view in the hand, in its own units, that aims the drop; absent (the default) or `null` aims with the finger. */
1029
+ aim?: {
1030
+ x: number;
1031
+ y: number;
1032
+ } | null;
873
1033
  };
874
1034
  /**
875
1035
  * Where the one pointer is, in reference units. `justPressed` and `justReleased` are true for
876
- * exactly one frame.
1036
+ * exactly one frame. `id` is the `pointerId` of the pointer the gesture machine follows, `-1` when
1037
+ * it follows none. It changes while `down` stays true when a resting finger (pressed, not moved
1038
+ * past the tap slop, no long press, no trace) gives way to another finger: a system that measures
1039
+ * the finger's travel from frame to frame starts over then.
877
1040
  *
878
1041
  * @example
879
1042
  * ```ts
880
1043
  * const value: PointerValue = {
881
- * x: 540, y: 960, down: true, justPressed: false, justReleased: false
1044
+ * x: 540, y: 960, down: true, justPressed: false, justReleased: false, id: 3
882
1045
  * };
883
1046
  * ```
884
1047
  */
@@ -887,7 +1050,8 @@ type PointerValue = {
887
1050
  y: number;
888
1051
  down: boolean;
889
1052
  justPressed: boolean;
890
- justReleased: boolean;
1053
+ justReleased: boolean; /** The `pointerId` the resource follows; `-1` at rest. */
1054
+ id: number;
891
1055
  };
892
1056
  /**
893
1057
  * A tap on this view answers `{ intent, payload }`.
@@ -899,7 +1063,8 @@ declare const Tappable: ComponentType<IntentValue>;
899
1063
  declare const Pressable: ComponentType<IntentValue>;
900
1064
  /**
901
1065
  * This view can be carried by the finger. It names no intent; the drop target does. The views
902
- * whose keys `carry` lists hang under it from the grab to the release and fly home with it.
1066
+ * whose keys `carry` lists hang under it from the grab to the release and fly home with it. With
1067
+ * an `aim`, the hover and the drop are looked up under that point of the view in the hand.
903
1068
  */
904
1069
  declare const Draggable: ComponentType<CarryValue>;
905
1070
  /**
@@ -948,7 +1113,8 @@ declare const Pressed: TagType;
948
1113
  */
949
1114
  declare const PointerOver: TagType;
950
1115
  /**
951
- * Where the one pointer is, in reference units. Written once per frame by the frame step.
1116
+ * Where the one pointer is, in reference units. Written once per frame by the frame step. `id`
1117
+ * names the pointer it follows, `-1` at rest.
952
1118
  */
953
1119
  declare const Pointer: ResourceType<PointerValue>;
954
1120
  //#endregion
@@ -958,44 +1124,53 @@ declare const Pointer: ResourceType<PointerValue>;
958
1124
  * object cannot reach the scanner or the plugin. `defineGame` returns this helper typed by the
959
1125
  * game's `BundleKey`, so a name the scanner never saw does not compile.
960
1126
  *
961
- * @param map - Bundle name to its tier and, when it is a split bundle, its globs.
1127
+ * @param map - Bundle name to its tier and, when it is a split bundle, its globs; its release
1128
+ * and its mipmaps when it declares them.
962
1129
  * @returns The bundle map as plain data.
963
1130
  * @example
964
1131
  * ```ts
965
- * // features/board/assets.ts of a game: the board is a scene bundle, the chains load on demand.
1132
+ * // features/board/assets.ts of a game: the board is a scene bundle, the chains load on demand
1133
+ * // and leave with the board.
966
1134
  * export const boardAssets = defineBundles({
967
1135
  * board: { tier: "scene" },
968
- * "board.chains": { tier: "lazy", files: ["chains/*.png"] }
1136
+ * "board.chains": { tier: "lazy", files: ["chains/*.png"], release: "leave" }
969
1137
  * });
970
1138
  * ```
971
1139
  */
972
1140
  declare function defineBundles<Key extends string>(map: Partial<Record<Key, BundleSpec>>): BundleMap<Key>;
973
1141
  /**
974
1142
  * Creates the awaited effect that loads one or more bundles. The handler of the kind `"load"` is
975
- * registered by this plugin and runs in fast mode too, so a fast walk really loads.
1143
+ * registered by this plugin and runs in fast mode too, so a fast walk really loads. It resolves
1144
+ * `undefined` in an app without `assets`, such as the headless app of `game.headless()`.
976
1145
  *
977
1146
  * @param bundle - One bundle name, or a list of them in load order.
978
1147
  * @returns The descriptor a loading node awaits.
979
1148
  * @example
980
1149
  * ```ts
981
1150
  * // A loading node of a game: one bundle per turn, so the screen can draw progress.
982
- * await fx(load("board.chains")); // { loaded: ["board.chains"], mb: 1.25 }
1151
+ * const loaded = await fx(load("board.chains")); // { loaded: ["board.chains"], mb: 1.25 }
1152
+ * // undefined in an app without assets, such as the headless app of game.headless()
983
1153
  * await fx(load(["board", "ui"])); // both, in that order
984
1154
  * ```
985
1155
  */
986
- declare function load(bundle: string | readonly string[]): Descriptor;
1156
+ declare function load(bundle: string | readonly string[]): Descriptor<LoadResult | undefined>;
987
1157
  //#endregion
988
1158
  //#region src/plugins/scenes/define.d.ts
989
1159
  /**
990
1160
  * Declares a scene: a bundle, named layers in draw order, the projections it mounts and optional
991
- * music. A layer `ui` is appended for the HUD and the popups unless the scene declares one. The
1161
+ * music. A layer `ui` is appended for the HUD and the popups unless the scene declares one; a scene
1162
+ * whose layer says `above: "overlays"` (its HUD layer, drawn above every overlay) gets `ui` right under it. The
992
1163
  * layer names come from the keys of `layers` and that `ui`, so a projection whose `layer` or
993
1164
  * `lift` is not among them does not compile — and throws here for a caller without types.
1165
+ * `bundles` names bundles that depend on the committed state: the scene is mounted once those
1166
+ * are in too.
994
1167
  *
995
1168
  * @param id - Id of the scene. A node names it with `defineNode({ scene: id })`.
996
- * @param scene - The bundle, the layers, the projections and the optional music key.
1169
+ * @param scene - The bundle, the optional bundles of state, the layers, the projections and the
1170
+ * optional music key.
997
1171
  * @returns The scene as frozen data, ready for the `scenes` key of a feature.
998
- * @throws {Error} For an integer-like layer name, and for a `layer` or `lift` that is not declared.
1172
+ * @throws {Error} For an integer-like layer name, for a `layer` or `lift` that is not declared, for two HUD layers,
1173
+ * an `above` other than `"overlays"`, and a `ui` declared after the HUD layer.
999
1174
  * @example
1000
1175
  * ```ts
1001
1176
  * // features/board/view/scene.ts of a game.
@@ -1006,10 +1181,23 @@ declare function load(bundle: string | readonly string[]): Descriptor;
1006
1181
  * });
1007
1182
  *
1008
1183
  * boardScene.layers[2]; // { name: "items", sort: "y" }
1009
- * boardScene.layers[4]; // { name: "ui", sort: "none" }, appended for the HUD
1184
+ * boardScene.layers[4]; // { name: "ui", sort: "order" }, appended for the HUD
1185
+ *
1186
+ * // A HUD layer above every overlay: `ui` goes right under it.
1187
+ * defineScene("ward", { bundle: "ui", layers: { scene: {}, hud: { above: "overlays" } }, projections }).layers;
1188
+ * // [{ name: "scene", sort: "none" }, { name: "ui", sort: "order" }, { name: "hud", sort: "none", above: "overlays" }]
1189
+ *
1190
+ * // features/location/view/ward.ts: the room is the art of the episode the session plays.
1191
+ * export const wardScene = defineScene("ward", {
1192
+ * bundle: "location",
1193
+ * bundles: ({ session }) => [session.episode], // "ep01" | "ep02": bundle keys of the game
1194
+ * layers: { room: {}, glow: {} },
1195
+ * projections: [wardRoom, wardGlows]
1196
+ * });
1197
+ * wardScene.bundles?.({ player: {}, session: { episode: "ep02" } }); // ["ep02"]
1010
1198
  * ```
1011
1199
  */
1012
- declare function defineScene<Layers extends LayerMap, const Projections extends readonly AnySceneProjection[]>(id: string, scene: SceneSpec<Layers, Projections, string, string>): SceneDefinition;
1200
+ declare function defineScene<Layers extends LayerMap, const Projections extends readonly AnySceneProjection[], Player extends Json = Json, Session extends Json = Json>(id: string, scene: SceneSpec<Layers, Projections, string, string, Player, Session>): SceneDefinition;
1013
1201
  //#endregion
1014
1202
  //#region src/plugins/anim/components.d.ts
1015
1203
  /**
@@ -1082,6 +1270,10 @@ type MotionState = { readonly [Name in keyof MotionComponents]?: Readonly<Partia
1082
1270
  * Transform key is an offset from rest, and the last key repeats the first one. It is not part of
1083
1271
  * the motion `enter` returns.
1084
1272
  *
1273
+ * `when` says when `enter` and `exit` play: `"always"` (the default) or only for a commit
1274
+ * (`"change"`). `transition.reduced` and `loop.reduced` say what reduced motion does to their
1275
+ * tracks: `"cut"` (the default) or `"keep"`.
1276
+ *
1085
1277
  * @example
1086
1278
  * ```ts
1087
1279
  * const spec: MotionSpec = {
@@ -1098,6 +1290,14 @@ type MotionState = { readonly [Name in keyof MotionComponents]?: Readonly<Partia
1098
1290
  * loop: { track: "sway", ms: 2400 },
1099
1291
  * on: { enter: "small" }
1100
1292
  * };
1293
+ * // A card that stands at rest when its board mounts and fades in when a commit adds it, also
1294
+ * // under reduced motion.
1295
+ * const newCard: MotionSpec = {
1296
+ * states: { faded: { Shape: { alpha: 0 } } },
1297
+ * transition: { ms: 220, reduced: "keep" },
1298
+ * on: { enter: "faded" },
1299
+ * when: "change"
1300
+ * };
1101
1301
  * ```
1102
1302
  */
1103
1303
  type MotionSpec = {
@@ -1106,16 +1306,24 @@ type MotionSpec = {
1106
1306
  readonly transition?: {
1107
1307
  readonly ms?: number;
1108
1308
  readonly ease?: Ease;
1309
+ readonly reduced?: ReducedMotion;
1109
1310
  };
1110
1311
  readonly loop?: {
1111
1312
  readonly track: string;
1112
1313
  readonly ms?: number;
1314
+ readonly reduced?: ReducedMotion;
1113
1315
  };
1114
1316
  readonly on: {
1115
1317
  readonly enter?: string;
1116
1318
  readonly exit?: string;
1117
1319
  readonly change?: readonly (keyof MotionComponents & string)[];
1118
1320
  };
1321
+ /**
1322
+ * When `enter` and `exit` play: `"always"` (the default, as before) or only for a commit
1323
+ * (`"change"`); with `"change"` an element that comes or goes with its screen stands at rest and
1324
+ * leaves without a motion. The loop is not concerned.
1325
+ */
1326
+ readonly when?: "always" | "change";
1119
1327
  };
1120
1328
  /**
1121
1329
  * Builds the projection motion hooks of an element from named poses and keyframe tracks. The
@@ -1124,15 +1332,16 @@ type MotionSpec = {
1124
1332
  * the `loop` hook: `world` and `ui` play it wherever they play `enter`, so a projection view loops
1125
1333
  * from its enter, or from the first live frame after a direct reconcile, and `ui` swaps it when
1126
1334
  * the motion prop of an element changes. One cycle of the loop is `loop.ms`, or `transition.ms`
1127
- * when it is left out.
1335
+ * when it is left out. With `when: "change"` the enter and exit play only for a commit: an element
1336
+ * that comes or goes with its screen stands at rest and leaves without a motion.
1128
1337
  *
1129
1338
  * @param spec - The named poses, the keyframe tracks, the transition, the loop and the hooks to
1130
1339
  * build.
1131
1340
  * @returns The `enter`, `loop`, `exit` and `change` hooks. `settle` is left out: the default of
1132
1341
  * `world` applies.
1133
1342
  * @throws {Error} When a track is invalid, a name is both a state and a track, `on` names
1134
- * neither, `loop.track` names no track, `loop.ms` is not a finite number above 0, or the loop
1135
- * ends somewhere else than it starts.
1343
+ * neither, `loop.track` names no track, `loop.ms` is not a finite number above 0, the loop
1344
+ * ends somewhere else than it starts, or `when` or a `reduced` is not one of its words.
1136
1345
  * @example
1137
1346
  * ```ts
1138
1347
  * const buttonMotion = defineMotion({
@@ -1141,6 +1350,14 @@ type MotionSpec = {
1141
1350
  * on: { enter: "hidden", exit: "hidden", change: ["Transform"] }
1142
1351
  * });
1143
1352
  * buttonMotion.settle; // undefined
1353
+ *
1354
+ * const cardMotion = defineMotion({
1355
+ * states: { small: { Transform: { scale: 0.8 }, Shape: { alpha: 0 } } },
1356
+ * transition: { ms: 220, ease: "out" },
1357
+ * on: { enter: "small", exit: "small" },
1358
+ * when: "change"
1359
+ * });
1360
+ * // a scene mount shows it at rest; a commit that adds it grows it in over 220 ms
1144
1361
  * ```
1145
1362
  */
1146
1363
  declare function defineMotion(spec: MotionSpec): ProjectionMotion<unknown>;
@@ -1267,7 +1484,7 @@ declare function resolve(style: Style | undefined, flags: StyleFlags, viewport:
1267
1484
  * // music("board.theme") is { kind: "music", payload: { key: "board.theme" }, cosmetic: true }
1268
1485
  * ```
1269
1486
  */
1270
- declare function music(key: string | null, options?: MusicOptions): Descriptor;
1487
+ declare function music(key: string | null, options?: MusicOptions): Descriptor<void>;
1271
1488
  //#endregion
1272
1489
  //#region src/plugins/effects/filters/builtins.d.ts
1273
1490
  /**
@@ -1356,26 +1573,36 @@ declare const Alpha: ComponentType<AlphaValue>;
1356
1573
  //#region src/plugins/effects/filters/define.d.ts
1357
1574
  /**
1358
1575
  * Turns a WGSL fragment body and its GLSL ES 3.0 twin into a filter component type; Pixi draws
1359
- * the one of the running backend. To the WGSL the engine prepends the vertex stage, the input
1576
+ * the one of the running backend. A still view under the filter is kept as a picture by the
1577
+ * renderer (`cache`, default `"local"`); a body that needs its canvas position calls
1578
+ * `canvasPixel(uv)`, and then the view can still be kept as a picture. To the WGSL the engine prepends the vertex stage, the input
1360
1579
  * bindings and a `FilterUniforms` struct in declaration order, bound as `fu`. To the GLSL it
1361
1580
  * prepends `#version 300 es`, `vTextureCoord`, `finalColor`, `uTexture`, the global filter
1362
1581
  * uniforms as `vec4` and one `uniform` per declared uniform under its bare name. Every number
1363
1582
  * uniform is a number field, so the existing `tween` drives it; a colour is one hex field sent as
1364
1583
  * a `vec3`; a tuple is an array field and not tweenable. Every filter component also carries
1365
- * `enabled: true` and `order: 0`. Register it through the `filters` key of a feature.
1584
+ * `enabled: true` and `order: 0`. An input `blur` gives the body `sampleBlur(uv)`: the last texture
1585
+ * of its chain, read at the body's `uv`. A `fallback` draws instead when the filter is broken.
1586
+ * An `area` answers, from the value, the rectangle in the entity's own units outside of which the
1587
+ * filter draws nothing: Pixi then renders and fills only that box, not the view's bounds.
1588
+ * Register it through the `filters` key of a feature. The README shows a filter with a blur input
1589
+ * and one with an `area`.
1366
1590
  *
1367
1591
  * @param id - The filter id, also the component name; unique, and not one of the built-ins.
1368
- * @param spec - Both bodies, the uniforms, the passes one apply costs and the padding.
1592
+ * @param spec - Both bodies, the uniforms, the passes one apply costs, the padding, the inputs, the fallback, the
1593
+ * cache category and the area.
1369
1594
  * @returns The component type, with the frozen `filter` definition attached.
1370
1595
  * @throws {Error} When the id is empty, the WGSL has no `mainFragment`, the GLSL no `void main(`,
1371
- * a uniform is reserved, badly named or of no known form, or the passes or the padding break
1372
- * their rules.
1596
+ * a uniform is reserved, badly named or of no known form, the passes or the padding break
1597
+ * their rules, an input or the fallback breaks one of its rules, `passes` is given with inputs,
1598
+ * or `area` is not a function.
1373
1599
  * @example
1374
1600
  * ```ts
1375
1601
  * // features/board/effects.ts: a gold tint a motion hook tweens on a merge, on WebGPU and WebGL.
1376
1602
  * const Tint = defineFilter("fx.tint", { wgsl: tintWgsl, glsl: tintGlsl, uniforms: { amount: 0, color: { color: 0xffd700 } } });
1377
1603
  * Tint({ amount: 1 }).value; // { amount: 1, color: 0xffd700, enabled: true, order: 0 }
1378
1604
  * Tint.filter.glsl.includes("uniform vec3 color;"); // true
1605
+ * Tint.filter.cache; // "local"
1379
1606
  * ```
1380
1607
  */
1381
1608
  declare function defineFilter<Uniforms extends Record<string, UniformDeclaration> = Record<never, never>>(id: string, spec: FilterSpec<Uniforms>): FilterComponent<FilterValueOf<Uniforms>>;
@@ -1429,7 +1656,10 @@ declare function defineEmitter(id: string, config: EmitterConfig): EmitterDefini
1429
1656
  * });
1430
1657
  * ```
1431
1658
  */
1432
- declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs/core").AnyPluginInstance[] = readonly []>(options?: import("@moku-labs/core").CreateAppOptions<Config$9, Events$1, (import("@moku-labs/core").PluginInstance<"time", Config$7, State$7, Api$5, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"lifecycle", Config$4, State$4, Api$3, {
1659
+ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs/core").AnyPluginInstance[] = readonly []>(options?: import("@moku-labs/core").CreateAppOptions<Config$9, Events$1, (import("@moku-labs/core").PluginInstance<"time", Config$7, State$8, Api$5, {
1660
+ "time:thermal": ThermalReading;
1661
+ "time:rate": RateChange;
1662
+ }> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"lifecycle", Config$4, State$4, Api$3, {
1433
1663
  "lifecycle:changed": {
1434
1664
  reason: PauseReason;
1435
1665
  action: "push" | "pop";
@@ -1445,7 +1675,9 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
1445
1675
  roots: readonly Root[];
1446
1676
  cause: "edge" | "rollback" | "restore" | "load";
1447
1677
  };
1448
- }> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"clock", Config$2, State$2, Api$1, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"flow", Config$3, State$3, Api$2, {
1678
+ }> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"clock", Config$2, State$2, Api$1, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"debug", Record<string, never>, Record<string, never>, {
1679
+ overlay: OverlayApi;
1680
+ }, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"flow", Config$3, State$3, Api$2, {
1449
1681
  "flow:edge": {
1450
1682
  flow: string;
1451
1683
  node: string;
@@ -1469,7 +1701,10 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
1469
1701
  rolledBackTo: string;
1470
1702
  retry: boolean;
1471
1703
  };
1472
- }> & Record<never, never>) | ExtraPlugins[number], [...ExtraPlugins], 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>]>, 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>> | undefined) => import("@moku-labs/core").App<Config$9, Events$1, (import("@moku-labs/core").PluginInstance<"time", Config$7, State$7, Api$5, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"lifecycle", Config$4, State$4, Api$3, {
1704
+ }> & Record<never, never>) | ExtraPlugins[number], [...ExtraPlugins], 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>]>, 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>> | undefined) => import("@moku-labs/core").App<Config$9, Events$1, (import("@moku-labs/core").PluginInstance<"time", Config$7, State$8, Api$5, {
1705
+ "time:thermal": ThermalReading;
1706
+ "time:rate": RateChange;
1707
+ }> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"lifecycle", Config$4, State$4, Api$3, {
1473
1708
  "lifecycle:changed": {
1474
1709
  reason: PauseReason;
1475
1710
  action: "push" | "pop";
@@ -1485,7 +1720,9 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
1485
1720
  roots: readonly Root[];
1486
1721
  cause: "edge" | "rollback" | "restore" | "load";
1487
1722
  };
1488
- }> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"clock", Config$2, State$2, Api$1, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"flow", Config$3, State$3, Api$2, {
1723
+ }> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"clock", Config$2, State$2, Api$1, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"debug", Record<string, never>, Record<string, never>, {
1724
+ overlay: OverlayApi;
1725
+ }, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"flow", Config$3, State$3, Api$2, {
1489
1726
  "flow:edge": {
1490
1727
  flow: string;
1491
1728
  node: string;
@@ -1525,16 +1762,18 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
1525
1762
  declare const createPlugin: import("@moku-labs/core").BoundCreatePluginFunction<Config$9, Events$1, 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>]>>;
1526
1763
  /**
1527
1764
  * Binds the authoring helpers to the types of one game: "createApp for a game". Each plugin binds
1528
- * its own helpers (`flowFor`, `projectionFor`, `componentsFor`, `bundlesFor`, `scenesFor`); this
1529
- * only spreads them, so the kit's type is inferred and never written by hand. At run time these
1530
- * are the same functions and component objects the plugins export.
1765
+ * its own helpers (`flowFor`, `projectionFor`, `systemsFor`, `componentsFor`, `bundlesFor`,
1766
+ * `scenesFor`, `i18nFor`, `audioFor`); this only spreads them, so the kit's type is inferred and
1767
+ * never written by hand. At run time these are the same functions and component objects the
1768
+ * plugins export. The kit's `system` and `volumes` read the game's player and session; `key` types
1769
+ * a string key written in code (a key that comes from data is checked with `app.i18n.isKey`).
1531
1770
  *
1532
- * @returns The helpers typed with the game's `player`, `session`, `assets`, `bundles`, `strings`
1533
- * and `emitters`.
1771
+ * @returns The helpers typed with the game's `player`, `session`, `assets`, `bundles`, `strings`,
1772
+ * `emitters` and `hud` (the HUD part keys of `HudPart` and `Overlay`).
1534
1773
  * @example
1535
1774
  * ```ts
1536
1775
  * // kit.ts of a game: bound once, imported by every node, flow and view file.
1537
- * export const { defineNode, defineFlow, defineFeature, projection, sprite, Sprite, defineBundles, load, defineScene } =
1776
+ * export const { defineNode, defineFlow, defineFeature, projection, system, sprite, Sprite, defineBundles, load, defineScene, tr, key, volumes } =
1538
1777
  * defineGame<{ player: Player; session: Session; assets: AssetKey; bundles: BundleKey; strings: StringTable }>();
1539
1778
  * ```
1540
1779
  */
@@ -1550,12 +1789,13 @@ declare function defineGame<Types extends GameTypes>(): {
1550
1789
  map?: Types["assets"];
1551
1790
  }>;
1552
1791
  music: MusicDescriptor<Types["assets"]>;
1792
+ volumes: VolumesFor<Types["player"]>;
1553
1793
  defineComponent: typeof defineComponent;
1554
1794
  defineStyle: <const Given extends Style<Types["assets"]>>(style: Given) => Readonly<Given>;
1555
1795
  defineTokens: typeof defineTokens;
1556
- popup: <Properties extends object, Local extends object>(component: PopupComponent<Properties, Local>, props: Properties, options?: {
1796
+ popup: <Properties extends object, Local extends object, Outcomes extends Record<string, unknown>>(component: PopupComponent<Properties, Local, Outcomes>, props: Properties, options?: {
1557
1797
  over?: string;
1558
- }) => Descriptor;
1798
+ }) => Descriptor<Answer<keyof Outcomes & string>>;
1559
1799
  intrinsics: IntrinsicElementsFor<Types["assets"], TextStylesOf<Types>, Extract<keyof Types["strings"], string>>;
1560
1800
  label: (options: Omit<LabelOptions, "style"> & {
1561
1801
  style: TextStylesOf<Types>;
@@ -1567,6 +1807,7 @@ declare function defineGame<Types extends GameTypes>(): {
1567
1807
  italic?: Types["assets"];
1568
1808
  }>) => TextStyles;
1569
1809
  tr: TypedTr<Types["strings"]>;
1810
+ key: <const Key extends TextKey<Types["strings"]>>(key: Key) => Key;
1570
1811
  defineAnimation: typeof defineAnimation;
1571
1812
  frames: (target: Target, options: {
1572
1813
  keys: readonly Types["assets"][];
@@ -1580,7 +1821,7 @@ declare function defineGame<Types extends GameTypes>(): {
1580
1821
  Frames: Narrowed<FramesValue, Partial<Omit<FramesValue, "keys">> & {
1581
1822
  keys?: readonly Types["assets"][];
1582
1823
  }>;
1583
- defineScene: DefineScene<Types["assets"], BundlesOf<Types>>;
1824
+ defineScene: DefineScene<Types["assets"], BundlesOf<Types>, Types["player"], Types["session"]>;
1584
1825
  defineBundles: DefineBundles<BundlesOf<Types>>;
1585
1826
  load: LoadBundles<BundlesOf<Types>>;
1586
1827
  sprite: (options: Omit<SpriteOptions, "texture"> & {
@@ -1592,6 +1833,13 @@ declare function defineGame<Types extends GameTypes>(): {
1592
1833
  NineSlice: Narrowed<NineSliceValue, Partial<Omit<NineSliceValue, "texture">> & {
1593
1834
  texture?: Types["assets"];
1594
1835
  }>;
1836
+ Overlay: Narrowed<OverlayValue, Partial<Omit<OverlayValue, "hud">> & {
1837
+ hud?: "all" | "none" | readonly HudKeysOf<Types>[];
1838
+ }>;
1839
+ HudPart: Narrowed<HudPartValue, {
1840
+ key: HudKeysOf<Types>;
1841
+ }>;
1842
+ system: SystemFor<Types["player"], Types["session"]>;
1595
1843
  projection: ProjectionFor<Types["player"], Types["session"]>;
1596
1844
  defineNode: DefineNode<{
1597
1845
  player: Types["player"];
@@ -1610,7 +1858,7 @@ declare function defineGame<Types extends GameTypes>(): {
1610
1858
  * createApp({ plugins: [...screen, boardFeature], pluginConfigs: { renderer: { mount: "#game" } } });
1611
1859
  * ```
1612
1860
  */
1613
- declare const screen: readonly [import("@moku-labs/core").PluginInstance<"world", Config$8, State$8, Api$6, {
1861
+ declare const screen: readonly [import("@moku-labs/core").PluginInstance<"world", Config$8, State$9, Api$6, {
1614
1862
  "world:reconciled": {
1615
1863
  mode: "play" | "direct";
1616
1864
  projections: number;
@@ -1643,20 +1891,20 @@ declare const screen: readonly [import("@moku-labs/core").PluginInstance<"world"
1643
1891
  bundle: string;
1644
1892
  tier: Tier;
1645
1893
  mb: number;
1646
- reason: "budget" | "request";
1894
+ reason: "budget" | "request" | "leave";
1647
1895
  keys: readonly string[];
1648
1896
  };
1649
1897
  "assets:replaced": {
1650
1898
  bundle: string;
1651
1899
  keys: readonly string[];
1652
1900
  };
1653
- }> & Record<never, never>, import("@moku-labs/core").PluginInstance<"scenes", Record<string, never>, State$11, ScenesApi, {
1901
+ }> & Record<never, never>, import("@moku-labs/core").PluginInstance<"scenes", Record<string, never>, State$7, ScenesApi, {
1654
1902
  "scenes:changed": {
1655
1903
  from: string | undefined;
1656
1904
  to: string;
1657
1905
  music: string | undefined;
1658
1906
  };
1659
- }> & Record<never, never>, import("@moku-labs/core").PluginInstance<"anim", Config$10, State$9, AnimApi, {
1907
+ }> & Record<never, never>, import("@moku-labs/core").PluginInstance<"anim", Config$10, State$10, AnimApi, {
1660
1908
  "anim:mark": {
1661
1909
  animation: string;
1662
1910
  mark: string;
@@ -1668,6 +1916,6 @@ declare const screen: readonly [import("@moku-labs/core").PluginInstance<"world"
1668
1916
  "i18n:locale-changed": {
1669
1917
  locale: string;
1670
1918
  };
1671
- }> & Record<never, never>, import("@moku-labs/core").PluginInstance<"text", Config$16, State$16, TextApi, {}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"ui", Config$12, State$12, UiApi, {}> & Record<never, never>];
1919
+ }> & Record<never, never>, import("@moku-labs/core").PluginInstance<"text", Config$16, State$16, TextApi, {}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"ui", Config$13, State$13, UiApi, {}> & Record<never, never>];
1672
1920
  //#endregion
1673
- export { defineFeature as $, Held as A, Traced as B, Animation as C, bind as Ct, load as D, defineBundles as E, Pressed as F, component as G, Layer as H, Swipeable as I, system as J, mut as K, Tappable as L, Pointer as M, PointerOver as N, Draggable as O, Pressable as P, schedule as Q, Touchable as R, AnimPlayer as S, Text as St, defineScene as T, label as Tt, Order as U, Exiting as V, Tree as W, guide as X, tag as Y, hint as Z, defineStyle as _, audioPlugin as _t, defineEmitter as a, rendererPlugin as at, messageDuration as b, projection as bt, Alpha as c, PlatformProvider as ct, Displacement as d, lifecyclePlugin as dt, worldPlugin as et, Glow as f, inputPlugin as ft, resolve as g, clockPlugin as gt, music as h, effectsPlugin as ht, screen as i, scenesPlugin as it, Hovered as j, DropTarget as k, Blur as l, types_d_exports as lt, Outline as m, flowPlugin as mt, createPlugin as n, timePlugin as nt, Emitter as o, platformPlugin as ot, Noise as p, i18nPlugin as pt, resource as q, defineGame as r, textPlugin as rt, defineFilter as s, BackResult as st, createApp as t, uiPlugin as tt, ColorMatrix as u, modelPlugin as ut, tr as v, assetsPlugin as vt, Frames as w, defineTextStyles as wt, defineMotion as x, Countdown as xt, messageArgument as y, animPlugin as yt, Traceable as z };
1921
+ export { guide as $, Held as A, label as At, Traced as B, Animation as C, assetsPlugin as Ct, load as D, Text as Dt, defineBundles as E, Countdown as Et, Pressed as F, Order as G, Exiting as H, Swipeable as I, mut as J, Tree as K, Tappable as L, Pointer as M, PointerOver as N, Draggable as O, bind as Ot, Pressable as P, defineEffect as Q, Touchable as R, AnimPlayer as S, audioPlugin as St, defineScene as T, projection as Tt, Layer as U, frameAt as V, Now as W, system as X, resource as Y, tag as Z, defineStyle as _, i18nPlugin as _t, defineEmitter as a, uiPlugin as at, messageDuration as b, debugPlugin as bt, Alpha as c, scenesPlugin as ct, Displacement as d, BackResult as dt, hint as et, Glow as f, PlatformProvider as ft, resolve as g, inputPlugin as gt, music as h, lifecyclePlugin as ht, screen as i, worldPlugin as it, Hovered as j, DropTarget as k, defineTextStyles as kt, Blur as l, rendererPlugin as lt, Outline as m, modelPlugin as mt, createPlugin as n, defineFeature as nt, Emitter as o, timePlugin as ot, Noise as p, types_d_exports as pt, component as q, defineGame as r, flattenFeatures as rt, defineFilter as s, textPlugin as st, createApp as t, schedule as tt, ColorMatrix as u, platformPlugin as ut, tr as v, flowPlugin as vt, Frames as w, animPlugin as wt, defineMotion as x, clockPlugin as xt, messageArgument as y, effectsPlugin as yt, Traceable as z };