@moku-labs/game 0.15.1 → 0.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3365,12 +3365,31 @@ type FeatureTextStyles = {
3365
3365
  readonly kind: "textStyles";
3366
3366
  readonly map: Record<string, object>;
3367
3367
  };
3368
+ /**
3369
+ * When the systems of a feature run. `"always"` (the default): every frame, as before. `"active"`: only while the
3370
+ * feature is active — a node of it is on the flow stack, a scene it declares is mounted, a view of a projection it
3371
+ * registered exists, or `ui` holds a popup or a JSX root of it — leaving included, until the last view is gone.
3372
+ * Skipping changes nothing the flow sees: systems never write the model. The systems the engine's plugins
3373
+ * register always run.
3374
+ *
3375
+ * @example
3376
+ * ```ts
3377
+ * // features/board/index.ts: the board's four systems stop on the ward and on the splash.
3378
+ * export const boardFeature = defineFeature("board", {
3379
+ * flows: [mergeBoard],
3380
+ * systems: [looks, fade, leaving, veil],
3381
+ * systemsRun: "active"
3382
+ * });
3383
+ * ```
3384
+ */
3385
+ type SystemsRun = "always" | "active";
3368
3386
  /**
3369
3387
  * What a feature brings to the game. The logic keys are typed here; the keys of later milestones
3370
3388
  * pass through the index signature until their plugin types them. `flow` stores them untouched,
3371
3389
  * and `logicOnly` drops them. The V2 screen plugins read five of them through the index signature:
3372
3390
  * `projections`, `systems` and `components` (`world`), `scenes` (`scenes`, `assets`, and the
3373
- * scene-id check of `flow`) and `assets` (`assets`). The V3 interface keys are typed below.
3391
+ * scene-id check of `flow`) and `assets` (`assets`). `world` also reads the typed `systemsRun`.
3392
+ * The V3 interface keys are typed below.
3374
3393
  *
3375
3394
  * @example
3376
3395
  * ```ts
@@ -3400,7 +3419,8 @@ type FeatureDescription = {
3400
3419
  strings?: Record<string, CompiledMessagesLike | (() => Promise<unknown>)>; /** Text styles the feature owns, read by `text`. */
3401
3420
  textStyles?: FeatureTextStyles; /** Particle emitters the feature owns, read by `effects`. */
3402
3421
  emitters?: readonly FeatureEmitter[]; /** Filters the feature puts on its interface components, read by `effects`. */
3403
- filters?: readonly FeatureFilter[];
3422
+ filters?: readonly FeatureFilter[]; /** When the feature's systems run, read by `world`. Absent is `"always"`. */
3423
+ systemsRun?: SystemsRun;
3404
3424
  [later: string]: unknown;
3405
3425
  };
3406
3426
  /**
@@ -3600,7 +3620,7 @@ declare function to<const TargetName extends string, Payload, Output>(target: Ta
3600
3620
  */
3601
3621
  declare function slot(name: string): SlotNode;
3602
3622
  declare namespace types_d_exports$4 {
3603
- export { Allow, Answer, AnyFlow, AnyNode, AnyNodeContext, Api$3 as Api, Bookmark, BundlesOf, CheckedEdges, Config$4 as Config, Contribution, DefineNode, Deps$4 as Deps, Descriptor, Edges, Effect, EffectHandler, EffectOptions, EmitterIdOf, EnterCallback, Events$4 as Events, Exit, FeatureDescription, FeatureEmitter, FeatureFilter, FeaturePlugin, FeatureTree, FeaturesApi, FlowCtx, FlowDefinition, FlowEntry, FlowGraph, FlowKit, FlowSpec, FlowState, FxApi, FxHandler, GameState, GameTypes, GateApi, GraphError, GraphNode, GuideOptions, Hint, HudKeysOf, InboxApi, JournalEntry, KernelSlice$4 as KernelSlice, LifecycleChanged, Mapped, NodeContext, NodeDefinition, NodeFx, NodeInfo, NodeSpec, NodeTable, OutcomeTags, Position, RecoverContext, RegisteredFeature, Result, RouteStep, RunnerApi, SceneIdOf, SlotNode, Stage, State$4 as State, StringTableLike, Target, TextStylesOf, TypeTag, WorldEvent };
3623
+ export { Allow, Answer, AnyFlow, AnyNode, AnyNodeContext, Api$3 as Api, Bookmark, BundlesOf, CheckedEdges, Config$4 as Config, Contribution, DefineNode, Deps$4 as Deps, Descriptor, Edges, Effect, EffectHandler, EffectOptions, EmitterIdOf, EnterCallback, Events$4 as Events, Exit, FeatureDescription, FeatureEmitter, FeatureFilter, FeaturePlugin, FeatureTree, FeaturesApi, FlowCtx, FlowDefinition, FlowEntry, FlowGraph, FlowKit, FlowSpec, FlowState, FxApi, FxHandler, GameState, GameTypes, GateApi, GraphError, GraphNode, GuideOptions, Hint, HudKeysOf, InboxApi, JournalEntry, KernelSlice$4 as KernelSlice, LifecycleChanged, Mapped, NodeContext, NodeDefinition, NodeFx, NodeInfo, NodeSpec, NodeTable, OutcomeTags, Position, RecoverContext, RegisteredFeature, Result, RouteStep, RunnerApi, SceneIdOf, SlotNode, Stage, State$4 as State, StringTableLike, SystemsRun, Target, TextStylesOf, TypeTag, WorldEvent };
3604
3624
  }
3605
3625
  /**
3606
3626
  * flow plugin events.
@@ -4275,7 +4295,8 @@ type Cause = "edge" | "rollback" | "restore" | "load" | "mount" | "rerun";
4275
4295
  type View$1 = {
4276
4296
  entity: Entity;
4277
4297
  projection: string;
4278
- key: string;
4298
+ key: string; /** `{ projection, key }`, made once with the view: what `keyOf` answers, every call the same object. */
4299
+ readonly address: ProjectionKey;
4279
4300
  item: unknown; /** The last output of `view(item)`, by component name: what the picture equals at rest. */
4280
4301
  rest: Map<string, AnyComponentValue>;
4281
4302
  handles: MotionHandle[];
@@ -4363,6 +4384,13 @@ type Dirty = {
4363
4384
  roots: Set<Root>;
4364
4385
  force: boolean;
4365
4386
  };
4387
+ /**
4388
+ * A mute's fields joined with a type's owned fields, and the owned set they were joined with.
4389
+ */
4390
+ type JoinedFields = {
4391
+ readonly owned: ReadonlySet<string>;
4392
+ readonly joined: ReadonlySet<string>;
4393
+ };
4366
4394
  /**
4367
4395
  * projection module state.
4368
4396
  */
@@ -4386,10 +4414,28 @@ type ProjectionState = {
4386
4414
  * entity that is gone is dropped with its rest pose, and its side of `keys` with it.
4387
4415
  */
4388
4416
  keysByEntity: Map<Entity, ProjectionKey>; /** Entity to component name to the fields another writer owns. */
4389
- mutes: Map<Entity, Map<string, Set<string>>>; /** The `onConverged` listeners: the owners of elements, told after a restore or a load. */
4417
+ mutes: Map<Entity, Map<string, Set<string>>>; /** The owned fields of each component type as a set, by the type's frozen `owned` list: made once. */
4418
+ ownedSets: WeakMap<readonly string[], ReadonlySet<string>>; /** The muted and the owned fields joined, by the mute's field set: dropped when `mute()` or its release changes it. */
4419
+ joinedMutes: WeakMap<ReadonlySet<string>, JoinedFields>; /** The `onConverged` listeners: the owners of elements, told after a restore or a load. */
4390
4420
  converged: Array<() => void>;
4391
4421
  offHints: Array<() => void>; /** The cause of every view despawned since the last sweep, so a removal hook can still ask. */
4392
4422
  leaving: Map<Entity, MotionCause>;
4423
+ /**
4424
+ * Moves on every time a view enters `live`, leaves it, or leaves `leaving`, and on a clear:
4425
+ * `ui` hosts the views of a projection again only when it moved (`projection.membershipVersion()`).
4426
+ */
4427
+ membershipVersion: number;
4428
+ /**
4429
+ * A live view may hold a running handle: set by every view handle made, cleared by a sweep that
4430
+ * walked the live views and found none moving. While it is false the sweep walks no live view.
4431
+ */
4432
+ moving: boolean; /** Views were marked as owing their loop since the last start of the owed loops. */
4433
+ owedLoops: number;
4434
+ /**
4435
+ * The despawn count of the ecs when the sweep last looked for dead elements; -1 after a new
4436
+ * key, so the next sweep looks.
4437
+ */
4438
+ sweptDespawns: number;
4393
4439
  };
4394
4440
  /**
4395
4441
  * projection module API, `app.world.projection`: the bridge from the model to entities.
@@ -4543,7 +4589,8 @@ type ProjectionApi = {
4543
4589
  lift(entity: Entity, on: boolean): void;
4544
4590
  /**
4545
4591
  * The projection and key of an entity. Also answers for a view in the despawn queue and for an
4546
- * element registered with `registerKey`.
4592
+ * element registered with `registerKey`. A view answers the address it keeps for its life, the
4593
+ * same frozen object every call, so asking every frame allocates nothing.
4547
4594
  *
4548
4595
  * @param entity - The entity to ask about.
4549
4596
  * @returns The projection name and the key, or `undefined`.
@@ -4551,10 +4598,27 @@ type ProjectionApi = {
4551
4598
  * ```ts
4552
4599
  * // `renderer.sync` labels its display objects for the inspector.
4553
4600
  * app.world.projection.keyOf(1_048_576); // { projection: "board.items", key: "i7" }
4601
+ * app.world.projection.keyOf(1_048_576) === app.world.projection.keyOf(1_048_576); // true
4554
4602
  * app.world.projection.keyOf(42); // undefined: not a view
4555
4603
  * ```
4556
4604
  */
4557
4605
  keyOf(entity: Entity): ProjectionKey | undefined;
4606
+ /**
4607
+ * A number that moves every time a view enters the live views of a mounted projection, leaves
4608
+ * them (an exit or a despawn), or is forgotten after its despawn, and when the projections are
4609
+ * cleared. An equal number means the same views live as at the last read, so a plugin that
4610
+ * works on the live views (`ui` hosting them in an element) skips its step while it holds.
4611
+ * Reading it allocates nothing.
4612
+ *
4613
+ * @returns The version; 0 for a world where no view ever came or went.
4614
+ * @example
4615
+ * ```ts
4616
+ * // ui, at the start of its hosting step: nothing to do while no view came or went.
4617
+ * const version = ctx.require(worldPlugin).projection.membershipVersion(); // 7, as on the last frame
4618
+ * if (version === state.hostedMembership) return;
4619
+ * ```
4620
+ */
4621
+ membershipVersion(): number;
4558
4622
  /**
4559
4623
  * How the view of an entity came, or how it is leaving: `"mount"` when a direct reconcile or an unmount moved it,
4560
4624
  * `"change"` when a live commit did. A despawned view still answers until the next sweep, so a hook on its removal
@@ -4799,6 +4863,81 @@ type QueryPlan = {
4799
4863
  readonly names: readonly string[];
4800
4864
  readonly written: readonly string[];
4801
4865
  };
4866
+ /**
4867
+ * The walk of one system's declared query, made once when the system registers and reset by the
4868
+ * runner before every run. It allocates nothing per run: the entity list and the store list are
4869
+ * kept and overwritten by index, and every row it yields is the same array, written in place.
4870
+ * A row is valid until the next row; a system that keeps one copies it.
4871
+ */
4872
+ declare class SystemWalk implements Iterator<readonly unknown[], undefined> {
4873
+ private readonly ctx;
4874
+ /** The step handed back for every row: always the one row array. */
4875
+ private readonly step;
4876
+ /** The one row: the entity, then one stored value per name, sized at registration. */
4877
+ private readonly row;
4878
+ /** The component names of the terms, in order. */
4879
+ private readonly names;
4880
+ /** The names of the `mut()` terms, marked for every yielded row. */
4881
+ private readonly written;
4882
+ /** The store of each name, read once per run at the first step; `undefined` for a name no entity carried yet. */
4883
+ private readonly stores;
4884
+ /** The matching entities of this run, from index 0 to `count`; kept and overwritten by index. */
4885
+ private readonly entities;
4886
+ /** How many entities this run collected. */
4887
+ private count;
4888
+ /** The next entity to visit. */
4889
+ private index;
4890
+ /** Whether this run took its entities yet. */
4891
+ private started;
4892
+ /** The first store's size at the first step: a dev build compares it; -1 when not watched. */
4893
+ private size;
4894
+ /**
4895
+ * Prepares the walk of one system.
4896
+ *
4897
+ * @param ctx - Domain context of the world plugin.
4898
+ * @param plan - The system's resolved query.
4899
+ */
4900
+ constructor(ctx: WorldCtx, plan: QueryPlan);
4901
+ /**
4902
+ * The walk is its own iterator, so the runner hands it to `run` as the rows. A second loop over
4903
+ * it in the same run finds it walked.
4904
+ *
4905
+ * @returns This walk.
4906
+ */
4907
+ [Symbol.iterator](): SystemWalk;
4908
+ /**
4909
+ * Starts a new run: nothing is read before the first step.
4910
+ *
4911
+ * @returns This walk, the rows of the run.
4912
+ */
4913
+ reset(): SystemWalk;
4914
+ /**
4915
+ * Keeps one key of the first store when the entity carries every other name.
4916
+ *
4917
+ * @param entity - The key.
4918
+ */
4919
+ keep(entity: Entity): void;
4920
+ /**
4921
+ * Hands out the next row: the next collected entity, its values written into the one row, and
4922
+ * marked for every `mut()` name.
4923
+ *
4924
+ * @returns The step of the row, or the end.
4925
+ */
4926
+ next(): IteratorResult<readonly unknown[], undefined>;
4927
+ /**
4928
+ * Reads the stores of this run and collects the entities that carry every name, in the first
4929
+ * store's order. Structural changes are queued until the phase ends, so the matches stay true
4930
+ * while the rows are consumed.
4931
+ */
4932
+ private start;
4933
+ /**
4934
+ * Writes the row of one entity in place: the entity, then the value of every name.
4935
+ *
4936
+ * @param entity - The entity.
4937
+ * @returns False when the entity no longer carries a name, and the row is not handed out.
4938
+ */
4939
+ private fill;
4940
+ }
4802
4941
  //#endregion
4803
4942
  //#region src/plugins/world/ecs/types.d.ts
4804
4943
  /**
@@ -5087,6 +5226,7 @@ type QueryTuple<Terms extends readonly QueryTerm[]> = [Entity, ...QueryValues<Te
5087
5226
  * const run = (entities: Iterable<[Entity]>, ctx: SystemContext): void => {
5088
5227
  * ctx.res(Pointer).x = 0;
5089
5228
  * ctx.time.delta; // 16
5229
+ * ctx.resumed; // false: the system ran in the frame before
5090
5230
  * };
5091
5231
  * ```
5092
5232
  */
@@ -5095,6 +5235,13 @@ type SystemContext = {
5095
5235
  res<Value extends object>(resource: ResourceType<Value>): Value;
5096
5236
  readonly snapshot: Snapshot;
5097
5237
  readonly time: Readonly<Time>;
5238
+ /**
5239
+ * True on the first run after one or more runs of this system were skipped because its feature was not active
5240
+ * (`systemsRun: "active"`). Nothing was kept for it while it slept: `world.changed()` holds this frame's changes
5241
+ * only, so a system that caches what it drew rebuilds from the components when this is true. Always false for a
5242
+ * system that always runs. Read it during the run.
5243
+ */
5244
+ readonly resumed: boolean;
5098
5245
  };
5099
5246
  /**
5100
5247
  * A system definition, typed over its query tuple.
@@ -5115,6 +5262,12 @@ type SystemDefinition<Terms extends readonly QueryTerm[]> = {
5115
5262
  readonly name: string;
5116
5263
  readonly phase: WorldPhase;
5117
5264
  readonly query: Terms;
5265
+ /**
5266
+ * Runs the system once a frame in its phase. `entities` walks the declared `query` once; every
5267
+ * row it hands out is the same array, rewritten for the next row, so a row is valid until the
5268
+ * next row. A system that keeps a row copies what it keeps: `const [entity, transform] = row`.
5269
+ * `ecs.query()` called inside `run` hands out a new array per row.
5270
+ */
5118
5271
  run(entities: Iterable<QueryTuple<Terms>>, ctx: SystemContext): void;
5119
5272
  };
5120
5273
  /**
@@ -5168,23 +5321,52 @@ type SystemFor<Player, Session> = <const Terms extends readonly QueryTerm[]>(def
5168
5321
  type AnySystem = {
5169
5322
  readonly name: string;
5170
5323
  readonly phase: WorldPhase;
5171
- readonly query: readonly QueryTerm[];
5324
+ readonly query: readonly QueryTerm[]; /** As `SystemDefinition.run`: one row array per walk, valid until the next row. */
5172
5325
  run(entities: Iterable<readonly unknown[]>, ctx: SystemContext): void;
5173
5326
  };
5174
5327
  /**
5175
- * One registered system, the frame it was registered in and its query resolved once. A system
5176
- * registered during a frame runs from the next frame on. Spec 28 (deferred) extends it with the
5177
- * system's scope.
5178
- *
5179
- * @example
5180
- * ```ts
5181
- * const entry: SystemEntry = { definition: bobSystem, frame: 12, plan: { names: ["Transform"], written: ["Transform"] } };
5182
- * ```
5328
+ * One registered system, the frame it was registered in, its query resolved once, the walk the
5329
+ * runner resets for every run and its scope. A system registered during a frame runs from the
5330
+ * next frame on. Module state: no game reads it.
5183
5331
  */
5184
5332
  type SystemEntry = {
5185
5333
  readonly definition: AnySystem;
5186
5334
  readonly frame: number;
5187
5335
  readonly plan: QueryPlan;
5336
+ /**
5337
+ * The index of its feature in `ScopeState` for a system of a feature with `systemsRun: "active"`, -1 for a
5338
+ * system that always runs.
5339
+ */
5340
+ readonly scope: number; /** The system's last chance to run was skipped because its feature was not active. */
5341
+ skipped: boolean;
5342
+ /**
5343
+ * The walk of the declared query, made at registration; `undefined` for an empty query, which
5344
+ * the runner never walks. An entry built without one gets it on its first run.
5345
+ */
5346
+ walk?: SystemWalk | undefined;
5347
+ };
5348
+ /**
5349
+ * Which features are active, kept so a phase reads one byte per scoped system. Indexed by the feature's position in
5350
+ * `flow.features.all()`. Filled in `onStart`, sized once; nothing in it grows per frame.
5351
+ */
5352
+ type ScopeState = {
5353
+ /** Feature names by index, registration order. */names: string[]; /** Feature name to index. */
5354
+ index: Map<string, number>; /** Projection name to the index of the feature that registered it (rule V). */
5355
+ projections: Map<string, number>; /** Flow id to node name to the owner's index (rule N); built from one `describe()` when first needed. */
5356
+ owners: Map<string, Map<string, number>> | undefined; /** `describe()` threw: every feature counts as on the stack while the stack is not empty (fail-safe). */
5357
+ ownersFailed: boolean; /** The `flow.state()` object the stack flags were read from. */
5358
+ flow: FlowState | undefined; /** 1 while a frame of the stack addresses a node the feature owns. */
5359
+ onStack: Uint8Array; /** The holds `scenes` and `ui` keep on the feature. */
5360
+ holds: Int32Array; /** The live and leaving views of the projections the feature registered. */
5361
+ views: Int32Array; /** 1 while the feature is active, as of the last evaluation. */
5362
+ active: Uint8Array; /** A hold or a view count moved since the last evaluation. */
5363
+ dirty: boolean; /** At least one registered system runs only while its feature is active. */
5364
+ scoped: boolean;
5365
+ /**
5366
+ * Moves on at every start and every stop: a hold's release remembers the generation it was
5367
+ * taken in, and a release from an older one changes nothing (spec 28 W7.1).
5368
+ */
5369
+ generation: number;
5188
5370
  };
5189
5371
  /**
5190
5372
  * A structural change queued while a phase runs. Applied in call order when the phase ends.
@@ -5223,17 +5405,24 @@ type Command = {
5223
5405
  */
5224
5406
  type StructuralHook = (entity: Entity, value: unknown) => void;
5225
5407
  /**
5226
- * The frozen model snapshot of one frame, kept so four phases read it once.
5227
- *
5228
- * @example
5229
- * ```ts
5230
- * const cached: FrameSnapshot = { frame: 12, snapshot: { player: {}, session: {}, rng: rngState } };
5231
- * ```
5408
+ * The frozen model snapshot of one frame, kept so four phases read it once. One object per world,
5409
+ * rewritten when a new frame reads its snapshot.
5232
5410
  */
5233
5411
  type FrameSnapshot = {
5234
5412
  frame: number;
5235
5413
  snapshot: Snapshot;
5236
5414
  };
5415
+ /**
5416
+ * The context the runner hands every system of one world: one object, made at the first phase
5417
+ * run, whose `time` and `snapshot` are rewritten for every phase.
5418
+ */
5419
+ type PhaseContext = {
5420
+ /** The ecs API the systems of this world receive. */readonly world: EcsApi; /** The resource reader, one function per world. */
5421
+ readonly res: <Value extends object>(resource: ResourceType<Value>) => Value; /** The frozen model snapshot of the running frame. */
5422
+ snapshot: Snapshot; /** The running frame's `Time`. */
5423
+ time: Readonly<Time>; /** Written before every run: the system's runs before this one were skipped for its scope. */
5424
+ resumed: boolean;
5425
+ };
5237
5426
  /**
5238
5427
  * The JSON kind of one component field, read from its default value: what the editor's component
5239
5428
  * palette shows next to the field name. A nested shape is not described; `defaults` carries it.
@@ -5380,6 +5569,24 @@ type MarkCount = {
5380
5569
  marked: number;
5381
5570
  changed: number;
5382
5571
  };
5572
+ /**
5573
+ * The entities marked changed for one component in the current frame, each once, in mark order.
5574
+ * Both collections are kept from frame to frame, so a frame's marks allocate nothing once they
5575
+ * have grown to its size.
5576
+ */
5577
+ type ChangeList = {
5578
+ /** The marked entities of this frame, in mark order: what `changed()` hands out. */readonly entities: Entity[]; /** Entity to the frame stamp of its last mark; a stamp of the current frame is a repeat. */
5579
+ readonly frames: Map<Entity, number>;
5580
+ };
5581
+ /**
5582
+ * A plan `ecs.query()` remembers: the plan, and the type objects and `mut()` places it was made
5583
+ * for, compared by identity at every call.
5584
+ */
5585
+ type KnownPlan = {
5586
+ readonly plan: QueryPlan;
5587
+ readonly types: readonly AnyComponentType[];
5588
+ readonly written: readonly boolean[];
5589
+ };
5383
5590
  /**
5384
5591
  * ecs module state.
5385
5592
  */
@@ -5389,8 +5596,10 @@ type EcsState = {
5389
5596
  owners: Map<Entity, Owner>; /** Key is `"kind:name"` of the owner. */
5390
5597
  byOwner: Map<string, Set<Entity>>;
5391
5598
  types: Map<string, AnyComponentType>;
5392
- stores: Map<string, Map<Entity, object | true>>;
5393
- resources: Map<string, object>;
5599
+ stores: Map<string, Map<Entity, object | true>>; /** The store of each type object that was read, written or asked through, once it has one. */
5600
+ typeStores: Map<AnyComponentType, Map<Entity, object | true>>;
5601
+ resources: Map<string, object>; /** The value of each resource type object that was read, so a read is one lookup. */
5602
+ resourceSlots: Map<ResourceType<object>, object>;
5394
5603
  /**
5395
5604
  * The type object stored under each engine resource name (`"Now"`, `"Pointer"`, …), so a game
5396
5605
  * resource of the same name is refused instead of sharing the engine's value.
@@ -5398,18 +5607,24 @@ type EcsState = {
5398
5607
  engineResources: Map<string, object>;
5399
5608
  systems: Record<WorldPhase, SystemEntry[]>;
5400
5609
  running: WorldPhase | undefined;
5401
- commands: Command[];
5402
- changed: Map<string, Set<Entity>>;
5610
+ commands: Command[]; /** The change list of each component marked since the world began, emptied at every `signals`. */
5611
+ changed: Map<string, ChangeList>; /** The stamp of the current frame's marks, moved on by every clear of the change lists. */
5612
+ changeFrame: number;
5403
5613
  added: Map<string, StructuralHook[]>;
5404
5614
  removed: Map<string, StructuralHook[]>;
5405
5615
  ownerLeft: Array<(owner: Owner) => void>;
5406
5616
  mode: WorldMode;
5407
5617
  offFrame: Array<() => void>;
5408
- frameSnapshot: FrameSnapshot | undefined; /** The frame history: dev builds only, from the first frame on; `undefined` before it. */
5618
+ frameSnapshot: FrameSnapshot | undefined; /** The context of every system run of this world; `undefined` before the first phase ran. */
5619
+ phaseContext: PhaseContext | undefined; /** The frame history: dev builds only, from the first frame on; `undefined` before it. */
5409
5620
  history: History | undefined; /** Time per system of an agent build (H2b); `undefined` without the flag and before start. */
5410
5621
  timing: SystemTiming | undefined; /** The row of each timed system in `timing`, by name: a system that comes back keeps its row. */
5411
5622
  timingSlots: Map<string, number>; /** A dev build reported a store whose keys changed while a phase walked it: reported once. */
5412
- walkReported: boolean;
5623
+ walkReported: boolean; /** The plans of `ecs.query()` by the type of their first term, made once per tuple of types. */
5624
+ queryPlans: Map<AnyComponentType, KnownPlan[]>; /** The entity lists of ended `ecs.query()` walks, taken by the next walks: no key copy per call. */
5625
+ walkLists: Entity[][]; /** How many entities were despawned since the world began: the sweep looks for dead elements when it moved. */
5626
+ despawns: number; /** Which features are active, for the systems of the features with `systemsRun: "active"`. */
5627
+ scope: ScopeState;
5413
5628
  };
5414
5629
  /**
5415
5630
  * ecs module API, `app.world.ecs`: the screen as data. Plain-object components in one store per
@@ -5441,6 +5656,40 @@ type EcsApi = {
5441
5656
  * ```
5442
5657
  */
5443
5658
  system(definition: AnySystem): () => void;
5659
+ /**
5660
+ * Keeps a feature active while something of it is shown that the world cannot see: `scenes` holds the feature that
5661
+ * declares the mounted scene, `ui` the feature of each popup or JSX root it holds. Holds are counted; the returned
5662
+ * release is idempotent. A name that is not a registered feature holds nothing (a dev warning
5663
+ * `world:hold-unknown-feature`). Takes effect at the next phase that runs systems.
5664
+ *
5665
+ * @param feature - The feature to keep active.
5666
+ * @returns The release.
5667
+ * @example
5668
+ * ```ts
5669
+ * // scenes, as it mounts the scene "ward" that the feature "screens" declares:
5670
+ * const release = ctx.require(worldPlugin).ecs.hold("screens");
5671
+ * app.world.ecs.isActive("screens"); // true
5672
+ * release(); // the next scene replaced the ward
5673
+ * app.world.ecs.isActive("screens"); // false: no node, view or hold of "screens" is left
5674
+ * ```
5675
+ */
5676
+ hold(feature: string): () => void;
5677
+ /**
5678
+ * Whether a feature is active now: a node of it is on the flow stack, a scene it declares is mounted, a view of a
5679
+ * projection it registered exists (leaving included), or `ui` holds a popup or JSX root of it. Answers for any
5680
+ * feature, whatever its `systemsRun`; the systems of a feature with `systemsRun: "active"` run exactly while this
5681
+ * is true. False for a name that is not a feature.
5682
+ *
5683
+ * @param feature - The feature name.
5684
+ * @returns True while it is active.
5685
+ * @example
5686
+ * ```ts
5687
+ * // A test of the board: the graph rests at the board's awaitIntent and the shop sheet is closed.
5688
+ * app.world.ecs.isActive("board"); // true: a node of the board is on the stack, its views are drawn
5689
+ * app.world.ecs.isActive("shop"); // false: no view of the sheet, no node of the shop on the stack
5690
+ * ```
5691
+ */
5692
+ isActive(feature: string): boolean;
5444
5693
  /**
5445
5694
  * Creates an entity. The id is reserved and returned at once, also inside a phase, where the
5446
5695
  * components are attached when the phase ends.
@@ -5590,8 +5839,10 @@ type EcsApi = {
5590
5839
  * Walks the store of the FIRST term in insertion order and keeps the entities that carry every
5591
5840
  * term. Deterministic. A `mut()` term marks every yielded entity changed for that component
5592
5841
  * (README, "Marking what changed"). Inside a system the walk reads the store live (changes are
5593
- * queued until the phase ends); outside one it walks the keys taken at the start. Every row is a
5594
- * new array: keep it if you like. Put the rarest component first: the walk visits its store.
5842
+ * queued until the phase ends); outside one it walks the keys taken at the start. Every row of
5843
+ * `ecs.query()` is a new array: keep it if you like. The rows a system's `run` gets for its
5844
+ * declared `query` are not: they share one array, valid until the next row. Put the rarest
5845
+ * component first: the walk visits its store.
5595
5846
  *
5596
5847
  * @param terms - Component types, tag types and `mut()` terms.
5597
5848
  * @returns The matching rows: the entity and one value per term.
@@ -5696,7 +5947,12 @@ type EcsApi = {
5696
5947
  onRemoved(tagType: TagType, fn: (entity: Entity) => void): () => void;
5697
5948
  /**
5698
5949
  * The coarse change set of the frame, cleared in `time` phase `signals` after every `sync`
5699
- * system ran.
5950
+ * system ran. It is the world's own list, in mark order, each entity once: walk it in the frame
5951
+ * and copy what you keep, because the clear empties it in place. A component nothing marked
5952
+ * answers one shared empty list. Asking allocates nothing. Inside a system nothing leaves the
5953
+ * list until the phase ends. Outside a phase a despawn, or a removal of the component, takes the
5954
+ * entity out at once and the entities after it move up, so a loop that despawns or removes
5955
+ * outside a phase walks a copy: `const copy = [...ecs.changed(C)]`.
5700
5956
  *
5701
5957
  * @param component - The component type to ask about.
5702
5958
  * @returns The entities marked changed for it this frame.
@@ -5874,6 +6130,22 @@ type EcsInternal = {
5874
6130
  * Drops every entity, component, resource, system and hook.
5875
6131
  */
5876
6132
  clear(): void;
6133
+ /**
6134
+ * Counts a new view of a projection for the feature that registered it (rule V of `systemsRun`).
6135
+ *
6136
+ * @param projection - The projection name.
6137
+ */
6138
+ viewCame(projection: string): void;
6139
+ /**
6140
+ * Takes back the count of a despawned view; never below 0.
6141
+ *
6142
+ * @param projection - The projection name.
6143
+ */
6144
+ viewLeft(projection: string): void;
6145
+ /**
6146
+ * Drops every view count: the projections were cleared.
6147
+ */
6148
+ viewsCleared(): void;
5877
6149
  };
5878
6150
  //#endregion
5879
6151
  //#region src/plugins/world/ecs/systems.d.ts
@@ -6058,6 +6330,52 @@ type ProjectionModule = ProjectionApi & ProjectionInternal;
6058
6330
  */
6059
6331
  declare const DEMAND_REASONS: readonly ["always", "first", "resize", "restore", "layers", "debug", "wake", "capture", "request", "mark", "verify", "none", "overlay", "retake"];
6060
6332
  //#endregion
6333
+ //#region src/plugins/renderer/demand/marks.d.ts
6334
+ /**
6335
+ * The marks of one kind of the decision running now, in mark order, each entity once.
6336
+ */
6337
+ declare class MarkList implements Marks {
6338
+ /** Entities marked in this decision. */
6339
+ size: number;
6340
+ /** The marked entities: the first `size` of them; the rest is left from earlier decisions. */
6341
+ private readonly entities;
6342
+ /** The decision each entity was last marked in. */
6343
+ private readonly stamps;
6344
+ /** The number of this decision. */
6345
+ private stamp;
6346
+ /**
6347
+ * Tells whether an entity is marked in this decision.
6348
+ *
6349
+ * @param entity - The entity.
6350
+ * @returns True when it is.
6351
+ */
6352
+ has(entity: Entity): boolean;
6353
+ /**
6354
+ * The entity marked `index`-th in this decision.
6355
+ *
6356
+ * @param index - 0 to `size - 1`.
6357
+ * @returns The entity; 0 past the end.
6358
+ */
6359
+ at(index: number): Entity;
6360
+ /**
6361
+ * Marks an entity; a second mark of the same decision changes nothing.
6362
+ *
6363
+ * @param entity - The entity.
6364
+ */
6365
+ add(entity: Entity): void;
6366
+ /**
6367
+ * Empties the list: the next decision gets a new number, so every stamp is stale. Allocates nothing, except when the
6368
+ * stamps grew past `STAMPS_KEPT` or the numbers ran out: then they are dropped.
6369
+ */
6370
+ clear(): void;
6371
+ /**
6372
+ * Walks the marks of this decision in mark order. Allocates an iterator: for a test or a spread, never per frame.
6373
+ *
6374
+ * @yields {Entity} Each marked entity.
6375
+ */
6376
+ [Symbol.iterator](): Iterator<Entity>;
6377
+ }
6378
+ //#endregion
6061
6379
  //#region src/plugins/renderer/demand/types.d.ts
6062
6380
  /**
6063
6381
  * Why the render phase drew a frame, or `"none"` when it did not. Internal: `monitor` and the agent log read it.
@@ -6070,6 +6388,28 @@ type DemandReason = (typeof DEMAND_REASONS)[number];
6070
6388
  * out of the tree, no view). Internal: `sync.loopsHeld` reads it.
6071
6389
  */
6072
6390
  type Unseen = "shown" | "alpha-above" | "alpha-own" | "off-screen" | "other";
6391
+ /**
6392
+ * The change marks of one kind of the running decision, read: each entity once, in mark order. What a `Set` offered
6393
+ * its readers, kept in a list that empties without allocating (`MarkList`). Internal.
6394
+ */
6395
+ type Marks = {
6396
+ /** Entities marked in this decision. */readonly size: number;
6397
+ /**
6398
+ * Tells whether an entity is marked in this decision.
6399
+ *
6400
+ * @param entity - The entity.
6401
+ * @returns True when it is.
6402
+ */
6403
+ has(entity: Entity): boolean;
6404
+ /**
6405
+ * The entity marked `index`-th in this decision: a walk by index makes no iterator.
6406
+ *
6407
+ * @param index - 0 to `size - 1`.
6408
+ * @returns The entity; 0 past the end.
6409
+ */
6410
+ at(index: number): Entity; /** Walks the marks, allocating an iterator: for a test or a spread, never per frame. */
6411
+ [Symbol.iterator](): Iterator<Entity>;
6412
+ };
6073
6413
  /**
6074
6414
  * The last decision of the render phase, one object reused every frame.
6075
6415
  */
@@ -6082,12 +6422,12 @@ type DemandFrame = {
6082
6422
  * demand module state, `ctx.state.demand`.
6083
6423
  */
6084
6424
  type DemandState = {
6085
- /** Entities marked by a compared or structural write since the last decision. */marked: Set<Entity>; /** Marked entities whose view was not drawn at mark time; counted at the decision when drawn then. */
6086
- pending: Set<Entity>; /** Entities a display adapter reported after its `update` (not `false`): counted unless an ancestor is hidden. */
6087
- loose: Set<Entity>; /** Marked by a write that changes what the view draws (`mark`): the kept cache retakes its picture. */
6088
- visual: Set<Entity>; /** Marked by a write of the view's own transform or depth (`markMoved`): a kept picture only moves. */
6089
- moved: Set<Entity>; /** Marked through the public `invalidate`: a filter value or a self-drawn object about to change. */
6090
- published: Set<Entity>;
6425
+ /** Entities marked by a compared or structural write since the last decision. */marked: MarkList; /** Marked entities whose view was not drawn at mark time; counted at the decision when drawn then. */
6426
+ pending: MarkList; /** Entities a display adapter reported after its `update` (not `false`): counted unless an ancestor is hidden. */
6427
+ loose: MarkList; /** Marked by a write that changes what the view draws (`mark`): the kept cache retakes its picture. */
6428
+ visual: MarkList; /** Marked by a write of the view's own transform or depth (`markMoved`): a kept picture only moves. */
6429
+ moved: MarkList; /** Marked through the public `invalidate`: a filter value or a self-drawn object about to change. */
6430
+ published: MarkList;
6091
6431
  /**
6092
6432
  * Every whole-frame reason found since the last decision (O17, LEAD-FIXES-3). The first one added is
6093
6433
  * `frame().reason`, as spec 14 says; the set keeps the others visible to the overlay step and `kept.collect`.
@@ -6128,11 +6468,11 @@ type DemandInternal = {
6128
6468
  frame(): Readonly<DemandFrame>; /** The F6/F18a predicate: `unseenBy(entity) === "shown"`. */
6129
6469
  shown(entity: Entity): boolean; /** Where the walk of `shown` stopped for the entity's view, for `sync.loopsHeld` (spec 26 R1.7.3). */
6130
6470
  unseenBy(entity: Entity): Unseen; /** Marks of the current decision. */
6131
- marked(): ReadonlySet<Entity>; /** The adapter marks of the current decision, as `marked()` for the others. */
6132
- loose(): ReadonlySet<Entity>; /** The marks of the current decision made by `mark`: what a view draws changed. */
6133
- visual(): ReadonlySet<Entity>; /** The marks of the current decision made by `markMoved`: a view's own transform or depth changed. */
6134
- moved(): ReadonlySet<Entity>; /** The marks of the current decision made through the public `invalidate`. */
6135
- published(): ReadonlySet<Entity>; /** The pixel oracle switch, behind `DebugApi.verifyFrames`. */
6471
+ marked(): Marks; /** The adapter marks of the current decision, as `marked()` for the others. */
6472
+ loose(): Marks; /** The marks of the current decision made by `mark`: what a view draws changed. */
6473
+ visual(): Marks; /** The marks of the current decision made by `markMoved`: a view's own transform or depth changed. */
6474
+ moved(): Marks; /** The marks of the current decision made through the public `invalidate`. */
6475
+ published(): Marks; /** The pixel oracle switch, behind `DebugApi.verifyFrames`. */
6136
6476
  verifyFrames(on: boolean): void; /** Whether the pixel oracle is on. */
6137
6477
  verifying(): boolean; /** The body of the public `renderer.invalidate`: a mark of an entity that has a view. */
6138
6478
  invalidate(entity: Entity): void;
@@ -6569,6 +6909,12 @@ type KeptState = {
6569
6909
  verifySkipped: number; /** True while `bypass(true)` draws everything live for an extract. */
6570
6910
  bypassed: boolean; /** Render passes the last flush cost: the estimate `sync.renderPasses()` adds (P9.2). */
6571
6911
  flushPasses: number;
6912
+ /**
6913
+ * The frame `collect` read had no mark and no whole-frame reason: nothing a kept picture reads changed, so a kept
6914
+ * record that owes nothing is drawn from its picture as it stands, without its step (E5). Set by `collect`, spent by
6915
+ * the next flush.
6916
+ */
6917
+ calm: boolean;
6572
6918
  };
6573
6919
  //#endregion
6574
6920
  //#region src/plugins/renderer/viewport/types.d.ts
@@ -7669,6 +8015,12 @@ type SyncInternal = {
7669
8015
  */
7670
8016
  layerOf(entity: Entity): string | undefined; /** The overlays of this frame: modes, ranges, reasons, dims, HUD parts, and the pictures to take (spec 22). */
7671
8017
  stepOverlays(): void;
8018
+ /**
8019
+ * Hands Pixi again the filters of every view whose filters were switched on or off since they were written: Pixi
8020
+ * holds only the enabled ones (E3). Run by the draw callback before anything reads the tree, so a switch is drawn in
8021
+ * the frame it was made. Allocates nothing when no filter was switched.
8022
+ */
8023
+ stepFilters(): void;
7672
8024
  /**
7673
8025
  * The `Graphics` paths the engine drew since the last call (shapes, clip masks, nine-slice outlines), and zeroes the
7674
8026
  * count: the monitor's `stats().redraws` (spec 26 R2.3).
@@ -7998,10 +8350,20 @@ type SyncState = {
7998
8350
  overlay: OverlayState; /** `Graphics` paths drawn since the monitor last took them: shapes, clip masks, outlines (spec 26 R2.3). */
7999
8351
  redraws: number;
8000
8352
  /**
8001
- * Where the walk of `shown` stopped for the entities whose loops asked since the last sync pass (spec 26 R1.7.3):
8002
- * an entity with several endless loops is walked once a frame. Cleared by every pass, which may change the tree.
8353
+ * Where the walk of `shown` stopped for the entities whose loops asked (spec 26 R1.7.3), at the `passesVersion` it
8354
+ * was taken: an answer stands while the version does, so an entity with several endless loops is walked once, and a
8355
+ * still board not at all (E4). One record per entity, made at its first ask, dropped with its view.
8356
+ */
8357
+ held: Map<Entity, HeldUnseen>;
8358
+ /**
8359
+ * Moves on with every change that may change the render passes of a frame or where a walk of `shown` stops: a filter
8360
+ * set, forgotten or switched, a node's `renderable` flipped (every hidden reason, the alpha's too), a view hung,
8361
+ * moved, wrapped or dropped (a pass that did work), a kept picture taken or let go, a HUD factor, a new viewport, a
8362
+ * write a plugin announced with `invalidate`.
8003
8363
  */
8004
- held: Map<Entity, Unseen>;
8364
+ passesVersion: number; /** The filtered views' passes of `renderPassesOf`, counted at `passesVersion` `at` under `root`. */
8365
+ passes: PassCount; /** The name of the scene's HUD layer (`above: "overlays"`), kept with the layers; `undefined` without one. */
8366
+ hudLayer: string | undefined;
8005
8367
  cleanups: Array<() => void>;
8006
8368
  };
8007
8369
  /**
@@ -8017,6 +8379,24 @@ type OverdrawState = {
8017
8379
  matrix: PixiFilter | undefined;
8018
8380
  listeners: Array<(on: boolean) => void>;
8019
8381
  };
8382
+ /** Where the walk of `shown` stopped for one entity, and the `passesVersion` it was taken at. */
8383
+ type HeldUnseen = {
8384
+ answer: Unseen;
8385
+ at: number;
8386
+ };
8387
+ /**
8388
+ * The filtered views' part of the render passes, counted once and read every frame while nothing it reads changed: the
8389
+ * version and the root it was counted at, and every filter of the filter table with its `enabled` then (a plugin may
8390
+ * switch a filter by its field alone). Not public.
8391
+ */
8392
+ type PassCount = {
8393
+ at: number;
8394
+ root: PixiContainer | undefined;
8395
+ filtered: number; /** Filters recorded: the first `count` of `filters` and `enabled`. */
8396
+ count: number;
8397
+ filters: Array<PixiFilter | undefined>;
8398
+ enabled: boolean[];
8399
+ };
8020
8400
  //#endregion
8021
8401
  //#region src/plugins/renderer/monitor/log-types.d.ts
8022
8402
  /**
@@ -8169,6 +8549,45 @@ type PerfLine<Kind extends string> = {
8169
8549
  t: number;
8170
8550
  build: string | null;
8171
8551
  };
8552
+ /**
8553
+ * Which groups of the monitor's per-frame work run in an agent build, each on unless switched off (spec 11 R14, the
8554
+ * names of the editor's contract, telemetry proposal §2.7): `gpu` the GPU timer; `passes` the pass ring with its stencil
8555
+ * count and the draws, filter applies, uploads, instruction rebuilds and render targets the counting classes count;
8556
+ * `shaders` the pipeline compiles and shader modules; `problems` the problem rules' accumulators and their judgment;
8557
+ * `memory` the heap read of every frame and its `gc?` hint; `systems` the time of every world system and the five
8558
+ * slowest of a frame; `nodes` the change marks of the frame and its draw reason; `longFrames` the long frames the
8559
+ * browser reports. A section switched off skips its work, and its columns and sample fields read as not measured.
8560
+ *
8561
+ * @example
8562
+ * ```ts
8563
+ * // The editor measures the ward without the per-system timing, the rest as it was.
8564
+ * const sections: MonitorSections = {
8565
+ * gpu: true, passes: true, shaders: true, problems: true, memory: true, systems: false, nodes: true, longFrames: true
8566
+ * };
8567
+ * ```
8568
+ */
8569
+ type MonitorSections = {
8570
+ gpu: boolean;
8571
+ passes: boolean;
8572
+ shaders: boolean;
8573
+ problems: boolean;
8574
+ memory: boolean;
8575
+ systems: boolean;
8576
+ nodes: boolean;
8577
+ longFrames: boolean;
8578
+ };
8579
+ /**
8580
+ * The sections of the monitor in their order: the order of a `sections` event's lists and of `sample.sectionsMs`
8581
+ * (which adds `base`, the rest of the commit). New sections are only ever appended.
8582
+ *
8583
+ * @example
8584
+ * ```ts
8585
+ * // The editor draws one switch per section of the device's monitor, in the engine's order, and greys the ones off.
8586
+ * app.renderer.monitor.sections({ systems: false });
8587
+ * MONITOR_SECTIONS.filter(section => !app.renderer.monitor.sections()[section]); // ["systems"]
8588
+ * ```
8589
+ */
8590
+ declare const MONITOR_SECTIONS: readonly ["gpu", "passes", "shaders", "problems", "memory", "systems", "nodes", "longFrames"];
8172
8591
  /**
8173
8592
  * What an agent build could measure on this page; the header lists it.
8174
8593
  */
@@ -8254,6 +8673,12 @@ type PerfHeaderLine = PerfLine<"header"> & {
8254
8673
  debug?: {
8255
8674
  overdraw: boolean;
8256
8675
  };
8676
+ /**
8677
+ * The sections of the monitor at the moment of the header, as `monitor.sections()` answers them (a `sections` event
8678
+ * marks a switch later): a section `measured` lists but `false` here is switched off, not missing. The engine always
8679
+ * writes it; optional for a reader of an older log.
8680
+ */
8681
+ sections?: Readonly<MonitorSections>;
8257
8682
  };
8258
8683
  /**
8259
8684
  * One Long Animation Frame (or long task) of the page.
@@ -8426,6 +8851,13 @@ type PerfSampleLine = PerfLine<"sample"> & {
8426
8851
  created: number;
8427
8852
  destroyed: number;
8428
8853
  } | null;
8854
+ /**
8855
+ * What each section of the monitor cost in the second: page-clock ms its part of the frame commits took, summed over
8856
+ * the second, 0 for a section switched off; `base` is the rest of the commits. Pixi-side counting is not timed. A
8857
+ * WebView's clock ticks in 0.1 ms, so a part shorter than that adds 0 or 0.1 at a time: the sum over a second is
8858
+ * what to read. The engine always writes it; optional for a reader of an older log.
8859
+ */
8860
+ sectionsMs?: { readonly [Section in keyof MonitorSections | "base"]: number };
8429
8861
  };
8430
8862
  /**
8431
8863
  * Why a frame is a spike: a rule (`gap`, `js`, `gpu`) or an annotation of a spike. `compile` is a compile in the frame or,
@@ -8569,9 +9001,10 @@ type PerfLongFrameLine = PerfLine<"longFrame"> & LongFrameEntry & {
8569
9001
  /**
8570
9002
  * The names of `event` lines (`"devtools"` is the editor's overlay event, in 2b because the editor's page agent emits
8571
9003
  * it on the 2b debug build; `"pool-trim"` is the pool trim of spec 25, detail `PoolTrimDetail`; `"warm"` is the end of
8572
- * a pipeline warm-up run of spec 27, detail `WarmDetail`).
9004
+ * a pipeline warm-up run of spec 27, detail `WarmDetail`; `"sections"` is a switch of the monitor's sections, detail
9005
+ * `{ on, off }`: the names of the sections on and off, in the order of `MONITOR_SECTIONS`).
8573
9006
  */
8574
- type PerfEventName = "scene" | "overlay" | "bundle" | "compile" | "upload" | "resolution" | "device-lost" | "device-restored" | "pause" | "resume" | "switch" | "display" | "command" | "recorder" | "rate" | "devtools" | "pool-trim" | "warm" | "shader" | "problem" | "debug";
9007
+ type PerfEventName = "scene" | "overlay" | "bundle" | "compile" | "upload" | "resolution" | "device-lost" | "device-restored" | "pause" | "resume" | "switch" | "display" | "command" | "recorder" | "rate" | "devtools" | "pool-trim" | "warm" | "shader" | "problem" | "debug" | "sections";
8575
9008
  /**
8576
9009
  * What an `overlay` event line says happened to an overlay (spec 22 O10.2): it opened, landed (its enter motion is
8577
9010
  * over), started to leave, is gone, or its range went live or was kept again (the live fallback).
@@ -9428,7 +9861,9 @@ type MonitorSinks = {
9428
9861
  compiles: CompileRing; /** The WebGPU pass sink, set at attach. */
9429
9862
  passes: PassSink | undefined; /** A pass counter runs (F8): the counting encoder exists, or the WebGL runner items are subscribed. */
9430
9863
  measuring: boolean; /** Pixi's instruction rebuilds since the monitor last took them, in a frame or between frames (spec 26 R2.3). */
9431
- rebuildsWindow: number;
9864
+ rebuildsWindow: number; /** The `SECTION` bits of the sections that run in the frame now: what the commit and the counting classes test. */
9865
+ sections: number; /** The `SECTION` bits a switch asked for: they apply at the start of the next frame, so a frame is measured whole. */
9866
+ sectionsNext: number;
9432
9867
  };
9433
9868
  /**
9434
9869
  * The ring's render passes, written in place: `capacity * 4` of them. Not public.
@@ -9593,8 +10028,14 @@ type PerfState = {
9593
10028
  /** `config.monitor.budgetMs`; a frame's budget is `budgetOf` it. */budget: number | "rate"; /** `config.monitor.frames`: the capacity the ring gets at the first attach. */
9594
10029
  frames: number;
9595
10030
  ring: PerfRing; /** `capacity` long, for percentiles at a flush. */
9596
- scratch: Float32Array; /** Doubles kept unboxed: `[0]` the budget of the frame being committed, `[1]` the end of a flushed window. */
9597
- staged: Float64Array; /** The display's frame period from the ticks: the budget's display part while `time` does not know the display. */
10031
+ scratch: Float32Array;
10032
+ /**
10033
+ * Doubles kept unboxed: `[0]` the budget of the frame being committed, `[1]` the end of a flushed window, `[2]` the
10034
+ * page clock of the last lap of the commit, where the next section's cost starts.
10035
+ */
10036
+ staged: Float64Array; /** The sections `monitor.sections()` answers: the config's at first, then the last switch; frozen. */
10037
+ sections: Readonly<MonitorSections>; /** Page-clock ms of the commits of the current second, by section in `COST` order, `base` last. */
10038
+ sectionsMs: Float64Array; /** The display's frame period from the ticks: the budget's display part while `time` does not know the display. */
9598
10039
  ticks: TickEstimate; /** The `time.rate()` snapshot the last frame saw: a new one may carry another `displayHz` (a `display` event). */
9599
10040
  rate: Readonly<FrameRate> | undefined;
9600
10041
  drawn: boolean; /** The `CHANGED` bits of the frame running now. */
@@ -9636,8 +10077,9 @@ type PerfState = {
9636
10077
  * wait for a drawn frame.
9637
10078
  */
9638
10079
  type MonitorState = {
9639
- /** Clock time at the start of the frame being drawn; `undefined` between frames. */frameStart: number | undefined; /** Clock time at the start of the last frame, the far end of the next interval. */
9640
- lastStart: number | undefined; /** Clock milliseconds between frame starts, summed over the open window. */
10080
+ /** Clock time at the start of the frame being drawn; NaN between frames. A double from the start: never boxed. */frameStart: number; /** Clock time at the start of the last frame, the far end of the next interval; NaN before the first. */
10081
+ lastStart: number; /** `[0]`: the clock reading `begin` or `end` hands the window, staged: a double handed to a call is boxed. */
10082
+ staged: Float64Array; /** Clock milliseconds between frame starts, summed over the open window. */
9641
10083
  windowMs: number; /** Intervals between frame starts in the open window. */
9642
10084
  intervals: number; /** Clock milliseconds spent inside frames in the open window. */
9643
10085
  workMs: number; /** Frames finished in the open window. */
@@ -9843,6 +10285,25 @@ type PerfMonitorApi = {
9843
10285
  * ```
9844
10286
  */
9845
10287
  setResolution(resolution: number | undefined): number;
10288
+ /**
10289
+ * The sections of the monitor of a debug build, each on unless switched off: what runs every frame, and what can be
10290
+ * switched off to measure the game without it. Without an argument it reads them. With one it switches the sections
10291
+ * it names, from the next frame on, and writes a `sections` event; a write needs control (`--debug`, or a dev page):
10292
+ * a read-only page (`--debug=read`) keeps the sections and throws. A section off skips its work: its ring columns and its sample fields read as not measured, and its
10293
+ * `sample.sectionsMs` is 0. Agent builds only: elsewhere every section answers on and nothing switches.
10294
+ *
10295
+ * @param next - The sections to switch: `true` on, `false` off; a section left out keeps its switch.
10296
+ * @returns The sections from the next frame on, one frozen object until the next switch.
10297
+ * @throws {Error} With `reason: "read-only"` when a page without control is asked to change a section.
10298
+ * @example
10299
+ * ```ts
10300
+ * // The editor's Mission control: what does the ward cost without the per-system timing?
10301
+ * app.renderer.monitor.sections().systems; // true
10302
+ * app.renderer.monitor.sections({ systems: false }); // { gpu: true, passes: true, shaders: true, problems: true, memory: true, systems: false, nodes: true, longFrames: true }
10303
+ * // a stream() listener gets { kind: "event", name: "sections", detail: { on: ["gpu", "passes", "shaders", "problems", "memory", "nodes", "longFrames"], off: ["systems"] }, … }
10304
+ * ```
10305
+ */
10306
+ sections(next?: Partial<MonitorSections>): Readonly<MonitorSections>;
9846
10307
  /**
9847
10308
  * The live object counts of a debug build: a plugin the renderer cannot depend on (it depends on the renderer)
9848
10309
  * registers a count here, and the monitor reads it once a second into `sample.counts` and `stats().counts`.
@@ -10065,7 +10526,7 @@ type PictureRequest = {
10065
10526
  reject: (error: Error) => void;
10066
10527
  };
10067
10528
  declare namespace types_d_exports$2 {
10068
- export { Api$1 as Api, AspectRange, BitmapFontData, CaptureOptions, Captured, Config$2 as Config, CountingClasses, CoverFrame, CreateTextureOptions$1 as CreateTextureOptions, DebugApi, DebugSwitches, DemandFrame, DemandModule, DemandReason, DemandState, Deps$2 as Deps, DisplayAdapter, DisplayEntry, DisplaysApi, DrawCounter, Events$2 as Events, FilterCache, FilterSlot, FilterSlotInputs, FiltersApi, FontsApi, FrameColumns, FrameReadResult, FrameReadout, FrameRecord, FrameRing, HitBox, HostApi, HostInternal, HostModule, HostState, HudPartValue, KeptInternal, KeptModule, KeptRange, KeptState, KeptStats, KernelSlice$2 as KernelSlice, LayerEntry, LegendEntry, LongFrameEntry, Modules, MonitorApi, MonitorConfig, MonitorCounts, MonitorDeps, MonitorInternal, MonitorModule, MonitorState, NineBorders$1 as NineBorders, Orientation, OverlayEventDetail, OverlayLevelValue, OverlayMode, OverlayPhase, OverlayReport, OverlayValue, OverlayWhat, PassKind, PassRecord, PerfCause, PerfChange, PerfChangeEntry, PerfCollectorLine, PerfCounts, PerfDisplay, PerfEventLine, PerfEventName, PerfGapLine, PerfHeaderLine, PerfLogLine, PerfLongFrameLine, PerfMarkLine, PerfMeasured, PerfMonitorApi, PerfSampleLine, PerfSpikeLine, PerfStartupLine, PerfTelemetryLine, PerfThermalLine, PictureRect, PixiApplication, PixiBitmapFont, PixiBounds, PixiContainer, PixiFilter, PixiFilterManager, PixiGraphics, PixiMatrix, PixiModule, PixiNineSliceSprite, PixiRectangle, PixiRenderTexture, PixiSprite, PixiTexture, Point, PoolTrim, PoolTrimDetail, ProblemEventDetail, ProblemRule, Rect, RenderStats, RendererCtx, RendererKind, SafeArea, ShaderEventDetail, ShaderWhat, SliceFrame, State$2 as State, SyncApi, SyncCounts, SyncInternal, SyncModule, SyncState, TeardownScope, TextureProvider, TextureUsage, TexturesApi, Under, View, ViewKind, ViewportApi, ViewportInternal, ViewportModule, ViewportSize, ViewportState, WarmDetail };
10529
+ export { Api$1 as Api, AspectRange, BitmapFontData, CaptureOptions, Captured, Config$2 as Config, CountingClasses, CoverFrame, CreateTextureOptions$1 as CreateTextureOptions, DebugApi, DebugSwitches, DemandFrame, DemandModule, DemandReason, DemandState, Deps$2 as Deps, DisplayAdapter, DisplayEntry, DisplaysApi, DrawCounter, Events$2 as Events, FilterCache, FilterSlot, FilterSlotInputs, FiltersApi, FontsApi, FrameColumns, FrameReadResult, FrameReadout, FrameRecord, FrameRing, HitBox, HostApi, HostInternal, HostModule, HostState, HudPartValue, KeptInternal, KeptModule, KeptRange, KeptState, KeptStats, KernelSlice$2 as KernelSlice, LayerEntry, LegendEntry, LongFrameEntry, Modules, MonitorApi, MonitorConfig, MonitorCounts, MonitorDeps, MonitorInternal, MonitorModule, MonitorSections, MonitorState, NineBorders$1 as NineBorders, Orientation, OverlayEventDetail, OverlayLevelValue, OverlayMode, OverlayPhase, OverlayReport, OverlayValue, OverlayWhat, PassKind, PassRecord, PerfCause, PerfChange, PerfChangeEntry, PerfCollectorLine, PerfCounts, PerfDisplay, PerfEventLine, PerfEventName, PerfGapLine, PerfHeaderLine, PerfLogLine, PerfLongFrameLine, PerfMarkLine, PerfMeasured, PerfMonitorApi, PerfSampleLine, PerfSpikeLine, PerfStartupLine, PerfTelemetryLine, PerfThermalLine, PictureRect, PixiApplication, PixiBitmapFont, PixiBounds, PixiContainer, PixiFilter, PixiFilterManager, PixiGraphics, PixiMatrix, PixiModule, PixiNineSliceSprite, PixiRectangle, PixiRenderTexture, PixiSprite, PixiTexture, Point, PoolTrim, PoolTrimDetail, ProblemEventDetail, ProblemRule, Rect, RenderStats, RendererCtx, RendererKind, SafeArea, ShaderEventDetail, ShaderWhat, SliceFrame, State$2 as State, SyncApi, SyncCounts, SyncInternal, SyncModule, SyncState, TeardownScope, TextureProvider, TextureUsage, TexturesApi, Under, View, ViewKind, ViewportApi, ViewportInternal, ViewportModule, ViewportSize, ViewportState, WarmDetail };
10069
10530
  }
10070
10531
  /**
10071
10532
  * The part of Pixi the engine uses: the classes `sync` builds views from (a `Rectangle` frames the
@@ -10290,6 +10751,8 @@ type Config$2 = {
10290
10751
  * createApp({ pluginConfigs: { renderer: { mount: "#game", monitor: { budgetMs: 8.3, frames: 2048 } } } });
10291
10752
  * // A game with a large blurred backdrop flags it sooner: 30 still frames over 0.1 Mpx.
10292
10753
  * createApp({ pluginConfigs: { renderer: { mount: "#game", monitor: { budgetMs: "rate", frames: 1024, stillFrames: 30, stillMpx: 0.1 } } } });
10754
+ * // A debug build that starts without the per-system timing: app.renderer.monitor.sections().systems is false.
10755
+ * createApp({ pluginConfigs: { renderer: { mount: "#game", monitor: { budgetMs: "rate", frames: 1024, sections: { systems: false } } } } });
10293
10756
  * ```
10294
10757
  */
10295
10758
  type MonitorConfig = {
@@ -10306,6 +10769,11 @@ type MonitorConfig = {
10306
10769
  churnPerSecond?: number; /** `target-churn`: seconds of churn in a row before the problem. Default 3. */
10307
10770
  churnSeconds?: number; /** `target-churn`: a render target made this many ms after a pool trim is churn at once. Default 1000. */
10308
10771
  churnAfterTrimMs?: number;
10772
+ /**
10773
+ * The sections of the monitor a debug build starts with (spec 11 R14): a section left out is on. `monitor.sections`
10774
+ * switches them later.
10775
+ */
10776
+ sections?: Partial<MonitorSections>;
10309
10777
  };
10310
10778
  /**
10311
10779
  * renderer plugin state: one branch per module.
@@ -10716,7 +11184,13 @@ type State$1 = {
10716
11184
  */
10717
11185
  named: readonly string[];
10718
11186
  owner: SceneOwner; /** The remover of the `onEnter` callback: set in `onStart`, run in `onStop`. */
10719
- teardown: (() => void) | undefined;
11187
+ teardown: (() => void) | undefined; /** Scene id to the feature that declares it, filled in `onStart`. */
11188
+ owners: Map<string, string>;
11189
+ /**
11190
+ * The release of the hold on the mounted scene's feature (`world.ecs.hold`), so the systems of a
11191
+ * feature with `systemsRun: "active"` run while its scene is mounted.
11192
+ */
11193
+ held: (() => void) | undefined;
10720
11194
  };
10721
11195
  /**
10722
11196
  * scenes plugin events.
@@ -11732,4 +12206,4 @@ type BundleCompanion = {
11732
12206
  unload(bundle: string): void;
11733
12207
  };
11734
12208
  //#endregion
11735
- export { PerfCause as $, JournalEntry as $n, types_d_exports$3 as $t, PixiSprite as A, Api$3 as An, SnapshotOf as Ar, ViewportSize as At, FrameReadResult as B, defineFlow as Bn, Api$7 as Br, Shape as Bt, State$1 as C, NumericFields as Cn, types_d_exports$6 as Cr, ShaderWhat as Ct, MonitorConfig as D, TrackOptions as Dn, SaveDoc as Dr, FilterSlotInputs as Dt, Config$2 as E, ReducedMotion as En, ProviderCall as Er, FilterSlot as Et, types_d_exports$2 as F, HudKeysOf as Fn, Config$7 as Fr, NineSlice$1 as Ft, OverlayEventDetail as G, FeatureDescription as Gn, ThermalReading as Gr, Transform as Gt, FrameRecord as H, slot as Hn, FrameRate as Hr, Sprite as Ht, Captured as I, Position as In, Events$6 as Ir, NineSliceValue as It, PERF_GAP_BUCKETS as J, AnyFlow as Jn, Config$9 as Jr, DEMAND_REASONS as Jt, OverlayWhat as K, FeaturePlugin as Kn, Time as Kr, TransformValue as Kt, MonitorCounts as L, State$4 as Ln, PauseReason as Lr, Overlay as Lt, PoolTrim as M, Config$4 as Mn, RngApi as Mr, Display as Mt, State$2 as N, EmitterIdOf as Nn, RngState as Nr, HudPart as Nt, PixiFilter as O, TrackSegment as On, SaveUnreadableError as Or, Orientation as Ot, Under as P, GameTypes as Pn, Api$6 as Pr, HudPartValue as Pt, PassRecord as Q, FlowState as Qn, State$3 as Qt, RenderStats as R, TextStylesOf as Rn, State$7 as Rr, OverlayValue as Rt, ScenesApi as S, MotionHandle as Sn, State$6 as Sr, ShaderEventDetail as St, Api$1 as T, ProjectionSpec as Tn, PlayerStateProvider as Tr, DebugSwitches as Tt, FrameRing as U, to as Un, RateChange as Ur, SpriteOptions as Ut, FrameReadout as V, exit as Vn, Config$8 as Vr, ShapeValue as Vt, LongFrameEntry as W, type as Wn, State$8 as Wr, SpriteValue as Wt, PROBLEM_RULES as X, DefineNode as Xn, Require as Xr, Config$3 as Xt, PERF_LOG_VERSION as Y, Bookmark as Yn, Events$8 as Yr, Api$2 as Yt, PassKind as Z, FlowGraph as Zn, Explained as Zt, DefineScene as _, ChangeHook as _n, Api$5 as _r, PerfThermalLine as _t, Config as a, ComponentType as an, Effect as ar, PerfEventLine as at, SceneDefinition as b, Motion as bn, Json as br, ProblemRule as bt, LoadBundles as c, EntitySnapshot as cn, Hint as cr, PerfHeaderLine as ct, Manifest as d, Narrowed as dn, Api$4 as dr, PerfMarkLine as dt, AnyComponent as en, NodeTable as er, PerfChange as et, State as f, QueryTerm as fn, ClockSource as fr, PerfMeasured as ft, AnySceneProjection as g, TagType as gn, types_d_exports$5 as gr, PerfTelemetryLine as gt, types_d_exports as h, SystemFor as hn, State$5 as hr, PerfStartupLine as ht, BundleSpec as i, ComponentSchema as in, Descriptor as ir, PerfDisplay as it, PixiTexture as j, BundlesOf as jn, StoreApi as jr, FilterCache as jt, PixiModule as k, ViewHandle as kn, Snapshot as kr, Point as kt, LoadReason as l, FrameDiff as ln, NodeFx as lr, PerfLogLine as lt, Usage as m, SystemDefinition as mn, FakeClock as mr, PerfSpikeLine as mt, AssetsIo as n, AnyComponentValue as nn, SceneIdOf as nr, PerfCollectorLine as nt, DefineBundles as o, ComponentValue as on, EffectOptions as or, PerfEventName as ot, Tier as p, ResourceType as pn, Config$5 as pr, PerfSampleLine as pt, PERF_CAUSES as q, FeatureTree as qn, types_d_exports$8 as qr, sprite as qt, BundleMap as r, ComponentHandle as rn, TypeTag as rr, PerfCounts as rt, Events as s, Entity as sn, GuideOptions as sr, PerfGapLine as st, Api as t, AnyComponentType as tn, RouteStep as tr, PerfChangeEntry as tt, LoadResult as u, Mut as un, Answer as ur, PerfLongFrameLine as ut, Events$1 as v, DescriptionNode as vn, Config$6 as vr, PoolTrimDetail as vt, types_d_exports$1 as w, ProjectionMotion as wn, Patch as wr, WarmDetail as wt, SceneSpec as x, MotionCause as xn, Root as xr, SHADER_WHATS as xt, LayerMap as y, Ease as yn, Events$5 as yr, ProblemEventDetail as yt, FrameColumns as z, types_d_exports$4 as zn, types_d_exports$7 as zr, Parent as zt };
12209
+ export { PassKind as $, FlowGraph as $n, Explained as $t, PixiSprite as A, TrackSegment as An, SaveUnreadableError as Ar, Orientation as At, FrameReadResult as B, TextStylesOf as Bn, State$7 as Br, OverlayValue as Bt, State$1 as C, MotionCause as Cn, Root as Cr, SHADER_WHATS as Ct, MonitorConfig as D, ProjectionSpec as Dn, PlayerStateProvider as Dr, DebugSwitches as Dt, Config$2 as E, ProjectionMotion as En, Patch as Er, WarmDetail as Et, types_d_exports$2 as F, EmitterIdOf as Fn, RngState as Fr, HudPart as Ft, MONITOR_SECTIONS as G, to as Gn, RateChange as Gr, SpriteOptions as Gt, FrameRecord as H, defineFlow as Hn, Api$7 as Hr, Shape as Ht, Captured as I, GameTypes as In, Api$6 as Ir, HudPartValue as It, OverlayWhat as J, FeaturePlugin as Jn, Time as Jr, TransformValue as Jt, MonitorSections as K, type as Kn, State$8 as Kr, SpriteValue as Kt, MonitorCounts as L, HudKeysOf as Ln, Config$7 as Lr, NineSlice$1 as Lt, PoolTrim as M, Api$3 as Mn, SnapshotOf as Mr, ViewportSize as Mt, State$2 as N, BundlesOf as Nn, StoreApi as Nr, FilterCache as Nt, PixiFilter as O, ReducedMotion as On, ProviderCall as Or, FilterSlot as Ot, Under as P, Config$4 as Pn, RngApi as Pr, Display as Pt, PROBLEM_RULES as Q, DefineNode as Qn, Require as Qr, Config$3 as Qt, RenderStats as R, Position as Rn, Events$6 as Rr, NineSliceValue as Rt, ScenesApi as S, Motion as Sn, Json as Sr, ProblemRule as St, Api$1 as T, NumericFields as Tn, types_d_exports$6 as Tr, ShaderWhat as Tt, FrameRing as U, exit as Un, Config$8 as Ur, ShapeValue as Ut, FrameReadout as V, types_d_exports$4 as Vn, types_d_exports$7 as Vr, Parent as Vt, LongFrameEntry as W, slot as Wn, FrameRate as Wr, Sprite as Wt, PERF_GAP_BUCKETS as X, AnyFlow as Xn, Config$9 as Xr, DEMAND_REASONS as Xt, PERF_CAUSES as Y, FeatureTree as Yn, types_d_exports$8 as Yr, sprite as Yt, PERF_LOG_VERSION as Z, Bookmark as Zn, Events$8 as Zr, Api$2 as Zt, DefineScene as _, SystemFor as _n, State$5 as _r, PerfStartupLine as _t, Config as a, ComponentHandle as an, TypeTag as ar, PerfCounts as at, SceneDefinition as b, DescriptionNode as bn, Config$6 as br, PoolTrimDetail as bt, LoadBundles as c, ComponentValue as cn, EffectOptions as cr, PerfEventName as ct, Manifest as d, FrameDiff as dn, NodeFx as dr, PerfLogLine as dt, State$3 as en, FlowState as er, PassRecord as et, State as f, Mut as fn, Answer as fr, PerfLongFrameLine as ft, AnySceneProjection as g, SystemDefinition as gn, FakeClock as gr, PerfSpikeLine as gt, types_d_exports as h, ResourceType as hn, Config$5 as hr, PerfSampleLine as ht, BundleSpec as i, AnyComponentValue as in, SceneIdOf as ir, PerfCollectorLine as it, PixiTexture as j, ViewHandle as jn, Snapshot as jr, Point as jt, PixiModule as k, TrackOptions as kn, SaveDoc as kr, FilterSlotInputs as kt, LoadReason as l, Entity as ln, GuideOptions as lr, PerfGapLine as lt, Usage as m, QueryTerm as mn, ClockSource as mr, PerfMeasured as mt, AssetsIo as n, AnyComponent as nn, NodeTable as nr, PerfChange as nt, DefineBundles as o, ComponentSchema as on, Descriptor as or, PerfDisplay as ot, Tier as p, Narrowed as pn, Api$4 as pr, PerfMarkLine as pt, OverlayEventDetail as q, FeatureDescription as qn, ThermalReading as qr, Transform as qt, BundleMap as r, AnyComponentType as rn, RouteStep as rr, PerfChangeEntry as rt, Events as s, ComponentType as sn, Effect as sr, PerfEventLine as st, Api as t, types_d_exports$3 as tn, JournalEntry as tr, PerfCause as tt, LoadResult as u, EntitySnapshot as un, Hint as ur, PerfHeaderLine as ut, Events$1 as v, TagType as vn, types_d_exports$5 as vr, PerfTelemetryLine as vt, types_d_exports$1 as w, MotionHandle as wn, State$6 as wr, ShaderEventDetail as wt, SceneSpec as x, Ease as xn, Events$5 as xr, ProblemEventDetail as xt, LayerMap as y, ChangeHook as yn, Api$5 as yr, PerfThermalLine as yt, FrameColumns as z, State$4 as zn, PauseReason as zr, Overlay as zt };