@moku-labs/game 0.13.1 → 0.13.3

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 (42) hide show
  1. package/dist/app/page.d.mts +1 -1
  2. package/dist/app/system.d.mts +3 -3
  3. package/dist/app.d.mts +2 -2
  4. package/dist/app.mjs +1 -1
  5. package/dist/assets.d.mts +1 -1
  6. package/dist/assets.mjs +1 -1
  7. package/dist/{capture-fpd83Mi5.mjs → capture-D7XvoHdH.mjs} +78 -1
  8. package/dist/cli.d.mts +7 -5
  9. package/dist/cli.mjs +74 -36
  10. package/dist/{commands-DvFr8Uwp.d.mts → commands-DRhJ_LIH.d.mts} +5 -5
  11. package/dist/control.d.mts +4 -4
  12. package/dist/control.mjs +1 -1
  13. package/dist/{define-CCc0ozKe.d.mts → define-Ckp70_GR.d.mts} +2 -2
  14. package/dist/{headless-BsNdJs9W.mjs → headless-BA6ffzqD.mjs} +30 -9
  15. package/dist/{headless-G4nuZ-xz.d.mts → headless-CYgYzro0.d.mts} +1 -1
  16. package/dist/hot.d.mts +3 -3
  17. package/dist/hot.mjs +11 -9
  18. package/dist/{index-rnOYAriI.d.mts → index-CjuObHhF.d.mts} +12 -4
  19. package/dist/index.d.mts +5 -5
  20. package/dist/index.mjs +1 -1
  21. package/dist/inspect.d.mts +7 -7
  22. package/dist/jsx-dev-runtime.d.mts +1 -1
  23. package/dist/jsx-runtime.d.mts +1 -1
  24. package/dist/{memory-DwDhfFWK.d.mts → memory-DKo9rRWW.d.mts} +1 -1
  25. package/dist/project.mjs +1 -1
  26. package/dist/{run-wYty_Lwo.mjs → run-BtyrJjmW.mjs} +130 -40
  27. package/dist/{runtime-B276Gg0s.d.mts → runtime-iTxTcukZ.d.mts} +1 -1
  28. package/dist/{src-SmT-XxVf.mjs → src-DlyYl_9X.mjs} +1414 -277
  29. package/dist/testing.d.mts +4 -4
  30. package/dist/testing.mjs +2 -2
  31. package/dist/{types-ZQLYXo5X.d.mts → types-BSMmnpFm.d.mts} +138 -29
  32. package/dist/{types-Bcdo5-2w.d.mts → types-B_Bp2tWK.d.mts} +7 -3
  33. package/dist/{types-DAdwEJMp.d.mts → types-Bonifz5M.d.mts} +2 -2
  34. package/dist/{types-DLghaGEy.d.mts → types-DkO3s9YX.d.mts} +4 -4
  35. package/dist/{types-BrTpz9oL.d.mts → types-Dm5Oh5bH.d.mts} +19 -6
  36. package/dist/{types-D_2G6Q68.d.mts → types-dJMOXXL3.d.mts} +21 -13
  37. package/dist/visual.d.mts +6 -6
  38. package/dist/visual.mjs +1 -1
  39. package/llms.txt +10 -7
  40. package/package.json +4 -2
  41. package/dist/{assets-DYiKxPBX.mjs → assets-BrKSg1O6.mjs} +1 -1
  42. package/dist/{watch-CB8IWDBi.mjs → watch-CWI_on4T.mjs} +1 -1
@@ -1,7 +1,7 @@
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-rnOYAriI.mjs";
3
- import { n as saveOf, t as memory } from "./memory-DwDhfFWK.mjs";
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";
1
+ import { Dt as AnyFlow, Ht as ClockSource, Nt as NodeTable, Wt as FakeClock, Xt as Json, ht as FeaturePlugin } from "./types-BSMmnpFm.mjs";
2
+ import { t as createApp } from "./index-CjuObHhF.mjs";
3
+ import { n as saveOf, t as memory } from "./memory-DKo9rRWW.mjs";
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-CYgYzro0.mjs";
5
5
  import { AnyPluginInstance } from "@moku-labs/core";
6
6
 
7
7
  //#region src/plugins/clock/fake.d.ts
package/dist/testing.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { Kt as type, Ut as exit, t as createApp } from "./src-SmT-XxVf.mjs";
1
+ import { Kt as type, Ut as exit, t as createApp } from "./src-DlyYl_9X.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
- import { i as stepFrames, r as runRepro, t as createHeadless } from "./headless-BsNdJs9W.mjs";
4
+ import { i as stepFrames, r as runRepro, t as createHeadless } from "./headless-BA6ffzqD.mjs";
5
5
  //#region src/testing/isolate.ts
6
6
  const noPayload = null;
7
7
  /** Id of the harness main flow. */
@@ -37,7 +37,12 @@ type Config$8 = {
37
37
  * ```
38
38
  */
39
39
  type Events$6 = {
40
- /** A dev hot swap was applied: the saved module's new exports. `ui` emits it, `effects` replaces its emitters on it. */"ui:hot-swap": {
40
+ /**
41
+ * A dev hot swap was applied: the saved module's new exports. `ui` emits it, `effects` replaces
42
+ * its emitters on it, and `assets` hears it for the stamp module `.moku/assets-stamp.ts`: it
43
+ * replaces the asset files the stamp names as changed.
44
+ */
45
+ "ui:hot-swap": {
41
46
  file: string;
42
47
  module: Readonly<Record<string, unknown>>;
43
48
  };
@@ -831,7 +836,9 @@ type StoreState = {
831
836
  /**
832
837
  * store module API, `app.model.store`. Logic changes the trees only inside a transaction, and only
833
838
  * a rest point hands patches to the provider, so a kill between two rest nodes loses a whole
834
- * transition and never half of one.
839
+ * transition and never half of one. One restore differs: `flow.restore` of a bookmark taken at a
840
+ * transit node marks a rest point there, so the provider receives a document from between two rest
841
+ * nodes, and a kill right after it loads that state at the start node.
835
842
  *
836
843
  * @example
837
844
  * ```ts
@@ -2134,20 +2141,21 @@ type RouteStep = {
2134
2141
  };
2135
2142
  };
2136
2143
  /**
2137
- * A rest node plus a state that really existed there. Serialisable. `graph` is the hash of
2138
- * `describe()`.
2144
+ * A node plus a state that really existed there. Serialisable. `path` names a rest node, or a
2145
+ * transit node that waited at the gate for the answer of an effect (a popup); for the second the
2146
+ * state is the one committed when the node was entered. `graph` is the hash of `describe()`.
2139
2147
  *
2140
2148
  * @example
2141
2149
  * ```ts
2150
+ * // Taken while the info popup of the mini game waits for its answer, opened from "home".
2142
2151
  * const bookmark: Bookmark = {
2143
- * path: "board/awaitIntent", input: null,
2144
- * player: { coins: 7 }, session: { taps: 0 },
2145
- * rng: { seed: 42, streams: {} }, graph: "fe4d257a"
2152
+ * path: "info/show", input: null, player: { count: 0 }, session: { opened: 0 },
2153
+ * rng: { seed: 42, streams: {} }, graph: "0e0d2aa8", rest: { path: "home", input: null }
2146
2154
  * };
2147
2155
  * ```
2148
2156
  */
2149
2157
  type Bookmark = {
2150
- path: string;
2158
+ /** Path of a rest node, or of a transit node that waited at the gate. */path: string;
2151
2159
  input: Json;
2152
2160
  player: Json;
2153
2161
  session: Json;
@@ -2158,6 +2166,15 @@ type Bookmark = {
2158
2166
  * `game.restore`; `flow.restore` ignores it.
2159
2167
  */
2160
2168
  scene?: string;
2169
+ /**
2170
+ * The rest point before a transit `path`: the last rest node and its input. `restore` enters
2171
+ * it instead when the graph changed since the bookmark. Absent for a bookmark of a rest node,
2172
+ * and when no rest node came before the transit node.
2173
+ */
2174
+ rest?: {
2175
+ path: string;
2176
+ input: Json;
2177
+ };
2161
2178
  };
2162
2179
  /**
2163
2180
  * What `onEnter` callbacks learn about the node being entered.
@@ -2281,8 +2298,16 @@ type EnterCallback = (node: NodeInfo, ctx: {
2281
2298
  * game just runs: `walk.ts` and `restore` create it through `loopSeam` when they need it.
2282
2299
  */
2283
2300
  type LoopSeam = {
2284
- /** Sub-flow results a walk substitutes, by path. The loop takes each one once. */substitutions: Map<string, Result>; /** Called with the path every time the loop enters a rest node. */
2285
- rest: ((path: string) => void)[]; /** Called every time the loop opens the gate of a rest node. The walk waits on it. */
2301
+ /** Sub-flow results a walk substitutes, by path. The loop takes each one once. */substitutions: Map<string, Result>;
2302
+ /**
2303
+ * Called with the path every time the loop enters a rest node, and once when it enters the
2304
+ * node of a bookmark, which may be a transit node. `restore` resolves on the second.
2305
+ */
2306
+ rest: ((path: string) => void)[];
2307
+ /**
2308
+ * Called every time the loop opens a gate: the wait of a rest node, or an effect with answers
2309
+ * inside any node. The walk waits on it, and so does `restore` after it entered a transit node.
2310
+ */
2286
2311
  gateOpen: (() => void)[]; /** The bookmark the loop enters at the next turn. */
2287
2312
  restoring: Bookmark | undefined;
2288
2313
  };
@@ -2293,7 +2318,12 @@ type RunnerState = {
2293
2318
  /** Flush started by a background pause. `onStop` awaits it. */flushing: Promise<void> | undefined; /** Every flow of the graph by id, collected at `run()`. */
2294
2319
  flows: Map<string, AnyFlow>;
2295
2320
  enterCallbacks: Record<Stage, EnterCallback[]>; /** The position: one frame per nesting level. */
2296
- stack: Frame[]; /** The stack of the last rest node: the rollback target. */
2321
+ stack: Frame[];
2322
+ /**
2323
+ * The frames a failed node is retried from, paired with the state a rollback returns to: the
2324
+ * last rest node, or the node the graph started at or a restore entered. The last two may be
2325
+ * transit nodes, so `bookmark()` writes its `rest` only when these frames name a rest node.
2326
+ */
2297
2327
  restFrame: Frame[] | undefined; /** Inside a slot: the contribution the loop just finished. The slot continues after it. */
2298
2328
  slotAfter: string | undefined; /** Edges since the last checkpoint. */
2299
2329
  journal: JournalEntry[];
@@ -2368,7 +2398,10 @@ type RunnerApi = {
2368
2398
  /**
2369
2399
  * Walks a route in fast mode through the running loop: it answers the gate at each step's `at`
2370
2400
  * and substitutes the result of every sub-flow node the route skips. A `from` bookmark is
2371
- * entered through the same check as `restore`. The mode of the caller is put back afterwards.
2401
+ * entered through the same check as `restore`, with the same fallback. A rest node is entered
2402
+ * before the switch to fast mode: its stages see the mode of the caller. A transit node is
2403
+ * entered after the switch and without the wait `restore` adds for it: its popup is not shown,
2404
+ * the route answers it. The mode of the caller is put back afterwards.
2372
2405
  *
2373
2406
  * @param route - The player's answers and substituted sub-flow results, in order.
2374
2407
  * @param options - Walk options.
@@ -2390,32 +2423,57 @@ type RunnerApi = {
2390
2423
  from?: Bookmark;
2391
2424
  }): Promise<FlowState>;
2392
2425
  /**
2393
- * Makes a bookmark of the current rest point: the rest node plus the committed state.
2426
+ * Makes a bookmark of where the graph stands: the last rest node plus the committed state.
2427
+ * While a transit node waits at the gate for the answer of an effect (a `popup`, or any
2428
+ * descriptor with `answers`), the bookmark names that node instead. Its state is the one
2429
+ * committed when the node was entered: what the node wrote before the wait is not in it, the
2430
+ * node writes it again when it is restored. `rest` then names the rest point before the node.
2431
+ * While a transit node awaits anything else (an animation, a request) the bookmark still names
2432
+ * the last rest node.
2394
2433
  *
2395
2434
  * @returns The bookmark, ready for JSON.
2396
2435
  * @throws {Error} When the graph has no position yet.
2397
2436
  * @example
2398
2437
  * ```ts
2399
- * // A devtools button keeps the position while the board rests.
2400
- * const bookmark = app.flow.bookmark();
2401
- * bookmark.path; // "board/awaitIntent"
2402
- * JSON.stringify(bookmark); // plain data: path, input, player, session, rng and the graph hash
2438
+ * // A devtools button keeps the position. The board rests: the bookmark names its rest node.
2439
+ * const atBoard = app.flow.bookmark(); // plain data, ready for JSON.stringify
2440
+ * atBoard.path; // "board/awaitIntent"
2441
+ * // The mini game with its info popup open: the bookmark names the node that waits.
2442
+ * const atPopup = app.flow.bookmark();
2443
+ * atPopup.path; // "info/show"
2444
+ * atPopup.rest; // { path: "home", input: null }: the rest point before it
2403
2445
  * ```
2404
2446
  */
2405
2447
  bookmark(): Bookmark;
2406
2448
  /**
2407
- * Replaces the state with the bookmark's and enters its node. A checkpoint is always
2408
- * accepted; any other rest node only while the graph is unchanged.
2449
+ * Replaces the state with the bookmark's and enters its node. A rest checkpoint is always
2450
+ * accepted; any other node only while the graph is unchanged. A transit node is never taken
2451
+ * for a checkpoint: when the graph changed, such a bookmark is entered at its `rest` point
2452
+ * instead, if that is a checkpoint, and the log gets `flow:restore-fell-back`. A renamed or
2453
+ * removed node is a changed graph too: a bookmark with `rest` whose path names no node takes
2454
+ * the same fallback.
2455
+ *
2456
+ * A rest node: the promise resolves when the node is entered, before its scene stage ran. A
2457
+ * transit node runs again from its first line, live, with the bookmark's input, so its effects
2458
+ * before the gate play again; the promise resolves when its gate is open, or at the rest node
2459
+ * or the end of the loop it reaches without one. A node that does none of these keeps the
2460
+ * promise pending. An open gate is not a drawn popup: the popup shows on the next frame. And
2461
+ * `setMode` still throws there, since the graph waits inside a transit node.
2409
2462
  *
2410
2463
  * @param bookmark - The bookmark to enter.
2411
- * @returns A promise that resolves once the graph rests at the bookmark's node.
2412
- * @throws {Error} When the bookmark names no rest node of this graph, when the graph changed
2413
- * since a bookmark of a plain rest node, and before `run()`.
2464
+ * @returns A promise that resolves once a rest node is entered, or a transit node waits at
2465
+ * its gate.
2466
+ * @throws {Error} When the bookmark names no node of this graph and has no `rest`, when the
2467
+ * graph changed since the bookmark and neither it nor its `rest` point is a rest checkpoint,
2468
+ * and before `run()`.
2414
2469
  * @example
2415
2470
  * ```ts
2416
2471
  * // The next session opens where the last one stopped: state and position come back together.
2417
- * await app.flow.restore(bookmark);
2472
+ * await app.flow.restore(atBoard);
2418
2473
  * app.flow.state().path; // "board/awaitIntent"
2474
+ * // A bookmark the mini game took at its info popup: the popup waits again when this resolves.
2475
+ * await app.flow.restore(atPopup);
2476
+ * app.flow.state().pending.gate; // ["ok", "close"], and state().path is "info/show"
2419
2477
  * ```
2420
2478
  */
2421
2479
  restore(bookmark: Bookmark): Promise<void>;
@@ -2463,7 +2521,9 @@ type RunnerApi = {
2463
2521
  */
2464
2522
  history(): readonly JournalEntry[];
2465
2523
  /**
2466
- * Switches between live and fast mode. Legal before `run()` and while the graph rests.
2524
+ * Switches between live and fast mode. Legal before `run()` and while the graph rests. A
2525
+ * transit node that waits at the gate for a popup does not rest: it throws there too, also
2526
+ * right after a `restore` into such a node.
2467
2527
  *
2468
2528
  * @param mode - `"live"` or `"fast"`.
2469
2529
  * @throws {Error} When a transit node is running.
@@ -2768,7 +2828,12 @@ type Events$3 = {
2768
2828
  };
2769
2829
  index: number;
2770
2830
  now: number;
2771
- }; /** The graph reached a rest node. */
2831
+ };
2832
+ /**
2833
+ * The graph reached a rest node, or entered the node of a bookmark. The second also happens
2834
+ * for a transit node that waited at the gate: `path` is then no rest node and `checkpoint` is
2835
+ * false.
2836
+ */
2772
2837
  "flow:rest": {
2773
2838
  path: string;
2774
2839
  checkpoint: boolean;
@@ -6465,7 +6530,7 @@ type TeardownScope = {
6465
6530
  readonly state: State$1;
6466
6531
  };
6467
6532
  declare namespace types_d_exports {
6468
- export { Api, AssetKind, AssetsCtx, AssetsIo, AtlasFrame, AtlasPage, AudioAsset, AudioMime, BundleMap, BundleRecord, BundleSpec, BundleUsage, Config, CreateTextureOptions, DecodedImage, DefineBundles, Deps, Events, FetchResponse, FlowRest, FontAsset, FontPage, Inflight, KernelSlice, LoadBundles, LoadReason, LoadResult, LoadedAssets, LoadedFont, Manifest, ManifestBundle, ManifestFile, NineBorders, NineSlice, PreloadQueue, State, Texture, Tier, Usage };
6533
+ export { Api, AssetKind, AssetStamps, AssetsCtx, AssetsIo, AtlasFrame, AtlasPage, AudioAsset, AudioMime, BundleMap, BundleRecord, BundleSpec, BundleUsage, Config, CreateTextureOptions, DecodedImage, DefineBundles, Deps, Events, FetchResponse, FlowRest, FontAsset, FontPage, HotSwap, Inflight, KernelSlice, LoadBundles, LoadReason, LoadResult, LoadedAssets, LoadedFont, Manifest, ManifestBundle, ManifestFile, NineBorders, NineSlice, PreloadQueue, State, Texture, Tier, Usage };
6469
6534
  }
6470
6535
  /**
6471
6536
  * When a bundle is loaded. `boot` and `core` stay for the whole session, `scene` and `feature`
@@ -6920,6 +6985,27 @@ type PreloadQueue = {
6920
6985
  bundles: string[];
6921
6986
  controller: AbortController;
6922
6987
  };
6988
+ /**
6989
+ * What the keys watch of `moku-game dev` knows about the asset files of a game: the default export
6990
+ * of the generated `.moku/assets-stamp.ts`. The dev hot swap compares it with the map it applied
6991
+ * last and replaces the files whose stamp differs.
6992
+ *
6993
+ * @example
6994
+ * ```ts
6995
+ * // The stamp after a save of fx-spark.webp: every watched file, and the one that changed.
6996
+ * const stamps: AssetStamps = {
6997
+ * files: {
6998
+ * "features/ui/assets/font-body.fnt": "1810:1791536000000",
6999
+ * "features/ui/assets/fx-spark.webp": "2554:1791536552578"
7000
+ * },
7001
+ * changed: ["features/ui/assets/fx-spark.webp"]
7002
+ * };
7003
+ * ```
7004
+ */
7005
+ type AssetStamps = {
7006
+ /** Every watched asset file, root-relative with `/`, and its `size:mtimeMs`. Sorted by path. */files: Readonly<Record<string, string>>; /** The files whose stamp differs from the batch before. Empty in the first stamp of a run. */
7007
+ changed: readonly string[];
7008
+ };
6923
7009
  /**
6924
7010
  * assets plugin config.
6925
7011
  *
@@ -6954,7 +7040,9 @@ type State = {
6954
7040
  current: NodeInfo | undefined;
6955
7041
  useCounter: number; /** Keys already reported missing, so one key warns and starts its background load once. */
6956
7042
  warned: Set<string>; /** `onEnter`, the `load` handler and the texture provider. */
6957
- removers: Array<() => void>;
7043
+ removers: Array<() => void>; /** The `files` map of the stamp the dev hot swap applied last. `undefined` until the first swap. */
7044
+ stamps: Readonly<Record<string, string>> | undefined; /** The running dev hot swap. The next one waits for it, so two swaps never overlap. */
7045
+ swapping: Promise<void> | undefined;
6958
7046
  };
6959
7047
  /**
6960
7048
  * What `usage()` reports about one loaded bundle.
@@ -7004,6 +7092,13 @@ type Usage = {
7004
7092
  * }
7005
7093
  * })
7006
7094
  * }); // a board bundle of four files sets share to 0.25, 0.5, 0.75 and 1; bundle-loaded follows
7095
+ *
7096
+ * // The audio plugin drops the buffer it decoded from a sound a dev save replaced.
7097
+ * hooks: ctx => ({
7098
+ * "assets:replaced": ({ keys }) => {
7099
+ * for (const key of keys) ctx.state.decoded.delete(key); // the next play decodes the new bytes
7100
+ * }
7101
+ * }); // a save of features/ui/assets/click.mp3 sends { bundle: "ui", keys: ["ui.click"] }
7007
7102
  * ```
7008
7103
  */
7009
7104
  type Events = {
@@ -7030,6 +7125,15 @@ type Events = {
7030
7125
  reason: "budget" | "request";
7031
7126
  keys: readonly string[];
7032
7127
  };
7128
+ /**
7129
+ * Files of a loaded bundle were replaced by a dev hot swap: one event per bundle per swap. `keys`
7130
+ * names every asset that has new bytes; each of them answers a new texture, font or sound, and
7131
+ * the old textures are destroyed. Dev builds only.
7132
+ */
7133
+ "assets:replaced": {
7134
+ bundle: string;
7135
+ keys: readonly string[];
7136
+ };
7033
7137
  };
7034
7138
  /**
7035
7139
  * assets plugin API, `app.assets`. Bundles of textures by key: the graph decides when they arrive,
@@ -7159,7 +7263,7 @@ type Deps = {
7159
7263
  * What the kernel context offers before the deps are attached.
7160
7264
  *
7161
7265
  * `index.ts` writes `events` with an annotated `register` (core spec `14-EVENT-REGISTRATION.md`
7162
- * row 8), so the two own events reach the context the kernel hands the factories and `emit` is the
7266
+ * row 8), so the own events reach the context the kernel hands the factories and `emit` is the
7163
7267
  * kernel's own, assets-typed one. No member of the context is cast.
7164
7268
  */
7165
7269
  type KernelSlice = PluginCtx<Config, State, Events> & {
@@ -7174,11 +7278,16 @@ type AssetsCtx = KernelSlice & {
7174
7278
  readonly deps: Deps;
7175
7279
  };
7176
7280
  /**
7177
- * Payload of the one event assets listens to.
7281
+ * Payload of the `flow:rest` hook: where the graph rests.
7178
7282
  */
7179
7283
  type FlowRest = {
7180
7284
  path: string;
7181
7285
  checkpoint: boolean;
7182
7286
  };
7287
+ /**
7288
+ * Payload of the global `ui:hot-swap` hook: the saved file and its new exports. For the stamp of
7289
+ * the keys watch, `module.default` is the `AssetStamps`.
7290
+ */
7291
+ type HotSwap = Events$6["ui:hot-swap"];
7183
7292
  //#endregion
7184
7293
  export { DescriptionNode as $, types_d_exports$5 as $t, Api$2 as A, FlowGraph as At, ComponentType as B, Answer as Bt, types_d_exports$1 as C, slot as Ct, FilterSlot as D, AnyFlow as Dt, DebugSwitches as E, FeatureDescription as Et, AnyComponent as F, SceneIdOf as Ft, Mut as G, State$4 as Gt, Entity as H, ClockSource as Ht, AnyComponentType as I, TypeTag as It, QueryTerm as J, Config$5 as Jt, Narrowed as K, types_d_exports$4 as Kt, AnyComponentValue as L, Descriptor as Lt, Explained as M, JournalEntry as Mt, State$2 as N, NodeTable as Nt, Point as O, Bookmark as Ot, types_d_exports$2 as P, RouteStep as Pt, ChangeHook as Q, State$5 as Qt, ComponentHandle as R, GuideOptions as Rt, Under as S, Require as Sn, exit as St, RenderStats as T, type as Tt, EntitySnapshot as U, Config$4 as Ut, ComponentValue as V, Api$4 as Vt, FrameDiff as W, FakeClock as Wt, SystemDefinition as X, Json as Xt, ResourceType as Y, Events$4 as Yt, TagType as Z, Root as Zt, PixiFilter as _, State$7 as _n, Position as _t, Config as a, Snapshot as an, NumericFields as at, PixiTexture as b, Config$8 as bn, types_d_exports$3 as bt, LoadBundles as c, RngState as cn, TrackOptions as ct, State as d, Events$5 as dn, Api$3 as dt, Patch as en, Ease as et, Tier as f, PauseReason as fn, BundlesOf as ft, Config$1 as g, Config$7 as gn, GameTypes as gt, Api$1 as h, Api$7 as hn, FeaturePlugin as ht, BundleSpec as i, SaveUnreadableError as in, MotionHandle as it, Config$2 as j, FlowState as jt, ViewportSize as k, DefineNode as kt, LoadReason as l, Api$6 as ln, TrackSegment as lt, types_d_exports as m, types_d_exports$6 as mn, EmitterIdOf as mt, AssetsIo as n, ProviderCall as nn, LayerSpec as nt, DefineBundles as o, StoreApi as on, ProjectionMotion as ot, Usage as p, State$6 as pn, Config$3 as pt, Owner as q, Api$5 as qt, BundleMap as r, SaveDoc as rn, Motion as rt, Events as s, RngApi as sn, ProjectionSpec as st, Api as t, PlayerStateProvider as tn, LayerSort as tt, Manifest as u, Config$6 as un, ViewHandle as ut, PixiModule as v, Time as vn, State$3 as vt, Captured as w, to as wt, State$1 as x, Events$6 as xn, defineFlow as xt, PixiSprite as y, types_d_exports$7 as yn, TextStylesOf as yt, ComponentSchema as z, Hint as zt };
@@ -1,5 +1,5 @@
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-D_2G6Q68.mjs";
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-BSMmnpFm.mjs";
2
+ import { x as AnimApi } from "./types-dJMOXXL3.mjs";
3
3
  import { Log } from "@moku-labs/common/browser";
4
4
  import { PluginCtx } from "@moku-labs/core";
5
5
 
@@ -523,7 +523,7 @@ type EmitterInstance = {
523
523
  readonly particleClass: PixiModule["Particle"];
524
524
  };
525
525
  declare namespace types_d_exports {
526
- export { AlphaValue, BlurValue, BundleUnloaded, ColorMatrixValue, Config, CoreKind, Curve, Deps, DisplacementValue, EffectsApi, EffectsCtx, EffectsStats, EmitterConfig, EmitterDefinition, EmitterValue, FilterComponent, FilterDefinition, FilterSpec, FilterValueOf, GlowValue, HotSwap, KernelSlice, NoiseValue, OutlineValue, Range, ResolvedEmitterConfig, Shape, State, UniformDeclaration, UniformSpec, UniformValue };
526
+ export { AlphaValue, AssetsReplaced, BlurValue, BundleUnloaded, ColorMatrixValue, Config, CoreKind, Curve, Deps, DisplacementValue, EffectsApi, EffectsCtx, EffectsStats, EmitterConfig, EmitterDefinition, EmitterValue, FilterComponent, FilterDefinition, FilterSpec, FilterValueOf, GlowValue, HotSwap, KernelSlice, NoiseValue, OutlineValue, Range, ResolvedEmitterConfig, Shape, State, UniformDeclaration, UniformSpec, UniformValue };
527
527
  }
528
528
  /**
529
529
  * effects plugin config. `maxParticles` here is the global warning line; the `maxParticles` of an
@@ -644,6 +644,10 @@ type EffectsCtx = KernelSlice & {
644
644
  * Payload of the `assets:bundle-unloaded` hook: `keys` names every texture that is gone.
645
645
  */
646
646
  type BundleUnloaded = Events["assets:bundle-unloaded"];
647
+ /**
648
+ * Payload of the `assets:replaced` hook: `keys` names every asset a dev hot swap gave new bytes.
649
+ */
650
+ type AssetsReplaced = Events["assets:replaced"];
647
651
  /**
648
652
  * Payload of the global `ui:hot-swap` hook: the saved file and its new exports.
649
653
  */
@@ -1,5 +1,5 @@
1
- import { Xt as Json, an as Snapshot } from "./types-ZQLYXo5X.mjs";
2
- import { t as HeadlessApp } from "./headless-G4nuZ-xz.mjs";
1
+ import { Xt as Json, an as Snapshot } from "./types-BSMmnpFm.mjs";
2
+ import { t as HeadlessApp } from "./headless-CYgYzro0.mjs";
3
3
  import { Log } from "@moku-labs/common/browser";
4
4
 
5
5
  //#region src/plugins/flow/doors/types.d.ts
@@ -1,7 +1,7 @@
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-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
- import { t as memory } from "./memory-DwDhfFWK.mjs";
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-BSMmnpFm.mjs";
2
+ import { o as AudioContextLike, s as Config$4 } from "./types-dJMOXXL3.mjs";
3
+ import { _t as audioPlugin, ct as PlatformProvider, ht as effectsPlugin, i as screen, ot as platformPlugin, t as createApp } from "./index-CjuObHhF.mjs";
4
+ import { t as memory } from "./memory-DKo9rRWW.mjs";
5
5
  import { AnyPluginInstance } from "@moku-labs/core";
6
6
 
7
7
  //#region src/app/types.d.ts
@@ -1,4 +1,4 @@
1
- import { A as Api$2, B as ComponentType, F as AnyComponent, H as Entity, I as AnyComponentType, L as AnyComponentValue, Lt as Descriptor, O as Point$2, Q as ChangeHook, Sn as Require, V as ComponentValue, Vt as Api$5, Xt as Json, at as NumericFields, dt as Api$1, h as Api$3, hn as Api, it as MotionHandle, k as ViewportSize, ot as ProjectionMotion, rt as Motion, s as Events$1, t as Api$4, ut as ViewHandle, zt as Hint } from "./types-ZQLYXo5X.mjs";
1
+ import { A as Api$2, B as ComponentType, F as AnyComponent, H as Entity, I as AnyComponentType, L as AnyComponentValue, Lt as Descriptor, O as Point$2, Q as ChangeHook, Sn as Require, V as ComponentValue, Vt as Api$5, Xt as Json, at as NumericFields, dt as Api$1, h as Api$3, hn as Api, it as MotionHandle, k as ViewportSize, ot as ProjectionMotion, rt as Motion, s as Events$1, t as Api$4, ut as ViewHandle, zt as Hint } from "./types-BSMmnpFm.mjs";
2
2
  import { Log } from "@moku-labs/common/browser";
3
3
  import { PluginCtx } from "@moku-labs/core";
4
4
 
@@ -1403,7 +1403,7 @@ declare function defineComponent<Properties extends object, Local extends object
1403
1403
  */
1404
1404
  declare function defineComponent<Properties extends object, Local extends object>(name: string, spec: ComponentSpec<Properties, Local, never>): ComponentDefinition<Properties, Local, undefined>;
1405
1405
  declare namespace types_d_exports {
1406
- export { AdvanceTable, BindField, BindOptions, BundleLoaded, BundleUnloaded, Config, CountdownValue, Deps, DrawnLabel, IconRun, KernelSlice, LayoutOptions, Line, LocaleChanged, Point, Run, SeenText, Size, State, TextAlign, TextApi, TextBind, TextCtx, TextFormat, TextLayout, TextRun, TextShadow, TextStyle, TextStyleInput, TextStyles, TextValue, TextWrap, Warn };
1406
+ export { AdvanceTable, AssetsReplaced, BindField, BindOptions, BundleLoaded, BundleUnloaded, Config, CountdownValue, Deps, DrawnLabel, IconRun, KernelSlice, LayoutOptions, Line, LocaleChanged, Point, Run, SeenText, Size, State, TextAlign, TextApi, TextBind, TextCtx, TextFormat, TextLayout, TextRun, TextShadow, TextStyle, TextStyleInput, TextStyles, TextValue, TextWrap, Warn };
1407
1407
  }
1408
1408
  /**
1409
1409
  * A point in reference units: where a label sits, and which point of the block sits there.
@@ -1707,13 +1707,16 @@ type TextLayout = {
1707
1707
  height: number;
1708
1708
  };
1709
1709
  /**
1710
- * What one label container was last filled from: the style object and the laid-out block. An
1711
- * update with the same style object, the same anchor and the same lines and runs writes the new
1712
- * text and positions into the objects already there.
1710
+ * What one label container was last filled from: the style object, the laid-out block and the
1711
+ * generation of the state at that moment. An update with the same style object, the same
1712
+ * generation, the same anchor and the same lines and runs writes the new text and positions into
1713
+ * the objects already there. An older generation means a dev hot swap replaced a font or an icon
1714
+ * since: the objects hold textures that are destroyed, so they are built again.
1713
1715
  */
1714
1716
  type DrawnLabel = {
1715
1717
  style: TextStyle;
1716
1718
  layout: TextLayout;
1719
+ generation: number;
1717
1720
  };
1718
1721
  /**
1719
1722
  * A dev warning that is written once per key. Pure modules take it as an argument, so nothing
@@ -1783,7 +1786,12 @@ type State = {
1783
1786
  measured: Map<Entity, Size>; /** Layout per `style + resolved`, oldest dropped first. */
1784
1787
  cache: Map<string, TextLayout>; /** What every live label container was last filled from, by container. */
1785
1788
  drawn: WeakMap<object, DrawnLabel>; /** Entities to re-resolve in the next layout phase. */
1786
- dirty: Set<Entity>; /** Warning keys already written, so a style, a tag, a glyph or a font warns once. */
1789
+ dirty: Set<Entity>;
1790
+ /**
1791
+ * Counts the dev hot swaps that replaced a font or an inline icon of a live label. A label
1792
+ * container drawn under an older count is built again on its next update.
1793
+ */
1794
+ generation: number; /** Warning keys already written, so a style, a tag, a glyph or a font warns once. */
1787
1795
  warned: Set<string>; /** The system, the two world hooks and the display adapter. */
1788
1796
  removers: Array<() => void>;
1789
1797
  };
@@ -1904,6 +1912,11 @@ type BundleLoaded = Events$1["assets:bundle-loaded"];
1904
1912
  * Payload of the `assets:bundle-unloaded` hook: `keys` names the assets that left.
1905
1913
  */
1906
1914
  type BundleUnloaded = Events$1["assets:bundle-unloaded"];
1915
+ /**
1916
+ * Payload of the `assets:replaced` hook: a dev hot swap put new bytes behind `keys`. Each of them
1917
+ * answers a new font or texture already, and the old pages and textures are destroyed.
1918
+ */
1919
+ type AssetsReplaced = Events$1["assets:replaced"];
1907
1920
  /**
1908
1921
  * Payload of the `i18n:locale-changed` hook: every message has to be resolved again.
1909
1922
  */
@@ -1,5 +1,5 @@
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, rt as StylesState, x as TextApi } from "./types-BrTpz9oL.mjs";
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-BSMmnpFm.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-Dm5Oh5bH.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";
@@ -1297,9 +1297,10 @@ type State$2 = {
1297
1297
  /** Scene id to its declaration, filled in `onStart` from `flow.features`. */scenes: Map<string, SceneDefinition>; /** Id of the scene that is mounted now. */
1298
1298
  current: string | undefined;
1299
1299
  /**
1300
- * The scene the next rest node without its own `scene` mounts: the one a transit node named in
1301
- * fast mode, or the one the restore door expected with `expect`. A rest node clears it; an over
1302
- * rest node takes it only while nothing is mounted.
1300
+ * The scene the next node without its own `scene` mounts, at a rest node or at a transit node
1301
+ * in live mode: the one a transit node named in fast mode, or the one the restore door expected
1302
+ * with `expect`. A rest node clears it; a transit node clears it only when it took it; an over
1303
+ * node takes it only while nothing is mounted.
1303
1304
  */
1304
1305
  pending: string | undefined;
1305
1306
  owner: SceneOwner; /** The remover of the `onEnter` callback: set in `onStart`, run in `onStop`. */
@@ -1348,19 +1349,22 @@ type ScenesApi = {
1348
1349
  */
1349
1350
  current(): string | undefined;
1350
1351
  /**
1351
- * Names the scene the next rest node without its own `scene` mounts. The restore door calls it
1352
- * with the scene of a bookmark, so a bookmark at a popup comes back with the scene under it.
1353
- * An over rest node takes the expected scene only while nothing is mounted; it never switches a
1352
+ * Names the scene the next node without its own `scene` mounts. A rest node reads it, and so
1353
+ * does a transit node in live mode; a transit node of a fast walk leaves it for the rest point.
1354
+ * The restore door calls it with the scene of a bookmark, so a bookmark at a popup comes back
1355
+ * with the scene under it, also when the popup is a transit node that waits for its answer:
1356
+ * the scene of such a popup is mounted before `flow.restore` resolves.
1357
+ * An over node takes the expected scene only while nothing is mounted; it never switches a
1354
1358
  * mounted one.
1355
1359
  *
1356
1360
  * @param id - Id of a scene a feature declared.
1357
1361
  * @throws {Error} For an id no feature declared, also before `onStart` filled the registry.
1358
1362
  * @example
1359
1363
  * ```ts
1360
- * // A fresh page restores a bookmark taken at the Settings popup over Home.
1364
+ * // A fresh page restores a bookmark taken at the Settings popup over Home, a transit node
1365
+ * // that waits for its answer.
1361
1366
  * app.scenes.expect("home");
1362
- * await app.flow.restore(bookmark);
1363
- * await app.flow.walk([]); // the scene stage runs after restore resolves
1367
+ * await app.flow.restore(bookmark); // resolves when the popup's gate is open
1364
1368
  * app.scenes.current(); // "home"
1365
1369
  * ```
1366
1370
  */
@@ -1406,7 +1410,7 @@ type RunContext = {
1406
1410
  signal: AbortSignal;
1407
1411
  };
1408
1412
  declare namespace types_d_exports$1 {
1409
- export { AudioApi, AudioContextLike, AudioCtx, AudioSessionLike, AudioSessionType, BundleUnloaded, Bus, BusState, Config$1 as Config, Deps$1 as Deps, KernelSlice$1 as KernelSlice, LifecycleChanged, ModelCommitted, MusicDescriptor, MusicMode, MusicOptions, MusicRequest, MusicSwitch, MusicTrack, RetiringTrack, SceneChanged, SfxRequest, SoundEntry, State$1 as State, StreamTrack, Volumes };
1413
+ export { AssetsReplaced, AudioApi, AudioContextLike, AudioCtx, AudioSessionLike, AudioSessionType, BundleUnloaded, Bus, BusState, Config$1 as Config, Deps$1 as Deps, KernelSlice$1 as KernelSlice, LifecycleChanged, ModelCommitted, MusicDescriptor, MusicMode, MusicOptions, MusicRequest, MusicSwitch, MusicTrack, RetiringTrack, SceneChanged, SfxRequest, SoundEntry, State$1 as State, StreamTrack, Volumes };
1410
1414
  }
1411
1415
  /**
1412
1416
  * The three volume buses. `master` carries the whole game, `music` the scene track, `sfx` every
@@ -1623,7 +1627,7 @@ type State$1 = {
1623
1627
  paused: boolean;
1624
1628
  unlocked: boolean; /** A gesture called `resume()` and it has not settled yet. */
1625
1629
  resuming: boolean; /** Sounds fired while `resuming`, one per key; played when the context runs, dropped when it does not. */
1626
- pendingSfx: Map<string, SfxRequest>; /** Per key, evicted per key on `assets:bundle-unloaded`. */
1630
+ pendingSfx: Map<string, SfxRequest>; /** Per key, evicted per key on `assets:bundle-unloaded` and `assets:replaced`. */
1627
1631
  decoded: Map<string, Promise<AudioBuffer>>; /** Asset keys that already got their one warning. */
1628
1632
  warned: Set<string>; /** `config.volumes` threw once and was reported; it is not reported again this run. */
1629
1633
  warnedVolumes: boolean;
@@ -1783,6 +1787,10 @@ type LifecycleChanged = Events$3["lifecycle:changed"];
1783
1787
  * Payload of the `assets:bundle-unloaded` hook: `keys` names every decoded sound that is gone.
1784
1788
  */
1785
1789
  type BundleUnloaded = Events$4["assets:bundle-unloaded"];
1790
+ /**
1791
+ * Payload of the `assets:replaced` hook: `keys` names every asset a dev hot swap gave new bytes.
1792
+ */
1793
+ type AssetsReplaced = Events$4["assets:replaced"];
1786
1794
  /**
1787
1795
  * What one play of a sound asks for: the key and the bus the sound goes to.
1788
1796
  */
package/dist/visual.d.mts CHANGED
@@ -1,9 +1,9 @@
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-D_2G6Q68.mjs";
3
- import { A as InputApi } from "./types-BrTpz9oL.mjs";
4
- import { r as Repro } from "./headless-G4nuZ-xz.mjs";
5
- import { a as InputOf, r as ControlApp } from "./types-DAdwEJMp.mjs";
6
- import { t as commands } from "./commands-DvFr8Uwp.mjs";
1
+ import { A as Api$1, h as Api, ln as Api$3, qt as Api$2 } from "./types-BSMmnpFm.mjs";
2
+ import { r as UiApi, x as AnimApi } from "./types-dJMOXXL3.mjs";
3
+ import { A as InputApi } from "./types-Dm5Oh5bH.mjs";
4
+ import { r as Repro } from "./headless-CYgYzro0.mjs";
5
+ import { a as InputOf, r as ControlApp } from "./types-Bonifz5M.mjs";
6
+ import { t as commands } from "./commands-DRhJ_LIH.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. */
package/dist/visual.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as read, t as sources } from "./sources-Duzj6lhV.mjs";
2
- import { n as commands, t as run } from "./run-wYty_Lwo.mjs";
2
+ import { n as commands, t as run } from "./run-BtyrJjmW.mjs";
3
3
  import path from "node:path";
4
4
  import { createBrandConsole } from "@moku-labs/common/cli";
5
5
  import { mkdir, readFile, writeFile } from "node:fs/promises";