@moku-labs/game 0.15.13 → 0.15.16
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.
- package/dist/app/page.d.mts +1 -1
- package/dist/app/page.mjs +1 -1
- package/dist/app/system.d.mts +3 -3
- package/dist/app.d.mts +3 -3
- package/dist/app.mjs +1 -1
- package/dist/assets.d.mts +1 -1
- package/dist/{commands-aLTGwuyk.d.mts → commands-Ay-OfSPt.d.mts} +5 -5
- package/dist/control.d.mts +4 -4
- package/dist/{define-DbxBzO-G.d.mts → define-BfWdvNHC.d.mts} +2 -2
- package/dist/{headless-DHtavbqk.d.mts → headless-ByFLyHxx.d.mts} +1 -1
- package/dist/{index-YUceiUFm.d.mts → index-rLpq23uS.d.mts} +7 -6
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +2 -2
- package/dist/inspect.d.mts +6 -6
- package/dist/inspect.mjs +1 -1
- package/dist/jsx-dev-runtime.d.mts +1 -1
- package/dist/jsx-runtime.d.mts +1 -1
- package/dist/{runtime-B5OD9JTT.d.mts → runtime-DkhhsFss.d.mts} +1 -1
- package/dist/{sources-Fbq_PFVH.mjs → sources-24TY22DK.mjs} +1 -1
- package/dist/{src-3_HjYegY.mjs → src-AvZjWoPX.mjs} +481 -92
- package/dist/testing.d.mts +4 -4
- package/dist/testing.mjs +1 -1
- package/dist/{types-CuEK0Vam.d.mts → types-DOldmhIw.d.mts} +21 -5
- package/dist/{types-3bEK86Z1.d.mts → types-De1AZYym.d.mts} +2 -53
- package/dist/{types-xmH1X8qd.d.mts → types-DklpXQQk.d.mts} +132 -15
- package/dist/{types-Dm4tM5nH.d.mts → types-WqPbnC6B.d.mts} +4 -4
- package/dist/{types-_a6-ALzz.d.mts → types-qsE-I59e.d.mts} +2 -2
- package/dist/{visual-DExHHx-a.d.mts → visual-B1mq5n-9.d.mts} +6 -6
- package/dist/{visual-CbGKzlj0.mjs → visual-BStMZRVc.mjs} +28 -10
- package/dist/visual.d.mts +1 -1
- package/dist/visual.mjs +1 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
package/dist/testing.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Qn as AnyFlow, Xn as FeaturePlugin, cr as Descriptor, fr as Hint, gr as ClockSource, ir as NodeTable, pr as NodeFx, vr as FakeClock, wr as Json } from "./types-
|
|
2
|
-
import { t as createApp } from "./index-
|
|
3
|
-
import { b as saveOf, v as WithGameState, y as memory } from "./types-
|
|
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-
|
|
1
|
+
import { Qn as AnyFlow, Xn as FeaturePlugin, cr as Descriptor, fr as Hint, gr as ClockSource, ir as NodeTable, pr as NodeFx, vr as FakeClock, wr as Json } from "./types-DOldmhIw.mjs";
|
|
2
|
+
import { t as createApp } from "./index-rLpq23uS.mjs";
|
|
3
|
+
import { b as saveOf, v as WithGameState, y as memory } from "./types-WqPbnC6B.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-ByFLyHxx.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,4 +1,4 @@
|
|
|
1
|
-
import { $t as exit, Qt as refuseStart, m as flattenFeatures, nn as type, t as createApp } from "./src-
|
|
1
|
+
import { $t as exit, Qt as refuseStart, m as flattenFeatures, nn as type, t as createApp } from "./src-AvZjWoPX.mjs";
|
|
2
2
|
import { n as saveOf, t as memory } from "./memory-CWlqhS7l.mjs";
|
|
3
3
|
import { t as fakeClock } from "./fake-6mazmHK3.mjs";
|
|
4
4
|
import { i as stepFrames, r as runRepro, t as createHeadless } from "./headless-BA6ffzqD.mjs";
|
|
@@ -11712,7 +11712,11 @@ type ManifestBundle = {
|
|
|
11712
11712
|
* manifest.
|
|
11713
11713
|
*/
|
|
11714
11714
|
dir?: string;
|
|
11715
|
-
tier: Tier;
|
|
11715
|
+
tier: Tier;
|
|
11716
|
+
/**
|
|
11717
|
+
* `"leave"`: unloaded at the next rest once its feature left, or once the exit of a scene that named it is over.
|
|
11718
|
+
* Absent: `"budget"`.
|
|
11719
|
+
*/
|
|
11716
11720
|
release?: "leave";
|
|
11717
11721
|
mb: number;
|
|
11718
11722
|
pages?: readonly AtlasPage[];
|
|
@@ -11962,11 +11966,17 @@ type State = {
|
|
|
11962
11966
|
queue: PreloadQueue | undefined;
|
|
11963
11967
|
current: NodeInfo | undefined;
|
|
11964
11968
|
useCounter: number; /** Keys already reported missing, so one key warns and starts its background load once. */
|
|
11965
|
-
warned: Set<string>; /** `onEnter`, the `load` handler
|
|
11969
|
+
warned: Set<string>; /** `onEnter`, the `load` handler, the texture provider, and the start and the end of an exit in `world`. */
|
|
11966
11970
|
removers: Array<() => void>; /** The `files` map of the stamp the dev hot swap applied last. `undefined` until the first swap. */
|
|
11967
11971
|
stamps: Readonly<Record<string, string>> | undefined; /** The running dev hot swap. The next one waits for it, so two swaps never overlap. */
|
|
11968
11972
|
swapping: Promise<void> | undefined; /** The list the mounted scene names, from the last `sceneBundles` call. */
|
|
11969
|
-
sceneNamed: readonly string[];
|
|
11973
|
+
sceneNamed: readonly string[];
|
|
11974
|
+
/**
|
|
11975
|
+
* The bundles a scene named before and the list names no more: held while anything carries `Exiting`, so a
|
|
11976
|
+
* leaving scene's pictures stay until its elements played their exit (F51).
|
|
11977
|
+
*/
|
|
11978
|
+
sceneLeaving: string[]; /** How many entities carry `Exiting` now, counted from the world's `onAdded` and `onRemoved` of the tag. */
|
|
11979
|
+
exiting: number; /** Registered companions, in registration order. */
|
|
11970
11980
|
companions: BundleCompanion[]; /** A live rest was announced; the arriving node's `load` stage runs the release. */
|
|
11971
11981
|
restPending: boolean;
|
|
11972
11982
|
};
|
|
@@ -12188,7 +12198,9 @@ type Api = {
|
|
|
12188
12198
|
/**
|
|
12189
12199
|
* Tells assets which bundles the mounted scene names: its `bundle`, then what its `bundles(state)` returned.
|
|
12190
12200
|
* Each call replaces the list before it. A bundle in the list is never a victim of the budget and is not
|
|
12191
|
-
* released by `release: "leave"` while it stays in the list.
|
|
12201
|
+
* released by `release: "leave"` while it stays in the list. A bundle the list named before and names no more
|
|
12202
|
+
* stays held while anything carries `Exiting`, so a leaving scene's pictures stay until its elements played their
|
|
12203
|
+
* exit; then a `"leave"` one goes at once (F51). Called by `scenes`; a game never calls it.
|
|
12192
12204
|
*
|
|
12193
12205
|
* @param named - The bundle names of the mounted scene, the scene bundle first.
|
|
12194
12206
|
* @example
|
|
@@ -12196,6 +12208,8 @@ type Api = {
|
|
|
12196
12208
|
* // scenes, right after it mounted the ward for episode 1 (and after a re-read that changed the list).
|
|
12197
12209
|
* ctx.require(assetsPlugin).sceneBundles(["ui", "ep01"]);
|
|
12198
12210
|
* // ep01 (release "leave") now stays while the ward shows it, even after the ep01 flow left the stack
|
|
12211
|
+
* ctx.require(assetsPlugin).sceneBundles(["board"]);
|
|
12212
|
+
* // the board is mounted: ep01 stays until the ward's elements played their exit, then goes
|
|
12199
12213
|
* ```
|
|
12200
12214
|
*/
|
|
12201
12215
|
sceneBundles(named: readonly string[]): void;
|
|
@@ -12248,6 +12262,7 @@ type Deps = {
|
|
|
12248
12262
|
renderer: Api$1;
|
|
12249
12263
|
time: Api$7;
|
|
12250
12264
|
model: Api$5;
|
|
12265
|
+
world: Api$2;
|
|
12251
12266
|
};
|
|
12252
12267
|
/**
|
|
12253
12268
|
* What the kernel context offers before the deps are attached.
|
|
@@ -12282,7 +12297,8 @@ type HotSwap = Events$8["ui:hot-swap"];
|
|
|
12282
12297
|
/**
|
|
12283
12298
|
* When a bundle leaves besides the budget. `"budget"` (default): only the LRU unloads it when memory
|
|
12284
12299
|
* runs out. `"leave"`: also unloaded at the next rest once no node of its feature is on the stack
|
|
12285
|
-
* and no mounted scene names it
|
|
12300
|
+
* and no mounted scene names it; a scene that named it and left holds it until its elements played
|
|
12301
|
+
* their exit, and then it goes at once.
|
|
12286
12302
|
*
|
|
12287
12303
|
* @example
|
|
12288
12304
|
* ```ts
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { $r as Events$2, $t as Api$3, An as ReducedMotion, Br as Events$5, Cn as Ease, Cr as Events$3, D as FilterSlotInputs, Dn as NumericFields, E as FilterSlot, En as MotionHandle, K as Api$4, Mn as TrackSegment, O as SyncApi, Pn as Api$2, Q as PixiTexture, Wr as Api$1, X as PixiModule, Y as PixiFilter, Z as PixiSprite, cr as Descriptor, dn as Entity, ei as Require, in as AnyComponent, jn as TrackOptions, ln as ComponentType, lt as FilterCache, on as AnyComponentValue, s as Events$1, sn as ComponentHandle, sr as TypeTag, st as Point, t as Api$5, v as Events$4, wr as Json, xr as Api$6 } from "./types-
|
|
2
|
-
import {
|
|
1
|
+
import { $r as Events$2, $t as Api$3, An as ReducedMotion, Br as Events$5, Cn as Ease, Cr as Events$3, D as FilterSlotInputs, Dn as NumericFields, E as FilterSlot, En as MotionHandle, K as Api$4, Mn as TrackSegment, O as SyncApi, Pn as Api$2, Q as PixiTexture, Wr as Api$1, X as PixiModule, Y as PixiFilter, Z as PixiSprite, cr as Descriptor, dn as Entity, ei as Require, in as AnyComponent, jn as TrackOptions, ln as ComponentType, lt as FilterCache, on as AnyComponentValue, s as Events$1, sn as ComponentHandle, sr as TypeTag, st as Point, t as Api$5, v as Events$4, wr as Json, xr as Api$6 } from "./types-DOldmhIw.mjs";
|
|
2
|
+
import { N as InputApi, R as I18nApi, X as StylesState, c as UiNode, i as Finding, l as LayoutState, n as ElementChange, o as JsxState, r as ElementMotion, w as TextApi } from "./types-DklpXQQk.mjs";
|
|
3
3
|
import { Log } from "@moku-labs/common/browser";
|
|
4
4
|
import { PluginCtx } from "@moku-labs/core";
|
|
5
|
-
import { Node, Yoga } from "yoga-layout/load";
|
|
6
5
|
|
|
7
6
|
//#region src/plugins/debug/types.d.ts
|
|
8
7
|
declare namespace types_d_exports$4 {
|
|
@@ -2807,56 +2806,6 @@ type MusicRequest = {
|
|
|
2807
2806
|
key: string | null;
|
|
2808
2807
|
fadeMs: number;
|
|
2809
2808
|
};
|
|
2810
|
-
//#endregion
|
|
2811
|
-
//#region src/plugins/ui/layout/types.d.ts
|
|
2812
|
-
/**
|
|
2813
|
-
* The patches the scroll step writes with, one object each, filled in place: a frame builds none.
|
|
2814
|
-
* Every number in them is a whole reference unit.
|
|
2815
|
-
*/
|
|
2816
|
-
type ScrollPatches = {
|
|
2817
|
-
scroll: {
|
|
2818
|
-
offset: number;
|
|
2819
|
-
min: number;
|
|
2820
|
-
};
|
|
2821
|
-
state: {
|
|
2822
|
-
offset: number;
|
|
2823
|
-
max: number;
|
|
2824
|
-
moving: boolean;
|
|
2825
|
-
};
|
|
2826
|
-
scrollable: {
|
|
2827
|
-
moving: boolean;
|
|
2828
|
-
};
|
|
2829
|
-
x: {
|
|
2830
|
-
x: number;
|
|
2831
|
-
};
|
|
2832
|
-
y: {
|
|
2833
|
-
y: number;
|
|
2834
|
-
};
|
|
2835
|
-
};
|
|
2836
|
-
/**
|
|
2837
|
-
* layout module state. `nodes` is attach minus detach: Yoga 3.2.1 has no instance counter.
|
|
2838
|
-
* `scrolling` is the scroll the finger holds; `scrollClock` the ms the scroll step has run, the
|
|
2839
|
-
* clock of the samples; `scrollRing` the last pointer samples of the press on its axis, a
|
|
2840
|
-
* position and a time each, `scrollHead` the slot the next one takes and `scrollSamples` how
|
|
2841
|
-
* many it holds; `scrollMoved` when the finger last moved.
|
|
2842
|
-
*/
|
|
2843
|
-
type LayoutState = {
|
|
2844
|
-
yoga: Yoga | undefined;
|
|
2845
|
-
byEntity: Map<Entity, Node>;
|
|
2846
|
-
nodes: number;
|
|
2847
|
-
measured: number;
|
|
2848
|
-
solves: number;
|
|
2849
|
-
scrolling: Entity | undefined;
|
|
2850
|
-
scrollClock: number;
|
|
2851
|
-
scrollRing: Float64Array;
|
|
2852
|
-
scrollHead: number;
|
|
2853
|
-
scrollSamples: number;
|
|
2854
|
-
scrollMoved: number;
|
|
2855
|
-
scrollPatches: ScrollPatches; /** One line of the `body` style as the icons were last measured with it; none before that. */
|
|
2856
|
-
iconLine: number | undefined;
|
|
2857
|
-
order: number;
|
|
2858
|
-
cleanups: Array<() => void>;
|
|
2859
|
-
};
|
|
2860
2809
|
declare namespace types_d_exports {
|
|
2861
2810
|
export { Config, Deps, ElementChange, ElementMotion, Finding, FocusRing, KernelSlice, State, TextInputLook, UiApi, UiCtx, UiNode };
|
|
2862
2811
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { $t as Api$2, Dn as NumericFields, En as MotionHandle, K as Api$3, Nn as ViewHandle, On as ProjectionMotion, Pn as Api$1, Tn as MotionCause, U as TransformValue, Wr as Api, an as AnyComponentType, bn as TagType, cr as Descriptor, ct as ViewportSize, dn as Entity, ei as Require, fr as Hint, hr as Api$5, in as AnyComponent, ln as ComponentType, mr as Answer, on as AnyComponentValue, s as Events$1, t as Api$4, wn as Motion, wr as Json, xn as ChangeHook } from "./types-
|
|
1
|
+
import { $t as Api$2, An as ReducedMotion, Cn as Ease, Dn as NumericFields, En as MotionHandle, K as Api$3, Nn as ViewHandle, On as ProjectionMotion, Pn as Api$1, Tn as MotionCause, U as TransformValue, Wr as Api, an as AnyComponentType, bn as TagType, cr as Descriptor, ct as ViewportSize, dn as Entity, ei as Require, fr as Hint, hr as Api$5, in as AnyComponent, ln as ComponentType, mr as Answer, on as AnyComponentValue, s as Events$1, t as Api$4, wn as Motion, wr as Json, xn as ChangeHook } from "./types-DOldmhIw.mjs";
|
|
2
2
|
import { Log } from "@moku-labs/common/browser";
|
|
3
3
|
import { PluginCtx } from "@moku-labs/core";
|
|
4
|
+
import { Node, Yoga } from "yoga-layout/load";
|
|
4
5
|
|
|
5
6
|
//#region src/plugins/ui/styles/types.d.ts
|
|
6
7
|
/**
|
|
@@ -1421,16 +1422,23 @@ type CountdownValue = {
|
|
|
1421
1422
|
/**
|
|
1422
1423
|
* What the `Text` component holds. `resolved` is engine-owned: a game writes `content`, `style`,
|
|
1423
1424
|
* `bind`, `anchor` and `alpha`, and reads `resolved`. `alpha` fades every run, shadow and icon of
|
|
1424
|
-
* the block together, 1 by default; a change is written in place and a tween can drive it.
|
|
1425
|
+
* the block together, 1 by default; a change is written in place and a tween can drive it. `box`
|
|
1426
|
+
* is the width a style with `wrap: "box"` wraps at: `ui` writes the laid-out width of the text
|
|
1427
|
+
* element there, 0 means no box and one line. A style that wraps otherwise ignores it.
|
|
1425
1428
|
*
|
|
1426
1429
|
* @example
|
|
1427
1430
|
* ```ts
|
|
1428
1431
|
* const value: TextValue = {
|
|
1429
1432
|
* content: "+5", style: "body", bind: undefined, anchor: { x: 0.5, y: 0.5 }, alpha: 1,
|
|
1430
|
-
* resolved: "+5"
|
|
1433
|
+
* box: 0, resolved: "+5"
|
|
1431
1434
|
* };
|
|
1432
1435
|
* // The hint of an empty name field, at half alpha.
|
|
1433
1436
|
* const hint: TextValue = { ...value, content: "Your name", alpha: 0.5, resolved: "Your name" };
|
|
1437
|
+
* // A player name in a "card.name" style with wrap "box", laid out 200 wide by ui: two lines.
|
|
1438
|
+
* const name: TextValue = {
|
|
1439
|
+
* ...value, content: "Aleksandra Kucherenko", style: "card.name", box: 200,
|
|
1440
|
+
* resolved: "Aleksandra Kucherenko"
|
|
1441
|
+
* };
|
|
1434
1442
|
* ```
|
|
1435
1443
|
*/
|
|
1436
1444
|
type TextValue = {
|
|
@@ -1439,6 +1447,7 @@ type TextValue = {
|
|
|
1439
1447
|
bind: TextBind | undefined;
|
|
1440
1448
|
anchor: Point;
|
|
1441
1449
|
alpha: number;
|
|
1450
|
+
box: number;
|
|
1442
1451
|
resolved: string;
|
|
1443
1452
|
};
|
|
1444
1453
|
/**
|
|
@@ -1451,14 +1460,17 @@ type TextValue = {
|
|
|
1451
1460
|
*/
|
|
1452
1461
|
type TextAlign = "left" | "center" | "right";
|
|
1453
1462
|
/**
|
|
1454
|
-
* The wrap width of a style in reference pixels
|
|
1463
|
+
* The wrap width of a style in reference pixels; `"box"` for the width the `ui` layout gave the
|
|
1464
|
+
* text element, one line outside a layout; or `"none"` for one line per `\n` segment.
|
|
1455
1465
|
*
|
|
1456
1466
|
* @example
|
|
1457
1467
|
* ```ts
|
|
1458
1468
|
* const wrap: TextWrap = 480;
|
|
1469
|
+
* // A name that wraps at the room its row leaves it: the boxes on the way need `shrink: 1`.
|
|
1470
|
+
* const name: TextWrap = "box";
|
|
1459
1471
|
* ```
|
|
1460
1472
|
*/
|
|
1461
|
-
type TextWrap = number | "none";
|
|
1473
|
+
type TextWrap = number | "box" | "none";
|
|
1462
1474
|
/**
|
|
1463
1475
|
* The drop shadow of a style as the plugin stores it: a copy of every glyph run in `color`, at
|
|
1464
1476
|
* `alpha`, moved by `dx` and `dy` reference pixels.
|
|
@@ -1662,13 +1674,15 @@ type LayoutOptions = {
|
|
|
1662
1674
|
* What was resolved for one entity last, so the frame step knows whether anything moved. `unit`
|
|
1663
1675
|
* is what the shown string of a bound label was built from: the rounded value for `"int"`, whole
|
|
1664
1676
|
* seconds for a time format. `bindRef` is the bind object `bind` was keyed from, so the key is
|
|
1665
|
-
* built once per attached bind and a frame compares one reference.
|
|
1677
|
+
* built once per attached bind and a frame compares one reference. `box` is the `Text.box` the
|
|
1678
|
+
* label was laid out at: a label of a `"box"` style is laid out again when it moves.
|
|
1666
1679
|
*
|
|
1667
1680
|
* @example
|
|
1668
1681
|
* ```ts
|
|
1669
1682
|
* const left = bind(Countdown, "left", { format: "mm:ss" });
|
|
1670
1683
|
* const seen: SeenText = {
|
|
1671
|
-
* content: "", style: "digits", bindRef: left, bind: "Countdown.left:mm:ss", locale: "ru",
|
|
1684
|
+
* content: "", style: "digits", bindRef: left, bind: "Countdown.left:mm:ss", locale: "ru",
|
|
1685
|
+
* unit: 95, box: 0
|
|
1672
1686
|
* };
|
|
1673
1687
|
* ```
|
|
1674
1688
|
*/
|
|
@@ -1679,6 +1693,7 @@ type SeenText = {
|
|
|
1679
1693
|
bind: string | undefined;
|
|
1680
1694
|
locale: string;
|
|
1681
1695
|
unit: number | undefined;
|
|
1696
|
+
box: number;
|
|
1682
1697
|
};
|
|
1683
1698
|
/**
|
|
1684
1699
|
* text plugin config.
|
|
@@ -1705,7 +1720,7 @@ type State = {
|
|
|
1705
1720
|
installed: Set<string>; /** What was resolved for an entity last. */
|
|
1706
1721
|
seen: Map<Entity, SeenText>; /** `bind.component` to its world type; `undefined` after the one warning. */
|
|
1707
1722
|
bindTypes: Map<string, AnyComponent | undefined>; /** The measured size of every live label, for `ui`. */
|
|
1708
|
-
measured: Map<Entity, Size>; /** Layout per `style + resolved`, oldest dropped first. */
|
|
1723
|
+
measured: Map<Entity, Size>; /** Layout per `style + resolved`, and the box width for a `"box"` style; oldest dropped first. */
|
|
1709
1724
|
cache: Map<string, TextLayout>; /** What every live label container was last filled from, by container. */
|
|
1710
1725
|
drawn: WeakMap<object, DrawnLabel>; /** Entities to re-resolve in the next layout phase. */
|
|
1711
1726
|
dirty: Set<Entity>;
|
|
@@ -1743,10 +1758,13 @@ type TextApi = {
|
|
|
1743
1758
|
/**
|
|
1744
1759
|
* The size of a piece of text in reference pixels, from the advance table of the style's font.
|
|
1745
1760
|
* A `Message` is formatted in the current locale first. Never touches a canvas, so the answer
|
|
1746
|
-
* is the same in a browser and in plain Bun. Cached per style and resolved string
|
|
1761
|
+
* is the same in a browser and in plain Bun. Cached per style and resolved string, and per
|
|
1762
|
+
* width for a `"box"` style.
|
|
1747
1763
|
*
|
|
1748
1764
|
* @param content - A plain string, or what `tr` returned.
|
|
1749
1765
|
* @param style - A registered style name. An unknown one warns once and measures as `body`.
|
|
1766
|
+
* @param width - The width a style with `wrap: "box"` wraps at, in reference pixels. Left out
|
|
1767
|
+
* (or 0) the block is one line. A style that wraps otherwise ignores it.
|
|
1750
1768
|
* @returns The width and height of the block.
|
|
1751
1769
|
* @example
|
|
1752
1770
|
* ```ts
|
|
@@ -1754,9 +1772,12 @@ type TextApi = {
|
|
|
1754
1772
|
* const text = ctx.require(textPlugin);
|
|
1755
1773
|
*
|
|
1756
1774
|
* text.measure("120", "digits"); // { width: 57.6, height: 38.4 } on the 0.6 em fallback
|
|
1775
|
+
* // "card.name" is a 32 px style with wrap "box": the width Yoga offers wraps it.
|
|
1776
|
+
* text.measure("Aleksandra Kucherenko", "card.name", 200); // { width: 192, height: 76.8 }
|
|
1777
|
+
* text.measure("Aleksandra Kucherenko", "card.name"); // { width: 403.2, height: 38.4 }
|
|
1757
1778
|
* ```
|
|
1758
1779
|
*/
|
|
1759
|
-
measure(content: string | Message, style: string): Size;
|
|
1780
|
+
measure(content: string | Message, style: string, width?: number): Size;
|
|
1760
1781
|
/**
|
|
1761
1782
|
* Whether the font of a style has a glyph for one character, the lookup Pixi draws by. A
|
|
1762
1783
|
* character its font lacks is drawn as nothing and `measure` counts it 0 wide. While the font is
|
|
@@ -2339,6 +2360,74 @@ declare function popup<Properties extends object, Local extends object, Outcomes
|
|
|
2339
2360
|
over?: string;
|
|
2340
2361
|
}): Descriptor<Answer<keyof Outcomes & string>>;
|
|
2341
2362
|
//#endregion
|
|
2363
|
+
//#region src/plugins/ui/layout/types.d.ts
|
|
2364
|
+
/**
|
|
2365
|
+
* The patches the scroll step writes with, one object each, filled in place: a frame builds none.
|
|
2366
|
+
* Every number in them is a whole reference unit.
|
|
2367
|
+
*/
|
|
2368
|
+
type ScrollPatches = {
|
|
2369
|
+
scroll: {
|
|
2370
|
+
offset: number;
|
|
2371
|
+
min: number;
|
|
2372
|
+
};
|
|
2373
|
+
state: {
|
|
2374
|
+
offset: number;
|
|
2375
|
+
max: number;
|
|
2376
|
+
moving: boolean;
|
|
2377
|
+
};
|
|
2378
|
+
scrollable: {
|
|
2379
|
+
moving: boolean;
|
|
2380
|
+
};
|
|
2381
|
+
x: {
|
|
2382
|
+
x: number;
|
|
2383
|
+
};
|
|
2384
|
+
y: {
|
|
2385
|
+
y: number;
|
|
2386
|
+
};
|
|
2387
|
+
};
|
|
2388
|
+
/**
|
|
2389
|
+
* layout module state. `nodes` is attach minus detach: Yoga 3.2.1 has no instance counter.
|
|
2390
|
+
* `scrolling` is the scroll the finger holds; `scrollClock` the ms the scroll step has run, the
|
|
2391
|
+
* clock of the samples; `scrollRing` the last pointer samples of the press on its axis, a
|
|
2392
|
+
* position and a time each, `scrollHead` the slot the next one takes and `scrollSamples` how
|
|
2393
|
+
* many it holds; `scrollMoved` when the finger last moved.
|
|
2394
|
+
*/
|
|
2395
|
+
type LayoutState = {
|
|
2396
|
+
yoga: Yoga | undefined;
|
|
2397
|
+
byEntity: Map<Entity, Node>;
|
|
2398
|
+
nodes: number;
|
|
2399
|
+
measured: number;
|
|
2400
|
+
solves: number;
|
|
2401
|
+
scrolling: Entity | undefined;
|
|
2402
|
+
scrollClock: number;
|
|
2403
|
+
scrollRing: Float64Array;
|
|
2404
|
+
scrollHead: number;
|
|
2405
|
+
scrollSamples: number;
|
|
2406
|
+
scrollMoved: number;
|
|
2407
|
+
scrollPatches: ScrollPatches; /** One line of the `body` style as the icons were last measured with it; none before that. */
|
|
2408
|
+
iconLine: number | undefined;
|
|
2409
|
+
order: number;
|
|
2410
|
+
cleanups: Array<() => void>;
|
|
2411
|
+
};
|
|
2412
|
+
/**
|
|
2413
|
+
* The longest finite track a motion hook started through its view handle: where it ends (delay included), its length,
|
|
2414
|
+
* delay, ease and reduced-motion rule. The level of an overlay follows the root's own enter and exit motion by it
|
|
2415
|
+
* (spec 22, LEAD-FIXES-4 item 5a); `end` 0 means the hook started no timed track.
|
|
2416
|
+
*
|
|
2417
|
+
* @example
|
|
2418
|
+
* ```ts
|
|
2419
|
+
* // A sheet that fades in over 250 ms after 40 ms.
|
|
2420
|
+
* const span: MotionSpan = { end: 290, ms: 250, delayMs: 40, ease: "out", reduced: undefined };
|
|
2421
|
+
* ```
|
|
2422
|
+
*/
|
|
2423
|
+
type MotionSpan = {
|
|
2424
|
+
end: number;
|
|
2425
|
+
ms: number;
|
|
2426
|
+
delayMs: number;
|
|
2427
|
+
ease: Ease | undefined;
|
|
2428
|
+
reduced: ReducedMotion | undefined;
|
|
2429
|
+
};
|
|
2430
|
+
//#endregion
|
|
2342
2431
|
//#region src/plugins/ui/jsx/types.d.ts
|
|
2343
2432
|
/**
|
|
2344
2433
|
* One node of an element description, as the JSX runtime builds it. `key` is the third argument
|
|
@@ -2534,7 +2623,9 @@ type StyleBasis = {
|
|
|
2534
2623
|
* warnings of its props in `warned`; `scrolledIn` marks an element a range change of a windowed
|
|
2535
2624
|
* scroll created: it plays no `enter` hook. A scroll carries its `scroll` motion from its enter. A text or an icon that sizes itself keeps in
|
|
2536
2625
|
* `measuredSize` what its measure function last answered, before Yoga's clamp: a bound text whose
|
|
2537
|
-
* new string measures the same asks for no solve. `
|
|
2626
|
+
* new string measures the same asks for no solve. `measuredWidth` is the width Yoga offered that
|
|
2627
|
+
* call, `undefined` when it bounded none: a text of a `"box"` style is measured again at it, so the
|
|
2628
|
+
* lines it wraps into are compared, not one line. `basis` is what `style` was resolved on, set
|
|
2538
2629
|
* once the style is on the layout node and the components are written; an element without one is
|
|
2539
2630
|
* patched in full at its next patch. `index` is its place among the element children of its parent
|
|
2540
2631
|
* at the last diff (0 for a root element): with its `zIndex` it gives the child its `Order`.
|
|
@@ -2592,8 +2683,34 @@ type Element = {
|
|
|
2592
2683
|
width: number;
|
|
2593
2684
|
height: number;
|
|
2594
2685
|
};
|
|
2686
|
+
measuredWidth?: number | undefined;
|
|
2595
2687
|
basis?: StyleBasis; /** The motions of its hooks that started a `repeat: "forever"` track; made with the first one. */
|
|
2596
|
-
endless?: Set<MotionHandle>;
|
|
2688
|
+
endless?: Set<MotionHandle>; /** What its enter hook did at the `Box`, until `ui.enter` keeps the play or plays it again (F49). */
|
|
2689
|
+
posed?: PosedEnter | undefined;
|
|
2690
|
+
};
|
|
2691
|
+
/**
|
|
2692
|
+
* One `set` of an enter hook: the fields it wrote, and the values they had before. A hook may write any component of
|
|
2693
|
+
* the game, so the fields are kept by name, as records.
|
|
2694
|
+
*/
|
|
2695
|
+
type PoseWrite = {
|
|
2696
|
+
component: ComponentType<Record<string, unknown>>;
|
|
2697
|
+
wrote: Record<string, unknown>;
|
|
2698
|
+
before: Record<string, unknown>;
|
|
2699
|
+
};
|
|
2700
|
+
/**
|
|
2701
|
+
* What the play of an enter hook at the `Box` kept: the motion it returned, the components it read
|
|
2702
|
+
* (with their fields as they stood after the play), the names of the components it wrote, its
|
|
2703
|
+
* `set` writes, and the span noted for an overlay.
|
|
2704
|
+
*/
|
|
2705
|
+
type PosedEnter = {
|
|
2706
|
+
motion: MotionHandle | undefined;
|
|
2707
|
+
reads: Array<{
|
|
2708
|
+
component: ComponentType<Record<string, unknown>>;
|
|
2709
|
+
seen: Record<string, unknown>;
|
|
2710
|
+
}>;
|
|
2711
|
+
written: string[];
|
|
2712
|
+
writes: PoseWrite[];
|
|
2713
|
+
span: MotionSpan | undefined;
|
|
2597
2714
|
};
|
|
2598
2715
|
/**
|
|
2599
2716
|
* The popup side of a root: the handler that shows it now and the root it was opened over.
|
|
@@ -2792,8 +2909,8 @@ type JsxState = {
|
|
|
2792
2909
|
text: TextState;
|
|
2793
2910
|
hints: Hint[];
|
|
2794
2911
|
/**
|
|
2795
|
-
* The elements whose `Box` came since the last `sync`: their enter hooks
|
|
2796
|
-
* (F48). The first `count` slots are the queue; the array keeps its length, so a frame allocates nothing.
|
|
2912
|
+
* The elements whose `Box` came since the last `sync`: their enter hooks played at the `Box` (F49) and are settled
|
|
2913
|
+
* there, after the game's systems, played again when a system changed what a hook read (F48). The first `count` slots are the queue; the array keeps its length, so a frame allocates nothing.
|
|
2797
2914
|
*/
|
|
2798
2915
|
entering: {
|
|
2799
2916
|
list: Entity[];
|
|
@@ -2922,4 +3039,4 @@ type CommonProps = {
|
|
|
2922
3039
|
components?: ElementComponents;
|
|
2923
3040
|
};
|
|
2924
3041
|
//#endregion
|
|
2925
|
-
export {
|
|
3042
|
+
export { types_d_exports as A, Message as B, State as C, TextStyleInput as D, TextFormat as E, types_d_exports$1 as F, TypedTr as G, State$2 as H, Argument as I, ResolvedStyle as J, types_d_exports$2 as K, Config$2 as L, Config$1 as M, InputApi as N, TextStyles as O, State$1 as P, I18nApi as R, Point as S, TextBind as T, StringTable as U, Part as V, TextKey as W, StylesState as X, Style as Y, WhenFlags as Z, UiIntrinsicElements as _, JsxChild as a, Config as b, UiNode as c, DebugTrigger as d, LocalWrite as f, IntrinsicElementsFor as g, defineTokens as h, Finding as i, defineComponent as j, TextValue as k, LayoutState as l, popup as m, ElementChange as n, JsxState as o, ScrollState as p, IsFlags as q, ElementMotion as r, PopupComponent as s, DescriptionNode as t, Box as u, BindField as v, TextApi as w, CountdownValue as x, BindOptions as y, IntlKit as z };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Ar as ProviderCall, In as Config$1, Pr as SnapshotOf, Qn as AnyFlow, Sr as Config, X as PixiModule, Xn as FeaturePlugin, a as Config$3, d as Manifest, gr as ClockSource, jr as SaveDoc, kr as PlayerStateProvider, n as AssetsIo, ot as Orientation, q as Config$2, sr as TypeTag, vr as FakeClock, wr as Json } from "./types-
|
|
2
|
-
import { o as AudioContextLike, s as Config$4 } from "./types-
|
|
3
|
-
import {
|
|
4
|
-
import { ft as platformPlugin, i as screen, mt as PlatformProvider, t as createApp, wt as audioPlugin, xt as effectsPlugin } from "./index-
|
|
1
|
+
import { Ar as ProviderCall, In as Config$1, Pr as SnapshotOf, Qn as AnyFlow, Sr as Config, X as PixiModule, Xn as FeaturePlugin, a as Config$3, d as Manifest, gr as ClockSource, jr as SaveDoc, kr as PlayerStateProvider, n as AssetsIo, ot as Orientation, q as Config$2, sr as TypeTag, vr as FakeClock, wr as Json } from "./types-DOldmhIw.mjs";
|
|
2
|
+
import { o as AudioContextLike, s as Config$4 } from "./types-De1AZYym.mjs";
|
|
3
|
+
import { R as I18nApi, U as StringTable, W as TextKey } from "./types-DklpXQQk.mjs";
|
|
4
|
+
import { ft as platformPlugin, i as screen, mt as PlatformProvider, t as createApp, wt as audioPlugin, xt as effectsPlugin } from "./index-rLpq23uS.mjs";
|
|
5
5
|
import { AnyPluginInstance } from "@moku-labs/core";
|
|
6
6
|
|
|
7
7
|
//#region src/plugins/model/store/providers/memory.d.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Nr as Snapshot, wr as Json } from "./types-
|
|
2
|
-
import { t as HeadlessApp } from "./headless-
|
|
1
|
+
import { Nr as Snapshot, wr as Json } from "./types-DOldmhIw.mjs";
|
|
2
|
+
import { t as HeadlessApp } from "./headless-ByFLyHxx.mjs";
|
|
3
3
|
import { Log } from "@moku-labs/common/browser";
|
|
4
4
|
|
|
5
5
|
//#region src/plugins/flow/doors/types.d.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { $t as Api$1, K as Api, Rr as Api$3, xr as Api$2 } from "./types-
|
|
2
|
-
import { P as AnimApi, r as UiApi } from "./types-
|
|
3
|
-
import {
|
|
4
|
-
import { r as Repro } from "./headless-
|
|
5
|
-
import { a as InputOf, r as ControlApp } from "./types-
|
|
6
|
-
import { t as commands } from "./commands-
|
|
1
|
+
import { $t as Api$1, K as Api, Rr as Api$3, xr as Api$2 } from "./types-DOldmhIw.mjs";
|
|
2
|
+
import { P as AnimApi, r as UiApi } from "./types-De1AZYym.mjs";
|
|
3
|
+
import { N as InputApi } from "./types-DklpXQQk.mjs";
|
|
4
|
+
import { r as Repro } from "./headless-ByFLyHxx.mjs";
|
|
5
|
+
import { a as InputOf, r as ControlApp } from "./types-qsE-I59e.mjs";
|
|
6
|
+
import { t as commands } from "./commands-Ay-OfSPt.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. */
|
|
@@ -618,7 +618,8 @@ function rootPointOf(ecs, entity, point) {
|
|
|
618
618
|
* Words on the screen: a string or a message, the style it is drawn in, and the string `text`
|
|
619
619
|
* resolved out of it. A game writes `content`, `style`, `bind`, `anchor` and `alpha`; `resolved`
|
|
620
620
|
* is engine-owned and `ui` and the tests read it. `alpha` (1 by default) fades the whole block and
|
|
621
|
-
* is patched in place, so a tween on it rebuilds nothing.
|
|
621
|
+
* is patched in place, so a tween on it rebuilds nothing. `box` (0 by default) is the width a
|
|
622
|
+
* style with `wrap: "box"` wraps at; `ui` writes the laid-out width of a text element there.
|
|
622
623
|
*/
|
|
623
624
|
const Text = /*#__PURE__*/ component("Text", {
|
|
624
625
|
content: "",
|
|
@@ -629,6 +630,7 @@ const Text = /*#__PURE__*/ component("Text", {
|
|
|
629
630
|
y: .5
|
|
630
631
|
},
|
|
631
632
|
alpha: 1,
|
|
633
|
+
box: 0,
|
|
632
634
|
resolved: ""
|
|
633
635
|
}, { owned: ["resolved"] });
|
|
634
636
|
/** What a `Countdown` starts as. Its own const, because a component takes a typed defaults object. */
|
|
@@ -691,7 +693,7 @@ const Countdown = /*#__PURE__*/ component("Countdown", countdownDefaults, { owne
|
|
|
691
693
|
* ```ts
|
|
692
694
|
* label({ text: "+5", style: "board.float", at: { x: 90, y: 180 } });
|
|
693
695
|
* // [Text({ content: "+5", style: "board.float", bind: undefined,
|
|
694
|
-
* // anchor: { x: 0.5, y: 0.5 }, alpha: 1, resolved: "" }),
|
|
696
|
+
* // anchor: { x: 0.5, y: 0.5 }, alpha: 1, box: 0, resolved: "" }),
|
|
695
697
|
* // Transform({ x: 90, y: 180, rotation: 0, scale: 1 })]
|
|
696
698
|
* ```
|
|
697
699
|
*/
|
|
@@ -726,16 +728,30 @@ function shadowOf(input) {
|
|
|
726
728
|
};
|
|
727
729
|
}
|
|
728
730
|
/**
|
|
729
|
-
*
|
|
731
|
+
* Tells whether a wrap is one a style can carry: a width above zero, `"box"` or `"none"`. A style
|
|
732
|
+
* read back from a feature may carry anything, so a word is checked as well as a number.
|
|
733
|
+
*
|
|
734
|
+
* @param wrap - The wrap a style names, as it was stored.
|
|
735
|
+
* @returns False for a number that is not above zero, and for anything else.
|
|
736
|
+
* @example
|
|
737
|
+
* ```ts
|
|
738
|
+
* isWrap("box"); // true
|
|
739
|
+
* ```
|
|
740
|
+
*/
|
|
741
|
+
function isWrap(wrap) {
|
|
742
|
+
return typeof wrap === "number" ? wrap > 0 : wrap === "box" || wrap === "none";
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Fills the defaults of one style and refuses a wrap that is not a width, `"box"` or `"none"`.
|
|
730
746
|
*
|
|
731
747
|
* @param name - The style name, for the error.
|
|
732
748
|
* @param input - What the game wrote.
|
|
733
749
|
* @returns The style with every field filled.
|
|
734
|
-
* @throws {Error} When `wrap` is a number that is not greater than zero.
|
|
750
|
+
* @throws {Error} When `wrap` is a number that is not greater than zero, or another word.
|
|
735
751
|
*/
|
|
736
752
|
function normalizeStyle(name, input) {
|
|
737
753
|
const wrap = input.wrap ?? "none";
|
|
738
|
-
if (wrap
|
|
754
|
+
if (!isWrap(wrap)) throw new Error(`[game] Text style "${name}" has wrap ${wrap}.\n Use a width in reference px, "box" or "none".`);
|
|
739
755
|
return {
|
|
740
756
|
font: input.font,
|
|
741
757
|
bold: input.bold,
|
|
@@ -757,7 +773,7 @@ function normalizeStyle(name, input) {
|
|
|
757
773
|
*
|
|
758
774
|
* @param map - Style name to what that style looks like.
|
|
759
775
|
* @returns The registration a feature carries.
|
|
760
|
-
* @throws {Error} When a style names a wrap that is not a width
|
|
776
|
+
* @throws {Error} When a style names a wrap that is not a width, `"box"` or `"none"`.
|
|
761
777
|
* @example
|
|
762
778
|
* ```ts
|
|
763
779
|
* defineTextStyles({ "hud.digits": { font: "ui.font-digits", size: 40, fill: 0xffe082 } });
|
|
@@ -1182,9 +1198,10 @@ function contentOf(props) {
|
|
|
1182
1198
|
return props.content ?? "";
|
|
1183
1199
|
}
|
|
1184
1200
|
/**
|
|
1185
|
-
* The visual component of an element: a sprite for an image or an icon, the text for a text
|
|
1186
|
-
*
|
|
1187
|
-
*
|
|
1201
|
+
* The visual component of an element: a sprite for an image or an icon, the text for a text (with
|
|
1202
|
+
* its laid-out width as the box a `"box"` style wraps at), the nine-slice of its style (outlined
|
|
1203
|
+
* when the style sets `debug`), or a rounded rectangle, a triangle with `shape: "triangle"`, its
|
|
1204
|
+
* stroke dashed with `dash`, or an arc with `shape: "arc"`
|
|
1188
1205
|
* over the `sweep` of its style, ended by its `cap`. A clipping element (`scroll`,
|
|
1189
1206
|
* `overflow: "hidden"`) keeps the rectangle, which carries the clip; a text field's rectangle
|
|
1190
1207
|
* clips too, and a nine-slice field draws its slices and clips to them. A style with a stroke and
|
|
@@ -1221,7 +1238,8 @@ function visualOf(element) {
|
|
|
1221
1238
|
anchor: {
|
|
1222
1239
|
x: 0,
|
|
1223
1240
|
y: 0
|
|
1224
|
-
}
|
|
1241
|
+
},
|
|
1242
|
+
box: rect.w
|
|
1225
1243
|
})];
|
|
1226
1244
|
}
|
|
1227
1245
|
const clip = type === "scroll" || style.overflow === "hidden";
|
package/dist/visual.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as VisualApp, c as VisualRenderer, d as VisualStart, f as VisualStep, h as VisualTolerance, i as CheckpointResult, l as VisualReport, m as VisualTestResult, n as runVisualTests, o as VisualOptions, p as VisualTest, r as defineVisualTest, s as VisualPage, t as parseVisualArgv, u as VisualSetup } from "./visual-
|
|
1
|
+
import { a as VisualApp, c as VisualRenderer, d as VisualStart, f as VisualStep, h as VisualTolerance, i as CheckpointResult, l as VisualReport, m as VisualTestResult, n as runVisualTests, o as VisualOptions, p as VisualTest, r as defineVisualTest, s as VisualPage, t as parseVisualArgv, u as VisualSetup } from "./visual-B1mq5n-9.mjs";
|
|
2
2
|
export { type CheckpointResult, type VisualApp, type VisualOptions, type VisualPage, type VisualRenderer, type VisualReport, type VisualSetup, type VisualStart, type VisualStep, type VisualTest, type VisualTestResult, type VisualTolerance, defineVisualTest, parseVisualArgv, runVisualTests };
|
package/dist/visual.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as read, t as sources } from "./sources-
|
|
1
|
+
import { n as read, t as sources } from "./sources-24TY22DK.mjs";
|
|
2
2
|
import { n as commands, t as run } from "./run-BqYmcNo7.mjs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { createBrandConsole } from "@moku-labs/common/cli";
|
package/llms.txt
CHANGED
|
@@ -554,7 +554,7 @@ A screen is a projection whose `view` returns JSX. The game's `tsconfig.json` se
|
|
|
554
554
|
- `defineComponent(name, { local?, outcomes?, view(props, local) })`. A component with `outcomes` is a popup: `await fx(popup(Component, props))` opens the gate for its outcomes and resolves with `{ intent, payload }` of the pressed button. A button with `local` writes into the nearest component instance; it never reaches the graph.
|
|
555
555
|
- `tr(key, params?)` returns a frozen `Message` `{ key, params }`; no locale is read at the call site. Strings live in `strings/<locale>.json` of any feature or sub-feature, as ICU MessageFormat 1 (`{n, plural, one {# order} other {# orders}}`, `select`, `selectordinal`, `number`, `date`, `time`; no skeletons, no `currency`). `bun run assets:keys` compiles them. The keys of the top-level features and the layers go into `generated/strings.<locale>.ts`, which one feature registers; a sub-feature's keys start with `<name>.` (`ep01.title`) and go into `generated/strings.<name>.<locale>.ts`, which the sub-feature registers lazily, `strings: { en: () => import("@generated/strings.ep01.en"), ru: () => import("@generated/strings.ep01.ru") }`. With `assets` composed those modules load and unload with the bundle named like the sub-feature: every way the bundle comes (a node entry, a scene's `bundles`, `load`, a restore, the `safeNode`) brings its strings, a locale switch brings them in the new locale, and while the bundle is not loaded a key of it gives `⟦key⟧` and `has(key)` is false. A compiled module calls the root helpers `messageArgument(value, intl)` (an element stays an element part, a list goes through `Intl.ListFormat`, a number through `Intl.NumberFormat`, else text) and `messageDuration(ms)` (`95_000` gives `{ minutes: 1, seconds: 35 }`). `app.i18n`: `locale()`, `setLocale(locale)` (async, emits `i18n:locale-changed`), `format(message, locale?)` returns `Part[]`, `plain(message)` returns a string, `has(key)`, `isKey(value)`, `locales()`, `replace(locale, messages)` (dev hot swap of a generated strings file). Config: `locale: "en"`, `fallback: "en"`, `locales: {}`.
|
|
556
556
|
- Keys that come from data: `I18n.TextKey<Strings>` is the keys of the generated `Strings` without parameters (nothing new is generated). A data table types its keys `TextKey` or builds them with the kit's `key("board.hint.red")`; the kit's `tr` never takes a plain `string`. A key read back from a save is checked where the app is (an effect handler, app or page code, loading a save) with one `isKey(value)`: `defineGameApp({ ..., strings: type<Strings>() })` types the game's `app.i18n`, so a true `app.i18n.isKey(value)` narrows the value to `TextKey`; `ctx.require(i18nPlugin).isKey(value)` in a plugin narrows to `string`. `app.i18n.isKey(value)` answers true for a key of the loaded tables of the current locale or the fallback, and for the `<feature>.` prefix of a sub-feature whose strings are not loaded yet; a key that takes parameters answers true too.
|
|
557
|
-
- Text: `Text` component, `label({ text, style, at, anchor? })` for board text in a projection view, `defineTextStyles({ "hud.digits": { font, size, fill, bold?, italic?, stroke?, strokeWidth?, letterSpacing?, align?, wrap
|
|
557
|
+
- Text: `Text` component, `label({ text, style, at, anchor? })` for board text in a projection view, `defineTextStyles({ "hud.digits": { font, size, fill, bold?, italic?, stroke?, strokeWidth?, letterSpacing?, align?, wrap? (a width, "none" or "box": wrap at the laid-out width of its ui element), digits? } })` under the feature's `textStyles` key. Tags inside a string: `<b>`, `<i>`, `<color=#rrggbb>`, `<icon=key>`, `\<`, `\n`. Built-in styles `body` and `digits` from config `fonts: { body: "ui.font-body", digits: "ui.font-digits" }`. `app.text.measure(content, style, width?)` gives the same numbers in a browser and in Bun. `app.text.replaceStyles(styles)` is the dev hot swap of a saved `defineTextStyles` value.
|
|
558
558
|
- Animation is data: `defineAnimation(id, { slots: { name: type<Anim.Target>() }, build: (slots, { at }) => Step })`. Steps: `sequence(...)`, `parallel(...)`, `stagger(items, ms, item => Step)`, `tween(target, Component, to, { ms, ease?, delayMs?, additive?, space?, reduced? })`, `set(target, Component, patch)`, `wait(ms)`, `mark(name)`, `frames(target, { keys, fps, loop? })`, `sfx(key, { bus? })`, `haptic(kind)`, `use(animation, slots, tools?)`, `spawn` (a temporary entity, flying coins, that the timeline despawns when it ends; see the anim README). `Frames({ keys, fps, loop, playing })` is a component that walks a sprite through its textures for the entity's whole life. A target is `{ projection, key }` or an entity. A timeline resolves each `{ projection, key }` target once, when it starts: every step writes the view that held the key then, also after a commit removed it and while its exit plays, until it despawns; a view spawned again under the same key is not followed, and a key nothing held at the start is looked up at its step. `reduced: "keep"` (on a `tween` step, `transition` and `loop` of `defineMotion`, `TweenOptions`, `RestOptions`) plays a track as written under reduced motion, a fade for one; the default `"cut"` lands it at once or holds a loop on its first key. A node plays it with `await fx(play(animation, slots))`; in fast mode it finishes at once. `defineMotion({ states, transition?, on: { enter?, exit?, change? }, when? })` builds the enter, exit and change hooks for a projection or the `motion` prop of a tag; `when: "change"` plays enter and exit only for a commit, so an element that comes or goes with its screen stands at rest and leaves without a motion (default `"always"`). Events `anim:mark` `{ animation, mark }` and `anim:finished` `{ animation }`. `app.anim.replace(definition)` is the dev hot swap: the next `play` builds the new tree. A system cannot `require` a plugin, so it plays through the resource `AnimPlayer`: `res(AnimPlayer).play(animation, slots)` returns the same handle as `app.anim.play`, and the registered animation of `animation.id` wins, so a hot swap reaches the system. Play on a change, never every frame; from phase `input` the tree moves in `animate` of the same frame. Before `anim` starts it throws `[game] AnimPlayer is not ready: anim has not started.` Config `maxTracks: 2000`.
|
|
559
559
|
- Audio is opt-in: `plugins: [...screen, audioPlugin]`. `fx(sfx("orders.complete"))` resolves when the sound started. `await fx(music("board.theme"))` cross-fades; `music(null)` fades out; a scene's `music` key switches the track on `scenes:changed`. Buses `master`, `music`, `sfx`. Volumes come from the committed player: config `volumes: player => (player as Player).settings.audio`, applied on every `model:committed`. `app.audio`: `setVolume(bus, value)`, `volume(bus)`, `mute(bus, on)`, `muted(bus)`, `unlocked()`, `journal()` (the last started sounds, empty unless config `journal` is above 0). Config: `buses: { master: 1, music: 0.6, sfx: 1 }`, `musicFadeMs: 600`, `volumes`, `context`, `journal: 0`, `music: "decode" | "stream"` default `"decode"` (gapless buffer; `"stream"` is an `<audio>` element, less memory, a gap at every loop), `session: "ambient" | "playback" | "auto"` default `"ambient"` (iOS only: ambient mixes with other apps and obeys the silent switch). The context is asked to run at start: where the shell lets audio play (a native webview with the gesture requirement off) `unlocked()` is true with no touch; a browser that wants a gesture unlocks on the first `pointerdown` or `touchend`. Without `audio` every `sfx` and `music` effect resolves `undefined` at once, so the same node runs in a game with no sound.
|
|
560
560
|
- `app.ui`: `tree()` the live screen as plain data (a text node carries `content`, the words it draws after `tr()` and `bind`; a text field carries `value`), `find(key)` the entity of a keyed element, `fill(key, value)` types into the text field with that `key`, `scroll(key, to)` puts the `scroll` with that `key` at `to` from its start at once, inside `0..max`, its fling or glide stopped (`false` and `ui:scroll-without-scroll` for no live `scroll`, `false` and `ui:scroll-before-solve` for a `scroll` its first solve has not placed yet), `lint()` tap targets under `tapTargetPt` (default `44`), text that overflows in some locale, absolute elements without `reason`. Config: `tapTargetPt: 44`, `breakpoints: { tall: 2, wide: 1.5 }`. `ui` emits only the dev global event `ui:hot-swap`, see "Hot swap".
|