@moku-labs/game 0.14.11 → 0.14.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +13 -12
  2. package/dist/app/page.d.mts +8 -3
  3. package/dist/app/page.mjs +57 -12
  4. package/dist/app/system.d.mts +5 -3
  5. package/dist/app/system.mjs +2 -0
  6. package/dist/app.d.mts +15 -7
  7. package/dist/app.mjs +131 -27
  8. package/dist/{assets-BrKSg1O6.mjs → assets-CEMfBogh.mjs} +471 -120
  9. package/dist/assets.d.mts +30 -13
  10. package/dist/assets.mjs +1 -1
  11. package/dist/cli.d.mts +105 -8
  12. package/dist/cli.mjs +1036 -128
  13. package/dist/{commands-d5Zlh9hf.d.mts → commands-DAETmK86.d.mts} +43 -7
  14. package/dist/{config-CdARrrhU.mjs → config-B87aFTW-.mjs} +25 -4
  15. package/dist/control.d.mts +130 -17
  16. package/dist/control.mjs +4 -4
  17. package/dist/{define-BN15lAWb.d.mts → define-BASd9ZUh.d.mts} +32 -4
  18. package/dist/dev-DbHgx-R-.mjs +89 -0
  19. package/dist/{fake-MpzwZhIZ.mjs → fake-6mazmHK3.mjs} +20 -2
  20. package/dist/features-DowEilZm.mjs +266 -0
  21. package/dist/{headless-CrhefcLu.d.mts → headless-cFveciuY.d.mts} +1 -1
  22. package/dist/hot.d.mts +4 -2
  23. package/dist/hot.mjs +7 -4
  24. package/dist/{index-0GIP3tgm.d.mts → index-DedbED3T.d.mts} +317 -69
  25. package/dist/index.d.mts +5 -6
  26. package/dist/index.mjs +3 -3
  27. package/dist/inspect.d.mts +12 -7
  28. package/dist/inspect.mjs +2 -2
  29. package/dist/jsx-dev-runtime.d.mts +1 -1
  30. package/dist/jsx-runtime.d.mts +1 -1
  31. package/dist/lint.d.mts +8 -3
  32. package/dist/lint.mjs +432 -20
  33. package/dist/project.d.mts +15 -1
  34. package/dist/project.mjs +1 -1
  35. package/dist/{run-Bf2hKyjZ.mjs → run-BbipFRc6.mjs} +250 -51
  36. package/dist/{runtime-aLkoeoGj.d.mts → runtime-DoSlRx8X.d.mts} +1 -1
  37. package/dist/{session-DgukhR_7.mjs → session-CeKgO2hy.mjs} +30 -2
  38. package/dist/{sources-Duzj6lhV.mjs → sources-Cdvb0rOS.mjs} +33 -6
  39. package/dist/{src-Do697seR.mjs → src-BEbJ_sSx.mjs} +29154 -11121
  40. package/dist/testing.d.mts +119 -14
  41. package/dist/testing.mjs +97 -7
  42. package/dist/{types-BZa187kz.d.mts → types-7GXcXxxv.d.mts} +196 -242
  43. package/dist/{types-BT9S_Lo2.d.mts → types-BGcda5Le.d.mts} +4464 -735
  44. package/dist/{types-yiHtzg1Y.d.mts → types-C73hbmxi.d.mts} +129 -17
  45. package/dist/{types-Bc9AvZVO.d.mts → types-DngFQJro.d.mts} +43 -5
  46. package/dist/{types-kNiV7iFj.d.mts → types-GHE4J5Uf.d.mts} +1027 -192
  47. package/dist/{visual-dMW8iqAE.mjs → visual-2m4wJL_z.mjs} +111 -7
  48. package/dist/visual-_XhoGeIC.d.mts +345 -0
  49. package/dist/visual.d.mts +1 -332
  50. package/dist/visual.mjs +130 -20
  51. package/dist/{watch-CWI_on4T.mjs → watch-BEdrp80i.mjs} +149 -30
  52. package/llms.txt +103 -51
  53. package/package.json +8 -6
  54. package/dist/dev-Cc50Dk7H.mjs +0 -47
  55. package/dist/memory-DR1ibF_s.d.mts +0 -50
  56. package/dist/types-DMoi447V.d.mts +0 -656
@@ -1,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-BT9S_Lo2.mjs";
1
+ import { Ar as Api, Br as Require, Gt as AnyComponentType, It as TransformValue, Jn as Descriptor, Kt as AnyComponentValue, Qn as Hint, T as Api$3, Wt as AnyComponent, Yt as ComponentType, Zt as Entity, bn as Api$1, bt as ViewportSize, dn as MotionCause, er as Answer, fn as MotionHandle, mn as ProjectionMotion, on as TagType, pn as NumericFields, s as Events$1, sn as ChangeHook, t as Api$4, tr as Api$5, un as Motion, ur as Json, yn as ViewHandle, zt as Api$2 } from "./types-BGcda5Le.mjs";
2
2
  import { Log } from "@moku-labs/common/browser";
3
3
  import { PluginCtx } from "@moku-labs/core";
4
4
 
@@ -329,10 +329,10 @@ type Tokens = {
329
329
  */
330
330
  type StylesState = {
331
331
  flags: WhenFlags;
332
- viewport: ViewportSize | undefined;
332
+ viewport: Readonly<ViewportSize> | undefined;
333
333
  };
334
334
  declare namespace types_d_exports$2 {
335
- export { Argument, CompiledMessage, CompiledMessages, Config$2 as Config, DurationStyle, ElementNode, Events, I18nApi, I18nCtx, I18nKit, IntlKit, KeysWithoutParameters, Message, Part, RegisteredModule, ResolvedModule, State$2 as State, StringTable, StringsLoader, TypedTr };
335
+ export { Argument, CompiledMessage, CompiledMessages, Config$2 as Config, DurationStyle, ElementNode, Events, I18nApi, I18nCtx, I18nKit, IntlKit, KeysWithoutParameters, Message, Part, RegisteredModule, ResolvedModule, State$2 as State, StringTable, StringsLoader, TextKey, TypedTr };
336
336
  }
337
337
  /**
338
338
  * One interface element handed to a message as a parameter. Structural on purpose: it mirrors
@@ -489,6 +489,11 @@ type Config$2 = {
489
489
  type RegisteredModule = {
490
490
  /** The feature that brought the module, or `"pluginConfigs.i18n"` for a configured one. */from: string; /** The module itself, or the loader that fetches it on first use. */
491
491
  messages: CompiledMessages | StringsLoader;
492
+ /**
493
+ * Set for a sub-feature's lazy module: the bundle it loads and unloads with. Its loader is kept
494
+ * and never replaced.
495
+ */
496
+ bundle?: string;
492
497
  };
493
498
  /**
494
499
  * One registered module whose loader already ran, ready to be merged into a locale.
@@ -501,24 +506,38 @@ type ResolvedModule = {
501
506
  * i18n plugin state.
502
507
  */
503
508
  type State$2 = {
504
- /** The current locale; `config.locale` until `setLocale`. */locale: string; /** Per locale, one entry per feature and one for the config, filled in `onStart`. */
505
- registered: Map<string, RegisteredModule[]>; /** Merged and resolved modules per locale. */
509
+ /** The current locale; `config.locale` until `setLocale`. */locale: string;
510
+ /**
511
+ * Per locale, one entry per feature and one for the config, filled in `onStart`. Coupled
512
+ * entries keep their loader.
513
+ */
514
+ registered: Map<string, RegisteredModule[]>; /** Merged modules per locale: resolved non-coupled modules plus the coupled modules of loaded bundles. */
506
515
  loaded: Map<string, CompiledMessages>; /** One kit per locale, built on first use. */
507
- intl: Map<string, IntlKit>; /** Keys already reported missing, so each warns once. */
508
- warned: Set<string>; /** The `setLocale` in flight; a later call waits for it. */
509
- loading: Promise<void> | undefined;
516
+ intl: Map<string, IntlKit>; /** Keys already reported missing (or of a bundle not loaded), so each warns once. */
517
+ warned: Set<string>; /** The strings load in flight (start, `setLocale` or a bundle); the next one waits for it. */
518
+ loading: Promise<void> | undefined; /** Bundles assets reported loaded, each with the token of the load that brought it. */
519
+ held: Map<string, symbol>; /** Resolved coupled modules while their bundle is loaded: bundle to locale to messages. */
520
+ bundled: Map<string, Map<string, CompiledMessages>>; /** Sub-features whose lazy strings live with the bundle of their name. Filled in `onStart`. */
521
+ coupled: Set<string>; /** True once `onStart` collected the registry; before that a companion call only records the bundle. */
522
+ started: boolean;
510
523
  };
511
524
  /**
512
525
  * i18n plugin events.
513
526
  */
514
527
  type Events = {
515
- /** The current locale changed, or its messages were replaced. */"i18n:locale-changed": {
528
+ /**
529
+ * The current locale changed, its messages were replaced, or the strings of a bundle arrived
530
+ * for a key shown missing.
531
+ */
532
+ "i18n:locale-changed": {
516
533
  locale: string;
517
534
  };
518
535
  };
519
536
  /**
520
537
  * i18n plugin API, `app.i18n`. Messages are data everywhere else in the game; this is the one
521
- * place a locale is read and a sentence becomes parts.
538
+ * place a locale is read and a sentence becomes parts. `Key` is what `isKey` narrows to: the app
539
+ * of a game (`game.screen().app`) carries `I18n.TextKey<Strings>` of its generated table; an engine
540
+ * plugin's `ctx.require(i18nPlugin)` has no table, and `isKey` narrows to `string`.
522
541
  *
523
542
  * @example
524
543
  * ```ts
@@ -528,7 +547,7 @@ type Events = {
528
547
  * app.i18n.plain(tr("hud.orders", { n: 3 })); // "3 orders"
529
548
  * ```
530
549
  */
531
- type I18nApi = {
550
+ type I18nApi<Key extends string = string> = {
532
551
  /**
533
552
  * The locale every `format` without a second argument reads.
534
553
  *
@@ -541,8 +560,9 @@ type I18nApi = {
541
560
  locale(): string;
542
561
  /**
543
562
  * Switches the current locale. A lazy module is imported once, then `i18n:locale-changed` is
544
- * emitted; `text` re-resolves every message on it. A call for the locale already current
545
- * resolves at once and emits nothing.
563
+ * emitted; `text` re-resolves every message on it. The modules of every sub-feature whose bundle
564
+ * is loaded are imported for the new locale before the event; a sub-feature whose bundle is not
565
+ * loaded is left alone. A call for the locale already current resolves at once and emits nothing.
546
566
  *
547
567
  * @param locale - The locale to switch to.
548
568
  * @returns A promise that settles when the messages of that locale are loaded.
@@ -552,12 +572,16 @@ type I18nApi = {
552
572
  * // features/settings/nodes.ts: the language button of the settings screen.
553
573
  * await app.i18n.setLocale("en"); // loads the compiled module, then emits i18n:locale-changed
554
574
  * app.i18n.locale(); // "en"
575
+ * // The ward of episode 1 is on screen (bundle "ep01" loaded): strings.ep01.en came with the switch.
576
+ * app.i18n.plain(tr("ep01.ward.title")); // "Ward"
555
577
  * ```
556
578
  */
557
579
  setLocale(locale: string): Promise<void>;
558
580
  /**
559
581
  * Formats a message in the current locale. Resolution order is the current locale, then
560
582
  * `config.fallback`, then missing: a missing key gives one text part `⟦key⟧` and one warning.
583
+ * A key of a sub-feature whose strings live with its bundle, while that bundle is not loaded,
584
+ * gives `⟦key⟧` too, and its one warning names the bundle.
561
585
  *
562
586
  * @param message - What `tr` returned.
563
587
  * @returns The parts of the sentence, adjacent text merged.
@@ -565,12 +589,14 @@ type I18nApi = {
565
589
  * ```ts
566
590
  * // text resolves the `content` of a Text component every time the locale changes.
567
591
  * app.i18n.format(tr("hud.orders", { n: 3 })); // [{ kind: "text", text: "3 заказа" }]
592
+ * // Bundle "ep01" is not loaded: one warn "i18n: the bundle of a key is not loaded" { bundle: "ep01" }
593
+ * app.i18n.format(tr("ep01.ward.title")); // [{ kind: "text", text: "⟦ep01.ward.title⟧" }]
568
594
  * ```
569
595
  */
570
596
  format(message: Message): readonly Part[];
571
597
  /**
572
598
  * Formats a message in another registered locale, without switching. `ui.lint` measures a
573
- * label in every locale this way.
599
+ * label in every locale this way. Every loaded locale carries the strings of every loaded bundle.
574
600
  *
575
601
  * @param message - What `tr` returned.
576
602
  * @param locale - The registered locale to read.
@@ -597,7 +623,8 @@ type I18nApi = {
597
623
  */
598
624
  plain(message: Message): string;
599
625
  /**
600
- * Tells whether a key exists in the current locale or in the fallback.
626
+ * Tells whether a key exists in the current locale or in the fallback. A key of a sub-feature
627
+ * whose bundle is not loaded answers false.
601
628
  *
602
629
  * @param key - The message key.
603
630
  * @returns True when `format` would find a message for it.
@@ -605,9 +632,37 @@ type I18nApi = {
605
632
  * ```ts
606
633
  * // A projection hides the label of an order that has no description yet.
607
634
  * app.i18n.has("orders.hint"); // false: no locale brought that key
635
+ * app.i18n.has("ep01.ward.title"); // false until bundle "ep01" is loaded, then true
608
636
  * ```
609
637
  */
610
638
  has(key: string): boolean;
639
+ /**
640
+ * Tells whether a value read from saved JSON is a key the game still has: a key of the loaded
641
+ * tables of the current locale or of the fallback. For a key of a sub-feature whose strings are
642
+ * not loaded yet it answers by the prefix: `"<feature>."` of a known sub-feature that has strings
643
+ * is accepted (the exact key is checked when its bundle loads, and `text` shows `⟦key⟧` and warns
644
+ * once if it does not exist). Anything that is not a string answers false. The compiled tables
645
+ * carry no parameter list, so a key that takes parameters answers true as well: the check is
646
+ * for a key renamed or removed since the save was written. Call it where the app is: an effect
647
+ * handler, app or page code, the code that loads a save. On the app of a game a true answer types
648
+ * the value as a key `tr` takes alone (`I18n.TextKey<Strings>`); through
649
+ * `ctx.require(i18nPlugin)` it types it as a `string`.
650
+ *
651
+ * @param value - What the save or a data source holds.
652
+ * @returns True when the value is a key of the game's tables; it is then typed as one.
653
+ * @example
654
+ * ```ts
655
+ * // The page restores the toast kept in the save before it shows it.
656
+ * const { app } = game.screen();
657
+ * await app.start();
658
+ * app.i18n.isKey("ui.toast.saved"); // true: the value is typed TextKey, so tr takes it alone
659
+ * app.i18n.isKey("ui.toast.removedLastYear"); // false: renamed since, the toast shows its fallback
660
+ * app.i18n.isKey(3); // false: not a string
661
+ * // An engine plugin asks the same question; a true answer types the value as a string.
662
+ * ctx.require(i18nPlugin).isKey("casefile.title"); // true while the casefile bundle is not loaded
663
+ * ```
664
+ */
665
+ isKey(value: unknown): value is Key;
611
666
  /**
612
667
  * Formats milliseconds in the current locale through `Intl.DurationFormat`. The value is rounded
613
668
  * up to whole seconds, so a countdown never reads zero while time is left; a negative or
@@ -628,7 +683,8 @@ type I18nApi = {
628
683
  */
629
684
  duration(ms: number, style?: DurationStyle): string;
630
685
  /**
631
- * Every locale at least one feature or the config brought a module for, sorted.
686
+ * Every locale at least one feature, sub-feature or the config brought a module for, sorted. A
687
+ * sub-feature's lazy module counts while its bundle is not loaded.
632
688
  *
633
689
  * @returns The registered locales.
634
690
  * @example
@@ -640,19 +696,23 @@ type I18nApi = {
640
696
  locales(): readonly string[];
641
697
  /**
642
698
  * Swaps the compiled module of one feature in a loaded locale, for the dev hot swap. The one
643
- * registered module whose keys overlap `messages` takes them, the locale is merged again and
644
- * every key may warn once more. When the locale is the current one or the fallback,
645
- * `i18n:locale-changed` is emitted with the current locale, so `text` re-resolves every label.
646
- * A locale not loaded yet is left alone: its loader imports the new module later.
699
+ * module in memory whose keys overlap `messages` takes them (a sub-feature's module of a loaded
700
+ * bundle included), the locale is merged again and every key may warn once more. When the locale
701
+ * is the current one or the fallback, `i18n:locale-changed` is emitted with the current locale,
702
+ * so `text` re-resolves every label. A locale not loaded yet, and the module of a sub-feature
703
+ * whose bundle is not loaded, are left alone: the loader imports the new module later.
647
704
  *
648
- * @param locale - The locale of the saved `generated/strings.<locale>.ts`.
705
+ * @param locale - The locale of the saved `generated/strings.<locale>.ts` or `strings.<feature>.<locale>.ts`.
649
706
  * @param messages - The `default` export of the new module.
650
- * @throws {Error} When no registered module, or more than one, shares a key with `messages`.
707
+ * @throws {Error} When no module in memory, or more than one, shares a key with `messages`.
651
708
  * @example
652
709
  * ```ts
653
710
  * // ui's hot swap: generated/strings.ru.ts was written again with "hud.orders" as "3 заказа!".
654
711
  * ctx.require(i18nPlugin).replace("ru", next.default); // emits i18n:locale-changed
655
712
  * app.i18n.plain(tr("hud.orders", { n: 3 })); // "3 заказа!": text redraws the label
713
+ * // generated/strings.ep01.ru.ts was written again while bundle "ep01" is loaded.
714
+ * ctx.require(i18nPlugin).replace("ru", next.default); // emits i18n:locale-changed
715
+ * app.i18n.plain(tr("ep01.ward.title")); // "Палата!"
656
716
  * ```
657
717
  */
658
718
  replace(locale: string, messages: CompiledMessages): void;
@@ -667,7 +727,8 @@ type I18nApi = {
667
727
  type I18nCtx = PluginCtx<Config$2, State$2, Events> & {
668
728
  readonly global: object;
669
729
  readonly log: Log.LogApi;
670
- readonly require: Require;
730
+ readonly require: Require; /** Whether a plugin of that name is composed, whatever its place in the list. */
731
+ readonly has: (name: string) => boolean;
671
732
  };
672
733
  /**
673
734
  * The key-to-parameters table a game generates: `generated/strings.ts` exports it as `Strings`.
@@ -690,6 +751,21 @@ type StringTable = Record<string, unknown>;
690
751
  * ```
691
752
  */
692
753
  type KeysWithoutParameters<Table extends StringTable> = { [Key in keyof Table]: Record<never, never> extends Table[Key] ? Key : never }[keyof Table] & string;
754
+ /**
755
+ * The keys of a string table that take no parameters: what a data table or a save may hold and
756
+ * `tr` takes alone. Derived from the `Strings` type `moku-game keys` already writes (a key whose
757
+ * parameters are `Record<string, never>`), so no list is generated and the type cannot drift from
758
+ * the table.
759
+ *
760
+ * @example
761
+ * ```ts
762
+ * // core/tables.ts of a game
763
+ * import type { Strings } from "@generated/strings";
764
+ * type HintKey = I18n.TextKey<Strings>; // "board.hint.blue" | "board.hint.red" | …, never "hud.orders"
765
+ * export const generators: Record<string, { readonly hint: HintKey }> = { red: { hint: "board.hint.red" } };
766
+ * ```
767
+ */
768
+ type TextKey<Table extends StringTable> = KeysWithoutParameters<Table>;
693
769
  /**
694
770
  * `tr` as one game reads it: the key is checked against the generated table, and the parameters
695
771
  * are the ones that key declares. A key with no parameters takes no second argument.
@@ -714,214 +790,22 @@ type TypedTr<Table extends StringTable> = {
714
790
  * ```
715
791
  */
716
792
  type I18nKit<Table extends StringTable> = {
717
- tr: TypedTr<Table>;
718
- };
719
- //#endregion
720
- //#region src/plugins/renderer/components.d.ts
721
- /**
722
- * Where a view sits, in reference units and radians. Relative to the `Parent` when there is one.
723
- * `pivot` is the local point the view turns and scales around, and `x`, `y` is where that point
724
- * lands; the default pivot `{ x: 0, y: 0 }` is the view's own origin.
725
- *
726
- * @example
727
- * ```ts
728
- * // A 200 x 80 button that grows around its centre.
729
- * const value: TransformValue = {
730
- * x: 640, y: 340, rotation: 0, scale: 1.1, pivot: { x: 100, y: 40 }
731
- * };
732
- * ```
733
- */
734
- type TransformValue = {
735
- x: number;
736
- y: number;
737
- rotation: number;
738
- scale: number;
739
- pivot: Point$2;
740
- };
741
- /**
742
- * How a sized sprite fills its box: `"fill"` stretches, `"contain"` scales uniformly inside the
743
- * box and centres, `"cover"` scales uniformly over the box and crops the overflow.
744
- *
745
- * @example
746
- * ```ts
747
- * const fit: SpriteFit = "cover";
748
- * ```
749
- */
750
- type SpriteFit = "fill" | "contain" | "cover";
751
- /**
752
- * One textured quad. `texture` is an asset key; `defineGame` narrows it to the game's keys.
753
- * `width` and `height` are the box in reference units; 0 on an axis keeps the texture's own size
754
- * there. `anchor` is the point of the box that sits on the `Transform`. `alpha` fades the quad
755
- * and the entity's children.
756
- *
757
- * @example
758
- * ```ts
759
- * const value: SpriteValue = {
760
- * texture: "board.bg-forest-meadow", tint: 0xffffff, alpha: 1, anchor: { x: 0, y: 0 },
761
- * width: 1080, height: 1920, fit: "cover"
762
- * };
763
- * ```
764
- */
765
- type SpriteValue = {
766
- texture: string;
767
- tint: number;
768
- alpha: number;
769
- anchor: Point$2;
770
- width: number;
771
- height: number;
772
- fit: SpriteFit;
773
- };
774
- /**
775
- * A stretchable panel. The slice borders come with the texture, not with the component. `debug`
776
- * strokes the bounds and the four cut lines over the panel: cyan, red when the corners overlap or
777
- * the texture is missing. `clip` masks the children of the entity to the `width × height` box,
778
- * the same rule as `Shape.clip`: the mask is a filled rectangle and is never drawn, and the panel
779
- * itself is never masked. `alpha` fades the panel and the entity's children.
780
- *
781
- * @example
782
- * ```ts
783
- * const value: NineSliceValue = {
784
- * texture: "ui.panel", width: 600, height: 320, alpha: 1, tint: 0xffffff, debug: false,
785
- * clip: false
786
- * };
787
- * // The board tray, outlined while its insets are checked.
788
- * const tray: NineSliceValue = {
789
- * ...value, texture: "board.board-tray", width: 1000, height: 1040, debug: true
790
- * };
791
- * // A text field: a long value never draws outside the frame.
792
- * const field: NineSliceValue = {
793
- * ...value, texture: "ui.field", width: 480, height: 96, clip: true
794
- * };
795
- * ```
796
- */
797
- type NineSliceValue = {
798
- texture: string;
799
- width: number;
800
- height: number;
801
- alpha: number;
802
- tint: number;
803
- debug: boolean;
804
- clip: boolean;
805
- };
806
- /**
807
- * The escape hatch: the game owns a Pixi object and `sync` only attaches and detaches it.
808
- *
809
- * @example
810
- * ```ts
811
- * const value: DisplayValue = { object: spineAnimation };
812
- * ```
813
- */
814
- type DisplayValue = {
815
- object: unknown;
816
- };
817
- /**
818
- * A filled rounded rectangle or a triangle, anchored at the top left of the `Transform`. `kind`
819
- * picks the outline: `"rect"` (the default) or `"triangle"`, which fills its `w × h` box pointing
820
- * right (rotate the element for another direction) and ignores `radius`. `fillAlpha` is the alpha
821
- * of the fill alone: 0 draws only the stroke, a ring. `alpha` fades the whole shape and the
822
- * entity's children: a disabled button at 0.6 draws its icon at 0.6 too. `dash` is the
823
- * dash length of the stroke in reference units, with gaps of half a dash; 0 strokes a solid line.
824
- * `clip` masks the children of the entity to the shape, always solid, which is how `ui` draws a
825
- * scroll and an overflow. The shape itself is never masked, so its stroke is drawn whole.
826
- *
827
- * @example
828
- * ```ts
829
- * const value: ShapeValue = {
830
- * kind: "rect", w: 320, h: 96, fill: 0x101018, fillAlpha: 1, alpha: 1, radius: 16,
831
- * stroke: 0x000000, strokeWidth: 0, dash: 0, clip: false
832
- * };
833
- * // The honey ring on a selected cell: a stroke and no fill.
834
- * const ring: ShapeValue = {
835
- * kind: "rect", w: 140, h: 140, fill: 0xffffff, fillAlpha: 0, alpha: 1, radius: 24,
836
- * stroke: 0xffc233, strokeWidth: 6, dash: 0, clip: false
837
- * };
838
- * // The play glyph of a watch button, and a dashed focus ring: 10 u dashes, 5 u gaps.
839
- * const play: ShapeValue = { ...ring, kind: "triangle", w: 36, h: 40, fillAlpha: 1, strokeWidth: 0 };
840
- * const focus: ShapeValue = { ...ring, w: 200, h: 80, stroke: 0x3a2212, strokeWidth: 4, dash: 10 };
841
- * ```
842
- */
843
- type ShapeValue = {
844
- kind: "rect" | "triangle";
845
- w: number;
846
- h: number;
847
- fill: number;
848
- fillAlpha: number;
849
- alpha: number;
850
- radius: number;
851
- stroke: number;
852
- strokeWidth: number;
853
- dash: number;
854
- clip: boolean;
855
- };
856
- /**
857
- * What `sprite()` takes: the two things every visual needs, and the four that have defaults.
858
- *
859
- * @example
860
- * ```ts
861
- * const options: SpriteOptions = { texture: "board.cell", at: { x: 540, y: 300 } };
862
- * ```
863
- */
864
- type SpriteOptions = {
865
- texture: string;
866
- at: Point$2;
867
- tint?: number;
868
- alpha?: number;
869
- anchor?: Point$2;
870
- scale?: number;
793
+ /** `tr`, checked against the game's table. */tr: TypedTr<Table>;
794
+ /**
795
+ * Checks a key that does not take parameters against the game's table and returns it, typed:
796
+ * what a data table stores instead of a `string`. The same string at run time.
797
+ *
798
+ * @param key - A key of the game's table that takes no parameters.
799
+ * @returns The same key, typed as its literal.
800
+ * @example
801
+ * ```ts
802
+ * // core/tables.ts of a game: the hint of every generator, checked when the table is written.
803
+ * export const generators = { red: { hint: key("board.hint.red") }, blue: { hint: key("board.hint.blue") } };
804
+ * tr(generators.red.hint); // { key: "board.hint.red" }
805
+ * ```
806
+ */
807
+ key: <const Key extends TextKey<Table>>(key: Key) => Key;
871
808
  };
872
- /**
873
- * Where a view sits: reference units, radians, uniform scale, and the local point it turns
874
- * around.
875
- */
876
- declare const Transform: ComponentType<TransformValue>;
877
- /**
878
- * One textured quad. `texture` is an asset key, resolved through the texture providers; a size
879
- * and a `fit` draw it into a box.
880
- */
881
- declare const Sprite: ComponentType<SpriteValue>;
882
- /**
883
- * A stretchable panel, sized in reference units, with its own alpha and tint. `debug: true` draws
884
- * the slice outline over it. `clip: true` masks the children of the entity to the panel box.
885
- */
886
- declare const NineSlice: ComponentType<{
887
- texture: string;
888
- width: number;
889
- height: number;
890
- alpha: number;
891
- tint: number;
892
- debug: boolean;
893
- clip: boolean;
894
- }>;
895
- /**
896
- * The entity this view moves with. `0` means no parent.
897
- */
898
- declare const Parent: ComponentType<{
899
- entity: number;
900
- }>;
901
- /**
902
- * A display object the game owns. Never pooled, never destroyed by `sync`.
903
- */
904
- declare const Display: ComponentType<DisplayValue>;
905
- /**
906
- * A filled rounded rectangle or a right-pointing triangle, drawn with Pixi `Graphics` and redrawn
907
- * only when a field changed. `fillAlpha: 0` draws only the stroke, `dash` above 0 dashes it.
908
- * `clip: true` masks the children of the entity to the shape.
909
- */
910
- declare const Shape: ComponentType<ShapeValue>;
911
- /**
912
- * Bundles the two components every visual needs, so a projection `view` reads as one line.
913
- *
914
- * @param options - Texture key, position, and the four values that have defaults.
915
- * @returns The `Sprite` and the `Transform` value, in that order.
916
- * @example
917
- * ```ts
918
- * sprite({ texture: "board.cell", at: { x: 540, y: 300 } });
919
- * // [Sprite({ texture: "board.cell", tint: 0xffffff, alpha: 1, anchor: { x: 0.5, y: 0.5 },
920
- * // width: 0, height: 0, fit: "fill" }),
921
- * // Transform({ x: 540, y: 300, rotation: 0, scale: 1, pivot: { x: 0, y: 0 } })]
922
- * ```
923
- */
924
- declare function sprite(options: SpriteOptions): [ComponentValue<SpriteValue>, ComponentValue<TransformValue>];
925
809
  declare namespace types_d_exports$1 {
926
810
  export { Carried, Config$1 as Config, Deps$1 as Deps, Direction, GesturePhase, InputApi, InputCtx, KernelSlice$1 as KernelSlice, KeyInput, KeyListener, Point$1 as Point, PointerListener, RawSample, State$1 as State, TapListener, Target };
927
811
  }
@@ -1099,8 +983,14 @@ type Carried = {
1099
983
  */
1100
984
  type State$1 = {
1101
985
  /** Written by the DOM handlers, drained by the frame step. */samples: RawSample[];
1102
- phase: GesturePhase; /** The one active pointer. A sample of any other pointer is dropped while this is set. */
1103
- pointerId: number | undefined; /** The pressed or held entity. */
986
+ phase: GesturePhase;
987
+ /**
988
+ * The one followed pointer. A sample of any other pointer is dropped while this is set, except
989
+ * a press while this pointer rests (phase `pressed`, not `moved`): that press takes the pointer
990
+ * over and cancels the resting press.
991
+ */
992
+ pointerId: number | undefined; /** The followed pointer left the tap slop since its press: it started a gesture and keeps the pointer. */
993
+ moved: boolean; /** The pressed or held entity. */
1104
994
  entity: Entity | undefined; /** The projection key of `entity`, read once at press time. */
1105
995
  key: {
1106
996
  projection: string;
@@ -2282,6 +2172,21 @@ declare const Box: ComponentType<{
2282
2172
  * and `ui` merges the patch into the nearest component instance.
2283
2173
  */
2284
2174
  declare const LocalWrite: ComponentType<LocalWriteValue>;
2175
+ /**
2176
+ * On the view a player taps five times within three seconds to open the editor's overlay on a debug build: the
2177
+ * version line of the settings, usually. One helper on top of `app.debug.overlay.open()`; a game that wants another
2178
+ * gesture calls that itself. The view must take a press (a `button`, or any element with `Touchable`); a `button`
2179
+ * that names no intent is the plain choice. Without the agent flag the tag does nothing.
2180
+ *
2181
+ * @example
2182
+ * ```tsx
2183
+ * // The version line of the settings sheet. Five taps open the overlay of `moku-game build --debug` on the phone.
2184
+ * <button key="versionLine" style={versionLineStyle} components={[DebugTrigger()]}>
2185
+ * <text key="version" style="settings.version" content={tr("settings.version", { version: "1.4.0" })} />
2186
+ * </button>
2187
+ * ```
2188
+ */
2189
+ declare const DebugTrigger: TagType;
2285
2190
  /**
2286
2191
  * Builds the effect a node awaits to show a popup. The gate opens for the outcomes of the
2287
2192
  * component, so the node resolves with the intent one of its buttons answered. `over` names the
@@ -2300,6 +2205,7 @@ declare const LocalWrite: ComponentType<LocalWriteValue>;
2300
2205
  * });
2301
2206
  * popup(Reward, { gold: 5 });
2302
2207
  * // { kind: "popup", payload: { component: "Reward", props: { gold: 5 } }, answers: ["claim"] }
2208
+ * await fx(popup(Reward, { gold: 5 })); // Answer<"claim">: { intent: "claim" }
2303
2209
  * ```
2304
2210
  * @example
2305
2211
  * ```ts
@@ -2313,9 +2219,9 @@ declare const LocalWrite: ComponentType<LocalWriteValue>;
2313
2219
  * // answers: ["reset", "cancel"] }
2314
2220
  * ```
2315
2221
  */
2316
- declare function popup<Properties extends object, Local extends object>(component: PopupComponent<Properties, Local>, props: Properties, options?: {
2222
+ declare function popup<Properties extends object, Local extends object, Outcomes extends Record<string, unknown>>(component: PopupComponent<Properties, Local, Outcomes>, props: Properties, options?: {
2317
2223
  over?: string;
2318
- }): Descriptor;
2224
+ }): Descriptor<Answer<keyof Outcomes & string>>;
2319
2225
  //#endregion
2320
2226
  //#region src/plugins/ui/jsx/types.d.ts
2321
2227
  /**
@@ -2421,14 +2327,15 @@ type ComponentDefinition<Properties extends object = object, Local extends objec
2421
2327
  /**
2422
2328
  * A component that names outcomes, which is what `popup` takes. `Local` stays a parameter
2423
2329
  * because the `local` argument of `view` is contravariant: pinned to `object` it would refuse
2424
- * every component that keeps local state.
2330
+ * every component that keeps local state. `Outcomes` are its outcomes, so the popup's answer names
2331
+ * one of them.
2425
2332
  *
2426
2333
  * @example
2427
2334
  * ```ts
2428
- * const settings: PopupComponent<{ volume: number }, { tab: string }> = Settings;
2335
+ * const settings: PopupComponent<{ volume: number }, { tab: string }, { close: { saved: boolean } }> = Settings;
2429
2336
  * ```
2430
2337
  */
2431
- type PopupComponent<Properties extends object, Local extends object = object> = ComponentDefinition<Properties, Local, Record<string, unknown>>;
2338
+ type PopupComponent<Properties extends object, Local extends object = object, Outcomes extends Record<string, unknown> = Record<string, unknown>> = ComponentDefinition<Properties, Local, Outcomes>;
2432
2339
  /**
2433
2340
  * A component definition with its type arguments erased, as the registry stores it.
2434
2341
  */
@@ -2461,6 +2368,15 @@ type ScrollWindow = {
2461
2368
  first: number;
2462
2369
  last: number;
2463
2370
  };
2371
+ /**
2372
+ * What the style of an element was resolved on besides its own node: the epoch of the jsx state,
2373
+ * and the row height when the element is a row of a windowed scroll. While both stand, and the
2374
+ * raw `style` and the state flags say what they said, the resolved style is kept.
2375
+ */
2376
+ type StyleBasis = {
2377
+ epoch: number;
2378
+ rowHeight: number | undefined;
2379
+ };
2464
2380
  /**
2465
2381
  * One live element: the entity, the Yoga node, the resolved style and the place in the tree.
2466
2382
  * `rect` is natural: under a `fit` ancestor it is the rect before that ancestor's scale. `fit`
@@ -2473,13 +2389,23 @@ type ScrollWindow = {
2473
2389
  * warnings of its props in `warned`; `scrolledIn` marks an element a range change of a windowed
2474
2390
  * scroll created: it plays no `enter` hook. A text or an icon that sizes itself keeps in
2475
2391
  * `measuredSize` what its measure function last answered, before Yoga's clamp: a bound text whose
2476
- * new string measures the same asks for no solve.
2392
+ * new string measures the same asks for no solve. `basis` is what `style` was resolved on, set
2393
+ * once the style is on the layout node and the components are written; an element without one is
2394
+ * patched in full at its next patch. `index` is its place among the element children of its parent
2395
+ * at the last diff (0 for a root element): with its `zIndex` it gives the child its `Order`.
2396
+ * `cause` is why the element appeared: `"mount"` when it came with the first build of its root and
2397
+ * the root came by a mount, `"change"` otherwise; its `enter` hook is told. `rebuilds` counts the
2398
+ * patches in a row that brought a loop of another reference that is not really another loop: a
2399
+ * dev build names the element once it reaches three.
2477
2400
  */
2478
2401
  type Element = {
2479
2402
  entity: Entity;
2480
2403
  identity: string;
2481
2404
  type: string;
2482
2405
  key: string | undefined;
2406
+ index: number;
2407
+ cause: MotionCause;
2408
+ rebuilds: number;
2483
2409
  parentType: string | undefined;
2484
2410
  root: Entity;
2485
2411
  node: DescriptionNode;
@@ -2519,6 +2445,7 @@ type Element = {
2519
2445
  width: number;
2520
2446
  height: number;
2521
2447
  };
2448
+ basis?: StyleBasis;
2522
2449
  };
2523
2450
  /**
2524
2451
  * The popup side of a root: the handler that shows it now and the root it was opened over.
@@ -2533,7 +2460,10 @@ type PopupLink = {
2533
2460
  /**
2534
2461
  * One reconciled tree: a projection view or a popup, with the flags the frame step reads.
2535
2462
  * `covered` is true while the root is kept under another popup; every element of the root then
2536
- * resolves `is.covered`.
2463
+ * resolves `is.covered`. `cause` is how the root came, read at its first build: `"change"` for a
2464
+ * popup (its open is an event), the cause of its projection view otherwise, `"mount"` after a
2465
+ * restore or a load. `slot` is the host element the root is laid out in (`undefined` for the
2466
+ * viewport), `slotRect` the content box it was last solved in, in the host's own units.
2537
2467
  */
2538
2468
  type Root = {
2539
2469
  entity: Entity;
@@ -2546,6 +2476,14 @@ type Root = {
2546
2476
  element: Entity | undefined;
2547
2477
  popup: PopupLink | undefined;
2548
2478
  covered: boolean;
2479
+ cause: MotionCause | undefined;
2480
+ slot: Entity | undefined;
2481
+ slotRect: {
2482
+ x: number;
2483
+ y: number;
2484
+ w: number;
2485
+ h: number;
2486
+ } | undefined;
2549
2487
  };
2550
2488
  /**
2551
2489
  * Where the focus ring was last drawn: the layer and order of its root, the rect grown by the
@@ -2674,7 +2612,8 @@ type TextState = {
2674
2612
  * jsx module state. `hosts` holds the elements with a `hosts` prop; `hosted` maps a world view to
2675
2613
  * the element that hosts it; `fields` holds the text fields by entity. `hints` buffers the hints
2676
2614
  * released since the last frame step; `scrolls` holds the scroll containers; `windowRenders`
2677
- * counts the re-renders of a windowed list its range made.
2615
+ * counts the re-renders of a windowed list its range made. `styled` and `written` count the style
2616
+ * passes and the write passes of the reconcile, for `UiCounters`.
2678
2617
  */
2679
2618
  type JsxState = {
2680
2619
  components: Map<string, AnyComponentDefinition>;
@@ -2686,7 +2625,10 @@ type JsxState = {
2686
2625
  exiting: Set<Entity>;
2687
2626
  removing: Set<Entity>;
2688
2627
  hosts: Set<Entity>;
2689
- hosted: Map<Entity, Entity>;
2628
+ hosted: Map<Entity, Entity>; /** The host elements that became live in this solve: the solve hosts their views in the same frame (spec 16 U2). */
2629
+ risen: Set<Entity>; /** The views the full hosting step of this frame took back from their host; their removal lands at the flush. */
2630
+ released: Set<Entity>; /** The cause the elements entered by the diff running now take: the root's for its first build, else `"change"`. */
2631
+ building: MotionCause | undefined;
2690
2632
  reconciles: number;
2691
2633
  focus: FocusState;
2692
2634
  fields: Map<Entity, Field>;
@@ -2695,6 +2637,18 @@ type JsxState = {
2695
2637
  scrolls: Set<Entity>;
2696
2638
  windowRenders: number; /** True from a restore or a load until the next reconcile built every root again. */
2697
2639
  remount: boolean;
2640
+ /**
2641
+ * Counts what changes every style at once: a new viewport, a dev hot swap. An element last
2642
+ * patched in an earlier epoch is patched in full, however equal its description is. A new
2643
+ * locale and a font that arrives are no epoch: `text` resolves the labels again and the
2644
+ * remeasure step measures them.
2645
+ */
2646
+ epoch: number;
2647
+ styled: number;
2648
+ written: number; /** The wall times of the last taps on a `DebugTrigger` view, five at the most. */
2649
+ debugTaps: number[]; /** Whether `ui:debug-trigger-no-agent` was logged: once per app. */
2650
+ debugWarned: boolean; /** Elements that carry `Overlay`, from their enter to their despawn (spec 22 O4.5). */
2651
+ overlays: Set<Entity>;
2698
2652
  };
2699
2653
  /**
2700
2654
  * One node of the snapshot `tree()` answers with. `rect` is natural: under a `fit` ancestor it
@@ -2803,4 +2757,4 @@ type CommonProps = {
2803
2757
  components?: ElementComponents;
2804
2758
  };
2805
2759
  //#endregion
2806
- 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 };
2760
+ export { Config$1 as A, State$2 as B, TextBind as C, TextValue as D, TextStyles as E, Config$2 as F, IsFlags as G, TextKey as H, I18nApi as I, StylesState as J, ResolvedStyle as K, IntlKit as L, State$1 as M, types_d_exports$1 as N, types_d_exports as O, Argument as P, Message as R, TextApi as S, TextStyleInput as T, TypedTr as U, StringTable as V, types_d_exports$2 as W, WhenFlags as Y, BindOptions as _, JsxChild as a, Point as b, UiNode as c, LocalWrite as d, popup as f, BindField as g, UiIntrinsicElements as h, Finding as i, InputApi as j, defineComponent as k, Box as l, IntrinsicElementsFor as m, ElementChange as n, JsxState as o, defineTokens as p, Style as q, ElementMotion as r, PopupComponent as s, DescriptionNode as t, DebugTrigger as u, Config as v, TextFormat as w, State as x, CountdownValue as y, Part as z };