@moku-labs/game 0.15.7 → 0.15.9

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 (35) hide show
  1. package/dist/app/page.d.mts +1 -1
  2. package/dist/app/page.mjs +1 -1
  3. package/dist/app/system.d.mts +3 -3
  4. package/dist/app.d.mts +3 -3
  5. package/dist/app.mjs +1 -1
  6. package/dist/assets.d.mts +1 -1
  7. package/dist/{commands-C8aWbThW.d.mts → commands-5woFUxUr.d.mts} +13 -5
  8. package/dist/control.d.mts +4 -4
  9. package/dist/control.mjs +1 -1
  10. package/dist/{define-Bebctfvs.d.mts → define-B8A5IoeS.d.mts} +2 -2
  11. package/dist/{headless-DobgwTKK.d.mts → headless-CrxofjLt.d.mts} +1 -1
  12. package/dist/{index-CU4Oc2Qv.d.mts → index-DT9aYVGd.d.mts} +7 -6
  13. package/dist/index.d.mts +5 -5
  14. package/dist/index.mjs +3 -3
  15. package/dist/inspect.d.mts +6 -6
  16. package/dist/inspect.mjs +1 -1
  17. package/dist/jsx-dev-runtime.d.mts +1 -1
  18. package/dist/jsx-runtime.d.mts +1 -1
  19. package/dist/{run-DlxDjgOO.mjs → run-BqYmcNo7.mjs} +38 -5
  20. package/dist/{runtime-Bm_guAJR.d.mts → runtime-BZQQPq56.d.mts} +1 -1
  21. package/dist/{sources-OvHvyeJS.mjs → sources-QCowxSpC.mjs} +1 -1
  22. package/dist/{src-nJYt0LMr.mjs → src-Cs1bP3v7.mjs} +1044 -184
  23. package/dist/testing.d.mts +4 -4
  24. package/dist/testing.mjs +1 -1
  25. package/dist/{types-CZGuMhV8.d.mts → types-D8roM1u3.d.mts} +127 -9
  26. package/dist/{types-BkcgFOoB.d.mts → types-DDmfkONF.d.mts} +59 -7
  27. package/dist/{types-MocH_igX.d.mts → types-DK-IYk-s.d.mts} +4 -4
  28. package/dist/{types-Mj75CDO6.d.mts → types-YXykgTOp.d.mts} +2 -2
  29. package/dist/{types-C4D9UVgb.d.mts → types-i77Nrrv-.d.mts} +29 -16
  30. package/dist/{visual-BV2A3kpr.d.mts → visual-1doiBOD3.d.mts} +6 -6
  31. package/dist/{visual-2m4wJL_z.mjs → visual-CIUx49C0.mjs} +26 -6
  32. package/dist/visual.d.mts +1 -1
  33. package/dist/visual.mjs +2 -2
  34. package/llms.txt +8 -7
  35. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
- import { Cr as Json, Yn as FeaturePlugin, Zn as AnyFlow, _r as FakeClock, dr as Hint, fr as NodeFx, hr as ClockSource, rr as NodeTable, sr as Descriptor } from "./types-C4D9UVgb.mjs";
2
- import { t as createApp } from "./index-CU4Oc2Qv.mjs";
3
- import { b as saveOf, v as WithGameState, y as memory } from "./types-MocH_igX.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-DobgwTKK.mjs";
1
+ import { Cr as Json, Yn as FeaturePlugin, Zn as AnyFlow, _r as FakeClock, dr as Hint, fr as NodeFx, hr as ClockSource, rr as NodeTable, sr as Descriptor } from "./types-i77Nrrv-.mjs";
2
+ import { t as createApp } from "./index-DT9aYVGd.mjs";
3
+ import { b as saveOf, v as WithGameState, y as memory } from "./types-DK-IYk-s.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-CrxofjLt.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 { an as exit, cn as type, in as refuseStart, m as flattenFeatures, t as createApp } from "./src-nJYt0LMr.mjs";
1
+ import { an as refuseStart, ln as type, m as flattenFeatures, on as exit, t as createApp } from "./src-Cs1bP3v7.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";
@@ -1,4 +1,4 @@
1
- import { $r as Require, Cn as Motion, Cr as Json, Dn as ProjectionMotion, E as Api$3, En as NumericFields, Mn as ViewHandle, Nn as Api$1, Nt as ViewportSize, Qt as Api$2, Tn as MotionHandle, Ur as Api, Yt as TransformValue, an as AnyComponentValue, bn as ChangeHook, cn as ComponentType, dr as Hint, in as AnyComponentType, mr as Api$5, pr as Answer, rn as AnyComponent, s as Events$1, sr as Descriptor, t as Api$4, un as Entity, wn as MotionCause, yn as TagType } from "./types-C4D9UVgb.mjs";
1
+ import { $r as Require, Cn as Motion, Cr as Json, Dn as ProjectionMotion, E as Api$3, En as NumericFields, Mn as ViewHandle, Nn as Api$1, Nt as ViewportSize, Qt as Api$2, Tn as MotionHandle, Ur as Api, Yt as TransformValue, an as AnyComponentValue, bn as ChangeHook, cn as ComponentType, dr as Hint, in as AnyComponentType, mr as Api$5, pr as Answer, rn as AnyComponent, s as Events$1, sr as Descriptor, t as Api$4, un as Entity, wn as MotionCause, yn as TagType } from "./types-i77Nrrv-.mjs";
2
2
  import { Log } from "@moku-labs/common/browser";
3
3
  import { PluginCtx } from "@moku-labs/core";
4
4
 
@@ -126,6 +126,8 @@ type PositionStyle = {
126
126
  * // The play glyph of the Watch button, and a dashed ring around a slot.
127
127
  * const play: VisualStyle = { shape: "triangle", fill: 0xfffbe8 };
128
128
  * const slot: VisualStyle = { stroke: 0x3a2212, strokeWidth: 4, dash: 10, radius: 24 };
129
+ * // The slot timer: the time left as 42 % of a ring, from 12 o'clock clockwise, with round ends.
130
+ * const timer: VisualStyle = { shape: "arc", stroke: 0xc8a15a, strokeWidth: 2.2, sweep: 0.42, cap: "round" };
129
131
  * ```
130
132
  */
131
133
  type VisualStyle<Asset extends string = string> = {
@@ -136,11 +138,19 @@ type VisualStyle<Asset extends string = string> = {
136
138
  alpha?: number;
137
139
  /**
138
140
  * The shape of the rectangle an element without a nine-slice is drawn with: `"rect"` (the
139
- * default) or `"triangle"`, which fills the box pointing right and ignores `radius`. Turn the
140
- * element with `rotation` for another direction.
141
+ * default), `"triangle"`, which fills the box pointing right and ignores `radius` (turn the
142
+ * element with `rotation` for another direction), or `"arc"`, a `stroke` of `strokeWidth` on the
143
+ * circle inscribed in the box (`min(width, height) − strokeWidth` across, centred) from 12 o'clock
144
+ * clockwise over `sweep` of it. An arc draws no `fill` and ignores `radius` and `dash`.
141
145
  */
142
- shape?: "rect" | "triangle"; /** The dash length of the stroke in reference units, with gaps of half a dash; 0 is solid. */
146
+ shape?: "rect" | "triangle" | "arc"; /** The dash length of the stroke in reference units, with gaps of half a dash; 0 is solid. */
143
147
  dash?: number;
148
+ /**
149
+ * The share of the circle an arc sweeps, from 0 to 1 (1 by default): 0 draws nothing, 1 a
150
+ * closed ring; a value outside is clamped. A new value in a render draws the arc again once.
151
+ */
152
+ sweep?: number; /** How an open arc ends: `"round"` (the default) or `"butt"`, flat at its end. */
153
+ cap?: "round" | "butt";
144
154
  /**
145
155
  * The asset key of a nine-slice drawn at the rect instead of the rounded rectangle. Any tag
146
156
  * but `image`, `icon` and `text` takes it; a clipping element (`scroll`, `overflow: "hidden"`)
@@ -990,7 +1000,12 @@ type State$1 = {
990
1000
  * over and cancels the resting press.
991
1001
  */
992
1002
  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. */
1003
+ moved: boolean;
1004
+ /**
1005
+ * The press belongs to a scroll: it landed on a moving one and stopped it, or it was handed to
1006
+ * one past the tap slop. Its release answers nothing and runs no `onTap` listener.
1007
+ */
1008
+ caught: boolean; /** The pressed or held entity. */
994
1009
  entity: Entity | undefined; /** The projection key of `entity`, read once at press time. */
995
1010
  key: {
996
1011
  projection: string;
@@ -1870,8 +1885,51 @@ type ImageTexture = string & Brand<"ImageTexture">;
1870
1885
  type IconName = string & Brand<"IconName">;
1871
1886
  /** How an image or an icon fills its rect: inside it, over it (cropped), or stretched. */
1872
1887
  type ImageFit = ("contain" | "cover" | "fill") & Brand<"ImageFit">;
1873
- /** The axis a scroll container moves on. `"x"` throws until V4. */
1888
+ /**
1889
+ * The axis a scroll container moves on: `"y"`, the default, or `"x"`. Fixed when the scroll
1890
+ * spawns: another axis on a later render keeps the first one, with one warning
1891
+ * `ui:scroll-axis-fixed`. A windowed scroll moves on `"y"` only: `"x"` with `rows` throws.
1892
+ *
1893
+ * @example
1894
+ * ```tsx
1895
+ * // The order strip of the board moves sideways; the cards in it lay out in a row.
1896
+ * <scroll key="strip" axis="x" style={{ width: 306, height: 120 }}>
1897
+ * <row key="track" style={{ width: 696, height: 120 }} />
1898
+ * </scroll>;
1899
+ * // ScrollState of the strip: { offset: 0, max: 390, moving: false }
1900
+ * ```
1901
+ */
1874
1902
  type ScrollAxis = ("x" | "y") & Brand<"ScrollAxis">;
1903
+ /**
1904
+ * The stops a scroll comes to rest on, as offsets from the start, kept inside 0 to `max`. A
1905
+ * release glides to the stop nearest to where its velocity carries in 260 ms, on the curve
1906
+ * `1 − (1 − p)³`, in `min(620, 260 + distance × 1.1)` ms; without `snap` it flings.
1907
+ *
1908
+ * @example
1909
+ * ```tsx
1910
+ * // Three stops: the events, the orders, the end. A slow release at offset 300 glides to 318.
1911
+ * <scroll key="strip" axis="x" snap={[0, 318, 390]} style={{ width: 306, height: 120 }}>
1912
+ * <row key="track" style={{ width: 696, height: 120 }} />
1913
+ * </scroll>;
1914
+ * ```
1915
+ */
1916
+ type ScrollSnap = readonly number[] & Brand<"ScrollSnap">;
1917
+ /**
1918
+ * How far a scroll stands from its start, in reference units, kept inside 0 to `max`; 0 when
1919
+ * left out. The first frame draws it there. A later render with another value glides there on
1920
+ * the curve and in the time of `snap`; the same value changes nothing, so a scroll the finger
1921
+ * moved stays where it was left.
1922
+ *
1923
+ * @example
1924
+ * ```tsx
1925
+ * // The strip opens on the orders; closing the pinned column moves the game to 306.
1926
+ * <scroll key="strip" axis="x" offset={318} snap={[0, 318, 390]} style={{ width: 306, height: 120 }}>
1927
+ * <row key="track" style={{ width: 696, height: 120 }} />
1928
+ * </scroll>;
1929
+ * // first drawn frame: the content stands 318 u left of its rest, the orders in view
1930
+ * ```
1931
+ */
1932
+ type ScrollOffset = number & Brand<"ScrollOffset">;
1875
1933
  /** How many rows a windowed scroll has. */
1876
1934
  type ScrollRows = number & Brand<"ScrollRows">;
1877
1935
  /** The height of every row, in reference units; above 0. */
@@ -2041,11 +2099,14 @@ type ScrollWindowForm = {
2041
2099
  };
2042
2100
  /**
2043
2101
  * What a scroll container takes: children for a short list, or `rows`, `rowHeight` and `row` for
2044
- * a long one, whose rows exist only in the window.
2102
+ * a long one, whose rows exist only in the window; the `axis` it moves on, the `snap` stops a
2103
+ * release glides to, and the `offset` it stands at.
2045
2104
  *
2046
2105
  * @example
2047
2106
  * ```ts
2048
2107
  * const props: ScrollProps = { axis: "y" };
2108
+ * // The order strip: sideways, three stops, opened on the orders.
2109
+ * const strip: ScrollProps = { axis: "x", snap: [0, 318, 390], offset: 318 };
2049
2110
  * // 1000 orders of 120 u in a 1600 u list: rows 0 to 18 exist at offset 0.
2050
2111
  * const orders: ScrollProps = {
2051
2112
  * style: { height: 1600 },
@@ -2057,6 +2118,8 @@ type ScrollWindowForm = {
2057
2118
  */
2058
2119
  type ScrollProps = CommonProps & {
2059
2120
  axis?: ScrollAxis;
2121
+ snap?: ScrollSnap;
2122
+ offset?: ScrollOffset;
2060
2123
  } & (ScrollChildForm | ScrollWindowForm);
2061
2124
  /**
2062
2125
  * What a text field takes. `local` is required: every keystroke writes that field of the local
@@ -2200,6 +2263,31 @@ declare const Box: ComponentType<{
2200
2263
  * and `ui` merges the patch into the nearest component instance.
2201
2264
  */
2202
2265
  declare const LocalWrite: ComponentType<LocalWriteValue>;
2266
+ /**
2267
+ * On every scroll container: where it stands and whether it moves, for a game system and the
2268
+ * read door. `ui` writes it in a frame where the offset or `max` changed, and once more with
2269
+ * `moving: false` when it stops; a game reads it and never writes it.
2270
+ *
2271
+ * @example
2272
+ * ```ts
2273
+ * // A board system dims the events of the order strip while it rests on the orders.
2274
+ * export const stripMist = system({
2275
+ * name: "board.stripMist",
2276
+ * phase: "animate",
2277
+ * query: [ScrollState, OrderStrip],
2278
+ * run: entities => {
2279
+ * for (const [entity, scroll] of entities) {
2280
+ * // scroll: { offset: 318, max: 390, moving: false }
2281
+ * }
2282
+ * }
2283
+ * });
2284
+ * ```
2285
+ */
2286
+ declare const ScrollState: ComponentType<{
2287
+ offset: number;
2288
+ max: number;
2289
+ moving: boolean;
2290
+ }>;
2203
2291
  /**
2204
2292
  * On the view a player taps five times within three seconds to open the editor's overlay on a debug build: the
2205
2293
  * version line of the settings, usually. One helper on top of `app.debug.overlay.open()`; a game that wants another
@@ -2396,6 +2484,35 @@ type ScrollWindow = {
2396
2484
  first: number;
2397
2485
  last: number;
2398
2486
  };
2487
+ /**
2488
+ * How a scroll container moves, kept on its element: the axis it spawned with, what moves it now
2489
+ * (the finger `"held"`, a `"fling"` after a release, a `"glide"` to a stop or to a new `offset`
2490
+ * prop, or nothing, `"still"`), and the numbers of that motion in offsets from the start, 0 to
2491
+ * `max`. `offset` is exact: the components get it in whole units. `velocity` is in units a ms,
2492
+ * positive toward `max`. A glide runs from `from` to `to` over `duration` ms, `elapsed` of them
2493
+ * gone. `pointer` and `start` are the finger on the axis and the offset where the press began.
2494
+ * `seen` is the `offset` prop of the last render, 0 when it is left out; `placed` turns true when
2495
+ * the first solve put the scroll at it. `atProp` is true while the scroll follows that prop: it
2496
+ * stands at it or glides to it, so a new range puts it at the prop again. The first place and a
2497
+ * glide to a new prop set it; a press and `app.ui.scroll` clear it, and a fling or a snap glide
2498
+ * only comes after a press. Plain numbers written in place: a frame allocates nothing.
2499
+ */
2500
+ type ScrollMotion = {
2501
+ axis: "x" | "y";
2502
+ mode: "still" | "held" | "fling" | "glide";
2503
+ offset: number;
2504
+ max: number;
2505
+ velocity: number;
2506
+ from: number;
2507
+ to: number;
2508
+ duration: number;
2509
+ elapsed: number;
2510
+ pointer: number;
2511
+ start: number;
2512
+ seen: number;
2513
+ placed: boolean;
2514
+ atProp: boolean;
2515
+ };
2399
2516
  /**
2400
2517
  * What the style of an element was resolved on besides its own node: the epoch of the jsx state,
2401
2518
  * and the row height when the element is a row of a windowed scroll. While both stand, and the
@@ -2415,7 +2532,7 @@ type StyleBasis = {
2415
2532
  * `change` hook of each of them returned; `warnedOwned` the names of the `components` values the
2416
2533
  * element owns that were already logged. A windowed scroll carries its `window` and the one-time
2417
2534
  * warnings of its props in `warned`; `scrolledIn` marks an element a range change of a windowed
2418
- * scroll created: it plays no `enter` hook. A text or an icon that sizes itself keeps in
2535
+ * 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
2419
2536
  * `measuredSize` what its measure function last answered, before Yoga's clamp: a bound text whose
2420
2537
  * new string measures the same asks for no solve. `basis` is what `style` was resolved on, set
2421
2538
  * once the style is on the layout node and the components are written; an element without one is
@@ -2469,6 +2586,7 @@ type Element = {
2469
2586
  warned: Set<string>;
2470
2587
  scrolledIn: boolean;
2471
2588
  window?: ScrollWindow;
2589
+ scroll?: ScrollMotion;
2472
2590
  measuredSize?: {
2473
2591
  width: number;
2474
2592
  height: number;
@@ -2794,4 +2912,4 @@ type CommonProps = {
2794
2912
  components?: ElementComponents;
2795
2913
  };
2796
2914
  //#endregion
2797
- 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 };
2915
+ export { defineComponent as A, Part as B, TextApi as C, TextStyles as D, TextStyleInput as E, Argument as F, types_d_exports$2 as G, StringTable as H, Config$2 as I, Style as J, IsFlags as K, I18nApi as L, InputApi as M, State$1 as N, TextValue as O, types_d_exports$1 as P, IntlKit as R, State as S, TextFormat as T, TextKey as U, State$2 as V, TypedTr as W, WhenFlags as X, StylesState as Y, BindField as _, JsxChild as a, CountdownValue as b, UiNode as c, LocalWrite as d, ScrollState as f, UiIntrinsicElements as g, IntrinsicElementsFor as h, Finding as i, Config$1 as j, types_d_exports as k, Box as l, defineTokens as m, ElementChange as n, JsxState as o, popup as p, ResolvedStyle as q, ElementMotion as r, PopupComponent as s, DescriptionNode as t, DebugTrigger as u, BindOptions as v, TextBind as w, Point as x, Config as y, Message as z };
@@ -1,5 +1,5 @@
1
- import { $r as Require, A as PixiModule, An as TrackOptions, At as FilterSlotInputs, Cr as Json, E as Api$4, En as NumericFields, M as PixiTexture, Mt as Point, Nn as Api$2, Pt as FilterCache, Qr as Events$2, Qt as Api$3, Sn as Ease, Sr as Events$3, Tn as MotionHandle, Ur as Api$1, an as AnyComponentValue, br as Api$6, cn as ComponentType, j as PixiSprite, jn as TrackSegment, k as PixiFilter, kn as ReducedMotion, kt as FilterSlot, on as ComponentHandle, or as TypeTag, rn as AnyComponent, s as Events$1, sr as Descriptor, t as Api$5, un as Entity, v as Events$4, zr as Events$5 } from "./types-C4D9UVgb.mjs";
2
- import { I as I18nApi, J as StylesState, S as TextApi, c as UiNode, i as Finding, j as InputApi, n as ElementChange, o as JsxState, r as ElementMotion } from "./types-CZGuMhV8.mjs";
1
+ import { $r as Require, A as PixiModule, An as TrackOptions, At as FilterSlotInputs, Cr as Json, E as Api$4, En as NumericFields, M as PixiTexture, Mt as Point, Nn as Api$2, Pt as FilterCache, Qr as Events$2, Qt as Api$3, Sn as Ease, Sr as Events$3, Tn as MotionHandle, Ur as Api$1, an as AnyComponentValue, br as Api$6, cn as ComponentType, j as PixiSprite, jn as TrackSegment, k as PixiFilter, kn as ReducedMotion, kt as FilterSlot, on as ComponentHandle, or as TypeTag, rn as AnyComponent, s as Events$1, sr as Descriptor, t as Api$5, un as Entity, v as Events$4, zr as Events$5 } from "./types-i77Nrrv-.mjs";
2
+ import { C as TextApi, L as I18nApi, M as InputApi, Y as StylesState, c as UiNode, i as Finding, n as ElementChange, o as JsxState, r as ElementMotion } from "./types-D8roM1u3.mjs";
3
3
  import { Log } from "@moku-labs/common/browser";
4
4
  import { PluginCtx } from "@moku-labs/core";
5
5
  import { Node, Yoga } from "yoga-layout/load";
@@ -2809,8 +2809,36 @@ type MusicRequest = {
2809
2809
  };
2810
2810
  //#endregion
2811
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
+ };
2812
2836
  /**
2813
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.
2814
2842
  */
2815
2843
  type LayoutState = {
2816
2844
  yoga: Yoga | undefined;
@@ -2819,10 +2847,12 @@ type LayoutState = {
2819
2847
  measured: number;
2820
2848
  solves: number;
2821
2849
  scrolling: Entity | undefined;
2822
- scrollStart: {
2823
- pointerY: number;
2824
- offset: number;
2825
- }; /** One line of the `body` style as the icons were last measured with it; none before that. */
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. */
2826
2856
  iconLine: number | undefined;
2827
2857
  order: number;
2828
2858
  cleanups: Array<() => void>;
@@ -2960,7 +2990,7 @@ type UiCtx = KernelSlice & {
2960
2990
  /**
2961
2991
  * ui plugin API, `app.ui`. The screen is one more projection, so three members read it the way a
2962
2992
  * test reads the board: a snapshot, a key lookup and a list of findings; the fourth types into a
2963
- * text field.
2993
+ * text field, the fifth scrolls a `scroll`.
2964
2994
  *
2965
2995
  * @example
2966
2996
  * ```ts
@@ -3043,6 +3073,28 @@ type UiApi = {
3043
3073
  * ```
3044
3074
  */
3045
3075
  fill(key: string, value: string): boolean;
3076
+ /**
3077
+ * Scrolls a `scroll` element to an offset from its start, at once: the offset is kept inside 0
3078
+ * to `max`, a fling or a glide stops, and `ScrollState` reads the new offset with
3079
+ * `moving: false`. A finger that holds the scroll goes on from there. Works headless, for a
3080
+ * test, an agent or a visual test (the `game.scroll` command, the step `{ scroll: { key, to } }`).
3081
+ *
3082
+ * @param key - The `key` prop of the `scroll` element.
3083
+ * @param to - How far from the start, in reference units. `NaN` leaves the scroll where it is.
3084
+ * @returns True when a live scroll took it. False in two cases, each with one warning `{ key }`:
3085
+ * `ui:scroll-without-scroll` when no live `scroll` has the key, and `ui:scroll-before-solve`
3086
+ * when the `scroll` came in this frame and its first solve has not placed it yet: call it
3087
+ * again after the frame.
3088
+ * @example
3089
+ * ```ts
3090
+ * // A test shows the order strip on its events: the strip is 306 u over a 696 u track.
3091
+ * app.ui.scroll("strip", 0); // true
3092
+ * app.world.ecs.get(app.ui.find("strip") ?? 0, ScrollState); // { offset: 0, max: 390, moving: false }
3093
+ * app.ui.scroll("strip", 999); // true: it stands on the end, offset 390
3094
+ * app.ui.scroll("nothing", 0); // false, with the warning "ui:scroll-without-scroll"
3095
+ * ```
3096
+ */
3097
+ scroll(key: string, to: number): boolean;
3046
3098
  };
3047
3099
  //#endregion
3048
3100
  export { sequence as $, GlowValue as A, Target as B, BlurValue as C, FilterComponent as D, FilterArea as E, AnimPlayerValue as F, HAPTIC_KINDS as G, HapticKind as H, Config$3 as I, frames as J, defineAnimation as K, FramesValue as L, OutlineValue as M, UniformDeclaration as N, FilterSpec as O, AnimApi as P, play as Q, MotionKeyframe as R, AlphaValue as S, DisplacementValue as T, SfxDescriptor as U, types_d_exports$3 as V, Step as W, mark as X, haptic as Y, parallel as Z, State$2 as _, AudioApi as a, tween as at, EmitterDefinition as b, MusicDescriptor as c, OverlayApi as ct, State$1 as d, set as et, VolumesFor as f, EffectsStats as g, EffectsApi as h, types_d_exports as i, stagger as it, NoiseValue as j, FilterValueOf as k, MusicOptions as l, types_d_exports$4 as lt, Config$2 as m, State as n, spawn as nt, AudioContextLike as o, use as ot, types_d_exports$1 as p, external as q, UiApi as r, spawned as rt, Config$1 as s, wait as st, Config as t, sfx as tt, SoundEntry as u, types_d_exports$2 as v, ColorMatrixValue as w, EmitterValue as x, EmitterConfig as y, State$3 as z };
@@ -1,7 +1,7 @@
1
- import { A as PixiModule, Ar as SaveDoc, Cr as Json, D as Config$2, Fn as Config$1, Nr as SnapshotOf, Or as PlayerStateProvider, Yn as FeaturePlugin, Zn as AnyFlow, _r as FakeClock, a as Config$3, d as Manifest, hr as ClockSource, jt as Orientation, kr as ProviderCall, n as AssetsIo, or as TypeTag, xr as Config } from "./types-C4D9UVgb.mjs";
2
- import { o as AudioContextLike, s as Config$4 } from "./types-BkcgFOoB.mjs";
3
- import { H as TextKey, I as I18nApi, V as StringTable } from "./types-CZGuMhV8.mjs";
4
- import { ft as platformPlugin, i as screen, mt as PlatformProvider, t as createApp, wt as audioPlugin, xt as effectsPlugin } from "./index-CU4Oc2Qv.mjs";
1
+ import { A as PixiModule, Ar as SaveDoc, Cr as Json, D as Config$2, Fn as Config$1, Nr as SnapshotOf, Or as PlayerStateProvider, Yn as FeaturePlugin, Zn as AnyFlow, _r as FakeClock, a as Config$3, d as Manifest, hr as ClockSource, jt as Orientation, kr as ProviderCall, n as AssetsIo, or as TypeTag, xr as Config } from "./types-i77Nrrv-.mjs";
2
+ import { o as AudioContextLike, s as Config$4 } from "./types-DDmfkONF.mjs";
3
+ import { H as StringTable, L as I18nApi, U as TextKey } from "./types-D8roM1u3.mjs";
4
+ import { ft as platformPlugin, i as screen, mt as PlatformProvider, t as createApp, wt as audioPlugin, xt as effectsPlugin } from "./index-DT9aYVGd.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 { Cr as Json, Mr as Snapshot } from "./types-C4D9UVgb.mjs";
2
- import { t as HeadlessApp } from "./headless-DobgwTKK.mjs";
1
+ import { Cr as Json, Mr as Snapshot } from "./types-i77Nrrv-.mjs";
2
+ import { t as HeadlessApp } from "./headless-CrxofjLt.mjs";
3
3
  import { Log } from "@moku-labs/common/browser";
4
4
 
5
5
  //#region src/plugins/flow/doors/types.d.ts
@@ -6626,14 +6626,20 @@ type DisplayValue = {
6626
6626
  object: unknown;
6627
6627
  };
6628
6628
  /**
6629
- * A filled rounded rectangle or a triangle, anchored at the top left of the `Transform`. `kind`
6630
- * picks the outline: `"rect"` (the default) or `"triangle"`, which fills its `w × h` box pointing
6631
- * right (rotate the element for another direction) and ignores `radius`. `fillAlpha` is the alpha
6632
- * of the fill alone: 0 draws only the stroke, a ring. `alpha` fades the whole shape and the
6633
- * entity's children: a disabled button at 0.6 draws its icon at 0.6 too. `dash` is the
6634
- * dash length of the stroke in reference units, with gaps of half a dash; 0 strokes a solid line.
6635
- * `clip` masks the children of the entity to the shape, always solid, which is how `ui` draws a
6636
- * scroll and an overflow. The shape itself is never masked, so its stroke is drawn whole.
6629
+ * A filled rounded rectangle, a triangle or an arc, anchored at the top left of the `Transform`. `kind` picks the
6630
+ * outline: `"rect"` (the default), `"triangle"`, which fills its `w × h` box pointing right (rotate the element for
6631
+ * another direction) and ignores `radius`, or `"arc"`. `fillAlpha` is the alpha of the fill alone: 0 draws only the
6632
+ * stroke, a ring. `alpha` fades the whole shape and the entity's children: a disabled button at 0.6 draws its icon at
6633
+ * 0.6 too. `dash` is the dash length of the stroke in reference units, with gaps of half a dash; 0 strokes a solid
6634
+ * line. `clip` masks the children of the entity to the shape, always solid, which is how `ui` draws a scroll and an
6635
+ * overflow. The shape itself is never masked, so its stroke is drawn whole. An arc is a stroke on the circle inscribed
6636
+ * in the box: its diameter is `min(w, h) − strokeWidth`, centred, so the stroke stays inside the box. It starts at 12
6637
+ * o'clock and runs clockwise over `sweep` of the circle (0 to 1, clamped): 0 draws nothing, 1 a closed ring. `cap` ends
6638
+ * an open arc round or flat (`"butt"`). Both are optional: left out, `sweep` is 1 and `cap` is `"round"`
6639
+ * (`arcDefaults`). Only an arc reads them; a rectangle or a triangle ignores them. An arc draws only its stroke, in
6640
+ * `stroke`, `strokeWidth` and `alpha`: `fill`, `fillAlpha`, `radius` and `dash` are ignored, and `clip` masks the
6641
+ * children to its box. The path is built again only when a field it is drawn from changes: a still arc costs nothing a
6642
+ * frame, a new `fill` builds no arc again.
6637
6643
  *
6638
6644
  * @example
6639
6645
  * ```ts
@@ -6649,10 +6655,12 @@ type DisplayValue = {
6649
6655
  * // The play glyph of a watch button, and a dashed focus ring: 10 u dashes, 5 u gaps.
6650
6656
  * const play: ShapeValue = { ...ring, kind: "triangle", w: 36, h: 40, fillAlpha: 1, strokeWidth: 0 };
6651
6657
  * const focus: ShapeValue = { ...ring, w: 200, h: 80, stroke: 0x3a2212, strokeWidth: 4, dash: 10 };
6658
+ * // The time left on a slot's timer: 42 % of a ring 25.8 u across in a 28 u box, from 12 o'clock clockwise, round ends.
6659
+ * const timer: ShapeValue = { ...ring, kind: "arc", w: 28, h: 28, stroke: 0xc8a15a, strokeWidth: 2.2, sweep: 0.42 };
6652
6660
  * ```
6653
6661
  */
6654
6662
  type ShapeValue = {
6655
- kind: "rect" | "triangle";
6663
+ kind: "rect" | "triangle" | "arc";
6656
6664
  w: number;
6657
6665
  h: number;
6658
6666
  fill: number;
@@ -6662,7 +6670,9 @@ type ShapeValue = {
6662
6670
  stroke: number;
6663
6671
  strokeWidth: number;
6664
6672
  dash: number;
6665
- clip: boolean;
6673
+ clip: boolean; /** The share of the circle an arc sweeps, 0 to 1, from 12 o'clock clockwise; clamped. Only an arc reads it: 1 left out. */
6674
+ sweep?: number; /** How an open arc ends: `"round"` or `"butt"` (flat at its end). Only an arc reads it: `"round"` left out. */
6675
+ cap?: "round" | "butt";
6666
6676
  };
6667
6677
  /**
6668
6678
  * What `sprite()` takes: the two things every visual needs, and the four that have defaults.
@@ -6762,9 +6772,10 @@ declare const Parent: ComponentType<{
6762
6772
  */
6763
6773
  declare const Display: ComponentType<DisplayValue>;
6764
6774
  /**
6765
- * A filled rounded rectangle or a right-pointing triangle, drawn with Pixi `Graphics` and redrawn
6766
- * only when a field changed. `fillAlpha: 0` draws only the stroke, `dash` above 0 dashes it.
6767
- * `clip: true` masks the children of the entity to the shape.
6775
+ * A filled rounded rectangle, a right-pointing triangle or an arc (`kind: "arc"`, a stroke from 12 o'clock clockwise
6776
+ * over `sweep` of the circle in its box), drawn with Pixi `Graphics` and redrawn only when a field changed.
6777
+ * `fillAlpha: 0` draws only the stroke, `dash` above 0 dashes it. `clip: true` masks the children of the entity to the
6778
+ * shape.
6768
6779
  */
6769
6780
  declare const Shape: ComponentType<ShapeValue>;
6770
6781
  /**
@@ -7241,7 +7252,7 @@ type HitBox = {
7241
7252
  */
7242
7253
  type DrawnShape = {
7243
7254
  /** Drawn white, coloured by the object's tint (no stroke); false for a shape painted in its own colours. */tinted: boolean;
7244
- kind: "rect" | "triangle";
7255
+ kind: ShapeValue["kind"];
7245
7256
  w: number;
7246
7257
  h: number;
7247
7258
  fill: number;
@@ -7249,14 +7260,16 @@ type DrawnShape = {
7249
7260
  radius: number;
7250
7261
  stroke: number;
7251
7262
  strokeWidth: number;
7252
- dash: number;
7263
+ dash: number; /** An arc's `sweep` as the value held it, `undefined` when left out. */
7264
+ sweep: number | undefined; /** An arc's `cap` as the value held it, `undefined` when left out. */
7265
+ cap: ShapeValue["cap"];
7253
7266
  };
7254
7267
  /**
7255
7268
  * The fields of the clip rectangle last drawn into a view's mask: an equal value draws no mask again. Private to
7256
7269
  * `sync`.
7257
7270
  */
7258
7271
  type ClipDrawn = {
7259
- kind: "rect" | "triangle";
7272
+ kind: ShapeValue["kind"];
7260
7273
  w: number;
7261
7274
  h: number;
7262
7275
  radius: number;
@@ -1,9 +1,9 @@
1
- import { E as Api, Lr as Api$3, Qt as Api$1, br as Api$2 } from "./types-C4D9UVgb.mjs";
2
- import { P as AnimApi, r as UiApi } from "./types-BkcgFOoB.mjs";
3
- import { j as InputApi } from "./types-CZGuMhV8.mjs";
4
- import { r as Repro } from "./headless-DobgwTKK.mjs";
5
- import { a as InputOf, r as ControlApp } from "./types-Mj75CDO6.mjs";
6
- import { t as commands } from "./commands-C8aWbThW.mjs";
1
+ import { E as Api, Lr as Api$3, Qt as Api$1, br as Api$2 } from "./types-i77Nrrv-.mjs";
2
+ import { P as AnimApi, r as UiApi } from "./types-DDmfkONF.mjs";
3
+ import { M as InputApi } from "./types-D8roM1u3.mjs";
4
+ import { r as Repro } from "./headless-CrxofjLt.mjs";
5
+ import { a as InputOf, r as ControlApp } from "./types-YXykgTOp.mjs";
6
+ import { t as commands } from "./commands-5woFUxUr.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. */
@@ -195,6 +195,18 @@ const Now = /*#__PURE__*/ resource("Now", { now: 0 });
195
195
  * part), the engine's own overlay level, and the `sprite()` bundle helper. Pure: no ctx, no state, no Pixi. Made with the `component()` helper of `world`, so nothing has
196
196
  * to be registered.
197
197
  */
198
+ /**
199
+ * What an arc draws with when its `Shape` leaves `sweep` or `cap` out: the whole ring, round ends.
200
+ *
201
+ * @example
202
+ * ```ts
203
+ * arcDefaults.sweep; // 1
204
+ * ```
205
+ */
206
+ const arcDefaults = Object.freeze({
207
+ sweep: 1,
208
+ cap: "round"
209
+ });
198
210
  const overlayDefaults = {
199
211
  dim: 0,
200
212
  dimColor: 0,
@@ -270,9 +282,10 @@ const Parent = /*#__PURE__*/ component("Parent", { entity: 0 });
270
282
  */
271
283
  const Display = /*#__PURE__*/ component("Display", displayDefaults);
272
284
  /**
273
- * A filled rounded rectangle or a right-pointing triangle, drawn with Pixi `Graphics` and redrawn
274
- * only when a field changed. `fillAlpha: 0` draws only the stroke, `dash` above 0 dashes it.
275
- * `clip: true` masks the children of the entity to the shape.
285
+ * A filled rounded rectangle, a right-pointing triangle or an arc (`kind: "arc"`, a stroke from 12 o'clock clockwise
286
+ * over `sweep` of the circle in its box), drawn with Pixi `Graphics` and redrawn only when a field changed.
287
+ * `fillAlpha: 0` draws only the stroke, `dash` above 0 dashes it. `clip: true` masks the children of the entity to the
288
+ * shape.
276
289
  */
277
290
  const Shape = /*#__PURE__*/ component("Shape", shapeDefaults);
278
291
  /**
@@ -724,7 +737,8 @@ function contentOf(props) {
724
737
  /**
725
738
  * The visual component of an element: a sprite for an image or an icon, the text for a text, the
726
739
  * nine-slice of its style (outlined when the style sets `debug`), or a rounded rectangle, a
727
- * triangle with `shape: "triangle"`, its stroke dashed with `dash`. A clipping element (`scroll`,
740
+ * triangle with `shape: "triangle"`, its stroke dashed with `dash`, or an arc with `shape: "arc"`
741
+ * over the `sweep` of its style, ended by its `cap`. A clipping element (`scroll`,
728
742
  * `overflow: "hidden"`) keeps the rectangle, which carries the clip; a text field's rectangle
729
743
  * clips too, and a nine-slice field draws its slices and clips to them. A style with a stroke and
730
744
  * no fill draws only the stroke, a ring. A container with no fill and no stroke gets a rectangle that draws
@@ -775,7 +789,7 @@ function visualOf(element) {
775
789
  })];
776
790
  const filled = style.fill !== void 0 || style.stroke !== void 0;
777
791
  const invisible = isContainer(type) && !filled;
778
- return [Shape({
792
+ const shape = {
779
793
  kind: style.shape ?? "rect",
780
794
  w: rect.w,
781
795
  h: rect.h,
@@ -787,6 +801,12 @@ function visualOf(element) {
787
801
  strokeWidth: invisible ? 0 : style.strokeWidth ?? 0,
788
802
  dash: style.dash ?? 0,
789
803
  clip: clip || type === "input"
804
+ };
805
+ if (shape.kind !== "arc") return [Shape(shape)];
806
+ return [Shape({
807
+ ...shape,
808
+ sweep: style.sweep ?? arcDefaults.sweep,
809
+ cap: style.cap ?? arcDefaults.cap
790
810
  })];
791
811
  }
792
812
  /**
@@ -895,4 +915,4 @@ function drawnRect(pose, local) {
895
915
  };
896
916
  }
897
917
  //#endregion
898
- export { Order as A, Sprite as C, Exiting as D, sprite as E, system as F, systemsFor as I, tag as L, component as M, mut as N, Layer as O, resource as P, Shape as S, componentsFor as T, HudPart as _, scaleByFits as a, OverlayLevel as b, Countdown as c, builtInStyles as d, defineTextStyles as f, Display as g, textFor as h, samePose as i, Tree as j, Now as k, Text as l, readStyle as m, drawnRect as n, visualOf as o, label as p, fitScaleOf as r, visualRectOf as s, CONTENT as t, bind as u, NineSlice as v, Transform as w, Parent as x, Overlay as y };
918
+ export { Now as A, Sprite as C, sprite as D, componentsFor as E, resource as F, system as I, systemsFor as L, Tree as M, component as N, Exiting as O, mut as P, tag as R, Shape as S, arcDefaults as T, HudPart as _, scaleByFits as a, OverlayLevel as b, Countdown as c, builtInStyles as d, defineTextStyles as f, Display as g, textFor as h, samePose as i, Order as j, Layer as k, Text as l, readStyle as m, drawnRect as n, visualOf as o, label as p, fitScaleOf as r, visualRectOf as s, CONTENT as t, bind as u, NineSlice as v, Transform as w, Parent as x, Overlay as y };
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-BV2A3kpr.mjs";
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-1doiBOD3.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,5 +1,5 @@
1
- import { n as read, t as sources } from "./sources-OvHvyeJS.mjs";
2
- import { n as commands, t as run } from "./run-DlxDjgOO.mjs";
1
+ import { n as read, t as sources } from "./sources-QCowxSpC.mjs";
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";
5
5
  import { mkdir, readFile, writeFile } from "node:fs/promises";