@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,4 +1,4 @@
1
- import { m as StartedPage, r as GameConfig, t as AnyGameApp, u as PageOptions } from "../types-DLghaGEy.mjs";
1
+ import { m as StartedPage, r as GameConfig, t as AnyGameApp, u as PageOptions } from "../types-DkO3s9YX.mjs";
2
2
 
3
3
  //#region src/app/page.d.ts
4
4
  /**
@@ -1,6 +1,6 @@
1
- import { tn as PlayerStateProvider } from "../types-ZQLYXo5X.mjs";
2
- import { ct as PlatformProvider } from "../index-rnOYAriI.mjs";
3
- import { _ as SystemShellFactory, g as SystemName, h as SystemModules } from "../types-DLghaGEy.mjs";
1
+ import { tn as PlayerStateProvider } from "../types-BSMmnpFm.mjs";
2
+ import { ct as PlatformProvider } from "../index-CjuObHhF.mjs";
3
+ import { _ as SystemShellFactory, g as SystemName, h as SystemModules } from "../types-DkO3s9YX.mjs";
4
4
  import { Back, Haptics, KeepAwake, Lifecycle, Store } from "@moku-labs/system";
5
5
 
6
6
  //#region src/app/system.d.ts
package/dist/app.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { Xt as Json } from "./types-ZQLYXo5X.mjs";
2
- import { a as GameHandle, c as MemoryProvider, d as SaveKind, f as Scenario, g as SystemName, i as GameDefinition, l as PageAgent, n as GameApp, o as GamePluginConfigs, p as ScreenSeams, r as GameConfig, s as HeadlessSeams } from "./types-DLghaGEy.mjs";
1
+ import { Xt as Json } from "./types-BSMmnpFm.mjs";
2
+ import { a as GameHandle, c as MemoryProvider, d as SaveKind, f as Scenario, g as SystemName, i as GameDefinition, l as PageAgent, n as GameApp, o as GamePluginConfigs, p as ScreenSeams, r as GameConfig, s as HeadlessSeams } from "./types-DkO3s9YX.mjs";
3
3
  import { AnyPluginInstance } from "@moku-labs/core";
4
4
 
5
5
  //#region src/app/define.d.ts
package/dist/app.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { Ct as effectsPlugin, H as platformPlugin, Nt as audioPlugin, i as screen, t as createApp } from "./src-SmT-XxVf.mjs";
1
+ import { Ct as effectsPlugin, H as platformPlugin, Nt as audioPlugin, i as screen, t as createApp } from "./src-DlyYl_9X.mjs";
2
2
  import { t as memory } from "./memory-CWlqhS7l.mjs";
3
3
  import { t as fakeClock } from "./fake-MpzwZhIZ.mjs";
4
4
  //#region src/app/define.ts
package/dist/assets.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { u as Manifest } from "./types-ZQLYXo5X.mjs";
1
+ import { u as Manifest } from "./types-BSMmnpFm.mjs";
2
2
 
3
3
  //#region src/plugins/assets/scan/cli.d.ts
4
4
  /**
package/dist/assets.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as runCli, c as emitKeys, i as compileStrings, l as emitManifest, n as importStrings, o as scanAssets, r as checkStrings, s as packAssets, t as exportStrings } from "./assets-DYiKxPBX.mjs";
1
+ import { a as runCli, c as emitKeys, i as compileStrings, l as emitManifest, n as importStrings, o as scanAssets, r as checkStrings, s as packAssets, t as exportStrings } from "./assets-BrKSg1O6.mjs";
2
2
  export { checkStrings, compileStrings, emitKeys, emitManifest, exportStrings, importStrings, packAssets, runCli, scanAssets };
@@ -197,6 +197,24 @@ function findNode(main, path, contributionsOf = noContributions) {
197
197
  }
198
198
  }
199
199
  /**
200
+ * Tells whether an entry of a flow is a rest checkpoint: a rest node that carries the checkpoint
201
+ * flag, a place a save may stand on. A sub-flow and a slot are no nodes. A transit node is never
202
+ * one, whatever its flag says: it is a place inside a transition.
203
+ *
204
+ * @param entry - A node, a sub-flow or a slot of a flow.
205
+ * @returns True for a node with both `rest` and `checkpoint`.
206
+ * @example
207
+ * ```ts
208
+ * // `home` rests and is a checkpoint. `boot` is a transit node that carries the flag too.
209
+ * isRestCheckpoint(home); // true
210
+ * isRestCheckpoint(boot); // false
211
+ * isRestCheckpoint(boardFlow); // false: a sub-flow is no node
212
+ * ```
213
+ */
214
+ function isRestCheckpoint(entry) {
215
+ return entry.kind === "node" && entry.rest && entry.checkpoint;
216
+ }
217
+ /**
200
218
  * Renders an edge target as a string: a node name, `"exit:win"` or `"map:node"`.
201
219
  *
202
220
  * @param target - The target as the edge table holds it.
@@ -336,6 +354,65 @@ function describeGraph(flows, features) {
336
354
  };
337
355
  }
338
356
  /**
357
+ * Reads one node of a described flow by name. Own keys only: `nodes.constructor` is defined on
358
+ * every object.
359
+ *
360
+ * @param flow - The described flow, or `undefined` when the graph does not hold it.
361
+ * @param name - Name of the node.
362
+ * @returns The described node, or `undefined` when the flow has none of that name.
363
+ * @example
364
+ * ```ts
365
+ * ownNode({ nodes: {}, start: "home", edges: {} }, "constructor"); // undefined
366
+ * ```
367
+ */
368
+ function ownNode(flow, name) {
369
+ return flow !== void 0 && Object.hasOwn(flow.nodes, name) ? flow.nodes[name] : void 0;
370
+ }
371
+ /**
372
+ * Picks the described flow a path continues in after one node: the sub-flow it enters, or, behind
373
+ * a slot, the first contribution in order that has the next segment as a node. The same choice
374
+ * `findNode` makes on the flows themselves.
375
+ *
376
+ * @param graph - Result of `describeGraph`.
377
+ * @param node - The described node the path just passed.
378
+ * @param next - The next segment of the path.
379
+ * @returns The flow to go on in, or `undefined` when the path ends here.
380
+ * @example
381
+ * ```ts
382
+ * // In a graph whose main flow uses the sub-flow "board" as its node "board":
383
+ * describedFlowBehind(graph, graph.flows.main.nodes.board, "awaitIntent")?.start; // "awaitIntent"
384
+ * ```
385
+ */
386
+ function describedFlowBehind(graph, node, next) {
387
+ if (node.subFlow !== void 0) return graph.flows[node.subFlow];
388
+ if (node.slot === void 0) return void 0;
389
+ return (graph.slots[node.slot] ?? []).map((contribution) => graph.flows[contribution.flow]).find((flow) => ownNode(flow, next) !== void 0);
390
+ }
391
+ /**
392
+ * Finds the node a path names in a described graph, the way `findNode` finds it in the flows: one
393
+ * sub-flow per segment, and through a slot into the contribution that has the next segment. For a
394
+ * caller that holds only `flow.describe()`, such as a headless helper.
395
+ *
396
+ * @param graph - Result of `describeGraph`.
397
+ * @param path - A path as `framePath` renders it.
398
+ * @returns The described node, sub-flow or slot, or `undefined` when the path names nothing.
399
+ * @example
400
+ * ```ts
401
+ * describedNode(app.flow.describe(), "board/awaitIntent")?.rest; // true: a rest node
402
+ * describedNode(app.flow.describe(), "board")?.subFlow; // "board": a sub-flow, no rest node
403
+ * ```
404
+ */
405
+ function describedNode(graph, path) {
406
+ const names = path.split("/").filter(Boolean);
407
+ let flow = graph.flows[graph.main];
408
+ for (const [step, name] of names.entries()) {
409
+ const node = ownNode(flow, name);
410
+ const next = names[step + 1];
411
+ if (node === void 0 || next === void 0) return node;
412
+ flow = describedFlowBehind(graph, node, next);
413
+ }
414
+ }
415
+ /**
339
416
  * Compares two object keys without a locale, so the rendering is the same everywhere.
340
417
  *
341
418
  * @param first - First key.
@@ -1151,4 +1228,4 @@ async function captureFrame(mctx, options) {
1151
1228
  return shot === void 0 ? void 0 : answerOf(mctx, shot, options.against);
1152
1229
  }
1153
1230
  //#endregion
1154
- export { sheetAlone as a, findNode as c, slotNames as d, compact as f, servePaused as i, framePath as l, captureFrame as n, collectFlows as o, pushEntry as p, serveCaptures as r, describeGraph as s, cancelCaptures as t, graphHash as u };
1231
+ export { sheetAlone as a, describedNode as c, graphHash as d, isRestCheckpoint as f, pushEntry as h, servePaused as i, findNode as l, compact as m, captureFrame as n, collectFlows as o, slotNames as p, serveCaptures as r, describeGraph as s, cancelCaptures as t, framePath as u };
package/dist/cli.d.mts CHANGED
@@ -87,8 +87,9 @@ declare function runCli(argv: readonly string[]): Promise<number>;
87
87
  * `dev.ts`, `main.ts` with the scenarios of `tests/scenarios/` (and, with agents, the agents and
88
88
  * the game's `.dev` modules), and `bunfig.toml` with the engine's hot plugin. It also writes the
89
89
  * first `assets-stamp.ts`, the empty one, when the game has none: `main.ts` imports it, and
90
- * `watchKeys` rewrites it when an asset file changes. It starts no server and no watcher, and
91
- * throws the `[game]` errors of `moku-game dev`.
90
+ * `watchKeys` rewrites it when an asset file changes. The page accepts the new stamp: new bytes
91
+ * of a file swap in place, a new or removed file reloads the page. It starts no server and no
92
+ * watcher, and throws the `[game]` errors of `moku-game dev`.
92
93
  *
93
94
  * @param root - The game folder, relative to the cwd or absolute.
94
95
  * @param options - The agents, the preloads and the extra bundler plugins.
@@ -112,9 +113,10 @@ declare function preparePage(root: string, options?: PreparePageOptions): Promis
112
113
  * `strings/<locale>.json` scans again, with the same flags, outputs and layers; an output that
113
114
  * did not change is not rewritten. On the page a rewritten `generated/strings.<locale>.ts` hot
114
115
  * swaps. An asset file that is new, gone or saved again rewrites `.moku/assets-stamp.ts`, which
115
- * the page imports, so the page reloads and shows the new image or the new bytes of an old one. A
116
- * failed scan goes to `onError` and the watch goes on, the first scan too. The layers of
117
- * `config.ts` are read once: a changed layer needs a new `watchKeys`.
116
+ * the page imports and accepts as a hot swap: the new bytes of a file swap in place in the loaded
117
+ * bundles, with no reload, and a new or removed file reloads the page. A failed scan goes to
118
+ * `onError` and the watch goes on, the first scan too. The layers of `config.ts` are read once:
119
+ * a changed layer needs a new `watchKeys`.
118
120
  *
119
121
  * @param root - The game folder, relative to the cwd or absolute.
120
122
  * @param options - Where the message of a failed scan goes.
package/dist/cli.mjs CHANGED
@@ -1,12 +1,11 @@
1
1
  import { t as resolveConfig } from "./config-CdARrrhU.mjs";
2
- import { r as watchTree, t as createBatcher, x as isSkippedFolder$1 } from "./watch-CB8IWDBi.mjs";
3
- import { a as runCli$1, i as compileStrings, n as importStrings, t as exportStrings } from "./assets-DYiKxPBX.mjs";
2
+ import { r as watchTree, t as createBatcher, x as isSkippedFolder$1 } from "./watch-CWI_on4T.mjs";
3
+ import { a as runCli$1, i as compileStrings, n as importStrings, t as exportStrings } from "./assets-BrKSg1O6.mjs";
4
4
  import { constants, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, watch, writeFileSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import { createBrandConsole } from "@moku-labs/common/cli";
7
7
  import { parseArgs } from "node:util";
8
8
  import { pathToFileURL } from "node:url";
9
- import { createHash } from "node:crypto";
10
9
  //#region src/app/generate.ts
11
10
  /** The first line of a generated file a person may open. */
12
11
  const WRITTEN = "// Written by moku-game dev. Do not edit.";
@@ -230,6 +229,21 @@ function importLine(binding, specifier) {
230
229
  return `import ${binding} from ${JSON.stringify(specifier)};`;
231
230
  }
232
231
  /**
232
+ * Orders two texts by their code units, as `toSorted()` does without a comparer.
233
+ *
234
+ * @param first - One text.
235
+ * @param second - The other text.
236
+ * @returns A negative number, zero or a positive number.
237
+ * @example
238
+ * ```ts
239
+ * compareText("a/b.png", "a/c.png"); // -1
240
+ * ```
241
+ */
242
+ function compareText(first, second) {
243
+ if (first === second) return 0;
244
+ return first < second ? -1 : 1;
245
+ }
246
+ /**
233
247
  * The path from a page under `.moku/` to `.moku/` itself, where the one stamp of a game lives.
234
248
  *
235
249
  * @param toRoot - The path from the page to the game folder.
@@ -246,8 +260,9 @@ function toStampFolder(toRoot) {
246
260
  * The `main.ts` of the dev page: the dev flag first, then the assets stamp, the page entry, the
247
261
  * game, its config, one import per scenario, and, with agents, one per `.dev` module and one per
248
262
  * agent. It calls `startPage` with the scenarios by file stem, the shell with the loaders of the
249
- * named plugins when the game needs it, the agents and the `.dev` modules. The stamp import makes
250
- * the page reload when the keys watch writes a new stamp: an asset file changed.
263
+ * named plugins when the game needs it, the agents and the `.dev` modules. The stamp import puts
264
+ * the stamp module on the page: when the keys watch writes a new stamp, the hot plugin hands it to
265
+ * the running game.
251
266
  *
252
267
  * @param settings - The resolved `config.ts`.
253
268
  * @param sources - The scenario files, the `.dev` modules and the agents.
@@ -324,20 +339,34 @@ function devFlag() {
324
339
  return `${WRITTEN}\nglobalThis.__MOKU_GAME_DEV__ = true;\n`;
325
340
  }
326
341
  /**
327
- * The `assets-stamp.ts` module the dev `main.ts` imports: one string that changes when an asset
328
- * file of the game changes. The hot plugin takes it for a logic module, so a new stamp reloads the
329
- * page, and the page shows the new bytes of an image whose key stayed the same. The page starts
330
- * with the empty stamp; the keys watch writes the hash of the asset files.
342
+ * The `assets-stamp.ts` module the dev `main.ts` imports: the asset files of the game with their
343
+ * stamps, and the ones the last save changed. The hot plugin takes it for a module that swaps, so
344
+ * a new stamp reaches the running game, which reads the changed files again. The page starts with
345
+ * the empty stamp; the keys watch writes the files. Both lists are sorted here, and every path
346
+ * and stamp is written by `JSON.stringify`: a file name may hold a quote or a backslash.
331
347
  *
332
- * @param hash - The hash of the asset files, `""` before the first watch.
348
+ * @param files - Every watched asset file: its path relative to the game with `/`, and its stamp
349
+ * `<size>:<mtimeMs>`. None before the first watch.
350
+ * @param changed - The paths whose stamp differs from the batch before, the new ones too. None in
351
+ * the first stamp of a run.
333
352
  * @returns The text of `.moku/assets-stamp.ts`.
334
353
  * @example
335
354
  * ```ts
336
- * assetsStamp(""); // '// Written by moku-game dev. Do not edit.\nexport default "";\n'
355
+ * assetsStamp([], []); // '// Written by moku-game dev. Do not edit.\nexport default {\n files: {},\n changed: []\n};\n'
337
356
  * ```
338
357
  */
339
- function assetsStamp(hash) {
340
- return `${WRITTEN}\nexport default ${JSON.stringify(hash)};\n`;
358
+ function assetsStamp(files, changed) {
359
+ const entries = files.toSorted(([first], [second]) => compareText(first, second)).map(([file, stamp]) => ` ${JSON.stringify(file)}: ${JSON.stringify(stamp)}`);
360
+ const map = entries.length === 0 ? "{}" : `{\n${entries.join(",\n")}\n }`;
361
+ const list = changed.toSorted(compareText).map((file) => JSON.stringify(file)).join(", ");
362
+ return [
363
+ WRITTEN,
364
+ "export default {",
365
+ ` files: ${map},`,
366
+ ` changed: [${list}]`,
367
+ "};",
368
+ ""
369
+ ].join("\n");
341
370
  }
342
371
  /**
343
372
  * A TOML array of strings. `JSON.stringify` of a path is a valid TOML basic string, also for a
@@ -623,7 +652,7 @@ function writePage(root, settings, options, resolve, page = ".moku") {
623
652
  ];
624
653
  const stamp = path.join(root, ".moku", ASSETS_STAMP);
625
654
  for (const [file, text] of texts) writeIfChanged(file, text);
626
- if (!existsSync(stamp)) writeIfChanged(stamp, assetsStamp(""));
655
+ if (!existsSync(stamp)) writeIfChanged(stamp, assetsStamp([], []));
627
656
  return {
628
657
  html,
629
658
  bunfig
@@ -1797,11 +1826,12 @@ async function runCommand(argv, deps) {
1797
1826
  * events stop for a quiet period, a batch walks the game and reads the size and the time stamp of
1798
1827
  * every asset file and every `strings/<locale>.json`; it runs the scan of `moku-game keys` only
1799
1828
  * when they differ from the batch before. After a scan it writes `.moku/assets-stamp.ts` from the
1800
- * asset files, so the dev page reloads and shows the new bytes of an image. One scan runs at a
1801
- * time, and a failed scan never stops the watch. A batch that scanned is followed by one more
1802
- * walk: the platform reports only the first path of a burst of writes, so a save made in the same
1803
- * instant as the scan's own writes under `generated/` may never be reported. The scan, `fs.watch`
1804
- * and the console come in as seams, so a test drives it. Node and Bun only: the bin bundles it.
1829
+ * asset files: every file with its stamp, and the ones this batch found changed, so the dev page
1830
+ * reads only those again. One scan runs at a time, and a failed scan never stops the watch. A
1831
+ * batch that scanned is followed by one more walk: the platform reports only the first path of a
1832
+ * burst of writes, so a save made in the same instant as the scan's own writes under `generated/`
1833
+ * may never be reported. The scan, `fs.watch` and the console come in as seams, so a test drives
1834
+ * it. Node and Bun only: the bin bundles it.
1805
1835
  */
1806
1836
  /** The quiet period that closes a batch of file events. */
1807
1837
  const QUIET_MS = 100;
@@ -1882,19 +1912,24 @@ function changedPaths(before, after) {
1882
1912
  return [.../* @__PURE__ */ new Set([...before.keys(), ...after.keys()])].filter((file) => before.get(file) !== after.get(file)).toSorted();
1883
1913
  }
1884
1914
  /**
1885
- * Hashes the asset files of a walk: their paths, sizes and time stamps. The strings files stay
1886
- * out, so a strings save leaves the hash as it is.
1915
+ * The text of the stamp module after one batch: every asset file of the walk with its stamp, and
1916
+ * the asset files that differ from the batch before. The strings files stay out, so a batch that
1917
+ * saved only strings has no stamp to write. A removed file is not listed as changed: it shows by
1918
+ * its absence from the files. The first batch of a run has no batch before it, so it lists none.
1887
1919
  *
1888
- * @param inputs - The stamps of a walk.
1889
- * @returns The SHA-1 as 40 hex digits.
1920
+ * @param inputs - The stamps of this walk.
1921
+ * @param changed - The inputs that differ from the batch before: added, removed, or saved again.
1922
+ * @param first - True for the first batch of the watch.
1923
+ * @returns The text, or `undefined` when no asset file changed in a later batch.
1890
1924
  * @example
1891
1925
  * ```ts
1892
- * assetsHash(new Map([["features/home/strings/en.json", "9:1"]])); // "da39a3ee5e6b4b0d3255bfef95601890afd80709": no asset file
1926
+ * stampText(new Map([["a.png", "4:2"], ["strings/en.json", "9:1"]]), ["a.png", "strings/en.json"], false); // '// Written by moku-game dev. Do not edit.\nexport default {\n files: {\n "a.png": "4:2"\n },\n changed: ["a.png"]\n};\n'
1893
1927
  * ```
1894
1928
  */
1895
- function assetsHash(inputs) {
1896
- const assets = [...inputs].filter(([file]) => ASSET_FILE.test(file)).map(([file, stamp]) => `${file}:${stamp}`).toSorted();
1897
- return createHash("sha1").update(assets.join("\n")).digest("hex");
1929
+ function stampText(inputs, changed, first) {
1930
+ const moved = changed.filter((file) => ASSET_FILE.test(file));
1931
+ if (!first && moved.length === 0) return void 0;
1932
+ return assetsStamp([...inputs].filter(([file]) => ASSET_FILE.test(file)), first ? [] : moved.filter((file) => inputs.has(file)));
1898
1933
  }
1899
1934
  /**
1900
1935
  * The line of a later scan that worked: the first changed input, and how many more.
@@ -1984,9 +2019,9 @@ async function scanAndReport(watch, changed, first) {
1984
2019
  }
1985
2020
  /**
1986
2021
  * One batch: walks the game, and scans when an input differs from the batch before; the first
1987
- * batch always scans. Then it writes the stamp of the asset files, asks for one trailing batch,
1988
- * and arms the folder watchers with the folders of the walk. A batch that did not scan asks for
1989
- * nothing, so the trailing batch of a quiet game ends the chain.
2022
+ * batch always scans. Then it writes the stamp when an asset file changed, asks for one trailing
2023
+ * batch, and arms the folder watchers with the folders of the walk. A batch that did not scan
2024
+ * asks for nothing, so the trailing batch of a quiet game ends the chain.
1990
2025
  *
1991
2026
  * @param watch - The watch.
1992
2027
  */
@@ -1997,7 +2032,8 @@ async function runBatch(watch) {
1997
2032
  watch.inputs = walk.inputs;
1998
2033
  if (first || changed.length > 0) {
1999
2034
  await scanAndReport(watch, changed, first);
2000
- writeIfChanged(path.join(watch.root, ".moku", ASSETS_STAMP), assetsStamp(assetsHash(walk.inputs)));
2035
+ const stamp = stampText(walk.inputs, changed, first);
2036
+ if (stamp !== void 0) writeIfChanged(path.join(watch.root, ".moku", ASSETS_STAMP), stamp);
2001
2037
  watch.again();
2002
2038
  }
2003
2039
  if (!watch.closed) watch.tree.rearm(walk.folders);
@@ -2303,8 +2339,9 @@ async function runCli(argv) {
2303
2339
  * `dev.ts`, `main.ts` with the scenarios of `tests/scenarios/` (and, with agents, the agents and
2304
2340
  * the game's `.dev` modules), and `bunfig.toml` with the engine's hot plugin. It also writes the
2305
2341
  * first `assets-stamp.ts`, the empty one, when the game has none: `main.ts` imports it, and
2306
- * `watchKeys` rewrites it when an asset file changes. It starts no server and no watcher, and
2307
- * throws the `[game]` errors of `moku-game dev`.
2342
+ * `watchKeys` rewrites it when an asset file changes. The page accepts the new stamp: new bytes
2343
+ * of a file swap in place, a new or removed file reloads the page. It starts no server and no
2344
+ * watcher, and throws the `[game]` errors of `moku-game dev`.
2308
2345
  *
2309
2346
  * @param root - The game folder, relative to the cwd or absolute.
2310
2347
  * @param options - The agents, the preloads and the extra bundler plugins.
@@ -2335,9 +2372,10 @@ async function preparePage(root, options = {}) {
2335
2372
  * `strings/<locale>.json` scans again, with the same flags, outputs and layers; an output that
2336
2373
  * did not change is not rewritten. On the page a rewritten `generated/strings.<locale>.ts` hot
2337
2374
  * swaps. An asset file that is new, gone or saved again rewrites `.moku/assets-stamp.ts`, which
2338
- * the page imports, so the page reloads and shows the new image or the new bytes of an old one. A
2339
- * failed scan goes to `onError` and the watch goes on, the first scan too. The layers of
2340
- * `config.ts` are read once: a changed layer needs a new `watchKeys`.
2375
+ * the page imports and accepts as a hot swap: the new bytes of a file swap in place in the loaded
2376
+ * bundles, with no reload, and a new or removed file reloads the page. A failed scan goes to
2377
+ * `onError` and the watch goes on, the first scan too. The layers of `config.ts` are read once:
2378
+ * a changed layer needs a new `watchKeys`.
2341
2379
  *
2342
2380
  * @param root - The game folder, relative to the cwd or absolute.
2343
2381
  * @param options - Where the message of a failed scan goes.
@@ -1,8 +1,8 @@
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-D_2G6Q68.mjs";
3
- import { A as InputApi } from "./types-BrTpz9oL.mjs";
4
- import { t as HeadlessApp } from "./headless-G4nuZ-xz.mjs";
5
- import { n as Command, r as ControlApp } from "./types-DAdwEJMp.mjs";
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-BSMmnpFm.mjs";
2
+ import { a as AudioApi, r as UiApi, v as ScenesApi, x as AnimApi } from "./types-dJMOXXL3.mjs";
3
+ import { A as InputApi } from "./types-Dm5Oh5bH.mjs";
4
+ import { t as HeadlessApp } from "./headless-CYgYzro0.mjs";
5
+ import { n as Command, r as ControlApp } from "./types-Bonifz5M.mjs";
6
6
 
7
7
  //#region src/plugins/flow/doors/commands.d.ts
8
8
  /**
@@ -1,7 +1,7 @@
1
- import { t as HeadlessApp } from "./headless-G4nuZ-xz.mjs";
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-DvFr8Uwp.mjs";
4
- import { t as defineCommand } from "./define-CCc0ozKe.mjs";
1
+ import { t as HeadlessApp } from "./headless-CYgYzro0.mjs";
2
+ import { i as InputArguments, n as Command, o as InputSchema, s as Ran } from "./types-Bonifz5M.mjs";
3
+ import { t as commands } from "./commands-DRhJ_LIH.mjs";
4
+ import { t as defineCommand } from "./define-Ckp70_GR.mjs";
5
5
 
6
6
  //#region src/plugins/flow/doors/dev.d.ts
7
7
  /**
package/dist/control.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  import { t as controlRefused } from "./dev-Cc50Dk7H.mjs";
2
2
  import { s as defineCommand } from "./session-DgukhR_7.mjs";
3
- import { n as commands, t as run } from "./run-wYty_Lwo.mjs";
3
+ import { n as commands, t as run } from "./run-BtyrJjmW.mjs";
4
4
  export { commands, controlRefused, defineCommand, run };
@@ -1,5 +1,5 @@
1
- import { t as HeadlessApp } from "./headless-G4nuZ-xz.mjs";
2
- import { c as Source, n as Command, o as InputSchema } from "./types-DAdwEJMp.mjs";
1
+ import { t as HeadlessApp } from "./headless-CYgYzro0.mjs";
2
+ import { c as Source, n as Command, o as InputSchema } from "./types-Bonifz5M.mjs";
3
3
 
4
4
  //#region src/plugins/flow/doors/define.d.ts
5
5
  /**
@@ -1,4 +1,4 @@
1
- import { u as graphHash } from "./capture-fpd83Mi5.mjs";
1
+ import { c as describedNode, d as graphHash } from "./capture-D7XvoHdH.mjs";
2
2
  //#region src/plugins/flow/headless.ts
3
3
  const noPayload = null;
4
4
  /** Seed of a repro that pins no rng state, the seed `saveOf` writes. */
@@ -91,29 +91,50 @@ async function createHeadless(app) {
91
91
  };
92
92
  }
93
93
  /**
94
- * Reads the rest node a repro starts at: its checkpoint, or the start of the main flow.
94
+ * Names a checkpoint of a described graph, for the message of a refused repro: the first rest
95
+ * node that is one, or the start of the main flow when the graph has none.
96
+ *
97
+ * @param graph - The described graph.
98
+ * @returns The path of a checkpoint to suggest.
99
+ * @example
100
+ * ```ts
101
+ * someCheckpoint({ main: "main", flows: {}, slots: {} }); // "": an empty graph suggests nothing
102
+ * ```
103
+ */
104
+ function someCheckpoint(graph) {
105
+ for (const [id, flow] of Object.entries(graph.flows)) for (const [name, node] of Object.entries(flow.nodes)) if (node.rest && node.checkpoint) return id === graph.main ? name : `${id}/${name}`;
106
+ return graph.flows[graph.main]?.start ?? "";
107
+ }
108
+ /**
109
+ * Reads the rest node a repro starts at: its checkpoint, or the start of the main flow. A repro
110
+ * starts at a rest node only. `flow.restore` also enters a transit node while the graph is
111
+ * unchanged, and a repro carries the hash of the graph that runs now, so the path is checked here.
95
112
  *
96
113
  * @param app - The started app.
97
114
  * @param repro - Starting state, optional checkpoint and the route.
98
115
  * @returns The path of the node the repro enters.
99
- * @throws {Error} When the graph has no main flow to start from.
116
+ * @throws {Error} When the graph has no main flow to start from, and when the path names a node
117
+ * that is not a rest node.
100
118
  */
101
119
  function reproPath(app, repro) {
102
- if (repro.checkpoint !== void 0) return repro.checkpoint;
103
120
  const graph = app.flow.describe();
104
- const start = graph.flows[graph.main]?.start;
105
- if (start === void 0) throw new Error(`[game] runRepro() found no flow "${graph.main}" to start from.\n Name the checkpoint the repro was taken at.`);
106
- return start;
121
+ const path = repro.checkpoint ?? graph.flows[graph.main]?.start;
122
+ if (path === void 0) throw new Error(`[game] runRepro() found no flow "${graph.main}" to start from.\n Name the checkpoint the repro was taken at.`);
123
+ const node = describedNode(graph, path);
124
+ if (node !== void 0 && !node.rest) throw new Error(`[game] The bookmark "${path}" is not a rest node of the graph.\n Restore a rest node, for example the checkpoint "${someCheckpoint(graph)}".`);
125
+ return path;
107
126
  }
108
127
  /**
109
128
  * Builds the bookmark a repro is entered with: its state, its checkpoint and the hash of the
110
129
  * graph that runs now, so a checkpoint is accepted and any other rest node is checked. The route
111
- * is not part of it: the caller walks it after the restore.
130
+ * is not part of it: the caller walks it after the restore. A repro starts at a rest node: a
131
+ * checkpoint that names a transit node is refused here, although `flow.restore` enters one.
112
132
  *
113
133
  * @param app - The started app.
114
134
  * @param repro - Starting state, optional checkpoint and the route.
115
135
  * @returns The bookmark to restore.
116
- * @throws {Error} When the repro names no checkpoint and the graph has no main flow.
136
+ * @throws {Error} When the repro names no checkpoint and the graph has no main flow, and when
137
+ * the node it starts at is not a rest node.
117
138
  * @example
118
139
  * ```ts
119
140
  * // The game.restore command loads a bug report taken at the "home" checkpoint.
@@ -1,4 +1,4 @@
1
- import { Bt as Answer, Mt as JournalEntry, Pt as RouteStep, Xt as Json, cn as RngState, dt as Api$1, hn as Api, jt as FlowState } from "./types-ZQLYXo5X.mjs";
1
+ import { Bt as Answer, Mt as JournalEntry, Pt as RouteStep, Xt as Json, cn as RngState, dt as Api$1, hn as Api, jt as FlowState } from "./types-BSMmnpFm.mjs";
2
2
 
3
3
  //#region src/plugins/flow/headless.d.ts
4
4
  /**
package/dist/hot.d.mts CHANGED
@@ -15,9 +15,9 @@ type HotOptions = {
15
15
  /**
16
16
  * The files that get the footer. Default: `.tsx` files, `styles.ts`, `view.ts`,
17
17
  * `animations.ts`, `effects.ts`, any `.ts` directly in a `styles/`, `motion/`, `effects/` or
18
- * `views/` folder, and in `world/projections/` or `world/layout/`, and
19
- * `generated/strings.<locale>.ts`. Bun runs it as the load filter on the absolute path, so it
20
- * should not anchor at the start.
18
+ * `views/` folder, and in `world/projections/` or `world/layout/`,
19
+ * `generated/strings.<locale>.ts`, and the stamp module `.moku/assets-stamp.ts`. Bun runs it as
20
+ * the load filter on the absolute path, so it should not anchor at the start.
21
21
  */
22
22
  include?: RegExp;
23
23
  /**
package/dist/hot.mjs CHANGED
@@ -6,20 +6,22 @@ import { readFile } from "node:fs/promises";
6
6
  * a running game. It appends a footer to every view module it loads: the module accepts its own
7
7
  * update and hands the new exports to the running game through `globalThis.__moku_hot`. The `ui`
8
8
  * plugin installs that handler in dev builds only. What swaps: styles, components, projections,
9
- * animations, text styles, emitters and generated strings. A view module is a `.tsx` file, a
10
- * `styles.ts`, a `view.ts`, an `animations.ts`, an `effects.ts`, any `.ts` directly in a
11
- * `styles/`, `motion/`, `effects/` or `views/` folder, any `.ts` directly in `world/projections/`
12
- * or `world/layout/`, or a generated `generated/strings.<locale>.ts`; a logic module never gets
13
- * the footer (`world/components/` and `world/systems/` included: they are registered at start), so
14
- * its save reaches the root and the page reloads and restores its state. `moku-game dev` lists the
9
+ * animations, text styles, emitters, generated strings, and the asset files the stamp module of
10
+ * the keys watch names. A view module is a `.tsx` file, a `styles.ts`, a `view.ts`, an
11
+ * `animations.ts`, an `effects.ts`, any `.ts` directly in a `styles/`, `motion/`, `effects/` or
12
+ * `views/` folder, any `.ts` directly in `world/projections/` or `world/layout/`, or a generated
13
+ * `generated/strings.<locale>.ts`. The stamp module `.moku/assets-stamp.ts` gets the footer too:
14
+ * its new exports say which asset files changed. A logic module never gets the footer
15
+ * (`world/components/` and `world/systems/` included: they are registered at start, and
16
+ * `.moku/main.ts` too), so its save reaches the root and the page reloads and restores its state. `moku-game dev` lists the
15
17
  * plugin first in `[serve.static]` of the bunfig it writes, `.moku/bunfig.toml`; a game without the
16
18
  * shell lists it in its own `bunfig.toml`. The dev server only: `moku-game build` never loads it.
17
19
  */
18
20
  /**
19
- * The default view modules: the view files by name or by kind folder. Two literals joined, so
20
- * each stays readable.
21
+ * The default modules that swap: the view files by name or by kind folder, and the stamp module.
22
+ * Three literals joined, so each stays readable.
21
23
  */
22
- const DEFAULT_INCLUDE = new RegExp(`(${/\.tsx|\/styles\.ts|\/view\.ts|\/animations\.ts|\/effects\.ts|\/generated\/strings\.[\w-]+\.ts/.source}|${/\/(?:styles|motion|effects|views)\/[^/]+\.ts|\/world\/(?:projections|layout)\/[^/]+\.ts/.source})$`);
24
+ const DEFAULT_INCLUDE = new RegExp(`(${/\.tsx|\/styles\.ts|\/view\.ts|\/animations\.ts|\/effects\.ts|\/generated\/strings\.[\w-]+\.ts/.source}|${/\/(?:styles|motion|effects|views)\/[^/]+\.ts|\/world\/(?:projections|layout)\/[^/]+\.ts/.source}|${/\/\.moku\/assets-stamp\.ts/.source})$`);
23
25
  /** The generated strings of one locale, the one file under `generated/` that swaps. */
24
26
  const STRINGS = /\/generated\/strings\.[\w-]+\.ts$/;
25
27
  /** The default folders and test files that never hot swap. The outer group only scopes the `$`. */
@@ -1,7 +1,7 @@
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-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";
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-BSMmnpFm.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-dJMOXXL3.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-B_Bp2tWK.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-Dm5Oh5bH.mjs";
5
5
  import { Log } from "@moku-labs/common/browser";
6
6
  import { PluginCtx } from "@moku-labs/core";
7
7
 
@@ -196,6 +196,10 @@ declare const assetsPlugin: import("@moku-labs/core").PluginInstance<"assets", C
196
196
  reason: "budget" | "request";
197
197
  keys: readonly string[];
198
198
  };
199
+ "assets:replaced": {
200
+ bundle: string;
201
+ keys: readonly string[];
202
+ };
199
203
  }> & Record<never, never>;
200
204
  //#endregion
201
205
  //#region src/plugins/audio/index.d.ts
@@ -1641,6 +1645,10 @@ declare const screen: readonly [import("@moku-labs/core").PluginInstance<"world"
1641
1645
  reason: "budget" | "request";
1642
1646
  keys: readonly string[];
1643
1647
  };
1648
+ "assets:replaced": {
1649
+ bundle: string;
1650
+ keys: readonly string[];
1651
+ };
1644
1652
  }> & Record<never, never>, import("@moku-labs/core").PluginInstance<"scenes", Record<string, never>, State$11, ScenesApi, {
1645
1653
  "scenes:changed": {
1646
1654
  from: string | undefined;
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
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-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";
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-BSMmnpFm.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-dJMOXXL3.mjs";
3
+ import { a as types_d_exports$4 } from "./types-B_Bp2tWK.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-Dm5Oh5bH.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-CjuObHhF.mjs";
6
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 };