narraleaf-react 0.14.0 → 0.16.0

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 (45) hide show
  1. package/dist/game/nlcore/action/actionTypes.d.ts +16 -2
  2. package/dist/game/nlcore/action/actions/controlAction.d.ts +2 -0
  3. package/dist/game/nlcore/action/actions/vfxAction.d.ts +24 -0
  4. package/dist/game/nlcore/action/logicAction.d.ts +16 -13
  5. package/dist/game/nlcore/action/stackModel.d.ts +28 -0
  6. package/dist/game/nlcore/common/elements.d.ts +6 -1
  7. package/dist/game/nlcore/common/game.d.ts +2 -1
  8. package/dist/game/nlcore/common/transition.d.ts +8 -9
  9. package/dist/game/nlcore/elements/camera.d.ts +71 -0
  10. package/dist/game/nlcore/elements/character/sentence.d.ts +2 -1
  11. package/dist/game/nlcore/elements/character/textEvent.d.ts +67 -0
  12. package/dist/game/nlcore/elements/character/word.d.ts +2 -1
  13. package/dist/game/nlcore/elements/control.d.ts +62 -0
  14. package/dist/game/nlcore/elements/displayable/image.d.ts +2 -2
  15. package/dist/game/nlcore/elements/scene.d.ts +2 -2
  16. package/dist/game/nlcore/elements/story.d.ts +21 -1
  17. package/dist/game/nlcore/elements/transition/transitions/image/darkness.d.ts +16 -9
  18. package/dist/game/nlcore/elements/transition/transitions/image/dissolve.d.ts +9 -6
  19. package/dist/game/nlcore/elements/transition/transitions/image/fadeIn.d.ts +9 -8
  20. package/dist/game/nlcore/elements/transition/transitions/image/mask.d.ts +162 -0
  21. package/dist/game/nlcore/elements/transition/transitions/image/reveal.d.ts +33 -0
  22. package/dist/game/nlcore/elements/transition/transitions/image/throughColor.d.ts +34 -36
  23. package/dist/game/nlcore/elements/transition/transitions/image/transitionMaskUtils.d.ts +5 -16
  24. package/dist/game/nlcore/elements/transition/transitions/text/fontSize.d.ts +9 -2
  25. package/dist/game/nlcore/elements/vfx.d.ts +85 -0
  26. package/dist/game/nlcore/elements/video.d.ts +26 -0
  27. package/dist/game/nlcore/game/liveGame.d.ts +44 -5
  28. package/dist/game/player/elements/menu/type.d.ts +3 -2
  29. package/dist/game/player/elements/nvl/type.d.ts +2 -1
  30. package/dist/game/player/elements/nvl/useNvlDialogState.d.ts +2 -1
  31. package/dist/game/player/elements/player/Camera.d.ts +1 -0
  32. package/dist/game/player/elements/say/Sentence.d.ts +3 -2
  33. package/dist/game/player/elements/say/UIDialog.d.ts +2 -1
  34. package/dist/game/player/elements/say/textEventEffect.d.ts +19 -0
  35. package/dist/game/player/elements/say/type.d.ts +4 -3
  36. package/dist/game/player/elements/scene/SceneDialogs.d.ts +1 -0
  37. package/dist/game/player/elements/vfx/Vfx.d.ts +1 -0
  38. package/dist/game/player/gameState.d.ts +8 -0
  39. package/dist/game/player/type.d.ts +20 -1
  40. package/dist/main.js +44 -42
  41. package/package.json +1 -1
  42. package/dist/game/nlcore/elements/transition/transitions/image/blinds.d.ts +0 -28
  43. package/dist/game/nlcore/elements/transition/transitions/image/maskTransition.d.ts +0 -38
  44. package/dist/game/nlcore/elements/transition/transitions/image/softIris.d.ts +0 -28
  45. package/dist/game/nlcore/elements/transition/transitions/image/softWipe.d.ts +0 -28
@@ -3,6 +3,13 @@ import { TransformDefinitions } from "../../../../elements/transform/type";
3
3
  import { ImageTransition } from "../../../../elements/transition/transitions/image/imageTransition";
4
4
  import { GameState } from "../../../../../player/gameState";
5
5
  type AnimationType = [TransitionAnimationType.Number, TransitionAnimationType.Number, TransitionAnimationType.Number];
6
+ export type FadeInOptions = {
7
+ /** Duration in milliseconds. */
8
+ duration: number;
9
+ /** Pixel offset the target travels in from, as `[x, y]`. @default [0, 0] */
10
+ offset?: [xOffset: number, yOffset: number];
11
+ easing?: TransformDefinitions.EasingDefinition;
12
+ };
6
13
  /**
7
14
  * A fade in, optionally travelling from a pixel offset to rest.
8
15
  *
@@ -16,15 +23,9 @@ type AnimationType = [TransitionAnimationType.Number, TransitionAnimationType.Nu
16
23
  */
17
24
  export declare class FadeIn extends ImageTransition<AnimationType> {
18
25
  private duration;
19
- private startPos;
26
+ private offset;
20
27
  private easing?;
21
- /**
22
- * Fade in the target image with an optional position start position
23
- * @param startPos start position offset
24
- * @param duration duration in milliseconds
25
- * @param easing easing definition or existing easing name
26
- */
27
- constructor(duration: number, startPos?: [xOffset: number, yOffset: number], easing?: TransformDefinitions.EasingDefinition | undefined);
28
+ constructor(options: FadeInOptions);
28
29
  createTask(gameState: GameState): TransitionTask<HTMLImageElement, AnimationType>;
29
30
  copy(): FadeIn;
30
31
  }
@@ -0,0 +1,162 @@
1
+ import { CSSProps } from "../../../../elements/transition/type";
2
+ import { TransformDefinitions } from "../../../../elements/transform/type";
3
+ import { BlindsOrientation } from "../../../../elements/transition/transitions/image/transitionMaskUtils";
4
+ /**
5
+ * A parametric coverage mask: the geometry vocabulary shared by the two
6
+ * mask-driven transition engines — {@link Reveal} (direct A→B) and
7
+ * {@link ThroughColor} (cover with a colour, swap, uncover). Built through the
8
+ * static factories on {@link Mask} and passed to an engine's `pattern` option.
9
+ *
10
+ * Invariants every pattern upholds:
11
+ * - `mask(0)` is fully transparent and `mask(1)` fully opaque, feather included —
12
+ * the soft band is swept completely off both ends of the run.
13
+ * - The opaque fraction grows monotonically with `t`.
14
+ * - `mask(t, true)` is the complementary orientation of the same geometry at the
15
+ * same coverage: a wipe grows from the opposite side, an iris closes from the
16
+ * rim instead of growing from the centre, a clock hand sweeps the other way.
17
+ * This is what lets {@link ThroughColor} continue a pattern through the hold
18
+ * instead of backing it out.
19
+ */
20
+ export type MaskPattern = {
21
+ /**
22
+ * The CSS mask image whose opaque region covers fraction `t` (0–1) of the
23
+ * frame. May be a comma-separated multi-layer image list.
24
+ */
25
+ mask(t: number, inverted?: boolean): string;
26
+ /** `mask-size` for tiled patterns. @default "100% 100%" */
27
+ size?: string;
28
+ /** `mask-repeat` for tiled patterns. @default "no-repeat" */
29
+ repeat?: string;
30
+ };
31
+ export type WipePatternOptions = {
32
+ /**
33
+ * Direction the covering edge travels toward — a keyword, or any CSS
34
+ * gradient angle in degrees (`0` = up, `90` = right). @default "left"
35
+ */
36
+ direction?: TransformDefinitions.WipeDirection | number;
37
+ /** Width of the soft edge band, in percent. Use `0` for a hard edge. @default 12 */
38
+ feather?: number;
39
+ };
40
+ export type BarnDoorPatternOptions = {
41
+ /** Travel axis of the doors, or any CSS gradient angle in degrees. @default "horizontal" */
42
+ axis?: "horizontal" | "vertical" | number;
43
+ /** Width of the soft edge band, in percent. @default 12 */
44
+ feather?: number;
45
+ };
46
+ export type IrisPatternOptions = {
47
+ /** Centre of the iris, as a CSS position. @default "50% 50%" */
48
+ center?: string;
49
+ /** Width of the soft edge band, in percent. Use `0` for a hard edge. @default 12 */
50
+ feather?: number;
51
+ /** Ending shape of the iris. @default "circle" */
52
+ shape?: "circle" | "ellipse";
53
+ };
54
+ export type ClockPatternOptions = {
55
+ /** Centre of the sweep, as a CSS position. @default "50% 50%" */
56
+ center?: string;
57
+ /** Angle the sweep starts from, in degrees (`0` = up). @default 0 */
58
+ from?: number;
59
+ /** Width of the soft leading edge, in degrees. @default 24 */
60
+ feather?: number;
61
+ /** Sweep direction of the hand. @default "clockwise" */
62
+ direction?: "clockwise" | "counterclockwise";
63
+ };
64
+ export type FanPatternOptions = {
65
+ /** Number of blades sweeping in parallel. @default 4 */
66
+ blades?: number;
67
+ /** Centre of the sweep, as a CSS position. @default "50% 50%" */
68
+ center?: string;
69
+ /** Angle the sweep starts from, in degrees (`0` = up). @default 0 */
70
+ from?: number;
71
+ /** Width of each blade's soft leading edge, in degrees. @default 10 */
72
+ feather?: number;
73
+ };
74
+ export type BlindsPatternOptions = {
75
+ /** Slat orientation, or any CSS gradient angle in degrees. @default "horizontal" */
76
+ orientation?: BlindsOrientation | number;
77
+ /** Number of slats. @default 8 */
78
+ slats?: number;
79
+ /** Width of each slat's soft edge, in percent of the frame. @default 0 (hard slats) */
80
+ feather?: number;
81
+ };
82
+ export type DotsPatternOptions = {
83
+ /** Number of tile rows. @default 6 */
84
+ rows?: number;
85
+ /** Number of tile columns. @default 10 */
86
+ cols?: number;
87
+ /** Width of each dot's soft rim, in percent of its tile. @default 20 */
88
+ feather?: number;
89
+ /**
90
+ * Phase offset (0–1) of a second dot grid anchored on the tile corners,
91
+ * giving a staggered, checker-like fill instead of a uniform one.
92
+ * @default 0
93
+ */
94
+ stagger?: number;
95
+ };
96
+ /**
97
+ * The transition-animation vocabulary: static factories building the
98
+ * {@link MaskPattern} geometries that the transition engines animate.
99
+ *
100
+ * Engines are instantiated, patterns are not — a transition reads as
101
+ * "engine(animation)":
102
+ * ```ts
103
+ * new Reveal({duration: 1200, pattern: Mask.clock()})
104
+ * new ThroughColor({duration: 1800, pattern: Mask.clock(), uncover: "continue"})
105
+ * ```
106
+ * {@link Mask.invert} flips a pattern's orientation, and a hand-written
107
+ * `MaskPattern` object works anywhere a built-in one does.
108
+ */
109
+ export declare class Mask {
110
+ private constructor();
111
+ /** A feathered directional wipe, travelling toward any keyword or angle. */
112
+ static wipe(options?: WipePatternOptions): MaskPattern;
113
+ /**
114
+ * Barn doors: two feathered edges closing from opposite edges toward the
115
+ * centre. Inverted, a bar grows outward from the centre line instead.
116
+ */
117
+ static barnDoor(options?: BarnDoorPatternOptions): MaskPattern;
118
+ /**
119
+ * A feathered iris growing from the centre out. Inverted, it covers from
120
+ * the rim inward — the classic "iris to black" closes with
121
+ * `new ThroughColor({pattern: Mask.iris(), inverted: true})`.
122
+ */
123
+ static iris(options?: IrisPatternOptions): MaskPattern;
124
+ /**
125
+ * A clock sweep: one feathered radial edge travelling a full turn around
126
+ * the centre. The trailing edge at the start angle is hard by nature, as
127
+ * in a classic clock wipe; only the leading edge is feathered.
128
+ */
129
+ static clock(options?: ClockPatternOptions): MaskPattern;
130
+ /**
131
+ * A windmill of `blades` clock sweeps running in parallel, each covering
132
+ * its own sector. The feather compresses over the last few degrees of each
133
+ * sector so the blades can meet cleanly.
134
+ */
135
+ static fan(options?: FanPatternOptions): MaskPattern;
136
+ /**
137
+ * Venetian slats widening until they cover the frame. Hard-edged by
138
+ * default; raise `feather` for soft slats, or pass an angle for slanted
139
+ * ones.
140
+ */
141
+ static blinds(options?: BlindsPatternOptions): MaskPattern;
142
+ /**
143
+ * A tiled polka-dot fill: a dot grows inside every cell of a `cols`×`rows`
144
+ * grid until the cells flood together. With `stagger`, a second grid
145
+ * anchored on the cell corners runs behind the first for a denser,
146
+ * checker-like fill. (The staggered variant's inverted form is an
147
+ * approximation: the layers union, so mid-run coverage errs dark.)
148
+ */
149
+ static dots(options?: DotsPatternOptions): MaskPattern;
150
+ /**
151
+ * Swap a pattern's orientations: the inverted geometry becomes the natural
152
+ * one and vice versa (e.g. an iris that reveals rim-in instead of
153
+ * centre-out).
154
+ */
155
+ static invert(pattern: MaskPattern): MaskPattern;
156
+ /**
157
+ * The full mask style block for a pattern at coverage `t` — the pattern's
158
+ * image plus its tiling, mirrored to the `-webkit-` prefixes. For authors
159
+ * of custom transitions.
160
+ */
161
+ static toStyle(pattern: MaskPattern, t: number, inverted?: boolean): CSSProps;
162
+ }
@@ -0,0 +1,33 @@
1
+ import { TransitionAnimationType, TransitionTask } from "../../../../elements/transition/type";
2
+ import { TransformDefinitions } from "../../../../elements/transform/type";
3
+ import { ImageTransition } from "../../../../elements/transition/transitions/image/imageTransition";
4
+ import { MaskPattern } from "../../../../elements/transition/transitions/image/mask";
5
+ type AnimationType = [TransitionAnimationType.Number];
6
+ export type RevealOptions = {
7
+ /** Duration in milliseconds. */
8
+ duration: number;
9
+ /** The coverage geometry the target is revealed through. See {@link Mask}. */
10
+ pattern: MaskPattern;
11
+ easing?: TransformDefinitions.EasingDefinition;
12
+ };
13
+ /**
14
+ * The direct-cut engine: the target image is revealed over the previous one
15
+ * through any {@link MaskPattern}, with no colour hold in between — the
16
+ * "A→B" counterpart of {@link ThroughColor}.
17
+ *
18
+ * The geometry lives entirely in the pattern, so the same {@link Mask} factory
19
+ * moves a scene change between the two families with a one-word edit:
20
+ * ```ts
21
+ * new Reveal({duration: 1200, pattern: Mask.clock()})
22
+ * new ThroughColor({duration: 1800, pattern: Mask.clock()})
23
+ * ```
24
+ */
25
+ export declare class Reveal extends ImageTransition<AnimationType> {
26
+ private duration;
27
+ private pattern;
28
+ private easing?;
29
+ constructor(options: RevealOptions);
30
+ createTask(): TransitionTask<HTMLImageElement, AnimationType>;
31
+ copy(): Reveal;
32
+ }
33
+ export {};
@@ -1,36 +1,40 @@
1
1
  import { TransitionAnimationType, TransitionTask } from "../../../../elements/transition/type";
2
2
  import { TransformDefinitions } from "../../../../elements/transform/type";
3
3
  import { ImageTransition } from "../../../../elements/transition/transitions/image/imageTransition";
4
- import { BlindsOrientation } from "../../../../elements/transition/transitions/image/transitionMaskUtils";
4
+ import { MaskPattern } from "../../../../elements/transition/transitions/image/mask";
5
5
  type AnimationType = [TransitionAnimationType.Number];
6
- type ThroughColorBaseOptions = {
6
+ /**
7
+ * How the colour uncovers after the hold:
8
+ * - `"retreat"` — the cover pattern backs out the way it came (default).
9
+ * - `"continue"` — the edge keeps travelling in the same direction, so the
10
+ * pattern passes *through* the frame (a wipe exits out the far side, an iris
11
+ * that closed rim-in reopens centre-out, a clock hand completes a second lap).
12
+ * - a {@link MaskPattern} — the colour uncovers through an unrelated geometry
13
+ * of its own (cover with a clock, uncover with a wipe, ...).
14
+ */
15
+ export type ThroughColorUncover = "retreat" | "continue" | MaskPattern;
16
+ export type ThroughColorOptions = {
7
17
  /** Duration in milliseconds. */
8
18
  duration: number;
9
19
  /** Hold colour. @default "#000000" */
10
20
  color?: string;
11
21
  /** Fraction (0–1) of the duration spent fully covered by the colour. @default 0.3 */
12
22
  hold?: number;
23
+ /**
24
+ * The coverage geometry the colour covers the frame through. See
25
+ * {@link Mask}. Omit for a plain fade through the colour.
26
+ */
27
+ pattern?: MaskPattern;
28
+ /**
29
+ * Cover through the pattern's inverted orientation instead — e.g.
30
+ * `Mask.iris()` covers centre-out by default, and rim-in (the classic
31
+ * "iris to black") with `inverted: true`. @default false
32
+ */
33
+ inverted?: boolean;
34
+ /** How the colour uncovers after the hold. Ignored without a `pattern`. @default "retreat" */
35
+ uncover?: ThroughColorUncover;
13
36
  easing?: TransformDefinitions.EasingDefinition;
14
37
  };
15
- export type ThroughColorFadeOptions = ThroughColorBaseOptions;
16
- export type ThroughColorWipeOptions = ThroughColorBaseOptions & {
17
- /** Direction the feathered edge travels toward. @default "left" */
18
- direction?: TransformDefinitions.WipeDirection;
19
- /** Width of the soft edge band, in percent. @default 12 */
20
- feather?: number;
21
- };
22
- export type ThroughColorBlindsOptions = ThroughColorBaseOptions & {
23
- /** Slat orientation. @default "horizontal" */
24
- orientation?: BlindsOrientation;
25
- /** Number of slats. @default 8 */
26
- slats?: number;
27
- };
28
- export type ThroughColorIrisOptions = ThroughColorBaseOptions & {
29
- /** Centre of the iris, as a CSS position. @default "50% 50%" */
30
- center?: string;
31
- /** Width of the soft edge band, in percent. @default 12 */
32
- feather?: number;
33
- };
34
38
  /**
35
39
  * The "through colour" engine. A colour overlay covers the frame using the
36
40
  * chosen pattern, holds a solid-colour frame, then uncovers to reveal the
@@ -38,27 +42,21 @@ export type ThroughColorIrisOptions = ThroughColorBaseOptions & {
38
42
  * previous/target images simply swap opacity at the midpoint, unseen behind the
39
43
  * fully-covered frame.
40
44
  *
41
- * Created through its static factories (mirroring {@link MaskTransition}):
42
- * - {@link ThroughColor.fade} — the overlay fades in/out (fade-to-black/white; `hold: 0` = flash).
43
- * - {@link ThroughColor.wipe} a feathered directional edge (soft wipe through the colour).
44
- * - {@link ThroughColor.blinds} venetian slats (blinds through the colour).
45
- * - {@link ThroughColor.iris} — a circle closing from the rim in (iris to the colour).
45
+ * The geometry lives entirely in the `pattern` option (see {@link Mask});
46
+ * without one, the colour simply fades in and out (fade-to-black/white, or a
47
+ * flash with `hold: 0`). {@link Reveal} is the direct-cut counterpart that
48
+ * takes the same patterns. The `uncover` option picks how the second half
49
+ * plays: see {@link ThroughColorUncover}.
46
50
  */
47
51
  export declare class ThroughColor extends ImageTransition<AnimationType> {
48
52
  private duration;
49
53
  private color;
50
54
  private hold;
51
- private coverMask;
55
+ private pattern;
56
+ private inverted;
57
+ private uncover;
52
58
  private easing?;
53
- private constructor();
54
- /** Fade the frame to a solid colour, hold, then fade to the target. */
55
- static fade(options: ThroughColorFadeOptions): ThroughColor;
56
- /** Cover the frame with a feathered directional edge, hold, then uncover. */
57
- static wipe(options: ThroughColorWipeOptions): ThroughColor;
58
- /** Cover the frame with venetian slats, hold, then uncover. */
59
- static blinds(options: ThroughColorBlindsOptions): ThroughColor;
60
- /** Close a circle over the frame from the rim in, hold, then open it. */
61
- static iris(options: ThroughColorIrisOptions): ThroughColor;
59
+ constructor(options: ThroughColorOptions);
62
60
  /** Style for the colour overlay at a given coverage (0 = clear, 1 = fully covered). */
63
61
  private coverStyle;
64
62
  createTask(): TransitionTask<HTMLImageElement, AnimationType>;
@@ -1,30 +1,19 @@
1
1
  import { CSSProps } from "../../../../elements/transition/type";
2
2
  import { TransformDefinitions } from "../../../../elements/transform/type";
3
3
  /**
4
- * Shared, side-effect-free helpers for the mask/gradient driven image
5
- * transitions ({@link SoftWipe}, {@link Blinds}, {@link SoftIris},
6
- * {@link ThroughColor}). Kept internal — not exported from the package barrel.
4
+ * Shared, side-effect-free helpers for the mask-driven transition machinery
5
+ * ({@link Mask}, {@link ThroughColor}). Kept internal — not exported from the
6
+ * package barrel.
7
7
  */
8
- /** Orientation of {@link Blinds} slats / {@link ThroughColor} blinds pattern. */
8
+ /** Orientation of the {@link Mask.blinds} slats. */
9
9
  export type BlindsOrientation = "horizontal" | "vertical";
10
10
  /** Clamp a value into the `[0, 1]` range. */
11
11
  export declare function clamp01(value: number): number;
12
12
  /** The `mask-image` triplet, mirrored to the `-webkit-` prefix for WebKit. */
13
- export declare function maskStyle(image: string): CSSProps;
13
+ export declare function maskStyle(image: string, size?: string, repeat?: string): CSSProps;
14
14
  /** Full-bleed positioning for a synthetic colour overlay layer. */
15
15
  export declare function overlayBase(color: string): CSSProps;
16
16
  /** CSS gradient direction keyword for a wipe travelling toward `direction`. */
17
17
  export declare function wipeGradientDir(direction: TransformDefinitions.WipeDirection): string;
18
18
  /** Gradient axis for blinds slats of a given orientation. */
19
19
  export declare function blindsAxis(orientation: BlindsOrientation): string;
20
- /**
21
- * Feathered linear wipe mask. `progress` 0 → fully hidden, 1 → fully covered;
22
- * the opaque edge sweeps with a soft transition band of width `feather` (%).
23
- */
24
- export declare function linearWipeMask(direction: TransformDefinitions.WipeDirection, feather: number, progress: number): string;
25
- /** Venetian slats mask. `progress` 0 → open (hidden), 1 → shut (covered). */
26
- export declare function blindsCoverMask(orientation: BlindsOrientation, slats: number, progress: number): string;
27
- /** Iris that *covers* from the rim inward. `progress` 0 → hidden, 1 → covered. */
28
- export declare function irisCoverMask(center: string, feather: number, progress: number): string;
29
- /** Iris that *reveals* from the centre out. `progress` 0 → hidden, 1 → shown. */
30
- export declare function irisRevealMask(center: string, feather: number, progress: number): string;
@@ -2,11 +2,18 @@ import { TextTransition } from "../../../../elements/transition/transitions/text
2
2
  import { TransitionAnimationType, TransitionTask } from "../../../../elements/transition/type";
3
3
  import { TransformDefinitions } from "../../../../elements/transform/type";
4
4
  type AnimationType = [TransitionAnimationType.Number];
5
+ export type FontSizeOptions = {
6
+ /** Font size (px) the text transitions to. */
7
+ fontSize: number;
8
+ /** Duration in milliseconds. */
9
+ duration: number;
10
+ easing?: TransformDefinitions.EasingDefinition;
11
+ };
5
12
  export declare class FontSize extends TextTransition<AnimationType> {
6
- private textSize;
13
+ private fontSize;
7
14
  private duration;
8
15
  private easing?;
9
- constructor(textSize: number, duration: number, easing?: TransformDefinitions.EasingDefinition | undefined);
16
+ constructor(options: FontSizeOptions);
10
17
  createTask(): TransitionTask<HTMLSpanElement, AnimationType>;
11
18
  copy(): FontSize;
12
19
  }
@@ -0,0 +1,85 @@
1
+ import { Actionable } from "../action/actionable";
2
+ import type { TransformDefinitions } from "../elements/transform/type";
3
+ /**
4
+ * How the overlay video is composited onto the stage.
5
+ *
6
+ * - `"normal"` — plain overlay for true-alpha material (VP9 `yuva420p` alpha WebM);
7
+ * colors stay faithful on any background.
8
+ * - `"screen"` — additive blend for glow material rendered on a black background
9
+ * (light dust, rain, snow, magic sparks); tiny files, hardware decodable, but dark
10
+ * pixels get washed out on bright backgrounds.
11
+ * - `"multiply"` — for shadow material rendered on a white background.
12
+ */
13
+ export type VfxBlendMode = "normal" | "screen" | "multiply" | "lighten" | "color-dodge" | "overlay";
14
+ export type VfxConfig = {
15
+ src: string;
16
+ blendMode: VfxBlendMode;
17
+ loop: boolean;
18
+ muted: boolean;
19
+ opacity: number;
20
+ playbackRate: number;
21
+ fit: "cover" | "contain" | "fill";
22
+ zIndex: number;
23
+ };
24
+ export type VfxFadeOptions = {
25
+ duration?: number;
26
+ easing?: TransformDefinitions.EasingDefinition;
27
+ };
28
+ /**
29
+ * A full-screen looping video overlay for particle and ambience effects
30
+ * (falling petals, light dust, rain, snow, fog, light flares).
31
+ *
32
+ * The effect is a pre-rendered video that plays above the scenes and videos of the
33
+ * stage; camera transforms apply to it like any other stage content.
34
+ */
35
+ export declare class Vfx extends Actionable<VfxStateRaw> {
36
+ /**
37
+ * Create a video overlay effect.
38
+ * @param config - Source configuration; `src` is required.
39
+ * @example
40
+ * ```ts
41
+ * // true-alpha material: faithful colors on any background
42
+ * const petals = new Vfx({src: "/fx/petals-alpha.webm"});
43
+ *
44
+ * // black-background glow material + screen blending: tiny files
45
+ * const dust = new Vfx({src: "/fx/dust-black.webm", blendMode: "screen", opacity: 0.9});
46
+ * ```
47
+ */
48
+ constructor(config: Partial<VfxConfig> & {
49
+ src: string;
50
+ });
51
+ /**
52
+ * Add the overlay to the stage, fade it in, and start looping playback.
53
+ *
54
+ * The action waits for the fade-in to finish. Calling it while the overlay is
55
+ * already shown is idempotent (the fade-in is re-applied).
56
+ * @chainable
57
+ */
58
+ show(options?: VfxFadeOptions): ChainedVfx;
59
+ /**
60
+ * Fade the overlay out, then stop playback and remove it from the stage.
61
+ *
62
+ * The action waits for the fade-out to finish. Calling it while the overlay is
63
+ * not shown is a no-op (a weak warning is logged).
64
+ * @chainable
65
+ */
66
+ hide(options?: VfxFadeOptions): ChainedVfx;
67
+ /**
68
+ * Freeze the overlay on its current frame.
69
+ * @chainable
70
+ */
71
+ pause(): ChainedVfx;
72
+ /**
73
+ * Continue playback from the current frame.
74
+ * @chainable
75
+ */
76
+ resume(): ChainedVfx;
77
+ /**
78
+ * Adjust the playback speed (e.g. `0.5` for slow drifting).
79
+ *
80
+ * Runtime rate changes are not persisted; after loading a saved game the rate
81
+ * returns to `config.playbackRate`.
82
+ * @chainable
83
+ */
84
+ setPlaybackRate(rate: number): ChainedVfx;
85
+ }
@@ -32,4 +32,30 @@ export declare class Video extends Actionable<VideoStateRaw> {
32
32
  * ```
33
33
  */
34
34
  play(): ChainedVideo;
35
+ /**
36
+ * Pause the video, keeping its current position.
37
+ * @chainable
38
+ */
39
+ pause(): ChainedVideo;
40
+ /**
41
+ * Resume playback from the current position.
42
+ *
43
+ * Unlike {@link play}, this does not wait for the video to finish.
44
+ * @chainable
45
+ */
46
+ resume(): ChainedVideo;
47
+ /**
48
+ * Stop the video: pause it and end any pending {@link play} so the story continues.
49
+ * @chainable
50
+ */
51
+ stop(): ChainedVideo;
52
+ /**
53
+ * Seek to a specific time (in seconds).
54
+ * @chainable
55
+ * @example
56
+ * ```ts
57
+ * video.seek(3);
58
+ * ```
59
+ */
60
+ seek(time: number): ChainedVideo;
35
61
  }
@@ -8,7 +8,7 @@ import { LiveGameEventHandler, LiveGameEventToken } from "../types";
8
8
  import { EventDispatcher } from "../../../util/data";
9
9
  import { GameState } from "../../player/gameState";
10
10
  import { GameHistory } from "../action/gameHistory";
11
- import { StackModel } from "../action/stackModel";
11
+ import { StackModel, StackSnapshot } from "../action/stackModel";
12
12
  export declare class LiveGame {
13
13
  static DefaultNamespaces: {
14
14
  game: {};
@@ -19,6 +19,7 @@ export declare class LiveGame {
19
19
  static EventTypes: {
20
20
  readonly "event:character.prompt": "event:character.prompt";
21
21
  readonly "event:menu.choose": "event:menu.choose";
22
+ readonly "event:action.current": "event:action.current";
22
23
  };
23
24
  game: Game;
24
25
  events: EventDispatcher<LiveGameEvent>;
@@ -104,16 +105,29 @@ export declare class LiveGame {
104
105
  * ```
105
106
  *
106
107
  * @param options.until - `"menu"` (default) stops at the next menu; `"end"` runs until the
107
- * story finishes.
108
+ * story finishes; `{ actionId }` runs until that action surfaces as
109
+ * the next thing to execute and stops **just before** running it
110
+ * (so the play head is positioned at that line). A menu that blocks
111
+ * the path, the stack draining, or the step cap all stop early — the
112
+ * result then reports `reachedTarget: false` so the caller can tell an
113
+ * unreachable / already-passed id from a successful jump.
108
114
  * @param options.maxSteps - safety bound on the number of advance steps (defaults to the
109
115
  * `maxStackModelLoop` config).
110
- * @returns why it stopped: `"menu"`, `"end"` (the stack drained), or `"maxSteps"`.
116
+ * @returns why it stopped: `"action"` (reached `until.actionId`), `"menu"`, `"end"` (the stack
117
+ * drained), or `"maxSteps"`. When an `actionId` target was requested, `reachedTarget`
118
+ * is also set (`true` only for reason `"action"`).
119
+ *
120
+ * Note: only the root execution stack is scanned for the target — an id buried inside an
121
+ * in-flight parallel (`Control.all`/`any`) or async branch is not a stop point.
111
122
  */
112
123
  fastForward(options?: {
113
- until?: "menu" | "end";
124
+ until?: "menu" | "end" | {
125
+ actionId: string;
126
+ };
114
127
  maxSteps?: number;
115
128
  }): Promise<{
116
- reason: "menu" | "end" | "maxSteps";
129
+ reason: "menu" | "end" | "maxSteps" | "action";
130
+ reachedTarget?: boolean;
117
131
  }>;
118
132
  private assertScreenshot;
119
133
  /**
@@ -148,6 +162,31 @@ export declare class LiveGame {
148
162
  * When a player chooses a menu
149
163
  */
150
164
  onMenuChoose(fc: LiveGameEventHandler<LiveGameEvent["event:menu.choose"]>): LiveGameEventToken;
165
+ /**
166
+ * **Experimental.** Subscribe to the current-action-id stream: fires each time an action
167
+ * begins executing, carrying its id and type. Intended for an external play head (e.g. the
168
+ * Studio timeline) to follow along. Fires for branch/async actions too — filter by your own
169
+ * id set if you only track top-level lines.
170
+ *
171
+ * @returns a token; call `token.cancel()` to unsubscribe.
172
+ */
173
+ onCurrentActionChange(fc: LiveGameEventHandler<LiveGameEvent["event:action.current"]>): LiveGameEventToken;
174
+ /**
175
+ * **Experimental.** The id of the most recently executed action, or null before the first
176
+ * action runs. A pull-based companion to {@link onCurrentActionChange}.
177
+ */
178
+ getCurrentActionId(): string | null;
179
+ /**
180
+ * **Experimental, read-only.** A top-first snapshot of the current execution stacks for a
181
+ * call-stack / debug view: the root stack plus any in-flight async stacks (`Control.doAsync`
182
+ * / `Control.allAsync`). The shape is a convenience projection, not a stability contract — do
183
+ * not serialize it (use {@link serialize} for saves). Returns empty frames before the game
184
+ * starts.
185
+ */
186
+ getStackSnapshot(): {
187
+ root: StackSnapshot;
188
+ async: StackSnapshot[];
189
+ };
151
190
  /**
152
191
  * Start a new game
153
192
  */
@@ -3,18 +3,19 @@ import type { GameState } from "../../gameState";
3
3
  import { Sentence } from "../../../nlcore/elements/character/sentence";
4
4
  import { Word } from "../../../nlcore/elements/character/word";
5
5
  import { Pausing } from "../../../nlcore/elements/character/pause";
6
+ import { TextEvent } from "../../../nlcore/elements/character/textEvent";
6
7
  import { Chosen } from "../../type";
7
8
  export interface MenuElementProps {
8
9
  prompt: Sentence | null;
9
10
  choices: Choice[];
10
11
  afterChoose: (choice: Chosen) => void;
11
12
  state: GameState;
12
- words: Word<Pausing | string>[] | null;
13
+ words: Word<Pausing | string | TextEvent>[] | null;
13
14
  renderPrompt?: boolean;
14
15
  }
15
16
  export interface IUserMenuProps {
16
17
  items: number[];
17
18
  }
18
19
  export type ChoiceEvaluated = Choice & {
19
- words: Word<Pausing | string>[];
20
+ words: Word<Pausing | string | TextEvent>[];
20
21
  };
@@ -2,13 +2,14 @@ import type { GameState, NvlDialogEntry, NvlState } from "../../gameState";
2
2
  import type { TransformDefinitions } from "../../../nlcore/elements/transform/type";
3
3
  import type { Word } from "../../../nlcore/elements/character/word";
4
4
  import type { Pausing } from "../../../nlcore/elements/character/pause";
5
+ import type { TextEvent } from "../../../nlcore/elements/character/textEvent";
5
6
  import React from "react";
6
7
  export type NvlDialogProxy = {
7
8
  entry: NvlDialogEntry;
8
9
  index: number;
9
10
  isActive: boolean;
10
11
  gameState: GameState;
11
- words: Word<Pausing | string>[];
12
+ words: Word<Pausing | string | TextEvent>[];
12
13
  useTypeEffect: boolean;
13
14
  };
14
15
  export interface INvlContainerProps {
@@ -3,10 +3,11 @@ import { GameState } from "../../gameState";
3
3
  import type { NvlDialogEntry } from "../../gameState";
4
4
  import type { Word } from "../../../nlcore/elements/character/word";
5
5
  import type { Pausing } from "../../../nlcore/elements/character/pause";
6
+ import type { TextEvent } from "../../../nlcore/elements/character/textEvent";
6
7
  type UseNvlDialogStateParams = {
7
8
  entry: NvlDialogEntry;
8
9
  gameState: GameState;
9
- words: Word<Pausing | string>[];
10
+ words: Word<Pausing | string | TextEvent>[];
10
11
  isActive: boolean;
11
12
  useTypeEffect: boolean;
12
13
  };
@@ -0,0 +1 @@
1
+ export {};