@moku-labs/game 0.15.26 → 0.15.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/app/page.d.mts +1 -1
  2. package/dist/app/page.mjs +1 -1
  3. package/dist/app/system.d.mts +3 -3
  4. package/dist/app.d.mts +3 -3
  5. package/dist/app.mjs +1 -1
  6. package/dist/assets.d.mts +1 -1
  7. package/dist/{commands-KWKfdywA.d.mts → commands-BJ4gG5WZ.d.mts} +5 -5
  8. package/dist/control.d.mts +4 -4
  9. package/dist/{define-uiyy88hF.d.mts → define-CVYadV_I.d.mts} +2 -2
  10. package/dist/{headless-PssyKRFN.d.mts → headless-DBYmnluy.d.mts} +1 -1
  11. package/dist/{index-CM1goGHf.d.mts → index-Dn_v0Fqs.d.mts} +7 -5
  12. package/dist/index.d.mts +5 -5
  13. package/dist/index.mjs +3 -3
  14. package/dist/inspect.d.mts +6 -6
  15. package/dist/inspect.mjs +1 -1
  16. package/dist/jsx-dev-runtime.d.mts +1 -1
  17. package/dist/jsx-runtime.d.mts +1 -1
  18. package/dist/{runtime-C0YaA9fC.d.mts → runtime-DnjJ4Zo9.d.mts} +1 -1
  19. package/dist/{sources-Dpc4NXvG.mjs → sources-ncFMQIus.mjs} +1 -1
  20. package/dist/{src-DWYFupNb.mjs → src-DPvSTM8O.mjs} +485 -78
  21. package/dist/testing.d.mts +4 -4
  22. package/dist/testing.mjs +1 -1
  23. package/dist/{types-BdLJ4lTA.d.mts → types-Bsa1nFyU.d.mts} +4 -4
  24. package/dist/{types-C-wAHgpD.d.mts → types-C76NQm-h.d.mts} +119 -20
  25. package/dist/{types-ChZ4Ej7O.d.mts → types-C_nC_M4p.d.mts} +73 -11
  26. package/dist/{types-sfaYGg9l.d.mts → types-DTetCcBC.d.mts} +2 -2
  27. package/dist/{types-_OQ6H8WL.d.mts → types-bEJEga5m.d.mts} +21 -3
  28. package/dist/{visual-DmDWJEzs.d.mts → visual-BMRHt4IB.d.mts} +6 -6
  29. package/dist/{visual-kEC9nb-o.mjs → visual-ClVRMUAi.mjs} +35 -5
  30. package/dist/visual.d.mts +1 -1
  31. package/dist/visual.mjs +1 -1
  32. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
- import { $n as AnyFlow, Tr as Json, Zn as FeaturePlugin, _r as ClockSource, ar as NodeTable, lr as Descriptor, mr as NodeFx, pr as Hint, yr as FakeClock } from "./types-ChZ4Ej7O.mjs";
2
- import { t as createApp } from "./index-CM1goGHf.mjs";
3
- import { b as saveOf, v as WithGameState, y as memory } from "./types-BdLJ4lTA.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-PssyKRFN.mjs";
1
+ import { Er as Json, Qn as FeaturePlugin, br as FakeClock, er as AnyFlow, hr as NodeFx, mr as Hint, or as NodeTable, ur as Descriptor, vr as ClockSource } from "./types-C_nC_M4p.mjs";
2
+ import { t as createApp } from "./index-Dn_v0Fqs.mjs";
3
+ import { b as saveOf, v as WithGameState, y as memory } from "./types-Bsa1nFyU.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-DBYmnluy.mjs";
5
5
  import { AnyPluginInstance } from "@moku-labs/core";
6
6
 
7
7
  //#region src/plugins/clock/fake.d.ts
package/dist/testing.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $t as refuseStart, en as exit, m as flattenFeatures, rn as type, t as createApp } from "./src-DWYFupNb.mjs";
1
+ import { en as refuseStart, in as type, m as flattenFeatures, t as createApp, tn as exit } from "./src-DPvSTM8O.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-Bxxl_mQX.mjs";
@@ -1,7 +1,7 @@
1
- import { $n as AnyFlow, Ar as PlayerStateProvider, Cr as Config, Fr as SnapshotOf, J as Config$2, Ln as Config$1, Mr as SaveDoc, Tr as Json, Z as PixiModule, Zn as FeaturePlugin, _r as ClockSource, a as Config$3, cr as TypeTag, d as Manifest, jr as ProviderCall, n as AssetsIo, st as Orientation, yr as FakeClock } from "./types-ChZ4Ej7O.mjs";
2
- import { o as AudioContextLike, s as Config$4 } from "./types-C-wAHgpD.mjs";
3
- import { R as I18nApi, U as StringTable, W as TextKey } from "./types-_OQ6H8WL.mjs";
4
- import { St as effectsPlugin, Tt as audioPlugin, ht as PlatformProvider, i as screen, pt as platformPlugin, t as createApp } from "./index-CM1goGHf.mjs";
1
+ import { Er as Json, Ir as SnapshotOf, Mr as ProviderCall, Nr as SaveDoc, Q as PixiModule, Qn as FeaturePlugin, Rn as Config$1, Y as Config$2, a as Config$3, br as FakeClock, ct as Orientation, d as Manifest, er as AnyFlow, jr as PlayerStateProvider, lr as TypeTag, n as AssetsIo, vr as ClockSource, wr as Config } from "./types-C_nC_M4p.mjs";
2
+ import { o as AudioContextLike, s as Config$4 } from "./types-C76NQm-h.mjs";
3
+ import { R as I18nApi, U as StringTable, W as TextKey } from "./types-bEJEga5m.mjs";
4
+ import { St as effectsPlugin, Tt as audioPlugin, ht as PlatformProvider, i as screen, pt as platformPlugin, t as createApp } from "./index-Dn_v0Fqs.mjs";
5
5
  import { AnyPluginInstance } from "@moku-labs/core";
6
6
 
7
7
  //#region src/plugins/model/store/providers/memory.d.ts
@@ -1,5 +1,5 @@
1
- import { $ as PixiTexture, D as FilterSlot, Dn as MotionHandle, Fn as Api$2, Gr as Api$1, Mn as TrackOptions, Nn as TrackSegment, O as FilterSlotInputs, On as NumericFields, Q as PixiSprite, Sr as Api$6, Tr as Json, Vr as Events$5, X as PixiFilter, Z as PixiModule, an as AnyComponent, cn as ComponentHandle, cr as TypeTag, ct as Point, ei as Events$2, en as Api$3, fn as Entity, jn as ReducedMotion, k as SyncApi, lr as Descriptor, q as Api$4, s as Events$1, sn as AnyComponentValue, t as Api$5, ti as Require, un as ComponentType, ut as FilterCache, wn as Ease, wr as Events$3, y as Events$4 } from "./types-ChZ4Ej7O.mjs";
2
- import { N as InputApi, R as I18nApi, X as StylesState, c as UiNode, i as Finding, l as LayoutState, n as ElementChange, o as JsxState, r as ElementMotion, w as TextApi } from "./types-_OQ6H8WL.mjs";
1
+ import { $ as PixiSprite, Cr as Api$6, D as FilterSlot, Er as Json, Hr as Events$5, In as Api$2, J as Api$4, Kr as Api$1, Mn as ReducedMotion, Nn as TrackOptions, O as FilterSlotInputs, On as MotionHandle, Pn as TrackSegment, Q as PixiModule, Tn as Ease, Tr as Events$3, Z as PixiFilter, cn as AnyComponentValue, dn as ComponentType, dt as FilterCache, et as PixiTexture, k as SyncApi, kn as NumericFields, ln as ComponentHandle, lr as TypeTag, lt as Point, ni as Require, on as AnyComponent, pn as Entity, s as Events$1, t as Api$5, ti as Events$2, tn as Api$3, ur as Descriptor, y as Events$4 } from "./types-C_nC_M4p.mjs";
2
+ import { N as InputApi, R as I18nApi, X as StylesState, c as UiNode, i as Finding, l as LayoutState, n as ElementChange, o as JsxState, r as ElementMotion, w as TextApi } from "./types-bEJEga5m.mjs";
3
3
  import { Log } from "@moku-labs/common/browser";
4
4
  import { PluginCtx } from "@moku-labs/core";
5
5
 
@@ -391,20 +391,50 @@ declare function spawned(id: string): {
391
391
  };
392
392
  /**
393
393
  * A sound. `anim` owns the descriptor because it sits below `audio`; `audio` owns the handler,
394
- * and a game without `audio` plays nothing and hears no error.
394
+ * and a game without `audio` plays nothing and hears no error. A sound with an `id` is named:
395
+ * one sound plays per id, a new one with the same id fades the old one out over `fadeMs`, and
396
+ * `stopSfx(id)` stops it. The payload carries `id` and `fadeMs` only when they are given, so a
397
+ * sound without them stays `{ key, bus }`.
395
398
  *
396
399
  * @param key - Asset key of the sound.
397
- * @param options - The bus to play it on.
400
+ * @param options - The bus, the name and the fade.
398
401
  * @param options.bus - `"sfx"` when omitted.
402
+ * @param options.id - Name of the sound; one sound per id plays.
403
+ * @param options.fadeMs - Fade of the sound with the same id this one replaces; `audio`'s
404
+ * `sfxFadeMs` when omitted.
399
405
  * @returns The descriptor, usable as a timeline step and as `fx(...)` in a node.
400
406
  * @example
401
407
  * ```ts
402
408
  * sfx("board.merge"); // { kind: "sfx", payload: { key: "board.merge", bus: "sfx" }, cosmetic: true }
409
+ * sfx("voice.hello", { id: "voice", fadeMs: 200 });
410
+ * // { kind: "sfx", payload: { key: "voice.hello", bus: "sfx", id: "voice", fadeMs: 200 }, cosmetic: true }
403
411
  * ```
404
412
  */
405
413
  declare function sfx(key: string, options?: {
406
414
  bus?: string;
415
+ id?: string;
416
+ fadeMs?: number;
407
417
  }): SfxDescriptor;
418
+ /**
419
+ * Stops the named sound `sfx(key, { id })` started, fading it out over `fadeMs`. `audio` owns the
420
+ * handler; an id nothing plays is silent. It works as `fx.start(stopSfx("voice"))` in a node, as a
421
+ * step a timeline reaches, and as the hint `hint("stopSfx", { id: "voice" })`. A timeline that is
422
+ * finished or cut fires no effect, this one included: a game that must stop the voice then stops
423
+ * it from the node.
424
+ *
425
+ * @param id - The id the sound was played with.
426
+ * @param options - The fade.
427
+ * @param options.fadeMs - Fade-out in ms; `audio`'s `sfxFadeMs` when omitted.
428
+ * @returns The descriptor, usable as a timeline step and as `fx(...)` in a node.
429
+ * @example
430
+ * ```ts
431
+ * stopSfx("voice", { fadeMs: 200 }); // { kind: "stopSfx", payload: { id: "voice", fadeMs: 200 }, cosmetic: true }
432
+ * stopSfx("voice"); // { kind: "stopSfx", payload: { id: "voice" }, cosmetic: true }
433
+ * ```
434
+ */
435
+ declare function stopSfx(id: string, options?: {
436
+ fadeMs?: number;
437
+ }): StopSfxDescriptor;
408
438
  /**
409
439
  * A haptic tick. `platform` owns the handler; a device without one stays still.
410
440
  *
@@ -492,12 +522,14 @@ declare function defineAnimation<Tags extends SlotTags>(id: string, spec: Animat
492
522
  type ErasedFields = AnyComponent extends ComponentType<infer Value> ? Value : never;
493
523
  /**
494
524
  * A sound, owned by `anim` and handled by `audio`. It is a `flow` descriptor and a timeline step
495
- * at once: `fx(sfx("board.merge"))` in a node, or `sfx("board.merge")` inside a `sequence`.
525
+ * at once: `fx(sfx("board.merge"))` in a node, or `sfx("board.merge")` inside a `sequence`. A
526
+ * sound with an `id` is named: a second one with the same id fades the first out over `fadeMs`,
527
+ * and `stopSfx(id)` stops it. The payload carries `id` and `fadeMs` only when they were given.
496
528
  *
497
529
  * @example
498
530
  * ```ts
499
531
  * const descriptor: SfxDescriptor = {
500
- * kind: "sfx", payload: { key: "board.merge", bus: "sfx" }, cosmetic: true
532
+ * kind: "sfx", payload: { key: "voice.hello", bus: "sfx", id: "voice", fadeMs: 200 }, cosmetic: true
501
533
  * };
502
534
  * ```
503
535
  */
@@ -505,11 +537,33 @@ type SfxDescriptor = {
505
537
  readonly kind: "sfx";
506
538
  readonly payload: {
507
539
  readonly key: string;
508
- readonly bus: string;
540
+ readonly bus: string; /** Name of the sound: one sound per id plays, and `stopSfx(id)` stops it. */
541
+ readonly id?: string; /** Fade of the sound with the same id this one replaces; `audio`'s `sfxFadeMs` when absent. */
542
+ readonly fadeMs?: number;
509
543
  };
510
544
  readonly cosmetic: true; /** Never set: `await fx(sfx(...))` resolves nothing. */
511
545
  readonly $result?: () => void;
512
546
  };
547
+ /**
548
+ * Stops the named sound an `sfx(key, { id })` started, owned by `anim` and handled by `audio`.
549
+ * Like `sfx` it is a descriptor and a timeline step at once; an id nothing plays is silent.
550
+ *
551
+ * @example
552
+ * ```ts
553
+ * const descriptor: StopSfxDescriptor = {
554
+ * kind: "stopSfx", payload: { id: "voice", fadeMs: 200 }, cosmetic: true
555
+ * };
556
+ * ```
557
+ */
558
+ type StopSfxDescriptor = {
559
+ readonly kind: "stopSfx";
560
+ readonly payload: {
561
+ readonly id: string; /** Fade-out of the sound; `audio`'s `sfxFadeMs` when absent. */
562
+ readonly fadeMs?: number;
563
+ };
564
+ readonly cosmetic: true; /** Never set: `await fx(stopSfx(...))` resolves nothing. */
565
+ readonly $result?: () => void;
566
+ };
513
567
  /**
514
568
  * One haptic tick a device can play: the impact, selection and notification families of Tauri.
515
569
  * `HAPTIC_KINDS` lists the same seven at runtime.
@@ -540,7 +594,7 @@ type HapticDescriptor = {
540
594
  readonly $result?: () => void;
541
595
  };
542
596
  /**
543
- * The two descriptors `anim` owns. As a step, the descriptor is dispatched through
597
+ * The three descriptors `anim` owns. As a step, the descriptor is dispatched through
544
598
  * `flow.fx.dispatch` when the step is reached; a kind nobody handles is silent.
545
599
  *
546
600
  * @example
@@ -548,7 +602,7 @@ type HapticDescriptor = {
548
602
  * const step: FxStep = { kind: "haptic", payload: { kind: "light" }, cosmetic: true };
549
603
  * ```
550
604
  */
551
- type FxStep = SfxDescriptor | HapticDescriptor;
605
+ type FxStep = SfxDescriptor | StopSfxDescriptor | HapticDescriptor;
552
606
  /**
553
607
  * The descriptor `play(animation, slots)` builds. The payload names the animation, so the
554
608
  * handler resolves the definition from the registry instead of carrying a function.
@@ -776,7 +830,7 @@ type RunningTimeline = {
776
830
  readonly cctx: CursorCtx;
777
831
  };
778
832
  declare namespace types_d_exports$3 {
779
- export { AnimApi, AnimCtx, AnimPlayerValue, AnimationDefinition, AnimationSpec, AnyAnimationDefinition, BuildTools, Config$3 as Config, Cursor, Deps$3 as Deps, ErasedFields, Events, ExternalPlayer, FrameLoop, FramesValue, FxStep, HapticDescriptor, HapticKind, KernelSlice$3 as KernelSlice, MarkListener, MotionKeyframe, PlayDescriptor, PlayHandle, Pose, RunningTimeline, SfxDescriptor, SlotRecord, SlotTags, SlotValue, SlotValues, State$3 as State, Step, StepMotion, Target, TimelineRuntime, Track };
833
+ export { AnimApi, AnimCtx, AnimPlayerValue, AnimationDefinition, AnimationSpec, AnyAnimationDefinition, BuildTools, Config$3 as Config, Cursor, Deps$3 as Deps, ErasedFields, Events, ExternalPlayer, FrameLoop, FramesValue, FxStep, HapticDescriptor, HapticKind, KernelSlice$3 as KernelSlice, MarkListener, MotionKeyframe, PlayDescriptor, PlayHandle, Pose, RunningTimeline, SfxDescriptor, SlotRecord, SlotTags, SlotValue, SlotValues, State$3 as State, Step, StepMotion, StopSfxDescriptor, Target, TimelineRuntime, Track };
780
834
  }
781
835
  /**
782
836
  * What a step and a slot are pointed at: the projection key of a live view or of an element a
@@ -2390,7 +2444,7 @@ type AssetsReplaced$1 = Events$1["assets:replaced"];
2390
2444
  */
2391
2445
  type HotSwap = Events$2["ui:hot-swap"];
2392
2446
  declare namespace types_d_exports$1 {
2393
- export { AssetsReplaced, AudioApi, AudioContextLike, AudioCtx, AudioSessionLike, AudioSessionType, BundleUnloaded, Bus, BusState, Config$1 as Config, Deps$1 as Deps, KernelSlice$1 as KernelSlice, LifecycleChanged, ModelCommitted, MusicDescriptor, MusicMode, MusicOptions, MusicRequest, MusicSwitch, MusicTrack, RetiringTrack, SceneChanged, SfxRequest, SoundEntry, State$1 as State, StreamTrack, Volumes, VolumesFor };
2447
+ export { AssetsReplaced, AudioApi, AudioContextLike, AudioCtx, AudioSessionLike, AudioSessionType, BundleUnloaded, Bus, BusState, Config$1 as Config, Deps$1 as Deps, KernelSlice$1 as KernelSlice, LifecycleChanged, ModelCommitted, MusicDescriptor, MusicMode, MusicOptions, MusicRequest, MusicSwitch, MusicTrack, NamedSound, RetiringTrack, SceneChanged, SfxRequest, SoundEntry, State$1 as State, StreamTrack, Volumes, VolumesFor };
2394
2448
  }
2395
2449
  /**
2396
2450
  * The three volume buses. `master` carries the whole game, `music` the scene track, `sfx` every
@@ -2546,7 +2600,12 @@ type Config$1 = {
2546
2600
  music: number;
2547
2601
  sfx: number;
2548
2602
  }; /** Cross-fade of a music switch, in real milliseconds of the context clock. */
2549
- musicFadeMs: number; /** Reads the player's choice from the committed player. `undefined`: the buses stay at `buses`. */
2603
+ musicFadeMs: number;
2604
+ /**
2605
+ * Fade of a named sound, an `sfx` with `id`, in real milliseconds of the context clock: when a
2606
+ * new sound with its id replaces it and names no `fadeMs`, or a stop names none.
2607
+ */
2608
+ sfxFadeMs: number; /** Reads the player's choice from the committed player. `undefined`: the buses stay at `buses`. */
2550
2609
  volumes: Volumes | undefined; /** Context factory, the test seam. `undefined`: `new AudioContext()` when the global exists, otherwise headless. */
2551
2610
  context: (() => AudioContextLike) | undefined; /** How many started sounds `journal()` keeps, newest last. `0` turns the journal off. */
2552
2611
  journal: number; /** How music plays. `"stream"` needs MP3 or AAC: WebM Opus is silent through a media element in WebKit (bug 276813). Sounds always decode. */
@@ -2555,17 +2614,20 @@ type Config$1 = {
2555
2614
  };
2556
2615
  /**
2557
2616
  * One sound that started: a play of an `sfx` or a music track that began. `at` is the elapsed
2558
- * game time in milliseconds, `app.time.snapshot().elapsed` at the start.
2617
+ * game time in milliseconds, `app.time.snapshot().elapsed` at the start. `id` is there only for
2618
+ * an `sfx` started with one.
2559
2619
  *
2560
2620
  * @example
2561
2621
  * ```ts
2562
2622
  * const entry: SoundEntry = { key: "ui.click", bus: "sfx", kind: "sfx", at: 1600 };
2623
+ * const line: SoundEntry = { key: "story.line1", bus: "sfx", kind: "sfx", id: "voice", at: 2400 };
2563
2624
  * ```
2564
2625
  */
2565
2626
  type SoundEntry = {
2566
2627
  readonly key: string;
2567
2628
  readonly bus: Bus;
2568
2629
  readonly kind: "sfx" | "music";
2630
+ readonly id?: string;
2569
2631
  readonly at: number;
2570
2632
  };
2571
2633
  /**
@@ -2610,6 +2672,15 @@ type MusicTrack = {
2610
2672
  type MusicSwitch = {
2611
2673
  key: string;
2612
2674
  };
2675
+ /**
2676
+ * The sound that plays, or still decodes, under one id. The entry object is the token, as a
2677
+ * `MusicSwitch` is: a sound whose entry is no longer the one `named` holds when its buffer arrives
2678
+ * starts nothing. `gain` and `source` stay `undefined` until the sound started.
2679
+ */
2680
+ type NamedSound = {
2681
+ gain: GainNode | undefined;
2682
+ source: AudioBufferSourceNode | undefined;
2683
+ };
2613
2684
  /**
2614
2685
  * audio plugin state.
2615
2686
  */
@@ -2618,14 +2689,19 @@ type State$1 = {
2618
2689
  buses: Record<Bus, BusState>; /** A lifecycle push is in force: every bus is held at zero. */
2619
2690
  paused: boolean;
2620
2691
  unlocked: boolean; /** A gesture called `resume()` and it has not settled yet. The start attempt never sets it. */
2621
- resuming: boolean; /** Sounds fired while `resuming`, one per key; played when the context runs, dropped when it does not. */
2622
- pendingSfx: Map<string, SfxRequest>; /** Per key, evicted per key on `assets:bundle-unloaded` and `assets:replaced`. */
2692
+ resuming: boolean;
2693
+ /**
2694
+ * Sounds fired while `resuming`: one per id, under `"#" + id`, and one per key for a sound
2695
+ * without an id. Played when the context runs, dropped when it does not.
2696
+ */
2697
+ pendingSfx: Map<string, SfxRequest>; /** The sound that plays, or decodes, under each id; an entry leaves when its sound ends or stops. */
2698
+ named: Map<string, NamedSound>; /** Per key, evicted per key on `assets:bundle-unloaded` and `assets:replaced`. */
2623
2699
  decoded: Map<string, Promise<AudioBuffer>>; /** Asset keys that already got their one warning. */
2624
2700
  warned: Set<string>; /** `config.volumes` threw once and was reported; it is not reported again this run. */
2625
2701
  warnedVolumes: boolean;
2626
2702
  music: MusicTrack | undefined; /** The latest switch still decoding; `undefined` once it started or a later request replaced it. */
2627
2703
  musicPending: MusicSwitch | undefined; /** Removes the two window listeners of the unlock. */
2628
- unlock: (() => void) | undefined; /** The removers of the two fx handlers. */
2704
+ unlock: (() => void) | undefined; /** The removers of the three fx handlers. */
2629
2705
  removers: Array<() => void>; /** The `navigator.audioSession` that took `config.session`; `stop` writes `"auto"` back to it. */
2630
2706
  session: AudioSessionLike | undefined; /** Streamed tracks that fade out, each freed by its timer. */
2631
2707
  retiring: Set<RetiringTrack>;
@@ -2636,8 +2712,9 @@ type State$1 = {
2636
2712
  journal: readonly SoundEntry[];
2637
2713
  };
2638
2714
  /**
2639
- * audio plugin API, `app.audio`. Three buses and the unlock flag: what a game changes about sound
2640
- * it commits to the player state, which this plugin applies on the next commit.
2715
+ * audio plugin API, `app.audio`. Three buses, the unlock flag, the journal and the stop of a named
2716
+ * sound: what a game changes about sound it commits to the player state, which this plugin applies
2717
+ * on the next commit.
2641
2718
  *
2642
2719
  * @example
2643
2720
  * ```ts
@@ -2746,6 +2823,25 @@ type AudioApi = {
2746
2823
  * ```
2747
2824
  */
2748
2825
  journal(): readonly SoundEntry[];
2826
+ /**
2827
+ * Fades out and ends the sound that plays under one id, an `sfx` started with `{ id }`. The
2828
+ * same stop as the effect kind `stopSfx`: a sound with that id still decoding never starts, one
2829
+ * waiting for the unlock is dropped, and an id nothing plays under changes nothing. Headless it
2830
+ * does nothing.
2831
+ *
2832
+ * @param id - The id the sound was started with, `"voice"` for `sfx(key, { id: "voice" })`.
2833
+ * @param options - How the sound ends.
2834
+ * @param options.fadeMs - Length of the fade in real milliseconds; `config.sfxFadeMs` when absent, `0` cuts it at once.
2835
+ * @example
2836
+ * ```ts
2837
+ * // A test composed with `journal: 200` cuts the narrator's line before it checks the next screen.
2838
+ * app.audio.journal().at(-1); // { key: "story.line1", bus: "sfx", kind: "sfx", id: "voice", at: 0 }
2839
+ * app.audio.stop("voice", { fadeMs: 0 }); // the line ends now and stays in the journal
2840
+ * ```
2841
+ */
2842
+ stop(id: string, options?: {
2843
+ fadeMs?: number;
2844
+ }): void;
2749
2845
  };
2750
2846
  /**
2751
2847
  * Resolved dependency APIs.
@@ -2793,11 +2889,14 @@ type BundleUnloaded = Events$1["assets:bundle-unloaded"];
2793
2889
  */
2794
2890
  type AssetsReplaced = Events$1["assets:replaced"];
2795
2891
  /**
2796
- * What one play of a sound asks for: the key and the bus the sound goes to.
2892
+ * What one play of a sound asks for: the key, the bus the sound goes to, the id it plays under
2893
+ * (`undefined`: none), and the fade in milliseconds of the sound with that id it replaces.
2797
2894
  */
2798
2895
  type SfxRequest = {
2799
2896
  key: string;
2800
2897
  bus: string;
2898
+ id: string | undefined;
2899
+ fadeMs: number;
2801
2900
  };
2802
2901
  /**
2803
2902
  * What one music switch asks for: the key, or `null` to fade the current track out.
@@ -3049,4 +3148,4 @@ type UiApi = {
3049
3148
  scroll(key: string, to: number): boolean;
3050
3149
  };
3051
3150
  //#endregion
3052
- export { sequence as $, GlowValue as A, Target as B, BlurValue as C, FilterComponent as D, FilterArea as E, AnimPlayerValue as F, HAPTIC_KINDS as G, HapticKind as H, Config$3 as I, frames as J, defineAnimation as K, FramesValue as L, OutlineValue as M, UniformDeclaration as N, FilterSpec as O, AnimApi as P, play as Q, MotionKeyframe as R, AlphaValue as S, DisplacementValue as T, SfxDescriptor as U, types_d_exports$3 as V, Step as W, mark as X, haptic as Y, parallel as Z, State$2 as _, AudioApi as a, tween as at, EmitterDefinition as b, MusicDescriptor as c, OverlayApi as ct, State$1 as d, set as et, VolumesFor as f, EffectsStats as g, EffectsApi as h, types_d_exports as i, stagger as it, NoiseValue as j, FilterValueOf as k, MusicOptions as l, types_d_exports$4 as lt, Config$2 as m, State as n, spawn as nt, AudioContextLike as o, use as ot, types_d_exports$1 as p, external as q, UiApi as r, spawned as rt, Config$1 as s, wait as st, Config as t, sfx as tt, SoundEntry as u, types_d_exports$2 as v, ColorMatrixValue as w, EmitterValue as x, EmitterConfig as y, State$3 as z };
3151
+ export { sequence as $, GlowValue as A, Target as B, BlurValue as C, FilterComponent as D, FilterArea as E, AnimPlayerValue as F, HAPTIC_KINDS as G, HapticKind as H, Config$3 as I, frames as J, defineAnimation as K, FramesValue as L, OutlineValue as M, UniformDeclaration as N, FilterSpec as O, AnimApi as P, play as Q, MotionKeyframe as R, AlphaValue as S, DisplacementValue as T, SfxDescriptor as U, types_d_exports$3 as V, Step as W, mark as X, haptic as Y, parallel as Z, State$2 as _, AudioApi as a, stopSfx as at, EmitterDefinition as b, MusicDescriptor as c, wait as ct, State$1 as d, set as et, VolumesFor as f, EffectsStats as g, EffectsApi as h, types_d_exports as i, stagger as it, NoiseValue as j, FilterValueOf as k, MusicOptions as l, OverlayApi as lt, Config$2 as m, State as n, spawn as nt, AudioContextLike as o, tween as ot, types_d_exports$1 as p, external as q, UiApi as r, spawned as rt, Config$1 as s, use as st, Config as t, sfx as tt, SoundEntry as u, types_d_exports$4 as ut, types_d_exports$2 as v, ColorMatrixValue as w, EmitterValue as x, EmitterConfig as y, State$3 as z };
@@ -4378,6 +4378,11 @@ type Mounted = {
4378
4378
  * identity: a `mount` under the same list is a second mount of one scene, a `mount` under a new one keeps it.
4379
4379
  */
4380
4380
  layers: ReadonlyArray<LayerSpec>;
4381
+ /**
4382
+ * The state of its last reconcile: a play reconcile against the same `player` and `session` trees changes nothing
4383
+ * and is passed over (the frame after a scene mounted it direct). Absent before the first reconcile.
4384
+ */
4385
+ seen?: Snapshot;
4381
4386
  };
4382
4387
  /**
4383
4388
  * One track the projection started on the driver. The world keeps the component name and the
@@ -7936,6 +7941,11 @@ type KeptRecord = {
7936
7941
  */
7937
7942
  direct: boolean; /** A view of kind `"Display"` hangs in the subtree; `undefined` until a take attempt walks it (P4.1). */
7938
7943
  displays: boolean | undefined;
7944
+ /**
7945
+ * A walk found a node under the top that blends otherwise than normally (F68): the record is not taken, and the walk
7946
+ * is not taken again until a frame that sets `dirtyS1` (a change under the top) clears it.
7947
+ */
7948
+ blended: boolean;
7939
7949
  };
7940
7950
  /** One picture of an overlay's range (P7), keyed by the owner overlay's entity. */
7941
7951
  type RangeRecord = {
@@ -7977,7 +7987,8 @@ type KeptState = {
7977
7987
  drawnPictures: number; /** Debug switch `debug.kept` (P14); config `keptMb: 0` forces it off. */
7978
7988
  on: boolean; /** `keptMb > 0`: the switch can be turned on. */
7979
7989
  allowed: boolean; /** One warning per run for a budget refusal. */
7980
- warnedBudget: boolean; /** The pixel leg of the oracle (P13.2): frames skipped for being off-grid, for the verify log. */
7990
+ warnedBudget: boolean; /** The labels of the tops already warned for a blended node under them (`renderer:kept-blend`), once each per run. */
7991
+ warnedBlend: Set<string>; /** The pixel leg of the oracle (P13.2): frames skipped for being off-grid, for the verify log. */
7981
7992
  verifySkipped: number; /** True while `bypass(true)` draws everything live for an extract. */
7982
7993
  bypassed: boolean; /** Render passes the last flush cost: the estimate `sync.renderPasses()` adds (P9.2). */
7983
7994
  flushPasses: number;
@@ -9562,11 +9573,25 @@ type TransformValue = {
9562
9573
  * ```
9563
9574
  */
9564
9575
  type SpriteFit = "fill" | "contain" | "cover";
9576
+ /**
9577
+ * How a sprite or a nine-slice lays its own pixels over what is drawn under it. `"normal"` covers it by alpha, as a
9578
+ * view without the field does. `"screen"` lightens it: on a dark background it matches CSS `mix-blend-mode: screen`.
9579
+ * `"add"` adds the colours, brighter than `"screen"`. Both draw in the sprite batch, with no extra pass; each switch
9580
+ * between blends in draw order costs one more draw call.
9581
+ *
9582
+ * @example
9583
+ * ```ts
9584
+ * // The glow of the memory card: lightens the ward under it as the design's screen does.
9585
+ * const glow: SpriteBlend = "screen";
9586
+ * world.ecs.spawn(owner, [Layer({ name: "fx" }), Transform({ x: 540, y: 960 }), Sprite({ texture: "fx.glow", blend: glow })]);
9587
+ * ```
9588
+ */
9589
+ type SpriteBlend = "normal" | "add" | "screen";
9565
9590
  /**
9566
9591
  * One textured quad. `texture` is an asset key; `defineGame` narrows it to the game's keys.
9567
9592
  * `width` and `height` are the box in reference units; 0 on an axis keeps the texture's own size
9568
9593
  * there. `anchor` is the point of the box that sits on the `Transform`. `alpha` fades the quad
9569
- * and the entity's children.
9594
+ * and the entity's children. `blend` lays the quad over what is under it with `"add"` or `"screen"`.
9570
9595
  *
9571
9596
  * @example
9572
9597
  * ```ts
@@ -9574,6 +9599,8 @@ type SpriteFit = "fill" | "contain" | "cover";
9574
9599
  * texture: "board.bg-forest-meadow", tint: 0xffffff, alpha: 1, anchor: { x: 0, y: 0 },
9575
9600
  * width: 1080, height: 1920, fit: "cover"
9576
9601
  * };
9602
+ * // A spark over the board: its pixels add to the board's.
9603
+ * const spark: SpriteValue = { ...value, texture: "fx.spark", width: 96, height: 96, blend: "add" };
9577
9604
  * ```
9578
9605
  */
9579
9606
  type SpriteValue = {
@@ -9584,6 +9611,22 @@ type SpriteValue = {
9584
9611
  width: number;
9585
9612
  height: number;
9586
9613
  fit: SpriteFit;
9614
+ /**
9615
+ * How the quad lays its pixels over what is drawn under it: `"add"` adds them, `"screen"` lightens with them (CSS
9616
+ * `mix-blend-mode: screen` on a dark background), `"normal"` covers by alpha. It blends the quad alone, never the
9617
+ * entity's children. Absent by default, read as `"normal"`, so a sprite that never sets it keeps the values it had
9618
+ * before the field existed; `"normal"` is there so a patch can turn a glow off. Any other string draws normally and is
9619
+ * warned once (`renderer:blend-unknown`). A filtered view with a blended node inside is drawn live, never kept as a
9620
+ * picture (`renderer:kept-blend`, once).
9621
+ *
9622
+ * @example
9623
+ * ```ts
9624
+ * // The glow behind the found memory lightens the ward under it, then turns off.
9625
+ * const glow = world.ecs.spawn(owner, [Layer({ name: "fx" }), Transform({ x: 540, y: 960 }), Sprite({ texture: "fx.glow", alpha: 0.8, blend: "screen" })]);
9626
+ * world.ecs.set(glow, Sprite, { blend: "normal" });
9627
+ * ```
9628
+ */
9629
+ blend?: SpriteBlend;
9587
9630
  };
9588
9631
  /**
9589
9632
  * A stretchable panel. The slice borders come with the texture, not with the component. `debug`
@@ -9591,7 +9634,8 @@ type SpriteValue = {
9591
9634
  * the texture is missing. `clip` masks the children of the entity to the `width × height` box,
9592
9635
  * the same rule as `Shape.clip`: the mask is a filled rectangle and is never drawn, and the panel
9593
9636
  * itself is never masked. `alpha` fades the panel and the entity's children. `hollow` draws the
9594
- * rim alone: the eight border pieces, never the centre.
9637
+ * rim alone: the eight border pieces, never the centre. `blend` lays the panel over what is under it
9638
+ * with `"add"` or `"screen"`.
9595
9639
  *
9596
9640
  * @example
9597
9641
  * ```ts
@@ -9635,6 +9679,19 @@ type NineSliceValue = {
9635
9679
  * ```
9636
9680
  */
9637
9681
  hollow?: boolean;
9682
+ /**
9683
+ * How the panel lays its pixels over what is drawn under it, as `Sprite.blend`: `"add"` adds them, `"screen"`
9684
+ * lightens with them, `"normal"` covers by alpha. It blends the panel alone, filled or hollow, never the entity's
9685
+ * children. Absent by default, read as `"normal"`, so a panel that never sets it keeps the values it had before the
9686
+ * field existed.
9687
+ *
9688
+ * @example
9689
+ * ```ts
9690
+ * // The frost rim of the memory screen lightens the ward behind it; the centre stays empty.
9691
+ * world.ecs.spawn(owner, [Layer({ name: "ui" }), Transform(), NineSlice({ texture: "glass.frost", width: 960, height: 1400, hollow: true, blend: "screen" })]);
9692
+ * ```
9693
+ */
9694
+ blend?: SpriteBlend;
9638
9695
  };
9639
9696
  /**
9640
9697
  * The escape hatch: the game owns a Pixi object and `sync` only attaches and detaches it.
@@ -9776,13 +9833,14 @@ type OverlayLevelValue = {
9776
9833
  declare const Transform: ComponentType<TransformValue>;
9777
9834
  /**
9778
9835
  * One textured quad. `texture` is an asset key, resolved through the texture providers; a size
9779
- * and a `fit` draw it into a box.
9836
+ * and a `fit` draw it into a box. `blend: "add"` or `"screen"` lays it over what is under it.
9780
9837
  */
9781
9838
  declare const Sprite: ComponentType<SpriteValue>;
9782
9839
  /**
9783
9840
  * A stretchable panel, sized in reference units, with its own alpha and tint. `debug: true` draws
9784
9841
  * the slice outline over it. `clip: true` masks the children of the entity to the panel box.
9785
- * `hollow: true` draws its rim alone, never the centre cell.
9842
+ * `hollow: true` draws its rim alone, never the centre cell. `blend: "add"` or `"screen"` lays it over what is under
9843
+ * it.
9786
9844
  */
9787
9845
  declare const NineSlice$1: ComponentType<NineSliceValue>;
9788
9846
  /**
@@ -10868,10 +10926,11 @@ type AreaEntry = {
10868
10926
  rect: PixiRectangle | undefined;
10869
10927
  };
10870
10928
  /**
10871
- * What one probe draw of the warm-up draws: a content subject of the renderer (the batch pipeline of sprites, the
10872
- * graphics pipe's own, particles with either blend, distance-field text), or a filter handed to `filters.warm`.
10929
+ * What one probe draw of the warm-up draws: a content subject of the renderer (the batch pipeline of sprites, with the
10930
+ * normal, the add and the screen blend, the graphics pipe's own, particles with either blend, distance-field text), or
10931
+ * a filter handed to `filters.warm`.
10873
10932
  */
10874
- type WarmSubject = "sprite" | "graphics" | "particles-normal" | "particles-add" | "text" | PixiFilter;
10933
+ type WarmSubject = "sprite" | "sprite-add" | "sprite-screen" | "graphics" | "particles-normal" | "particles-add" | "text" | PixiFilter;
10875
10934
  /**
10876
10935
  * Where a probe draws: straight onto the canvas, or into a texture under a filter of the module's own, each with or
10877
10936
  * without a stencil clip. A WebGPU pipeline is keyed by all four.
@@ -10902,7 +10961,9 @@ type WarmObjects = {
10902
10961
  target: PixiRenderTexture; /** A filter subject's container: its `filters` is the draw's filter, during the draw only. */
10903
10962
  holder: PixiContainer; /** The one-entry list `holder.filters` is set from. */
10904
10963
  list: PixiFilter[];
10905
- sprite: PixiSprite;
10964
+ sprite: PixiSprite; /** The 4 × 4 white sprite of `sprite`, blending `"add"`: the batch pipeline of an added glow. */
10965
+ spriteAdd: PixiSprite; /** The 4 × 4 white sprite of `sprite`, blending `"screen"`: the batch pipeline of a screened glow. */
10966
+ spriteScreen: PixiSprite;
10906
10967
  graphics: PixiGraphics;
10907
10968
  particlesNormal: PixiContainer;
10908
10969
  particlesAdd: PixiContainer; /** A `BitmapText` of "0" in `WarmState.textFont`; made at its first draw. */
@@ -11132,7 +11193,8 @@ type SyncState = {
11132
11193
  */
11133
11194
  slices: WeakSet<PixiTexture>;
11134
11195
  invalidated: Set<string>; /** Keys already reported missing, so one key warns once. */
11135
- warned: Set<string>;
11196
+ warned: Set<string>; /** The `blend` values of a `Sprite` or a `NineSlice` already refused (`renderer:blend-unknown`), so each warns once. */
11197
+ blendWarned: Set<string>;
11136
11198
  added: Set<Entity>;
11137
11199
  removed: Set<Entity>; /** Entities whose `Parent` was removed: `world` marks no change then, only `onRemoved` fires. */
11138
11200
  reparented: Set<Entity>;
@@ -12535,4 +12597,4 @@ type BundleCompanion = {
12535
12597
  unload(bundle: string): void;
12536
12598
  };
12537
12599
  //#endregion
12538
- export { PixiTexture as $, AnyFlow as $n, Config$9 as $r, DEMAND_REASONS as $t, Display as A, ProjectionSpec as An, PlayerStateProvider as Ar, PerfCollectorLine as At, Sprite as B, HudKeysOf as Bn, Config$7 as Br, PerfMeasured as Bt, ScenesApi as C, DescriptionNode as Cn, Config$6 as Cr, PERF_LOG_VERSION as Ct, FilterSlot as D, MotionHandle as Dn, State$6 as Dr, PerfCause as Dt, DebugSwitches as E, MotionCause as En, Root as Er, PassRecord as Et, Overlay as F, Api$3 as Fn, SnapshotOf as Fr, PerfGapLine as Ft, sprite as G, defineFlow as Gn, Api$7 as Gr, PerfThermalLine as Gt, SpriteValue as H, State$4 as Hn, PauseReason as Hr, PerfSpikeLine as Ht, OverlayValue as I, BundlesOf as In, StoreApi as Ir, PerfHeaderLine as It, Config$2 as J, to as Jn, RateChange as Jr, ProblemRule as Jt, AdaptiveScale as K, exit as Kn, Config$8 as Kr, PoolTrimDetail as Kt, Parent as L, Config$4 as Ln, RngApi as Lr, PerfLogLine as Lt, HudPartValue as M, TrackOptions as Mn, SaveDoc as Mr, PerfDisplay as Mt, NineSlice$1 as N, TrackSegment as Nn, SaveUnreadableError as Nr, PerfEventLine as Nt, FilterSlotInputs as O, NumericFields as On, types_d_exports$6 as Or, PerfChange as Ot, NineSliceValue as P, ViewHandle as Pn, Snapshot as Pr, PerfEventName as Pt, PixiSprite as Q, FeatureTree as Qn, types_d_exports$8 as Qr, WarmDetail as Qt, Shape as R, EmitterIdOf as Rn, RngState as Rr, PerfLongFrameLine as Rt, SceneSpec as S, ChangeHook as Sn, Api$5 as Sr, PERF_GAP_BUCKETS as St, types_d_exports$1 as T, Motion as Tn, Json as Tr, PassKind as Tt, Transform as U, TextStylesOf as Un, State$7 as Ur, PerfStartupLine as Ut, SpriteOptions as V, Position as Vn, Events$6 as Vr, PerfSampleLine as Vt, TransformValue as W, types_d_exports$4 as Wn, types_d_exports$7 as Wr, PerfTelemetryLine as Wt, PixiFilter as X, FeatureDescription as Xn, ThermalReading as Xr, ShaderEventDetail as Xt, MonitorConfig as Y, type as Yn, State$8 as Yr, SHADER_WHATS as Yt, PixiModule as Z, FeaturePlugin as Zn, Time as Zr, ShaderWhat as Zt, AnySceneProjection as _, QueryTerm as _n, ClockSource as _r, MONITOR_SECTIONS as _t, Config as a, AnyComponent as an, NodeTable as ar, MonitorCounts as at, LayerMap as b, SystemFor as bn, State$5 as br, OverlayWhat as bt, LoadBundles as c, ComponentHandle as cn, TypeTag as cr, Point as ct, Manifest as d, ComponentValue as dn, EffectOptions as dr, FrameColumns as dt, Events$8 as ei, Api$2 as en, Bookmark as er, PoolTrim as et, ReadyBundles as f, Entity as fn, GuideOptions as fr, FrameReadResult as ft, types_d_exports as g, Narrowed as gn, Api$4 as gr, LongFrameEntry as gt, Usage as h, Mut as hn, Answer as hr, FrameRing as ht, BundleSpec as i, types_d_exports$3 as in, JournalEntry as ir, Captured as it, HudPart as j, ReducedMotion as jn, ProviderCall as jr, PerfCounts as jt, SyncApi as k, ProjectionMotion as kn, Patch as kr, PerfChangeEntry as kt, LoadReason as l, ComponentSchema as ln, Descriptor as lr, ViewportSize as lt, Tier as m, FrameDiff as mn, NodeFx as mr, FrameRecord as mt, AssetsIo as n, Explained as nn, FlowGraph as nr, Under as nt, DefineBundles as o, AnyComponentType as on, RouteStep as or, RenderStats as ot, State as p, EntitySnapshot as pn, Hint as pr, FrameReadout as pt, Api$1 as q, slot as qn, FrameRate as qr, ProblemEventDetail as qt, BundleMap as r, State$3 as rn, FlowState as rr, types_d_exports$2 as rt, Events as s, AnyComponentValue as sn, SceneIdOf as sr, Orientation as st, Api as t, Require as ti, Config$3 as tn, DefineNode as tr, State$2 as tt, LoadResult as u, ComponentType as un, Effect as ur, FilterCache as ut, DefineScene as v, ResourceType as vn, Config$5 as vr, MonitorSections as vt, State$1 as w, Ease as wn, Events$5 as wr, PROBLEM_RULES as wt, SceneDefinition as x, TagType as xn, types_d_exports$5 as xr, PERF_CAUSES as xt, Events$1 as y, SystemDefinition as yn, FakeClock as yr, OverlayEventDetail as yt, ShapeValue as z, GameTypes as zn, Api$6 as zr, PerfMarkLine as zt };
12600
+ export { PixiSprite as $, FeatureTree as $n, types_d_exports$8 as $r, WarmDetail as $t, Display as A, ProjectionMotion as An, Patch as Ar, PerfChangeEntry as At, Sprite as B, GameTypes as Bn, Api$6 as Br, PerfMarkLine as Bt, ScenesApi as C, ChangeHook as Cn, Api$5 as Cr, PERF_GAP_BUCKETS as Ct, FilterSlot as D, MotionCause as Dn, Root as Dr, PassRecord as Dt, DebugSwitches as E, Motion as En, Json as Er, PassKind as Et, Overlay as F, ViewHandle as Fn, Snapshot as Fr, PerfEventName as Ft, TransformValue as G, types_d_exports$4 as Gn, types_d_exports$7 as Gr, PerfTelemetryLine as Gt, SpriteOptions as H, Position as Hn, Events$6 as Hr, PerfSampleLine as Ht, OverlayValue as I, Api$3 as In, SnapshotOf as Ir, PerfGapLine as It, Api$1 as J, slot as Jn, FrameRate as Jr, ProblemEventDetail as Jt, sprite as K, defineFlow as Kn, Api$7 as Kr, PerfThermalLine as Kt, Parent as L, BundlesOf as Ln, StoreApi as Lr, PerfHeaderLine as Lt, HudPartValue as M, ReducedMotion as Mn, ProviderCall as Mr, PerfCounts as Mt, NineSlice$1 as N, TrackOptions as Nn, SaveDoc as Nr, PerfDisplay as Nt, FilterSlotInputs as O, MotionHandle as On, State$6 as Or, PerfCause as Ot, NineSliceValue as P, TrackSegment as Pn, SaveUnreadableError as Pr, PerfEventLine as Pt, PixiModule as Q, FeaturePlugin as Qn, Time as Qr, ShaderWhat as Qt, Shape as R, Config$4 as Rn, RngApi as Rr, PerfLogLine as Rt, SceneSpec as S, TagType as Sn, types_d_exports$5 as Sr, PERF_CAUSES as St, types_d_exports$1 as T, Ease as Tn, Events$5 as Tr, PROBLEM_RULES as Tt, SpriteValue as U, State$4 as Un, PauseReason as Ur, PerfSpikeLine as Ut, SpriteBlend as V, HudKeysOf as Vn, Config$7 as Vr, PerfMeasured as Vt, Transform as W, TextStylesOf as Wn, State$7 as Wr, PerfStartupLine as Wt, MonitorConfig as X, type as Xn, State$8 as Xr, SHADER_WHATS as Xt, Config$2 as Y, to as Yn, RateChange as Yr, ProblemRule as Yt, PixiFilter as Z, FeatureDescription as Zn, ThermalReading as Zr, ShaderEventDetail as Zt, AnySceneProjection as _, Narrowed as _n, Api$4 as _r, LongFrameEntry as _t, Config as a, types_d_exports$3 as an, JournalEntry as ar, Captured as at, LayerMap as b, SystemDefinition as bn, FakeClock as br, OverlayEventDetail as bt, LoadBundles as c, AnyComponentValue as cn, SceneIdOf as cr, Orientation as ct, Manifest as d, ComponentType as dn, Effect as dr, FilterCache as dt, Config$9 as ei, DEMAND_REASONS as en, AnyFlow as er, PixiTexture as et, ReadyBundles as f, ComponentValue as fn, EffectOptions as fr, FrameColumns as ft, types_d_exports as g, Mut as gn, Answer as gr, FrameRing as gt, Usage as h, FrameDiff as hn, NodeFx as hr, FrameRecord as ht, BundleSpec as i, State$3 as in, FlowState as ir, types_d_exports$2 as it, HudPart as j, ProjectionSpec as jn, PlayerStateProvider as jr, PerfCollectorLine as jt, SyncApi as k, NumericFields as kn, types_d_exports$6 as kr, PerfChange as kt, LoadReason as l, ComponentHandle as ln, TypeTag as lr, Point as lt, Tier as m, EntitySnapshot as mn, Hint as mr, FrameReadout as mt, AssetsIo as n, Require as ni, Config$3 as nn, DefineNode as nr, State$2 as nt, DefineBundles as o, AnyComponent as on, NodeTable as or, MonitorCounts as ot, State as p, Entity as pn, GuideOptions as pr, FrameReadResult as pt, AdaptiveScale as q, exit as qn, Config$8 as qr, PoolTrimDetail as qt, BundleMap as r, Explained as rn, FlowGraph as rr, Under as rt, Events as s, AnyComponentType as sn, RouteStep as sr, RenderStats as st, Api as t, Events$8 as ti, Api$2 as tn, Bookmark as tr, PoolTrim as tt, LoadResult as u, ComponentSchema as un, Descriptor as ur, ViewportSize as ut, DefineScene as v, QueryTerm as vn, ClockSource as vr, MONITOR_SECTIONS as vt, State$1 as w, DescriptionNode as wn, Config$6 as wr, PERF_LOG_VERSION as wt, SceneDefinition as x, SystemFor as xn, State$5 as xr, OverlayWhat as xt, Events$1 as y, ResourceType as yn, Config$5 as yr, MonitorSections as yt, ShapeValue as z, EmitterIdOf as zn, RngState as zr, PerfLongFrameLine as zt };
@@ -1,5 +1,5 @@
1
- import { Pr as Snapshot, Tr as Json } from "./types-ChZ4Ej7O.mjs";
2
- import { t as HeadlessApp } from "./headless-PssyKRFN.mjs";
1
+ import { Er as Json, Fr as Snapshot } from "./types-C_nC_M4p.mjs";
2
+ import { t as HeadlessApp } from "./headless-DBYmnluy.mjs";
3
3
  import { Log } from "@moku-labs/common/browser";
4
4
 
5
5
  //#region src/plugins/flow/doors/types.d.ts
@@ -1,4 +1,4 @@
1
- import { Dn as MotionHandle, En as MotionCause, Fn as Api$1, Gr as Api, On as NumericFields, Pn as ViewHandle, Sn as ChangeHook, Tn as Motion, Tr as Json, W as TransformValue, an as AnyComponent, en as Api$2, fn as Entity, gr as Api$5, hr as Answer, jn as ReducedMotion, kn as ProjectionMotion, lr as Descriptor, lt as ViewportSize, on as AnyComponentType, pr as Hint, q as Api$3, s as Events$1, sn as AnyComponentValue, t as Api$4, ti as Require, un as ComponentType, wn as Ease, xn as TagType } from "./types-ChZ4Ej7O.mjs";
1
+ import { An as ProjectionMotion, Cn as ChangeHook, Dn as MotionCause, En as Motion, Er as Json, Fn as ViewHandle, G as TransformValue, In as Api$1, J as Api$3, Kr as Api, Mn as ReducedMotion, On as MotionHandle, Sn as TagType, Tn as Ease, _r as Api$5, cn as AnyComponentValue, dn as ComponentType, gr as Answer, kn as NumericFields, mr as Hint, ni as Require, on as AnyComponent, pn as Entity, s as Events$1, sn as AnyComponentType, t as Api$4, tn as Api$2, ur as Descriptor, ut as ViewportSize } from "./types-C_nC_M4p.mjs";
2
2
  import { Log } from "@moku-labs/common/browser";
3
3
  import { PluginCtx } from "@moku-labs/core";
4
4
  import { Node, Yoga } from "yoga-layout/load";
@@ -171,7 +171,24 @@ type VisualStyle<Asset extends string = string> = {
171
171
  * app.world.ecs.get(app.ui.find("memFrost") ?? 0, NineSlice)?.hollow; // true
172
172
  * ```
173
173
  */
174
- hollow?: boolean; /** Multiplies the colour of a nine-slice or an image. */
174
+ hollow?: boolean;
175
+ /**
176
+ * How an image or icon, or the nine-slice of the style, lays its pixels over what is drawn
177
+ * under it: `"add"` adds its colour (a spark, a flare), `"screen"` lightens with it (a soft
178
+ * glow; on a dark background it matches CSS `mix-blend-mode: screen`). Absent, it covers by
179
+ * alpha. It blends the element's own quad alone, never its children, and does nothing on a
180
+ * rectangle, a shape or a text. Written into `Sprite.blend` or `NineSlice.blend`; a variant that
181
+ * drops it draws the element normally again. No render pass: each switch between blends in draw
182
+ * order costs one more draw call. Inside a kept picture the view is drawn live.
183
+ *
184
+ * @example
185
+ * ```tsx
186
+ * // The glow behind the reward chest: it lightens the board under it instead of covering it.
187
+ * <image key="glow" texture="art.glow" style={{ blend: "screen", alpha: 0.8 }} />;
188
+ * app.world.ecs.get(app.ui.find("glow") ?? 0, Sprite)?.blend; // "screen"
189
+ * ```
190
+ */
191
+ blend?: "add" | "screen"; /** Multiplies the colour of a nine-slice or an image. */
175
192
  tint?: number;
176
193
  /**
177
194
  * Outlines the nine-slice of the style: its bounds and the four slice lines, cyan, red when
@@ -2703,7 +2720,8 @@ type Element = {
2703
2720
  };
2704
2721
  measuredWidth?: number | undefined; /** True once the text wrapped at its box: from then on `ui` writes its box, 0 when it fits. */
2705
2722
  boxed?: boolean; /** True once its nine-slice was hollow: from then on `ui` writes `hollow`, false when the style drops it. */
2706
- hollowed?: boolean;
2723
+ hollowed?: boolean; /** True once its image or nine-slice blended: from then on `ui` writes `blend`, `"normal"` when the style drops it. */
2724
+ blended?: boolean;
2707
2725
  basis?: StyleBasis; /** The motions of its hooks that started a `repeat: "forever"` track; made with the first one. */
2708
2726
  endless?: Set<MotionHandle>; /** What its enter hook did at the `Box`, until `ui.enter` keeps the play or plays it again (F49). */
2709
2727
  posed?: PosedEnter | undefined;
@@ -1,9 +1,9 @@
1
- import { Sr as Api$2, en as Api$1, q as Api, zr as Api$3 } from "./types-ChZ4Ej7O.mjs";
2
- import { P as AnimApi, r as UiApi } from "./types-C-wAHgpD.mjs";
3
- import { N as InputApi } from "./types-_OQ6H8WL.mjs";
4
- import { r as Repro } from "./headless-PssyKRFN.mjs";
5
- import { a as InputOf, r as ControlApp } from "./types-sfaYGg9l.mjs";
6
- import { t as commands } from "./commands-KWKfdywA.mjs";
1
+ import { Br as Api$3, Cr as Api$2, J as Api, tn as Api$1 } from "./types-C_nC_M4p.mjs";
2
+ import { P as AnimApi, r as UiApi } from "./types-C76NQm-h.mjs";
3
+ import { N as InputApi } from "./types-bEJEga5m.mjs";
4
+ import { r as Repro } from "./headless-DBYmnluy.mjs";
5
+ import { a as InputOf, r as ControlApp } from "./types-DTetCcBC.mjs";
6
+ import { t as commands } from "./commands-BJ4gG5WZ.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. */