@moku-labs/game 0.15.2 → 0.15.4

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.
@@ -1,7 +1,7 @@
1
- import { Jn as FeaturePlugin, Sr as Json, Xn as AnyFlow, dr as NodeFx, gr as FakeClock, mr as ClockSource, nr as NodeTable, or as Descriptor, ur as Hint } from "./types-BHgJ1F6f.mjs";
2
- import { t as createApp } from "./index-w2uyRKkj.mjs";
3
- import { b as saveOf, v as WithGameState, y as memory } from "./types-DEYQF_tT.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-D6BrEwCf.mjs";
1
+ import { Jn as FeaturePlugin, Sr as Json, Xn as AnyFlow, dr as NodeFx, gr as FakeClock, mr as ClockSource, nr as NodeTable, or as Descriptor, ur as Hint } from "./types-vjWgmPqS.mjs";
2
+ import { t as createApp } from "./index-Cv5r0M9Y.mjs";
3
+ import { b as saveOf, v as WithGameState, y as memory } from "./types-VNoG7shY.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-oykCMFBV.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 { in as exit, p as flattenFeatures, rn as refuseStart, sn as type, t as createApp } from "./src-Ca8W8Dvv.mjs";
1
+ import { an as exit, cn as type, in as refuseStart, m as flattenFeatures, t as createApp } from "./src-tkKl-oCn.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 { Cn as MotionCause, En as ProjectionMotion, Hr as Api, Jt as TransformValue, Mn as Api$1, Mt as ViewportSize, Qr as Require, Sn as Motion, Sr as Json, T as Api$3, Tn as NumericFields, Zt as Api$2, fr as Answer, in as AnyComponentValue, jn as ViewHandle, ln as Entity, nn as AnyComponent, or as Descriptor, pr as Api$5, rn as AnyComponentType, s as Events$1, sn as ComponentType, t as Api$4, ur as Hint, vn as TagType, wn as MotionHandle, yn as ChangeHook } from "./types-BHgJ1F6f.mjs";
1
+ import { Cn as MotionCause, En as ProjectionMotion, Hr as Api, Jt as TransformValue, Mn as Api$1, Mt as ViewportSize, Qr as Require, Sn as Motion, Sr as Json, T as Api$3, Tn as NumericFields, Zt as Api$2, fr as Answer, in as AnyComponentValue, jn as ViewHandle, ln as Entity, nn as AnyComponent, or as Descriptor, pr as Api$5, rn as AnyComponentType, s as Events$1, sn as ComponentType, t as Api$4, ur as Hint, vn as TagType, wn as MotionHandle, yn as ChangeHook } from "./types-vjWgmPqS.mjs";
2
2
  import { Log } from "@moku-labs/common/browser";
3
3
  import { PluginCtx } from "@moku-labs/core";
4
4
 
@@ -1,5 +1,5 @@
1
- import { A as PixiSprite, An as TrackSegment, Hr as Api$1, Mn as Api$2, Nt as FilterCache, O as PixiFilter, On as ReducedMotion, Ot as FilterSlot, Qr as Require, Rr as Events$5, Sr as Json, T as Api$4, Tn as NumericFields, Zr as Events$2, Zt as Api$3, an as ComponentHandle, ar as TypeTag, in as AnyComponentValue, j as PixiTexture, jt as Point, k as PixiModule, kn as TrackOptions, kt as FilterSlotInputs, ln as Entity, nn as AnyComponent, or as Descriptor, s as Events$1, sn as ComponentType, t as Api$5, v as Events$4, wn as MotionHandle, xn as Ease, xr as Events$3, yr as Api$6 } from "./types-BHgJ1F6f.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-Bm7DVtA_.mjs";
1
+ import { A as PixiSprite, An as TrackSegment, Hr as Api$1, Mn as Api$2, Nt as FilterCache, O as PixiFilter, On as ReducedMotion, Ot as FilterSlot, Qr as Require, Rr as Events$5, Sr as Json, T as Api$4, Tn as NumericFields, Zr as Events$2, Zt as Api$3, an as ComponentHandle, ar as TypeTag, in as AnyComponentValue, j as PixiTexture, jt as Point, k as PixiModule, kn as TrackOptions, kt as FilterSlotInputs, ln as Entity, nn as AnyComponent, or as Descriptor, s as Events$1, sn as ComponentType, t as Api$5, v as Events$4, wn as MotionHandle, xn as Ease, xr as Events$3, yr as Api$6 } from "./types-vjWgmPqS.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-B6YgPkY8.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";
@@ -167,11 +167,19 @@ type Track = {
167
167
  */
168
168
  readonly reveals: "alpha" | "place" | "both" | undefined;
169
169
  /**
170
- * The patch the track writes, one per track with every field of `to` in it: a frame fills it in
171
- * place instead of building one. A field the frame leaves alone carries its stored value back.
172
- * Rebuilt when the track loses a field.
170
+ * The patch the track writes when a frame moves every field, one per track with every field of
171
+ * `to` in it: a frame fills it in place instead of building one. Rebuilt when the track loses a
172
+ * field.
173
173
  */
174
174
  patch: Record<string, unknown>;
175
+ /**
176
+ * The patch of a frame that moves only some fields (another writer holds one, or one stands
177
+ * still): exactly the fields `partialMoved` flags, filled in place by the next frame that moves
178
+ * the same ones and built again when they change, so a field the track lost, which never moves
179
+ * again, is never in it. `undefined` until the first such frame.
180
+ */
181
+ partial: Record<string, unknown> | undefined; /** The `moved` flags `partial` was built for, by slot. */
182
+ readonly partialMoved: Uint8Array;
175
183
  };
176
184
  /**
177
185
  * A motion handle that can also be advanced by hand: what the timeline cursor needs, so a track
@@ -1,5 +1,5 @@
1
- import { Sr as Json, jr as Snapshot } from "./types-BHgJ1F6f.mjs";
2
- import { t as HeadlessApp } from "./headless-D6BrEwCf.mjs";
1
+ import { Sr as Json, jr as Snapshot } from "./types-vjWgmPqS.mjs";
2
+ import { t as HeadlessApp } from "./headless-oykCMFBV.mjs";
3
3
  import { Log } from "@moku-labs/common/browser";
4
4
 
5
5
  //#region src/plugins/flow/doors/types.d.ts
@@ -1,7 +1,7 @@
1
- import { At as Orientation, Dr as PlayerStateProvider, E as Config$2, Jn as FeaturePlugin, Mr as SnapshotOf, Or as ProviderCall, Pn as Config$1, Sr as Json, Xn as AnyFlow, a as Config$3, ar as TypeTag, br as Config, d as Manifest, gr as FakeClock, k as PixiModule, kr as SaveDoc, mr as ClockSource, n as AssetsIo } from "./types-BHgJ1F6f.mjs";
2
- import { o as AudioContextLike, s as Config$4 } from "./types-fpFKYm6E.mjs";
3
- import { H as TextKey, I as I18nApi, V as StringTable } from "./types-Bm7DVtA_.mjs";
4
- import { Ct as audioPlugin, bt as effectsPlugin, dt as platformPlugin, i as screen, pt as PlatformProvider, t as createApp } from "./index-w2uyRKkj.mjs";
1
+ import { At as Orientation, Dr as PlayerStateProvider, E as Config$2, Jn as FeaturePlugin, Mr as SnapshotOf, Or as ProviderCall, Pn as Config$1, Sr as Json, Xn as AnyFlow, a as Config$3, ar as TypeTag, br as Config, d as Manifest, gr as FakeClock, k as PixiModule, kr as SaveDoc, mr as ClockSource, n as AssetsIo } from "./types-vjWgmPqS.mjs";
2
+ import { o as AudioContextLike, s as Config$4 } from "./types-CiTr21gu.mjs";
3
+ import { H as TextKey, I as I18nApi, V as StringTable } from "./types-B6YgPkY8.mjs";
4
+ import { ft as platformPlugin, i as screen, mt as PlatformProvider, t as createApp, wt as audioPlugin, xt as effectsPlugin } from "./index-Cv5r0M9Y.mjs";
5
5
  import { AnyPluginInstance } from "@moku-labs/core";
6
6
 
7
7
  //#region src/plugins/model/store/providers/memory.d.ts
@@ -3401,6 +3401,12 @@ type FeatureDescription = {
3401
3401
  textStyles?: FeatureTextStyles; /** Particle emitters the feature owns, read by `effects`. */
3402
3402
  emitters?: readonly FeatureEmitter[]; /** Filters the feature puts on its interface components, read by `effects`. */
3403
3403
  filters?: readonly FeatureFilter[];
3404
+ /**
3405
+ * The key of 0.15.3, removed: typed `never`, so a game that still writes it is told. A system
3406
+ * now runs while its query has an entity, and `scenes` on `system()` limits it to some scenes:
3407
+ * delete the key (world README, "When a system runs").
3408
+ */
3409
+ systemsRun?: never;
3404
3410
  [later: string]: unknown;
3405
3411
  };
3406
3412
  /**
@@ -5206,6 +5212,7 @@ type QueryTuple<Terms extends readonly QueryTerm[]> = [Entity, ...QueryValues<Te
5206
5212
  * const run = (entities: Iterable<[Entity]>, ctx: SystemContext): void => {
5207
5213
  * ctx.res(Pointer).x = 0;
5208
5214
  * ctx.time.delta; // 16
5215
+ * ctx.resumed; // false: the system ran in the frame before
5209
5216
  * };
5210
5217
  * ```
5211
5218
  */
@@ -5214,9 +5221,19 @@ type SystemContext = {
5214
5221
  res<Value extends object>(resource: ResourceType<Value>): Value;
5215
5222
  readonly snapshot: Snapshot;
5216
5223
  readonly time: Readonly<Time>;
5224
+ /**
5225
+ * True on the first run after one or more of this system's runs were skipped: its query had no entity, or none of
5226
+ * its `scenes` was mounted or leaving. Nothing was kept for it while it slept: `world.changed()` holds this frame's
5227
+ * changes only, so a system that caches what it drew, or remembers what it saw last, starts over from the
5228
+ * components when this is true. False on every other run. Read it during the run.
5229
+ */
5230
+ readonly resumed: boolean;
5217
5231
  };
5218
5232
  /**
5219
- * A system definition, typed over its query tuple.
5233
+ * A system definition, typed over its query tuple. A system with a query runs only while its query
5234
+ * can match: before each run the world looks at the store of every term, and when one of them holds
5235
+ * no entity the run is skipped (no walk, no `mut()` mark, no timing). A system without a query
5236
+ * always runs. `scenes` limits either kind to some scenes.
5220
5237
  *
5221
5238
  * @example
5222
5239
  * ```ts
@@ -5235,10 +5252,42 @@ type SystemDefinition<Terms extends readonly QueryTerm[]> = {
5235
5252
  readonly phase: WorldPhase;
5236
5253
  readonly query: Terms;
5237
5254
  /**
5238
- * Runs the system once a frame in its phase. `entities` walks the declared `query` once; every
5239
- * row it hands out is the same array, rewritten for the next row, so a row is valid until the
5240
- * next row. A system that keeps a row copies what it keeps: `const [entity, transform] = row`.
5241
- * `ecs.query()` called inside `run` hands out a new array per row.
5255
+ * The scenes the system runs on: it runs only while one of them is mounted or leaving. A scene
5256
+ * leaves from the switch that replaces it until nothing carries `Exiting` any more, so the exits
5257
+ * of its JSX elements play to the end; any exit counts, also one of the next scene, so a leave may
5258
+ * last longer than the scene's own exits. The next scene's entities already stand during a leave:
5259
+ * a query that matches them too hands them to the system, so it writes only its own scene's
5260
+ * entities. Left out, the system runs on every scene. Read once, when the system registers. A dev
5261
+ * build throws at start for a name no feature declares as a scene. For a system without a query,
5262
+ * or one whose entities stand on every screen.
5263
+ *
5264
+ * @example
5265
+ * ```ts
5266
+ * // features/board/world/systems/idle.ts: no query, so `scenes` alone keeps it to the board.
5267
+ * const BoardIdle = resource("BoardIdle", { ms: 0 });
5268
+ * export const idle = system({
5269
+ * name: "board.idle",
5270
+ * phase: "animate",
5271
+ * query: [],
5272
+ * scenes: ["board"],
5273
+ * run: (_rows, { res, time }) => {
5274
+ * res(BoardIdle).ms += time.delta;
5275
+ * }
5276
+ * });
5277
+ * // On the ward it is not run and BoardIdle.ms stands still. On the board it grows by each
5278
+ * // frame's delta. After the switch to the ward it runs while the board's elements play their
5279
+ * // exit, then not any more.
5280
+ * ```
5281
+ */
5282
+ readonly scenes?: readonly string[];
5283
+ /**
5284
+ * Runs the system once a frame in its phase, unless it is skipped: a term of its `query` has no
5285
+ * entity, or none of its `scenes` is mounted or leaving. `entities` walks the declared `query`
5286
+ * once; every row it hands out is the same array, rewritten for the next row, so a row is valid
5287
+ * until the next row. A system that keeps a row copies what it keeps:
5288
+ * `const [entity, transform] = row`. `ecs.query()` called inside `run` hands out a new array per
5289
+ * row. Work that must happen when the query has no entity (end a press, reset a resource) belongs
5290
+ * in a system without a query.
5242
5291
  */
5243
5292
  run(entities: Iterable<QueryTuple<Terms>>, ctx: SystemContext): void;
5244
5293
  };
@@ -5293,24 +5342,45 @@ type SystemFor<Player, Session> = <const Terms extends readonly QueryTerm[]>(def
5293
5342
  type AnySystem = {
5294
5343
  readonly name: string;
5295
5344
  readonly phase: WorldPhase;
5296
- readonly query: readonly QueryTerm[]; /** As `SystemDefinition.run`: one row array per walk, valid until the next row. */
5345
+ readonly query: readonly QueryTerm[]; /** As `SystemDefinition.scenes`: the scenes it runs on, every scene when left out. */
5346
+ readonly scenes?: readonly string[]; /** As `SystemDefinition.run`: one row array per walk, valid until the next row. */
5297
5347
  run(entities: Iterable<readonly unknown[]>, ctx: SystemContext): void;
5298
5348
  };
5349
+ /** One component store, keyed by entity: a component's value, `true` for a tag. */
5350
+ type ComponentStore = Map<Entity, object | true>;
5299
5351
  /**
5300
- * One registered system, the frame it was registered in, its query resolved once and the walk the
5301
- * runner resets for every run. A system registered during a frame runs from the next frame on.
5302
- * Spec 28 (deferred) extends it with the system's scope.
5352
+ * One registered system, the frame it was registered in, its query resolved once, the walk the
5353
+ * runner resets for every run, the stores its check reads and its scenes. A system registered
5354
+ * during a frame runs from the next frame on. Module state: no game reads it.
5303
5355
  */
5304
5356
  type SystemEntry = {
5305
5357
  readonly definition: AnySystem;
5306
5358
  readonly frame: number;
5307
5359
  readonly plan: QueryPlan;
5360
+ /**
5361
+ * The store of each term, in term order, kept once it exists: a store lives as long as the
5362
+ * systems of its world, so the check before a run reads sizes and looks nothing up.
5363
+ * `undefined` for a term no entity carried yet.
5364
+ */
5365
+ readonly stores: Array<ComponentStore | undefined>; /** The scenes it runs on, read once at registration; `undefined` for every scene. */
5366
+ readonly scenes: readonly string[] | undefined; /** Its last chance to run was skipped: the next run is told so with `resumed`. */
5367
+ skipped: boolean;
5308
5368
  /**
5309
5369
  * The walk of the declared query, made at registration; `undefined` for an empty query, which
5310
5370
  * the runner never walks. An entry built without one gets it on its first run.
5311
5371
  */
5312
5372
  walk?: SystemWalk | undefined;
5313
5373
  };
5374
+ /**
5375
+ * Which scene is mounted and which are still leaving, as `scenes` tells the world with
5376
+ * `ecs.setScene`: what a system with `scenes` runs on. Changed at a scene switch only; a phase
5377
+ * reads it.
5378
+ */
5379
+ type SceneState$1 = {
5380
+ /** The mounted scene, `undefined` before the first switch. */mounted: string | undefined; /** The scenes a switch replaced while something still carries `Exiting`, oldest first; no repeats. */
5381
+ leaving: string[]; /** The scene ids the features declare, read at start for the dev check of `scenes`; `undefined` before. */
5382
+ declared: ReadonlySet<string> | undefined;
5383
+ };
5314
5384
  /**
5315
5385
  * A structural change queued while a phase runs. Applied in call order when the phase ends.
5316
5386
  *
@@ -5363,7 +5433,8 @@ type PhaseContext = {
5363
5433
  /** The ecs API the systems of this world receive. */readonly world: EcsApi; /** The resource reader, one function per world. */
5364
5434
  readonly res: <Value extends object>(resource: ResourceType<Value>) => Value; /** The frozen model snapshot of the running frame. */
5365
5435
  snapshot: Snapshot; /** The running frame's `Time`. */
5366
- time: Readonly<Time>;
5436
+ time: Readonly<Time>; /** Written before every run: the system's last chance to run before this one was skipped. */
5437
+ resumed: boolean;
5367
5438
  };
5368
5439
  /**
5369
5440
  * The JSON kind of one component field, read from its default value: what the editor's component
@@ -5565,7 +5636,8 @@ type EcsState = {
5565
5636
  walkReported: boolean; /** The plans of `ecs.query()` by the type of their first term, made once per tuple of types. */
5566
5637
  queryPlans: Map<AnyComponentType, KnownPlan[]>; /** The entity lists of ended `ecs.query()` walks, taken by the next walks: no key copy per call. */
5567
5638
  walkLists: Entity[][]; /** How many entities were despawned since the world began: the sweep looks for dead elements when it moved. */
5568
- despawns: number;
5639
+ despawns: number; /** The mounted scene and the leaving ones, for the systems with `scenes`. */
5640
+ scene: SceneState$1;
5569
5641
  };
5570
5642
  /**
5571
5643
  * ecs module API, `app.world.ecs`: the screen as data. Plain-object components in one store per
@@ -5582,16 +5654,18 @@ type EcsState = {
5582
5654
  type EcsApi = {
5583
5655
  /**
5584
5656
  * Registers a system at the end of its phase list. A system registered during a frame runs
5585
- * from the next frame on.
5657
+ * from the next frame on. In every frame the system is skipped while a term of its query has no
5658
+ * entity, or while none of its `scenes` is mounted or leaving.
5586
5659
  *
5587
5660
  * @param definition - The system, built with `system()`.
5588
5661
  * @returns The remover; calling it twice is a no-op.
5589
- * @throws {Error} When a system of that name is already registered.
5662
+ * @throws {Error} When a system of that name is already registered, and in a dev build after
5663
+ * start for a name in `scenes` that no feature declares as a scene.
5590
5664
  * @example
5591
5665
  * ```ts
5592
5666
  * // `text` registers its layout system when the plugin starts.
5593
5667
  * const world = ctx.require(worldPlugin);
5594
- * const off = world.ecs.system(measureLabels); // runs from the next frame
5668
+ * const off = world.ecs.system(measureLabels); // runs from the next frame on which a label exists
5595
5669
  *
5596
5670
  * off(); // the plugin stops
5597
5671
  * ```
@@ -5897,6 +5971,24 @@ type EcsApi = {
5897
5971
  * ```
5898
5972
  */
5899
5973
  setMode(mode: WorldMode): void;
5974
+ /**
5975
+ * Tells the world which scene is mounted now, for the systems that list `scenes`. The scene
5976
+ * mounted before it, and any scene still leaving, keep their systems running until nothing
5977
+ * carries `Exiting` any more: the elements of their JSX views played their exit (the views themselves
5978
+ * go at the switch). Each system reads it
5979
+ * before its next run. The same scene again changes nothing. `scenes` calls it in the block that
5980
+ * mounts a scene; a game never needs to.
5981
+ *
5982
+ * @param scene - The id of the scene now mounted.
5983
+ * @example
5984
+ * ```ts
5985
+ * // scenes, in the block that replaces the ward with the board:
5986
+ * ctx.require(worldPlugin).ecs.setScene("board");
5987
+ * // In the next frame a system with scenes: ["board"] runs. One with scenes: ["ward"] runs
5988
+ * // until the ward's elements played their exit, then sleeps.
5989
+ * ```
5990
+ */
5991
+ setScene(scene: string): void;
5900
5992
  /**
5901
5993
  * The component type behind a name. A type registers itself on first use, so a name nobody
5902
5994
  * wrote, read or queried yet is unknown.
@@ -6800,6 +6892,12 @@ type KeptState = {
6800
6892
  verifySkipped: number; /** True while `bypass(true)` draws everything live for an extract. */
6801
6893
  bypassed: boolean; /** Render passes the last flush cost: the estimate `sync.renderPasses()` adds (P9.2). */
6802
6894
  flushPasses: number;
6895
+ /**
6896
+ * The frame `collect` read had no mark and no whole-frame reason: nothing a kept picture reads changed, so a kept
6897
+ * record that owes nothing is drawn from its picture as it stands, without its step (E5). Set by `collect`, spent by
6898
+ * the next flush.
6899
+ */
6900
+ calm: boolean;
6803
6901
  };
6804
6902
  //#endregion
6805
6903
  //#region src/plugins/renderer/viewport/types.d.ts
@@ -7900,6 +7998,12 @@ type SyncInternal = {
7900
7998
  */
7901
7999
  layerOf(entity: Entity): string | undefined; /** The overlays of this frame: modes, ranges, reasons, dims, HUD parts, and the pictures to take (spec 22). */
7902
8000
  stepOverlays(): void;
8001
+ /**
8002
+ * Hands Pixi again the filters of every view whose filters were switched on or off since they were written: Pixi
8003
+ * holds only the enabled ones (E3). Run by the draw callback before anything reads the tree, so a switch is drawn in
8004
+ * the frame it was made. Allocates nothing when no filter was switched.
8005
+ */
8006
+ stepFilters(): void;
7903
8007
  /**
7904
8008
  * The `Graphics` paths the engine drew since the last call (shapes, clip masks, nine-slice outlines), and zeroes the
7905
8009
  * count: the monitor's `stats().redraws` (spec 26 R2.3).
@@ -8229,14 +8333,16 @@ type SyncState = {
8229
8333
  overlay: OverlayState; /** `Graphics` paths drawn since the monitor last took them: shapes, clip masks, outlines (spec 26 R2.3). */
8230
8334
  redraws: number;
8231
8335
  /**
8232
- * Where the walk of `shown` stopped for the entities whose loops asked since the last sync pass (spec 26 R1.7.3):
8233
- * an entity with several endless loops is walked once a frame. Cleared by every pass, which may change the tree.
8336
+ * Where the walk of `shown` stopped for the entities whose loops asked (spec 26 R1.7.3), at the `passesVersion` it
8337
+ * was taken: an answer stands while the version does, so an entity with several endless loops is walked once, and a
8338
+ * still board not at all (E4). One record per entity, made at its first ask, dropped with its view.
8234
8339
  */
8235
- held: Map<Entity, Unseen>;
8340
+ held: Map<Entity, HeldUnseen>;
8236
8341
  /**
8237
- * Moves on with every change that may change the render passes of a frame: a filter set or forgotten, a node's
8238
- * `renderable` flipped, a view hung, wrapped or dropped (a pass that did work), a kept picture taken or let go, a
8239
- * write a plugin announced with `invalidate` (a filter switched on or off).
8342
+ * Moves on with every change that may change the render passes of a frame or where a walk of `shown` stops: a filter
8343
+ * set, forgotten or switched, a node's `renderable` flipped (every hidden reason, the alpha's too), a view hung,
8344
+ * moved, wrapped or dropped (a pass that did work), a kept picture taken or let go, a HUD factor, a new viewport, a
8345
+ * write a plugin announced with `invalidate`.
8240
8346
  */
8241
8347
  passesVersion: number; /** The filtered views' passes of `renderPassesOf`, counted at `passesVersion` `at` under `root`. */
8242
8348
  passes: PassCount; /** The name of the scene's HUD layer (`above: "overlays"`), kept with the layers; `undefined` without one. */
@@ -8256,6 +8362,11 @@ type OverdrawState = {
8256
8362
  matrix: PixiFilter | undefined;
8257
8363
  listeners: Array<(on: boolean) => void>;
8258
8364
  };
8365
+ /** Where the walk of `shown` stopped for one entity, and the `passesVersion` it was taken at. */
8366
+ type HeldUnseen = {
8367
+ answer: Unseen;
8368
+ at: number;
8369
+ };
8259
8370
  /**
8260
8371
  * The filtered views' part of the render passes, counted once and read every frame while nothing it reads changed: the
8261
8372
  * version and the root it was counted at, and every filter of the filter table with its `enabled` then (a plugin may
@@ -9193,9 +9304,9 @@ type HostState = {
9193
9304
  */
9194
9305
  uninstallPasses: (() => void) | undefined;
9195
9306
  /**
9196
- * Swaps Pixi's own bitmap text pipe back in. Set once per host state when the renderer's pipe,
9197
- * whose SDF shader applies the alpha once, went into Pixi's registry, so a restore reuses it;
9198
- * `undefined` while inert and when the module lacked the pieces.
9307
+ * Swaps Pixi's own bitmap text and batch pipes back in and drops the SDF batcher. Set once per host state when the
9308
+ * renderer's batched distance-field text went into Pixi's registry, so a restore reuses it; `undefined` while inert
9309
+ * and when the module lacked the pieces.
9199
9310
  */
9200
9311
  uninstallSdfText: (() => void) | undefined;
9201
9312
  /**
@@ -10408,9 +10519,9 @@ declare namespace types_d_exports$2 {
10408
10519
  * the render textures and matrices the kept pictures are drawn with (an `AlphaFilter` runs their pre-pass), and the
10409
10520
  * extension registry with the seven classes the counting of a dev or debug build swaps
10410
10521
  * (the three WebGPU draw classes, the filter system, both texture systems and the batcher pipe whose `buildStart`
10411
- * begins every instruction rebuild; production swaps the encoder alone, to count the passes) and the bitmap text
10412
- * pipe `host` swaps for one whose SDF shader applies the alpha once (with the WGSL and GLSL shader
10413
- * pieces it compiles that shader from). The module object
10522
+ * begins every instruction rebuild; production swaps the encoder alone, to count the passes), and the pieces of
10523
+ * batched distance-field text `host` installs: Pixi's `Batcher` with its geometry and buffers, the bitmap text pipe
10524
+ * and the batcher pipe it subclasses, and the WGSL and GLSL shader pieces of the batch's SDF shader. The module object
10414
10525
  * never arrives through a static import: `config.loadPixi()` returns it, so a game without a screen carries no
10415
10526
  * Pixi in its bundle.
10416
10527
  *
@@ -10422,10 +10533,11 @@ declare namespace types_d_exports$2 {
10422
10533
  * pixi.FilterSystem.extension.name; // "filter"
10423
10534
  * pixi.BatcherPipe.extension.name; // "batch"
10424
10535
  * pixi.BitmapTextPipe.extension.name; // "bitmapText"
10536
+ * pixi.ExtensionType.Batcher; // "batcher"
10425
10537
  * pixi.defaultFilterVert.startsWith("in vec2 aPosition;"); // true
10426
10538
  * ```
10427
10539
  */
10428
- type PixiModule = Pick<typeof import("pixi.js"), "AlphaFilter" | "Application" | "BatcherPipe" | "BitmapFont" | "BitmapText" | "BitmapTextPipe" | "BlurFilter" | "Bounds" | "Cache" | "ColorMatrixFilter" | "Container" | "DisplacementFilter" | "Filter" | "FilterSystem" | "GlProgram" | "GlTextureSystem" | "GpuBatchAdaptor" | "GpuEncoderSystem" | "GpuGraphicsAdaptor" | "GpuProgram" | "GpuTextureSystem" | "Graphics" | "Matrix" | "NineSliceSprite" | "NoiseFilter" | "Particle" | "ParticleContainer" | "Rectangle" | "RenderGroupPipe" | "RenderTexture" | "Shader" | "Sprite" | "Texture" | "TexturePool" | "UniformGroup" | "bitmapFontTextParser" | "bitmapFontXMLStringParser" | "colorBit" | "colorBitGl" | "compileHighShaderGlProgram" | "compileHighShaderGpuProgram" | "defaultFilterVert" | "extensions" | "generateTextureBatchBit" | "generateTextureBatchBitGl" | "getBatchSamplersUniformGroup" | "localUniformMSDFBit" | "localUniformMSDFBitGl" | "mSDFBit" | "mSDFBitGl" | "roundPixelsBit" | "roundPixelsBitGl">;
10540
+ type PixiModule = Pick<typeof import("pixi.js"), "AlphaFilter" | "Application" | "Batcher" | "BatcherPipe" | "BitmapFont" | "BitmapText" | "BitmapTextPipe" | "BlurFilter" | "Bounds" | "Buffer" | "BufferUsage" | "Cache" | "ColorMatrixFilter" | "Container" | "DefaultBatcher" | "DisplacementFilter" | "ExtensionType" | "Filter" | "FilterSystem" | "Geometry" | "GlProgram" | "GlTextureSystem" | "GpuBatchAdaptor" | "GpuEncoderSystem" | "GpuGraphicsAdaptor" | "GpuProgram" | "GpuTextureSystem" | "Graphics" | "Matrix" | "NineSliceSprite" | "NoiseFilter" | "Particle" | "ParticleContainer" | "Rectangle" | "RenderGroupPipe" | "RenderTexture" | "Shader" | "Sprite" | "Texture" | "TexturePool" | "UniformGroup" | "bitmapFontTextParser" | "bitmapFontXMLStringParser" | "colorBit" | "colorBitGl" | "compileHighShaderGlProgram" | "compileHighShaderGpuProgram" | "defaultFilterVert" | "extensions" | "generateTextureBatchBit" | "generateTextureBatchBitGl" | "getBatchSamplersUniformGroup" | "mSDFBit" | "mSDFBitGl" | "roundPixelsBit" | "roundPixelsBitGl">;
10429
10541
  /**
10430
10542
  * One Pixi application: renderer, canvas and stage.
10431
10543
  */
@@ -1,9 +1,9 @@
1
- import { Ir as Api$3, T as Api, Zt as Api$1, yr as Api$2 } from "./types-BHgJ1F6f.mjs";
2
- import { P as AnimApi, r as UiApi } from "./types-fpFKYm6E.mjs";
3
- import { j as InputApi } from "./types-Bm7DVtA_.mjs";
4
- import { r as Repro } from "./headless-D6BrEwCf.mjs";
5
- import { a as InputOf, r as ControlApp } from "./types-jiWJhLPE.mjs";
6
- import { t as commands } from "./commands-C_GccOFq.mjs";
1
+ import { Ir as Api$3, T as Api, Zt as Api$1, yr as Api$2 } from "./types-vjWgmPqS.mjs";
2
+ import { P as AnimApi, r as UiApi } from "./types-CiTr21gu.mjs";
3
+ import { j as InputApi } from "./types-B6YgPkY8.mjs";
4
+ import { r as Repro } from "./headless-oykCMFBV.mjs";
5
+ import { a as InputOf, r as ControlApp } from "./types-DY_wOvUF.mjs";
6
+ import { t as commands } from "./commands-CvWBaoEi.mjs";
7
7
 
8
8
  //#region src/visual/types.d.ts
9
9
  /** The base commands of the `/control` door, keyed by their short names. */
package/dist/visual.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-BvkKJOSz.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-B8ve4Qll.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/llms.txt CHANGED
@@ -101,6 +101,7 @@ function defineFeature(name: string, description: FeatureDescription): FeaturePl
101
101
  // contribute?: Record<string, { flow: AnyFlow; order: number; when?: (snapshot: Snapshot) => boolean }>;
102
102
  // features?: readonly FeaturePlugin[]; // sub-features, composed right after this one
103
103
  // projections?, systems?, components?, scenes?, assets?; // V2 keys, read by world, scenes and assets
104
+ // systemsRun?: never; // the 0.15.3 key, removed: a system runs while its query has an entity
104
105
  // animations?: readonly AnimationDefinition[]; // V3, read by anim
105
106
  // ui?: readonly ComponentDefinition[]; // V3, read by ui (defineComponent results)
106
107
  // strings?: Record<locale, CompiledMessages | (() => Promise<unknown>)>; // V3, read by i18n
@@ -527,6 +528,7 @@ The graph. Modules `runner`, `gate`, `inbox`, `fx`, `features`. Runner methods s
527
528
  - `app.assets`: `load(bundle)`, `unload(bundle)`, `isLoaded(bundle)`, `has(bundle)` (the manifest carries it, loaded or not), `texture(key)`, `font(key)`, `audio(key)`, `usage()`. Per bundle in a feature's `assets.ts`: `defineBundles({ ep01: { tier: "feature", release: "leave", mipmaps: ["items/**"] } })`. `release: "leave"` also unloads the bundle, with reason `"leave"`, at the next rest once nothing holds it: not pinned by the node entered, not named by the mounted scene, no node of its feature on the stack; a bundle the outgoing scene named leaves one rest later. The default `"budget"` leaves only under the texture budget. `mipmaps` (`true` or globs relative to `assets/`) uploads the textures with their full chain; such a texture stays loose in a pack. A sub-feature with resources gets its own bundles, named like its folder, with `dir` and `parent` in the manifest; a code-only one has none. `companions.add({ load(bundle), unload(bundle) })` adds what loads and unloads with every bundle; `i18n` adds the strings of a sub-feature that way, only when `assets` is composed. Events `assets:bundle-loaded`, `assets:bundle-progress`, `assets:bundle-unloaded` (`reason: "budget" | "request" | "leave"`), `assets:replaced` (dev). Config: `manifest`, `textureBudgetMb: 192`, `preloadDepth: 2`, `baseUrl`, `io`.
528
529
  - `resource(name, defaults)` clones plain JSON defaults into every world. `resource(name, () => value)` calls the factory once per world on first read, so the value may hold a `Map` or a function: `const Looks = resource("boardLooks", () => ({ shown: new Map<World.Entity, { look: string }>() }))`. A system keeps its own state there; `snapshot()` leaves a value that is not JSON out.
529
530
  - `Now` is the engine resource of the frame's moment: `world` writes `clock.now()` into it at start and first thing in every frame, headless too, so every system of a frame reads one moment: `const { now } = res(Now)`; a fake clock makes it exact. A system that shows time writes its component only when its picture changes. `snapshot().resources` holds `Now: { now }`. Reserved resource names: `Now`, `Pointer`, `AnimPlayer`, `UiCounters`; a game resource of one of them throws `[game] world: the resource name "Now" is the engine's (the frame's moment).`
531
+ - When a system runs: before each run the world checks it. A system with a `query` is skipped while a term of its query has no entity (the smallest store among the terms is empty): no walk, no `mut()` mark, no timing. A system without a query always runs. `system({ ..., scenes: ["board"] })` runs only while one of those scenes is mounted or leaving: `scenes` calls `app.world.ecs.setScene(id)` at every switch, and the scene before leaves until nothing carries `Exiting` (the elements of its JSX views played their exit; the next scene's entities already stand then, so a `scenes` system writes only its own scene's entities). A dev build throws at start for a name in `scenes` no feature declares: `[game] System "board.idle" runs on the scene "bord", which no feature declares.` `ctx.resumed` is true on the first run after a skip (a cache or a remembered cue starts over then). The same for every system, the engine's included; 0 B a frame. A run with no rows does not happen any more: work a system did besides its rows (a hover, a drop or a press that ends, a resource reset, something that outlives its entities) goes to a system with `query: []` and `scenes`, reading its rows with `world.query()`. From 0.15.3: delete `systemsRun` from every feature (the type refuses it), rewrite the systems that work outside their rows, add `scenes` only to a system whose entities stand on every screen; `ecs.hold` and `ecs.isActive` are gone (a test asks `app.scenes.current()` or whether the system ran). World README, "When a system runs".
530
532
  - Motion hooks are told why they play: `enter(view, item, hint, cause)` and `exit(view, item, hint, cause)` get `World.MotionCause`, `"mount"` (the view comes or goes with its screen: a mount, an unmount, a load, a restore, a paused or fast world) or `"change"` (a commit). A world projection plays them only for `"change"`; `ui` plays them for both. `app.world.projection.causeOf(entity)` answers how a view came or how it is leaving, also in a removal hook of its despawn, until the next frame.
531
533
  - `app.world.projection.replace(spec)` swaps the spec of a registered projection; a mounted one runs its new `view` on the next frame. An unknown name throws. The caller is the dev hot swap.
532
534
  - `input`: one followed pointer. A finger that has not started a gesture (pressed, inside the tap slop, no long press, no trace) gives way to the next finger that goes down, wherever it rests, and its press is cancelled; a finger that started a gesture keeps it. `Pointer.id` is the followed `pointerId` (`-1` at rest): a system that measures the finger's travel starts over when it changes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moku-labs/game",
3
- "version": "0.15.2",
3
+ "version": "0.15.4",
4
4
  "description": "2D puzzle game engine on TypeScript and PixiJS, built on @moku-labs/core.",
5
5
  "type": "module",
6
6
  "sideEffects": [