@moku-labs/game 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import { A as Api$2, E as DebugSwitches, Ot as Bookmark, h as Api$1, jt as FlowState, ln as Api, vn as Time, w as Captured } from "./types-ZQLYXo5X.mjs";
2
- import { a as AudioApi, r as UiApi, v as ScenesApi, x as AnimApi } from "./types-BM4shh8K.mjs";
3
- import { A as InputApi } from "./types-BUwDHKXm.mjs";
2
+ import { a as AudioApi, r as UiApi, v as ScenesApi, x as AnimApi } from "./types-D_2G6Q68.mjs";
3
+ import { A as InputApi } from "./types-BrTpz9oL.mjs";
4
4
  import { t as HeadlessApp } from "./headless-G4nuZ-xz.mjs";
5
5
  import { n as Command, r as ControlApp } from "./types-DAdwEJMp.mjs";
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { t as HeadlessApp } from "./headless-G4nuZ-xz.mjs";
2
2
  import { i as InputArguments, n as Command, o as InputSchema, s as Ran } from "./types-DAdwEJMp.mjs";
3
- import { t as commands } from "./commands-C4QlqijJ.mjs";
3
+ import { t as commands } from "./commands-DvFr8Uwp.mjs";
4
4
  import { t as defineCommand } from "./define-CCc0ozKe.mjs";
5
5
 
6
6
  //#region src/plugins/flow/doors/dev.d.ts
@@ -1,7 +1,7 @@
1
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-ZQLYXo5X.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-BM4shh8K.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-CefgYzFt.mjs";
4
- import { $ as ResolvedStyle, A as InputApi, B as SpriteOptions, E as TextValue, F as NineSliceValue, G as Argument, J as Message, K as Config$14, O as defineComponent, Q as IsFlags, R as ShapeValue, S as TextBind, T as TextStyles, U as TransformValue, V as SpriteValue, W as sprite, X as TypedTr, Y as State$14, _ as Config$16, b as State$16, et as Style, f as defineTokens, g as BindOptions, h as BindField, j as State$15, k as Config$15, nt as WhenFlags, p as IntrinsicElementsFor, q as I18nApi, s as PopupComponent, v as CountdownValue, w as TextStyleInput, x as TextApi, y as Point } from "./types-BUwDHKXm.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-D_2G6Q68.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-Bcdo5-2w.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-BrTpz9oL.mjs";
5
5
  import { Log } from "@moku-labs/common/browser";
6
6
  import { PluginCtx } from "@moku-labs/core";
7
7
 
@@ -476,6 +476,19 @@ type PlatformApi = {
476
476
  * ```
477
477
  */
478
478
  back(): BackResult;
479
+ /**
480
+ * Leaves the app through the provider, as the last step of `back()` does: no Escape, no intent
481
+ * `back`. A provider `exit` that throws is logged, never thrown. Without a provider it does
482
+ * nothing.
483
+ *
484
+ * @example
485
+ * ```ts
486
+ * // merge-game's exit plugin answers the fx "exit" of the Leave button.
487
+ * ctx.require(flowPlugin).fx.handle("exit", () => ctx.require(platformPlugin).exit());
488
+ * // a press of Leave: the provider leaves the app; on the web page without a provider, nothing
489
+ * ```
490
+ */
491
+ exit(): void;
479
492
  };
480
493
  /**
481
494
  * What the kernel context offers the files of the plugin.
@@ -1127,6 +1140,46 @@ type MotionSpec = {
1127
1140
  */
1128
1141
  declare function defineMotion(spec: MotionSpec): ProjectionMotion<unknown>;
1129
1142
  //#endregion
1143
+ //#region src/plugins/i18n/intl.d.ts
1144
+ /**
1145
+ * Splits milliseconds into the record `Intl.DurationFormat` reads. The value is rounded up to
1146
+ * whole seconds, so a countdown never reads zero while time is left; a negative or non-finite
1147
+ * value is zero. Hours and minutes appear when above zero, seconds always, because `format({})`
1148
+ * throws. A generated `strings.<locale>.ts` imports it as `duration` for a `{left, duration}`
1149
+ * message, and `app.i18n.duration` splits the same way.
1150
+ *
1151
+ * @param ms - The duration in milliseconds.
1152
+ * @returns The hours, minutes and seconds of the duration.
1153
+ * @example
1154
+ * ```ts
1155
+ * // A chest that opens in 95 s, then in an hour and 5 s; a timer that ran out.
1156
+ * messageDuration(95_000); // { minutes: 1, seconds: 35 }
1157
+ * messageDuration(3_605_000); // { hours: 1, seconds: 5 }
1158
+ * messageDuration(-5); // { seconds: 0 }
1159
+ * ```
1160
+ */
1161
+ declare function messageDuration(ms: number): Partial<Record<Intl.DurationFormatUnit, number>>;
1162
+ /**
1163
+ * One plain argument of a compiled message as a part: an element node keeps its place in the
1164
+ * sentence, a list goes through `Intl.ListFormat` and a number through `Intl.NumberFormat` of the
1165
+ * kit's locale, anything else is read as text. A generated `strings.<locale>.ts` imports it as
1166
+ * `argument` for a message with `{name}`.
1167
+ *
1168
+ * @param value - The parameter of the message.
1169
+ * @param intl - The formatter kit of the locale the message is formatted in.
1170
+ * @returns The part.
1171
+ * @example
1172
+ * ```ts
1173
+ * // A compiled module written by hand, the shape `moku-game keys` writes for "Host: {name}".
1174
+ * const lobby: I18n.CompiledMessages = {
1175
+ * "lobby.host": (p, intl) => [{ kind: "text", text: "Host: " }, messageArgument(p.name, intl)]
1176
+ * };
1177
+ * app.i18n.plain(tr("lobby.host", { name: ["Ann", "Bob", "Cy"] })); // "Host: Ann, Bob, and Cy"
1178
+ * app.i18n.format(tr("lobby.host", { name: coin })); // [{ kind: "text", text: "Host: " }, { kind: "element", node: coin }]
1179
+ * ```
1180
+ */
1181
+ declare function messageArgument(value: unknown, intl: IntlKit): Part;
1182
+ //#endregion
1130
1183
  //#region src/plugins/i18n/tr.d.ts
1131
1184
  /**
1132
1185
  * Builds a message. The result is frozen and the parameters are copied, so the caller's object
@@ -1608,4 +1661,4 @@ declare const screen: readonly [import("@moku-labs/core").PluginInstance<"world"
1608
1661
  };
1609
1662
  }> & 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>];
1610
1663
  //#endregion
1611
- export { uiPlugin as $, Pointer as A, Layer as B, defineScene as C, label as Ct, DropTarget as D, Draggable as E, Tappable as F, resource as G, Tree as H, Touchable as I, guide as J, system as K, Traceable as L, Pressable as M, Pressed as N, Held as O, Swipeable as P, worldPlugin as Q, Traced as R, Frames as S, defineTextStyles as St, load as T, component as U, Order as V, mut as W, schedule as X, hint as Y, defineFeature as Z, defineStyle as _, animPlugin as _t, defineEmitter as a, BackResult as at, AnimPlayer as b, Text as bt, Alpha as c, modelPlugin as ct, Displacement as d, i18nPlugin as dt, timePlugin as et, Glow as f, flowPlugin as ft, resolve as g, assetsPlugin as gt, music as h, audioPlugin as ht, screen as i, platformPlugin as it, PointerOver as j, Hovered as k, Blur as l, lifecyclePlugin as lt, Outline as m, clockPlugin as mt, createPlugin as n, scenesPlugin as nt, Emitter as o, PlatformProvider as ot, Noise as p, effectsPlugin as pt, tag as q, defineGame as r, rendererPlugin as rt, defineFilter as s, types_d_exports as st, createApp as t, textPlugin as tt, ColorMatrix as u, inputPlugin as ut, tr as v, projection as vt, defineBundles as w, Animation as x, bind as xt, defineMotion as y, Countdown as yt, Exiting as z };
1664
+ 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 };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { $ as DescriptionNode, $t as types_d_exports$9, C as types_d_exports$11, Ct as slot, Kt as types_d_exports$3, P as types_d_exports$16, St as exit, Tt as type, bt as types_d_exports$5, in as SaveUnreadableError, m as types_d_exports$1, mn as types_d_exports$8, wt as to, yn as types_d_exports$14 } from "./types-ZQLYXo5X.mjs";
2
- import { B as sequence, F as frames, G as stagger, H as sfx, I as haptic, J as wait, K as tween, L as mark, M as HAPTIC_KINDS, N as defineAnimation, O as types_d_exports, P as external, R as parallel, U as spawn, V as set, W as spawned, b as types_d_exports$12, f as types_d_exports$2, i as types_d_exports$15, k as HapticKind, q as use, z as play } from "./types-BM4shh8K.mjs";
3
- import { a as types_d_exports$4 } from "./types-CefgYzFt.mjs";
4
- import { C as TextFormat, D as types_d_exports$13, H as Transform, I as Parent, L as Shape, M as types_d_exports$7, N as Display, O as defineComponent, P as NineSlice, W as sprite, Z as types_d_exports$6, d as popup, f as defineTokens, g as BindOptions, l as Box, u as LocalWrite, v as CountdownValue, z as Sprite } from "./types-BUwDHKXm.mjs";
5
- import { $ as uiPlugin, A as Pointer, B as Layer, C as defineScene, Ct as label, D as DropTarget, E as Draggable, F as Tappable, G as resource, H as Tree, I as Touchable, J as guide, K as system, L as Traceable, M as Pressable, N as Pressed, O as Held, P as Swipeable, Q as worldPlugin, R as Traced, S as Frames, St as defineTextStyles, T as load, U as component, V as Order, W as mut, X as schedule, Y as hint, Z as defineFeature, _ as defineStyle, _t as animPlugin, a as defineEmitter, at as BackResult, b as AnimPlayer, bt as Text, c as Alpha, ct as modelPlugin, d as Displacement, dt as i18nPlugin, et as timePlugin, f as Glow, ft as flowPlugin, g as resolve, gt as assetsPlugin, h as music, ht as audioPlugin, i as screen, it as platformPlugin, j as PointerOver, k as Hovered, l as Blur, lt as lifecyclePlugin, m as Outline, mt as clockPlugin, n as createPlugin, nt as scenesPlugin, o as Emitter, ot as PlatformProvider, p as Noise, pt as effectsPlugin, q as tag, r as defineGame, rt as rendererPlugin, s as defineFilter, st as types_d_exports$10, t as createApp, tt as textPlugin, u as ColorMatrix, ut as inputPlugin, v as tr, vt as projection, w as defineBundles, x as Animation, xt as bind, y as defineMotion, yt as Countdown, z as Exiting } from "./index-xxSxKJJW.mjs";
6
- export { Alpha, types_d_exports as Anim, AnimPlayer, Animation, types_d_exports$1 as Assets, types_d_exports$2 as Audio, type BackResult, type BindOptions, Blur, Box, types_d_exports$3 as Clock, ColorMatrix, Countdown, type CountdownValue, type DescriptionNode, Displacement, Display, Draggable, DropTarget, types_d_exports$4 as Effects, Emitter, Exiting, types_d_exports$5 as Flow, Frames, Glow, HAPTIC_KINDS, type HapticKind, Held, Hovered, types_d_exports$6 as I18n, types_d_exports$7 as Input, Layer, types_d_exports$8 as Lifecycle, LocalWrite, types_d_exports$9 as Model, NineSlice, Noise, Order, Outline, Parent, types_d_exports$10 as Platform, type PlatformProvider, Pointer, PointerOver, Pressable, Pressed, types_d_exports$11 as Renderer, SaveUnreadableError, types_d_exports$12 as Scenes, Shape, Sprite, Swipeable, Tappable, Text, type TextFormat, types_d_exports$13 as TextTypes, types_d_exports$14 as Time, Touchable, Traceable, Traced, Transform, Tree, types_d_exports$15 as Ui, types_d_exports$16 as World, animPlugin, assetsPlugin, audioPlugin, bind, clockPlugin, component, createApp, createPlugin, defineAnimation, defineBundles, defineComponent, defineEmitter, defineFeature, defineFilter, defineGame, defineMotion, defineScene, defineStyle, defineTextStyles, defineTokens, effectsPlugin, exit, external, flowPlugin, frames, guide, haptic, hint, i18nPlugin, inputPlugin, label, lifecyclePlugin, load, mark, modelPlugin, music, mut, parallel, platformPlugin, 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 };
2
+ import { B as sequence, F as frames, G as stagger, H as sfx, I as haptic, J as wait, K as tween, L as mark, M as HAPTIC_KINDS, N as defineAnimation, O as types_d_exports, P as external, R as parallel, U as spawn, V as set, W as spawned, b as types_d_exports$12, f as types_d_exports$2, i as types_d_exports$15, k as HapticKind, q as use, z as play } from "./types-D_2G6Q68.mjs";
3
+ import { a as types_d_exports$4 } from "./types-Bcdo5-2w.mjs";
4
+ import { $ as types_d_exports$6, C as TextFormat, D as types_d_exports$13, H as Transform, I as Parent, L as Shape, M as types_d_exports$7, N as Display, O as defineComponent, P as NineSlice, W as sprite, d as popup, f as defineTokens, g as BindOptions, l as Box, u as LocalWrite, v as CountdownValue, z as Sprite } from "./types-BrTpz9oL.mjs";
5
+ import { $ as defineFeature, A as Held, B as Traced, C as Animation, Ct as bind, D as load, E as defineBundles, F as Pressed, G as component, H as Layer, I as Swipeable, J as system, K as mut, L as Tappable, M as Pointer, N as PointerOver, O as Draggable, P as Pressable, Q as schedule, R as Touchable, S as AnimPlayer, St as Text, T as defineScene, Tt as label, U as Order, V as Exiting, W as Tree, X as guide, Y as tag, Z as hint, _ as defineStyle, _t as audioPlugin, a as defineEmitter, at as rendererPlugin, b as messageDuration, bt as projection, c as Alpha, ct as PlatformProvider, d as Displacement, dt as lifecyclePlugin, et as worldPlugin, f as Glow, ft as inputPlugin, g as resolve, gt as clockPlugin, h as music, ht as effectsPlugin, i as screen, it as scenesPlugin, j as Hovered, k as DropTarget, l as Blur, lt as types_d_exports$10, m as Outline, mt as flowPlugin, n as createPlugin, nt as timePlugin, o as Emitter, ot as platformPlugin, p as Noise, pt as i18nPlugin, q as resource, r as defineGame, rt as textPlugin, s as defineFilter, st as BackResult, t as createApp, tt as uiPlugin, u as ColorMatrix, ut as modelPlugin, v as tr, vt as assetsPlugin, w as Frames, wt as defineTextStyles, x as defineMotion, xt as Countdown, y as messageArgument, yt as animPlugin, z as Traceable } from "./index-rnOYAriI.mjs";
6
+ export { Alpha, types_d_exports as Anim, AnimPlayer, Animation, types_d_exports$1 as Assets, types_d_exports$2 as Audio, type BackResult, type BindOptions, Blur, Box, types_d_exports$3 as Clock, ColorMatrix, Countdown, type CountdownValue, type DescriptionNode, Displacement, Display, Draggable, DropTarget, types_d_exports$4 as Effects, Emitter, Exiting, types_d_exports$5 as Flow, Frames, Glow, HAPTIC_KINDS, type HapticKind, Held, Hovered, types_d_exports$6 as I18n, types_d_exports$7 as Input, Layer, types_d_exports$8 as Lifecycle, LocalWrite, types_d_exports$9 as Model, NineSlice, Noise, Order, Outline, Parent, types_d_exports$10 as Platform, type PlatformProvider, Pointer, PointerOver, Pressable, Pressed, types_d_exports$11 as Renderer, SaveUnreadableError, types_d_exports$12 as Scenes, Shape, Sprite, Swipeable, Tappable, Text, type TextFormat, types_d_exports$13 as TextTypes, types_d_exports$14 as Time, Touchable, Traceable, Traced, Transform, Tree, types_d_exports$15 as Ui, types_d_exports$16 as World, animPlugin, assetsPlugin, audioPlugin, bind, clockPlugin, component, createApp, createPlugin, defineAnimation, defineBundles, defineComponent, defineEmitter, defineFeature, defineFilter, defineGame, defineMotion, defineScene, defineStyle, defineTextStyles, defineTokens, effectsPlugin, exit, external, flowPlugin, frames, guide, haptic, hint, i18nPlugin, inputPlugin, label, lifecyclePlugin, load, mark, messageArgument, messageDuration, modelPlugin, music, mut, parallel, platformPlugin, 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 };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as sfx, A as types_exports$3, At as defineFilter, B as defineStyle, Bt as flowPlugin, C as types_exports$10, Ct as Alpha, D as types_exports$6, Dt as Glow, E as types_exports$7, Et as Displacement, F as resolve, Ft as AnimPlayer, G as external, Gt as modelPlugin, H as platformPlugin, Ht as slot, I as Box, It as Animation, J as mark, Jt as timePlugin, K as frames, Kt as SaveUnreadableError, L as LocalWrite, Lt as Frames, M as types_exports$1, Mt as scenesPlugin, N as types_exports, Nt as assetsPlugin, O as types_exports$5, Ot as Noise, P as uiPlugin, Pt as animPlugin, Q as set, R as popup, Rt as rendererPlugin, S as types_exports$11, St as Emitter, T as types_exports$8, Tt as ColorMatrix, U as HAPTIC_KINDS, Ut as to, V as textPlugin, Vt as exit, W as defineAnimation, Wt as type, X as play, Y as parallel, Yt as clockPlugin, Z as sequence, _ as types_exports$16, _t as Touchable, a as defineMotion, at as wait, b as types_exports$13, bt as i18nPlugin, c as schedule, ct as DropTarget, d as tr, dt as Pointer, et as spawn, f as defineFeature, ft as PointerOver, g as load, gt as Tappable, h as defineBundles, ht as Swipeable, i as screen, it as use, j as types_exports$2, jt as audioPlugin, k as types_exports$4, kt as Outline, l as projection, lt as Held, m as music, mt as Pressed, n as createPlugin, nt as stagger, o as guide, ot as inputPlugin, p as defineEmitter, pt as Pressable, q as haptic, qt as lifecyclePlugin, r as defineGame, rt as tween, s as hint, st as Draggable, t as createApp, tt as spawned, u as defineScene, ut as Hovered, v as types_exports$15, vt as Traceable, w as types_exports$9, wt as Blur, x as types_exports$12, xt as effectsPlugin, y as types_exports$14, yt as Traced, z as defineTokens, zt as worldPlugin } from "./src-DSl1eNB1.mjs";
1
+ import { $ as sfx, A as types_exports$3, At as Noise, B as defineStyle, Bt as rendererPlugin, C as types_exports$10, Ct as effectsPlugin, D as types_exports$6, Dt as ColorMatrix, E as types_exports$7, Et as Blur, F as resolve, Ft as assetsPlugin, G as external, Gt as to, H as platformPlugin, Ht as flowPlugin, I as Box, It as animPlugin, J as mark, Jt as SaveUnreadableError, K as frames, Kt as type, L as LocalWrite, Lt as AnimPlayer, M as types_exports$1, Mt as defineFilter, N as types_exports, Nt as audioPlugin, O as types_exports$5, Ot as Displacement, P as uiPlugin, Pt as scenesPlugin, Q as set, R as popup, Rt as Animation, S as types_exports$11, St as messageDuration, T as types_exports$8, Tt as Alpha, U as HAPTIC_KINDS, Ut as exit, V as textPlugin, Vt as worldPlugin, W as defineAnimation, Wt as slot, X as play, Xt as timePlugin, Y as parallel, Yt as lifecyclePlugin, Z as sequence, Zt as clockPlugin, _ as types_exports$16, _t as Touchable, a as defineMotion, at as wait, b as types_exports$13, bt as i18nPlugin, c as schedule, ct as DropTarget, d as tr, dt as Pointer, et as spawn, f as defineFeature, ft as PointerOver, g as load, gt as Tappable, h as defineBundles, ht as Swipeable, i as screen, it as use, j as types_exports$2, jt as Outline, k as types_exports$4, kt as Glow, l as projection, lt as Held, m as music, mt as Pressed, n as createPlugin, nt as stagger, o as guide, ot as inputPlugin, p as defineEmitter, pt as Pressable, q as haptic, qt as modelPlugin, r as defineGame, rt as tween, s as hint, st as Draggable, t as createApp, tt as spawned, u as defineScene, ut as Hovered, v as types_exports$15, vt as Traceable, w as types_exports$9, wt as Emitter, x as types_exports$12, xt as messageArgument, y as types_exports$14, yt as Traced, z as defineTokens, zt as Frames } from "./src-SmT-XxVf.mjs";
2
2
  import { A as system, C as Exiting, D as component, E as Tree, O as mut, S as sprite, T as Order, _ as Parent, b as Transform, c as Text, d as defineTextStyles, f as label, g as NineSlice, h as Display, j as tag, k as resource, l as bind, s as Countdown, v as Shape, w as Layer, y as Sprite } from "./visual-dMW8iqAE.mjs";
3
3
  import { r as defineComponent } from "./flatten-BkXuscAV.mjs";
4
- export { Alpha, types_exports as Anim, AnimPlayer, Animation, types_exports$1 as Assets, types_exports$2 as Audio, Blur, Box, types_exports$3 as Clock, ColorMatrix, Countdown, Displacement, Display, Draggable, DropTarget, types_exports$4 as Effects, Emitter, Exiting, types_exports$5 as Flow, Frames, Glow, HAPTIC_KINDS, Held, Hovered, types_exports$6 as I18n, types_exports$7 as Input, Layer, types_exports$8 as Lifecycle, LocalWrite, types_exports$9 as Model, NineSlice, Noise, Order, Outline, Parent, types_exports$10 as Platform, Pointer, PointerOver, Pressable, Pressed, types_exports$11 as Renderer, SaveUnreadableError, types_exports$12 as Scenes, Shape, Sprite, Swipeable, Tappable, Text, types_exports$13 as TextTypes, types_exports$14 as Time, Touchable, Traceable, Traced, Transform, Tree, types_exports$15 as Ui, types_exports$16 as World, animPlugin, assetsPlugin, audioPlugin, bind, clockPlugin, component, createApp, createPlugin, defineAnimation, defineBundles, defineComponent, defineEmitter, defineFeature, defineFilter, defineGame, defineMotion, defineScene, defineStyle, defineTextStyles, defineTokens, effectsPlugin, exit, external, flowPlugin, frames, guide, haptic, hint, i18nPlugin, inputPlugin, label, lifecyclePlugin, load, mark, modelPlugin, music, mut, parallel, platformPlugin, 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 };
4
+ export { Alpha, types_exports as Anim, AnimPlayer, Animation, types_exports$1 as Assets, types_exports$2 as Audio, Blur, Box, types_exports$3 as Clock, ColorMatrix, Countdown, Displacement, Display, Draggable, DropTarget, types_exports$4 as Effects, Emitter, Exiting, types_exports$5 as Flow, Frames, Glow, HAPTIC_KINDS, Held, Hovered, types_exports$6 as I18n, types_exports$7 as Input, Layer, types_exports$8 as Lifecycle, LocalWrite, types_exports$9 as Model, NineSlice, Noise, Order, Outline, Parent, types_exports$10 as Platform, Pointer, PointerOver, Pressable, Pressed, types_exports$11 as Renderer, SaveUnreadableError, types_exports$12 as Scenes, Shape, Sprite, Swipeable, Tappable, Text, types_exports$13 as TextTypes, types_exports$14 as Time, Touchable, Traceable, Traced, Transform, Tree, types_exports$15 as Ui, types_exports$16 as World, animPlugin, assetsPlugin, audioPlugin, bind, clockPlugin, component, createApp, createPlugin, defineAnimation, defineBundles, defineComponent, defineEmitter, defineFeature, defineFilter, defineGame, defineMotion, defineScene, defineStyle, defineTextStyles, defineTokens, effectsPlugin, exit, external, flowPlugin, frames, guide, haptic, hint, i18nPlugin, inputPlugin, label, lifecyclePlugin, load, mark, messageArgument, messageDuration, modelPlugin, music, mut, parallel, platformPlugin, 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 };
@@ -1,7 +1,7 @@
1
1
  import { A as Api$1, At as FlowGraph, M as Explained, Mt as JournalEntry, S as Under, T as RenderStats, U as EntitySnapshot, W as FrameDiff, _t as Position, an as Snapshot, h as Api$2, p as Usage, qt as Api, t as Api$3, z as ComponentSchema } from "./types-ZQLYXo5X.mjs";
2
- import { a as AudioApi, r as UiApi, u as SoundEntry } from "./types-BM4shh8K.mjs";
3
- import { n as EffectsApi, r as EffectsStats } from "./types-CefgYzFt.mjs";
4
- import { c as UiNode } from "./types-BUwDHKXm.mjs";
2
+ import { a as AudioApi, r as UiApi, u as SoundEntry } from "./types-D_2G6Q68.mjs";
3
+ import { n as EffectsApi, r as EffectsStats } from "./types-Bcdo5-2w.mjs";
4
+ import { c as UiNode } from "./types-BrTpz9oL.mjs";
5
5
  import { t as HeadlessApp } from "./headless-G4nuZ-xz.mjs";
6
6
  import { a as InputOf, c as Source, i as InputArguments, l as WatchApp, o as InputSchema, t as CheatEntry, u as WatchInput } from "./types-DAdwEJMp.mjs";
7
7
  import { n as defineSource } from "./define-CCc0ozKe.mjs";
@@ -1,2 +1,2 @@
1
- import { a as jsxs, i as jsxDEV, n as JSX, r as jsx, t as Fragment } from "./runtime-DOBYM6g4.mjs";
1
+ import { a as jsxs, i as jsxDEV, n as JSX, r as jsx, t as Fragment } from "./runtime-B276Gg0s.mjs";
2
2
  export { Fragment, type JSX, jsx, jsxDEV, jsxs };
@@ -1,2 +1,2 @@
1
- import { a as jsxs, n as JSX, r as jsx, t as Fragment } from "./runtime-DOBYM6g4.mjs";
1
+ import { a as jsxs, n as JSX, r as jsx, t as Fragment } from "./runtime-B276Gg0s.mjs";
2
2
  export { Fragment, type JSX, jsx, jsxs };
package/dist/lint.mjs CHANGED
@@ -1370,6 +1370,8 @@ function isHelper(folders) {
1370
1370
  }
1371
1371
  /**
1372
1372
  * What test-suffix says about a file: a file in a test kind folder ends with that folder's suffix.
1373
+ * The `index` of a kind folder passes: it is the folder's door, such as the module of
1374
+ * `moku-game visual`, `tests/visual/index.ts`.
1373
1375
  *
1374
1376
  * @param file - The file, relative to the game root.
1375
1377
  * @param table - Kind folder to suffix.
@@ -1387,7 +1389,7 @@ function suffixMessage(file, table) {
1387
1389
  const kind = isHelper(folder.split("/")) ? void 0 : kindOf(`/${folder}/`, table);
1388
1390
  if (extension === void 0 || kind === void 0) return void 0;
1389
1391
  const suffix = extension === TSX_EXTENSION && kind.suffix.endsWith(TS_EXTENSION) ? `${kind.suffix}x` : kind.suffix;
1390
- if (name.endsWith(suffix)) return void 0;
1392
+ if (name.endsWith(suffix) || INDEX_FILE.test(name)) return void 0;
1391
1393
  const renamed = `${name.slice(0, -extension.length).replace(TEST_WORD, "")}${suffix}`;
1392
1394
  const helpers = kind.folder.includes(COLOCATED_TESTS) ? COLOCATED_HELPERS : ROOT_HELPERS;
1393
1395
  return `Tests: a file in ${kind.folder} ends with ${suffix}. Rename ${name} to ${renamed}, or move a helper to ${helpers}.`;
@@ -1,4 +1,4 @@
1
- import { a as JsxChild, m as UiIntrinsicElements, t as DescriptionNode } from "./types-BUwDHKXm.mjs";
1
+ import { a as JsxChild, m as UiIntrinsicElements, t as DescriptionNode } from "./types-BrTpz9oL.mjs";
2
2
 
3
3
  //#region src/plugins/ui/jsx/runtime.d.ts
4
4
  /** What the compiler passes as props: the children plus whatever the tag declared. */
@@ -20908,16 +20908,20 @@ function buildDurationFormat(locale, options) {
20908
20908
  * Splits milliseconds into the record `Intl.DurationFormat` reads. The value is rounded up to
20909
20909
  * whole seconds, so a countdown never reads zero while time is left; a negative or non-finite
20910
20910
  * value is zero. Hours and minutes appear when above zero, seconds always, because `format({})`
20911
- * throws. The generated `duration(ms)` helper of a locale module does the same split.
20911
+ * throws. A generated `strings.<locale>.ts` imports it as `duration` for a `{left, duration}`
20912
+ * message, and `app.i18n.duration` splits the same way.
20912
20913
  *
20913
20914
  * @param ms - The duration in milliseconds.
20914
20915
  * @returns The hours, minutes and seconds of the duration.
20915
20916
  * @example
20916
20917
  * ```ts
20917
- * durationInput(95_000); // { minutes: 1, seconds: 35 }
20918
+ * // A chest that opens in 95 s, then in an hour and 5 s; a timer that ran out.
20919
+ * messageDuration(95_000); // { minutes: 1, seconds: 35 }
20920
+ * messageDuration(3_605_000); // { hours: 1, seconds: 5 }
20921
+ * messageDuration(-5); // { seconds: 0 }
20918
20922
  * ```
20919
20923
  */
20920
- function durationInput(ms) {
20924
+ function messageDuration(ms) {
20921
20925
  const total = Number.isFinite(ms) ? Math.max(0, Math.ceil(ms / SECOND)) : 0;
20922
20926
  const hours = Math.floor(total / HOUR);
20923
20927
  const minutes = Math.floor(total % HOUR / MINUTE);
@@ -20928,6 +20932,52 @@ function durationInput(ms) {
20928
20932
  return input;
20929
20933
  }
20930
20934
  /**
20935
+ * Tells whether a parameter is an element node: an object with `type`, `props` and `children`.
20936
+ *
20937
+ * @param value - The parameter of the message.
20938
+ * @returns True for an element node.
20939
+ */
20940
+ function isElementNode(value) {
20941
+ return typeof value === "object" && value !== null && "type" in value && "props" in value && "children" in value;
20942
+ }
20943
+ /**
20944
+ * One plain argument of a compiled message as a part: an element node keeps its place in the
20945
+ * sentence, a list goes through `Intl.ListFormat` and a number through `Intl.NumberFormat` of the
20946
+ * kit's locale, anything else is read as text. A generated `strings.<locale>.ts` imports it as
20947
+ * `argument` for a message with `{name}`.
20948
+ *
20949
+ * @param value - The parameter of the message.
20950
+ * @param intl - The formatter kit of the locale the message is formatted in.
20951
+ * @returns The part.
20952
+ * @example
20953
+ * ```ts
20954
+ * // A compiled module written by hand, the shape `moku-game keys` writes for "Host: {name}".
20955
+ * const lobby: I18n.CompiledMessages = {
20956
+ * "lobby.host": (p, intl) => [{ kind: "text", text: "Host: " }, messageArgument(p.name, intl)]
20957
+ * };
20958
+ * app.i18n.plain(tr("lobby.host", { name: ["Ann", "Bob", "Cy"] })); // "Host: Ann, Bob, and Cy"
20959
+ * app.i18n.format(tr("lobby.host", { name: coin })); // [{ kind: "text", text: "Host: " }, { kind: "element", node: coin }]
20960
+ * ```
20961
+ */
20962
+ function messageArgument(value, intl) {
20963
+ if (Array.isArray(value)) return {
20964
+ kind: "text",
20965
+ text: intl.list().format(value)
20966
+ };
20967
+ if (typeof value === "number") return {
20968
+ kind: "text",
20969
+ text: intl.number().format(value)
20970
+ };
20971
+ if (isElementNode(value)) return {
20972
+ kind: "element",
20973
+ node: value
20974
+ };
20975
+ return {
20976
+ kind: "text",
20977
+ text: String(value)
20978
+ };
20979
+ }
20980
+ /**
20931
20981
  * Creates the formatter kit of one locale. Every kit is built once, on first use of its locale,
20932
20982
  * and kept in `state.intl`.
20933
20983
  *
@@ -21381,7 +21431,7 @@ function createI18nApi(ctx) {
21381
21431
  duration: (ms, style = "short") => kitOf(ctx.state, ctx.state.locale).duration({
21382
21432
  style,
21383
21433
  secondsDisplay: "always"
21384
- }).format(durationInput(ms)),
21434
+ }).format(messageDuration(ms)),
21385
21435
  locales: () => [...ctx.state.registered.keys()].toSorted(),
21386
21436
  replace: (locale, messages) => replaceModule(ctx, locale, messages)
21387
21437
  };
@@ -23490,13 +23540,24 @@ function setAwake(ctx, provider, on) {
23490
23540
  //#endregion
23491
23541
  //#region src/plugins/platform/api.ts
23492
23542
  /**
23493
- * @file platform plugin — API factory and the Back chain. One press runs three steps and the
23494
- * first that takes it wins: the Escape button of the top popup, the intent `back` of the resting
23495
- * node, the provider leaving the app.
23543
+ * @file platform plugin — API factory, the Back chain and the exit. One press runs three steps and
23544
+ * the first that takes it wins: the Escape button of the top popup, the intent `back` of the
23545
+ * resting node, the provider leaving the app. `exit()` is that last step alone.
23496
23546
  */
23497
23547
  /** The intent a resting node lists to take the Back press itself. */
23498
23548
  const BACK_INTENT = "back";
23499
23549
  /**
23550
+ * Leaves the app through the provider, guarded like every provider call. Without a provider it
23551
+ * does nothing. The last step of the Back chain and `exit()` both go through here.
23552
+ *
23553
+ * @param ctx - Kernel context of the platform plugin.
23554
+ */
23555
+ function leave(ctx) {
23556
+ const provider = ctx.config.provider;
23557
+ if (provider === void 0) return;
23558
+ safely(ctx.log, "exit", () => provider.exit());
23559
+ }
23560
+ /**
23500
23561
  * Runs the Back chain once. `back()` and the provider's `onBack` both go through here, so a test
23501
23562
  * and a real press end the same way. Escape is what ui answers with the `escape` button of its
23502
23563
  * top root; it also ends the editing of a text field. While the graph moves between nodes the gate
@@ -23507,22 +23568,24 @@ const BACK_INTENT = "back";
23507
23568
  * @returns What took the press, `"none"` without a provider.
23508
23569
  */
23509
23570
  function runBack(ctx) {
23510
- const provider = ctx.config.provider;
23511
- if (provider === void 0) return "none";
23571
+ if (ctx.config.provider === void 0) return "none";
23512
23572
  if (ctx.require(inputPlugin).pressKey("Escape")) return "popup";
23513
23573
  const gate = ctx.require(flowPlugin).gate;
23514
23574
  if (gate.answer({ intent: BACK_INTENT }) || !gate.state().open) return "intent";
23515
- safely(ctx.log, "exit", () => provider.exit());
23575
+ leave(ctx);
23516
23576
  return "exit";
23517
23577
  }
23518
23578
  /**
23519
- * Creates the platform API: the Back chain on demand.
23579
+ * Creates the platform API: the Back chain and the exit on demand.
23520
23580
  *
23521
23581
  * @param ctx - Kernel context of the platform plugin.
23522
23582
  * @returns The plugin API.
23523
23583
  */
23524
23584
  function createPlatformApi(ctx) {
23525
- return { back: () => runBack(ctx) };
23585
+ return {
23586
+ back: () => runBack(ctx),
23587
+ exit: () => leave(ctx)
23588
+ };
23526
23589
  }
23527
23590
  //#endregion
23528
23591
  //#region src/plugins/platform/state.ts
@@ -34254,7 +34317,7 @@ function defineMotion(spec) {
34254
34317
  * |---|---|
34255
34318
  * | `@moku-labs/game/app` | `defineGameApp`, the game as one data object with `headless()` and `screen()`; `startMoment`; the types of `index.ts` and `config.ts` (`GameConfig`) |
34256
34319
  * | `@moku-labs/game/app/page` | `startPage`, the page the generated `.moku/main.ts` calls: `?player=` scenarios, the system shell, the dev agents |
34257
- * | `@moku-labs/game/app/system` | the system shell over the optional peer `@moku-labs/system`: `systemShell`, `fromSystem`, `storeSave`, `createSystemApp` |
34320
+ * | `@moku-labs/game/app/system` | the system shell over the optional peer `@moku-labs/system`: `systemShellOf`, `fromSystem`, `storeSave`, `createSystemApp` |
34258
34321
  * | `@moku-labs/game/cli` | `runCli` of the bin `moku-game` and `preparePage` for the editor, node and bun only |
34259
34322
  * | `@moku-labs/game/testing` | headless play, repro runs, isolated feature tests (`isolate`, `stub`), the in-memory save, the fake clock |
34260
34323
  * | `@moku-labs/game/visual` | the visual tests, node and bun only |
@@ -34266,7 +34329,7 @@ function defineMotion(spec) {
34266
34329
  * | `@moku-labs/game/project` | the project index of a game's sources, node and bun only |
34267
34330
  * | `@moku-labs/game/jsx-runtime`, `/jsx-dev-runtime` | the JSX runtimes `jsxImportSource: "@moku-labs/game"` names |
34268
34331
  * | `@moku-labs/game/fonts/*` | the MSDF body font `font-body.fnt` + `.png` and its OFL licence; a game copies them into `features/ui/assets/` |
34269
- * | bin `moku-game` | `dev`, `build`, `native <verb>`, `keys`, `pack`: serves, builds, packages and packs a game folder, bun only |
34332
+ * | bin `moku-game` | `dev`, `build`, `native <verb>`, `keys`, `pack`, `visual`: serves, builds, packages, packs and visually tests a game folder, bun only |
34270
34333
  * | bin `moku-game-assets` | the asset scanner CLI, bun only |
34271
34334
  * | bin `moku-game-index` | the project index CLI, bun only |
34272
34335
  *
@@ -34363,4 +34426,4 @@ const screen = [
34363
34426
  uiPlugin
34364
34427
  ];
34365
34428
  //#endregion
34366
- export { sfx as $, types_exports$13 as A, defineFilter as At, defineStyle as B, flowPlugin as Bt, types_exports$6 as C, Alpha as Ct, types_exports$10 as D, Glow as Dt, types_exports$9 as E, Displacement as Et, resolve as F, AnimPlayer as Ft, external as G, modelPlugin as Gt, platformPlugin as H, slot as Ht, Box as I, Animation as It, mark as J, timePlugin as Jt, frames as K, SaveUnreadableError as Kt, LocalWrite as L, Frames as Lt, types_exports$15 as M, scenesPlugin as Mt, types_exports$16 as N, assetsPlugin as Nt, types_exports$11 as O, Noise as Ot, uiPlugin as P, animPlugin as Pt, set as Q, popup as R, rendererPlugin as Rt, types_exports$5 as S, Emitter as St, types_exports$8 as T, ColorMatrix as Tt, HAPTIC_KINDS as U, to as Ut, textPlugin as V, exit as Vt, defineAnimation as W, type as Wt, play$1 as X, parallel as Y, clockPlugin as Yt, sequence as Z, types_exports as _, Touchable as _t, defineMotion as a, wait as at, types_exports$3 as b, i18nPlugin as bt, schedule as c, DropTarget as ct, tr as d, Pointer as dt, spawn as et, defineFeature as f, PointerOver as ft, load as g, Tappable as gt, defineBundles as h, Swipeable as ht, screen as i, use as it, types_exports$14 as j, audioPlugin as jt, types_exports$12 as k, Outline as kt, projection as l, Held as lt, music as m, Pressed as mt, createPlugin as n, stagger as nt, guide as o, inputPlugin as ot, defineEmitter as p, Pressable as pt, haptic as q, lifecyclePlugin as qt, defineGame as r, tween as rt, hint as s, Draggable as st, createApp as t, spawned as tt, defineScene as u, Hovered as ut, types_exports$1 as v, Traceable as vt, types_exports$7 as w, Blur as wt, types_exports$4 as x, effectsPlugin as xt, types_exports$2 as y, Traced as yt, defineTokens as z, worldPlugin as zt };
34429
+ export { sfx as $, types_exports$13 as A, Noise as At, defineStyle as B, rendererPlugin as Bt, types_exports$6 as C, effectsPlugin as Ct, types_exports$10 as D, ColorMatrix as Dt, types_exports$9 as E, Blur as Et, resolve as F, assetsPlugin as Ft, external as G, to as Gt, platformPlugin as H, flowPlugin as Ht, Box as I, animPlugin as It, mark as J, SaveUnreadableError as Jt, frames as K, type as Kt, LocalWrite as L, AnimPlayer as Lt, types_exports$15 as M, defineFilter as Mt, types_exports$16 as N, audioPlugin as Nt, types_exports$11 as O, Displacement as Ot, uiPlugin as P, scenesPlugin as Pt, set as Q, popup as R, Animation as Rt, types_exports$5 as S, messageDuration as St, types_exports$8 as T, Alpha as Tt, HAPTIC_KINDS as U, exit as Ut, textPlugin as V, worldPlugin as Vt, defineAnimation as W, slot as Wt, play$1 as X, timePlugin as Xt, parallel as Y, lifecyclePlugin as Yt, sequence as Z, clockPlugin as Zt, types_exports as _, Touchable as _t, defineMotion as a, wait as at, types_exports$3 as b, i18nPlugin as bt, schedule as c, DropTarget as ct, tr as d, Pointer as dt, spawn as et, defineFeature as f, PointerOver as ft, load as g, Tappable as gt, defineBundles as h, Swipeable as ht, screen as i, use as it, types_exports$14 as j, Outline as jt, types_exports$12 as k, Glow as kt, projection as l, Held as lt, music as m, Pressed as mt, createPlugin as n, stagger as nt, guide as o, inputPlugin as ot, defineEmitter as p, Pressable as pt, haptic as q, modelPlugin as qt, defineGame as r, tween as rt, hint as s, Draggable as st, createApp as t, spawned as tt, defineScene as u, Hovered as ut, types_exports$1 as v, Traceable as vt, types_exports$7 as w, Emitter as wt, types_exports$4 as x, messageArgument as xt, types_exports$2 as y, Traced as yt, defineTokens as z, Frames as zt };
@@ -1,5 +1,5 @@
1
1
  import { Dt as AnyFlow, Ht as ClockSource, Nt as NodeTable, Wt as FakeClock, Xt as Json, ht as FeaturePlugin } from "./types-ZQLYXo5X.mjs";
2
- import { t as createApp } from "./index-xxSxKJJW.mjs";
2
+ import { t as createApp } from "./index-rnOYAriI.mjs";
3
3
  import { n as saveOf, t as memory } from "./memory-DwDhfFWK.mjs";
4
4
  import { a as createHeadless, i as ReproResult, n as HeadlessGame, o as runRepro, r as Repro, s as stepFrames, t as HeadlessApp } from "./headless-G4nuZ-xz.mjs";
5
5
  import { AnyPluginInstance } from "@moku-labs/core";
package/dist/testing.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { Vt as exit, Wt as type, t as createApp } from "./src-DSl1eNB1.mjs";
1
+ import { Kt as type, Ut as exit, t as createApp } from "./src-SmT-XxVf.mjs";
2
2
  import { n as saveOf, t as memory } from "./memory-CWlqhS7l.mjs";
3
3
  import { t as fakeClock } from "./fake-MpzwZhIZ.mjs";
4
4
  import { i as stepFrames, r as runRepro, t as createHeadless } from "./headless-BsNdJs9W.mjs";
@@ -1,5 +1,5 @@
1
1
  import { A as Api$1, B as ComponentType, D as FilterSlot, H as Entity, O as Point, R as ComponentHandle, Sn as Require, _ as PixiFilter, b as PixiTexture, dt as Api, h as Api$2, s as Events, t as Api$3, v as PixiModule, xn as Events$1, y as PixiSprite } from "./types-ZQLYXo5X.mjs";
2
- import { x as AnimApi } from "./types-BM4shh8K.mjs";
2
+ import { x as AnimApi } from "./types-D_2G6Q68.mjs";
3
3
  import { Log } from "@moku-labs/common/browser";
4
4
  import { PluginCtx } from "@moku-labs/core";
5
5
 
@@ -2777,4 +2777,4 @@ type CommonProps = {
2777
2777
  components?: ElementComponents;
2778
2778
  };
2779
2779
  //#endregion
2780
- export { ResolvedStyle as $, InputApi as A, SpriteOptions as B, TextFormat as C, types_d_exports as D, TextValue as E, NineSliceValue as F, Argument as G, Transform as H, Parent as I, Message as J, Config$2 as K, Shape as L, types_d_exports$1 as M, Display as N, defineComponent as O, NineSlice as P, IsFlags as Q, ShapeValue as R, TextBind as S, TextStyles as T, TransformValue as U, SpriteValue as V, sprite as W, TypedTr as X, State$2 as Y, types_d_exports$2 as Z, Config as _, JsxChild as a, State as b, UiNode as c, popup as d, Style as et, defineTokens as f, BindOptions as g, BindField as h, Finding as i, State$1 as j, Config$1 as k, Box as l, UiIntrinsicElements as m, ElementChange as n, WhenFlags as nt, JsxState as o, IntrinsicElementsFor as p, I18nApi as q, ElementMotion as r, PopupComponent as s, DescriptionNode as t, StylesState as tt, LocalWrite as u, CountdownValue as v, TextStyleInput as w, TextApi as x, Point as y, Sprite as z };
2780
+ export { types_d_exports$2 as $, InputApi as A, SpriteOptions as B, TextFormat as C, types_d_exports as D, TextValue as E, NineSliceValue as F, Argument as G, Transform as H, Parent as I, IntlKit as J, Config$2 as K, Shape as L, types_d_exports$1 as M, Display as N, defineComponent as O, NineSlice as P, TypedTr as Q, ShapeValue as R, TextBind as S, TextStyles as T, TransformValue as U, SpriteValue as V, sprite as W, Part as X, Message as Y, State$2 as Z, Config as _, JsxChild as a, State as b, UiNode as c, popup as d, IsFlags as et, defineTokens as f, BindOptions as g, BindField as h, Finding as i, WhenFlags as it, State$1 as j, Config$1 as k, Box as l, UiIntrinsicElements as m, ElementChange as n, Style as nt, JsxState as o, IntrinsicElementsFor as p, I18nApi as q, ElementMotion as r, StylesState as rt, PopupComponent as s, DescriptionNode as t, ResolvedStyle as tt, LocalWrite as u, CountdownValue as v, TextStyleInput as w, TextApi as x, Point as y, Sprite as z };
@@ -1,6 +1,6 @@
1
1
  import { Dt as AnyFlow, Ht as ClockSource, Jt as Config, Wt as FakeClock, Xt as Json, a as Config$3, g as Config$2, ht as FeaturePlugin, n as AssetsIo, pt as Config$1, tn as PlayerStateProvider, u as Manifest, v as PixiModule } from "./types-ZQLYXo5X.mjs";
2
- import { o as AudioContextLike, s as Config$4 } from "./types-BM4shh8K.mjs";
3
- import { ht as audioPlugin, i as screen, it as platformPlugin, ot as PlatformProvider, pt as effectsPlugin, t as createApp } from "./index-xxSxKJJW.mjs";
2
+ import { o as AudioContextLike, s as Config$4 } from "./types-D_2G6Q68.mjs";
3
+ import { _t as audioPlugin, ct as PlatformProvider, ht as effectsPlugin, i as screen, ot as platformPlugin, t as createApp } from "./index-rnOYAriI.mjs";
4
4
  import { t as memory } from "./memory-DwDhfFWK.mjs";
5
5
  import { AnyPluginInstance } from "@moku-labs/core";
6
6
 
@@ -440,12 +440,14 @@ type PageAgent<App = ScreenAppOfGame<AnyGameApp>> = (page: {
440
440
  modules: readonly object[];
441
441
  }) => void | Promise<void>;
442
442
  /**
443
- * Builds the system shell from the resolved config: the type of `systemShell` of
444
- * `@moku-labs/game/app/system`. The page reaches the shell only through this.
443
+ * Builds the system shell from the resolved config: what `systemShellOf` of
444
+ * `@moku-labs/game/app/system` returns over the loaders of the page. The page reaches the shell
445
+ * only through this.
445
446
  *
446
447
  * @example
447
448
  * ```ts
448
- * await startPage(game, config, { system: systemShell }); // systemShell is a SystemShellFactory
449
+ * const factory: SystemShellFactory = systemShellOf({ system: () => import("@moku-labs/system"), back: () => import("@moku-labs/system/back") });
450
+ * await startPage(game, config, { system: factory }); // the page builds the shell of config.system: ["back"]
449
451
  * ```
450
452
  */
451
453
  type SystemShellFactory = (config: ResolvedGameConfig, report: (problem: string) => void) => Promise<SystemShell>;
@@ -454,7 +456,8 @@ type SystemShellFactory = (config: ResolvedGameConfig, report: (problem: string)
454
456
  *
455
457
  * @example
456
458
  * ```ts
457
- * const options: PageOptions = { scenarios: { ready }, system: systemShell, agents: [agent0], devModules: [devModule0] };
459
+ * const system = systemShellOf({ system: () => import("@moku-labs/system"), haptics: () => import("@moku-labs/system/haptics") });
460
+ * const options: PageOptions = { scenarios: { ready }, system, agents: [agent0], devModules: [devModule0] };
458
461
  * ```
459
462
  */
460
463
  type PageOptions = {
@@ -477,13 +480,52 @@ type StartedPage<Game extends AnyGameApp> = {
477
480
  /** The screen app, started. */app: ScreenAppOfGame<Game>; /** The `@moku-labs/system` app, or `undefined` without a shell. Typed `unknown`: see `SystemShell.handle`. */
478
481
  system: unknown;
479
482
  };
483
+ /**
484
+ * The modules of `@moku-labs/system` the page loads, one loader per name of `config.ts`: the
485
+ * package itself always, and the entry of each plugin the game names, the store for a store save.
486
+ * The generated `main.ts` writes only the loaders of the names, so the page bundles only those
487
+ * plugins and never meets the native package of another. Typed `unknown`: a system type here would
488
+ * land in the `.d.mts` of every game and break the typecheck of a web-only one.
489
+ *
490
+ * @example
491
+ * ```ts
492
+ * // A page of its own for a game whose config.ts names haptics, with a memory save.
493
+ * const modules: SystemModules = {
494
+ * system: () => import("@moku-labs/system"),
495
+ * haptics: () => import("@moku-labs/system/haptics")
496
+ * };
497
+ * await startPage(game, config, { system: systemShellOf(modules) }); // the bundle holds no store plugin
498
+ * ```
499
+ */
500
+ type SystemModules = {
501
+ /** `@moku-labs/system` itself, for its `createApp`. Always there. */system: () => Promise<{
502
+ createApp: unknown;
503
+ }>; /** `@moku-labs/system/lifecycle`, when the game names `lifecycle`. */
504
+ lifecycle?: () => Promise<{
505
+ lifecyclePlugin: unknown;
506
+ }>; /** `@moku-labs/system/back`, when the game names `back`. */
507
+ back?: () => Promise<{
508
+ backPlugin: unknown;
509
+ }>; /** `@moku-labs/system/haptics`, when the game names `haptics`. */
510
+ haptics?: () => Promise<{
511
+ hapticsPlugin: unknown;
512
+ }>; /** `@moku-labs/system/keep-awake`, when the game names `keepAwake`. */
513
+ keepAwake?: () => Promise<{
514
+ keepAwakePlugin: unknown;
515
+ }>; /** `@moku-labs/system/store`, when the game names `store` or its save is `"store"`. */
516
+ store?: () => Promise<{
517
+ storePlugin: unknown;
518
+ }>;
519
+ };
480
520
  /**
481
521
  * The system shell: the `@moku-labs/system` app the config names, and what the engine takes from
482
- * it. `systemShell` builds it; the page starts it before the game and stops it after.
522
+ * it. The factory of `systemShellOf` builds it; the page starts it before the game and stops it
523
+ * after.
483
524
  *
484
525
  * @example
485
526
  * ```ts
486
- * const shell = await systemShell(resolveConfig(config), problem => problems.push(problem));
527
+ * const build = systemShellOf({ system: () => import("@moku-labs/system"), store: () => import("@moku-labs/system/store") });
528
+ * const shell = await build(resolveConfig({ page: { title: "T" }, save: "store" }), problem => problems.push(problem));
487
529
  * game.screen({ platform: shell.platform, provider: shell.save });
488
530
  * ```
489
531
  */
@@ -541,4 +583,4 @@ type SystemShell = {
541
583
  stop(): Promise<void>;
542
584
  };
543
585
  //#endregion
544
- export { SystemShell as _, GameHandle as a, MemoryProvider as c, ResolvedGameConfig as d, SaveKind as f, SystemName as g, StartedPage as h, GameDefinition as i, PageAgent as l, ScreenSeams as m, GameApp as n, GamePluginConfigs as o, Scenario as p, GameConfig as r, HeadlessSeams as s, AnyGameApp as t, PageOptions as u };
586
+ export { SystemShellFactory as _, GameHandle as a, MemoryProvider as c, SaveKind as d, Scenario as f, SystemName as g, SystemModules as h, GameDefinition as i, PageAgent as l, StartedPage as m, GameApp as n, GamePluginConfigs as o, ScreenSeams as p, GameConfig as r, HeadlessSeams as s, AnyGameApp as t, PageOptions as u };
@@ -1,5 +1,5 @@
1
1
  import { A as Api$2, B as ComponentType, F as AnyComponent, H as Entity, It as TypeTag, L as AnyComponentValue, Lt as Descriptor, R as ComponentHandle, Sn as Require, Xt as Json, Yt as Events$2, at as NumericFields, ct as TrackOptions, dn as Events$3, dt as Api$1, et as Ease, h as Api$5, hn as Api, it as MotionHandle, lt as TrackSegment, nt as LayerSpec, q as Owner, qt as Api$4, s as Events$4, t as Api$3, tt as LayerSort, xn as Events$5 } from "./types-ZQLYXo5X.mjs";
2
- import { A as InputApi, c as UiNode, i as Finding, n as ElementChange, o as JsxState, q as I18nApi, r as ElementMotion, tt as StylesState, x as TextApi } from "./types-BUwDHKXm.mjs";
2
+ import { A as InputApi, c as UiNode, i as Finding, n as ElementChange, o as JsxState, q as I18nApi, r as ElementMotion, rt as StylesState, x as TextApi } from "./types-BrTpz9oL.mjs";
3
3
  import { Log } from "@moku-labs/common/browser";
4
4
  import { PluginCtx } from "@moku-labs/core";
5
5
  import { Node, Yoga } from "yoga-layout/load";
package/dist/visual.d.mts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { A as Api$1, h as Api, ln as Api$3, qt as Api$2 } from "./types-ZQLYXo5X.mjs";
2
- import { r as UiApi, x as AnimApi } from "./types-BM4shh8K.mjs";
3
- import { A as InputApi } from "./types-BUwDHKXm.mjs";
2
+ import { r as UiApi, x as AnimApi } from "./types-D_2G6Q68.mjs";
3
+ import { A as InputApi } from "./types-BrTpz9oL.mjs";
4
4
  import { r as Repro } from "./headless-G4nuZ-xz.mjs";
5
5
  import { a as InputOf, r as ControlApp } from "./types-DAdwEJMp.mjs";
6
- import { t as commands } from "./commands-C4QlqijJ.mjs";
6
+ import { t as commands } from "./commands-DvFr8Uwp.mjs";
7
7
 
8
8
  //#region src/visual/types.d.ts
9
9
  /** The base commands of the `/control` door, keyed by their short names. */
@@ -273,9 +273,11 @@ declare function defineVisualTest(name: string, test: {
273
273
  //#endregion
274
274
  //#region src/visual/run.d.ts
275
275
  /**
276
- * Reads the flags of the visual tests from a command line: `--update`, `--no-pixels`, `--webgl`,
277
- * `--only <name>` (repeatable) and `--dir <path>`. An argument it does not know is left to the
278
- * script that got it, so a test runner's own arguments pass through.
276
+ * Reads the flags of the visual tests from a command line: `--update`, `--no-pixels`, `--pixels`,
277
+ * `--webgl`, `--only <name>` (repeatable) and `--dir <path>`. `--pixels` forces the pixel leg on
278
+ * off a Mac; the last of `--pixels` and `--no-pixels` wins. An argument it does not know is left
279
+ * to the script that got it, so a test runner's own arguments pass through. `moku-game visual`
280
+ * reads its flags with it.
279
281
  *
280
282
  * @param argv - The arguments after the script name.
281
283
  * @returns The flags that were given, and nothing else.
@@ -286,6 +288,7 @@ declare function defineVisualTest(name: string, test: {
286
288
  * parseVisualArgv(["--update", "--only", "reward-popup"]); // { update: true, only: ["reward-popup"] }
287
289
  * parseVisualArgv(["--no-pixels", "--dir", "shots"]); // { pixels: false, dir: "shots" }
288
290
  * parseVisualArgv(["--webgl"]); // { renderer: "webgl" }
291
+ * parseVisualArgv(["--pixels"]); // { pixels: true }
289
292
  * ```
290
293
  */
291
294
  declare function parseVisualArgv(argv: readonly string[]): VisualFlags;
package/dist/visual.mjs CHANGED
@@ -1906,9 +1906,11 @@ function valueAfter(argv, index, placeholder) {
1906
1906
  throw new Error(`[game] The flag ${flag} needs a value.\n Write it as ${flag} ${placeholder}.`);
1907
1907
  }
1908
1908
  /**
1909
- * Reads the flags of the visual tests from a command line: `--update`, `--no-pixels`, `--webgl`,
1910
- * `--only <name>` (repeatable) and `--dir <path>`. An argument it does not know is left to the
1911
- * script that got it, so a test runner's own arguments pass through.
1909
+ * Reads the flags of the visual tests from a command line: `--update`, `--no-pixels`, `--pixels`,
1910
+ * `--webgl`, `--only <name>` (repeatable) and `--dir <path>`. `--pixels` forces the pixel leg on
1911
+ * off a Mac; the last of `--pixels` and `--no-pixels` wins. An argument it does not know is left
1912
+ * to the script that got it, so a test runner's own arguments pass through. `moku-game visual`
1913
+ * reads its flags with it.
1912
1914
  *
1913
1915
  * @param argv - The arguments after the script name.
1914
1916
  * @returns The flags that were given, and nothing else.
@@ -1919,6 +1921,7 @@ function valueAfter(argv, index, placeholder) {
1919
1921
  * parseVisualArgv(["--update", "--only", "reward-popup"]); // { update: true, only: ["reward-popup"] }
1920
1922
  * parseVisualArgv(["--no-pixels", "--dir", "shots"]); // { pixels: false, dir: "shots" }
1921
1923
  * parseVisualArgv(["--webgl"]); // { renderer: "webgl" }
1924
+ * parseVisualArgv(["--pixels"]); // { pixels: true }
1922
1925
  * ```
1923
1926
  */
1924
1927
  function parseVisualArgv(argv) {
@@ -1927,6 +1930,7 @@ function parseVisualArgv(argv) {
1927
1930
  for (const [index, argument] of argv.entries()) {
1928
1931
  if (argument === "--update") flags.update = true;
1929
1932
  if (argument === "--no-pixels") flags.pixels = false;
1933
+ if (argument === "--pixels") flags.pixels = true;
1930
1934
  if (argument === "--webgl") flags.renderer = "webgl";
1931
1935
  if (argument === "--only") only.push(valueAfter(argv, index, "<name>"));
1932
1936
  if (argument === "--dir") flags.dir = valueAfter(argv, index, "<path>");