narraleaf-react 0.19.2 → 0.20.1

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 (39) hide show
  1. package/dist/built-in.d.ts +1 -1
  2. package/dist/game/nlcore/action/actionTypes.d.ts +13 -0
  3. package/dist/game/nlcore/action/actions/puppetAction.d.ts +59 -0
  4. package/dist/game/nlcore/action/logicAction.d.ts +15 -13
  5. package/dist/game/nlcore/common/elements.d.ts +4 -1
  6. package/dist/game/nlcore/elements/built-in/DevTools.d.ts +53 -0
  7. package/dist/game/nlcore/elements/built-in/screenEffects.d.ts +2 -2
  8. package/dist/game/nlcore/elements/camera.d.ts +3 -0
  9. package/dist/game/nlcore/elements/character/pause.d.ts +1 -1
  10. package/dist/game/nlcore/elements/character.d.ts +3 -0
  11. package/dist/game/nlcore/elements/condition.d.ts +13 -0
  12. package/dist/game/nlcore/elements/control.d.ts +29 -24
  13. package/dist/game/nlcore/elements/displayable/image.d.ts +4 -0
  14. package/dist/game/nlcore/elements/displayable/puppet.d.ts +230 -0
  15. package/dist/game/nlcore/elements/displayable/text.d.ts +4 -0
  16. package/dist/game/nlcore/elements/layer.d.ts +4 -0
  17. package/dist/game/nlcore/elements/persistent/serialize.d.ts +1 -0
  18. package/dist/game/nlcore/elements/persistent/storable.d.ts +11 -0
  19. package/dist/game/nlcore/elements/persistent/type.d.ts +51 -2
  20. package/dist/game/nlcore/elements/persistent.d.ts +12 -3
  21. package/dist/game/nlcore/elements/scene.d.ts +3 -0
  22. package/dist/game/nlcore/elements/script.d.ts +1 -0
  23. package/dist/game/nlcore/elements/sound.d.ts +3 -0
  24. package/dist/game/nlcore/elements/story.d.ts +1 -0
  25. package/dist/game/nlcore/elements/transform/position.d.ts +46 -0
  26. package/dist/game/nlcore/elements/vfx.d.ts +14 -5
  27. package/dist/game/nlcore/elements/video.d.ts +15 -7
  28. package/dist/game/nlcore/game/liveGame.d.ts +47 -0
  29. package/dist/game/nlcore/game/puppet/puppetBackend.d.ts +247 -0
  30. package/dist/game/nlcore/game.d.ts +43 -0
  31. package/dist/game/player/elements/displayable/Puppet.d.ts +1 -0
  32. package/dist/game/player/elements/displayable/type.d.ts +2 -1
  33. package/dist/game/player/elements/image/AspectScaleImage.d.ts +8 -0
  34. package/dist/game/player/elements/image/Image.d.ts +6 -0
  35. package/dist/game/player/gameState.d.ts +5 -0
  36. package/dist/game/player/gameState.type.d.ts +21 -1
  37. package/dist/game/player/type.d.ts +11 -1
  38. package/dist/main.js +52 -43
  39. package/package.json +3 -2
@@ -0,0 +1,230 @@
1
+ import type { TransformDefinitions } from "../../elements/transform/type";
2
+ import { Displayable } from "../../elements/displayable/displayable";
3
+ import { EventfulDisplayable } from "../../../player/elements/displayable/type";
4
+ import { Chained, Proxied } from "../../action/chain";
5
+ import { LogicAction } from "../../action/logicAction";
6
+ import { Layer } from "../../elements/layer";
7
+ import type { LiveGameEventToken } from "../../types";
8
+ import type { PuppetSize, PuppetStatus } from "../../game/puppet/puppetBackend";
9
+ export type PuppetConfig = {
10
+ backend: string;
11
+ src: string;
12
+ options: Record<string, unknown>;
13
+ size: PuppetSize | null;
14
+ className?: string;
15
+ layer: Layer | undefined;
16
+ };
17
+ export interface IPuppetUserConfig extends TransformDefinitions.ImageTransformProps {
18
+ /**
19
+ * Name of the registered backend that draws this puppet.
20
+ *
21
+ * See {@link import("../../game").Game.registerPuppetBackend}.
22
+ */
23
+ backend: string;
24
+ /**
25
+ * The resource descriptor handed to the backend, passed through verbatim.
26
+ *
27
+ * **A puppet cannot change its `src`.** The backend's instance lives for as long as the element
28
+ * is on stage, and swapping the model underneath it would mean tearing that instance down while
29
+ * the engine's box, transform and saved state stay put. Use a second element instead.
30
+ */
31
+ src: string;
32
+ /** Backend-specific options, passed through verbatim. */
33
+ options: Record<string, unknown>;
34
+ /**
35
+ * The logical size of the box, in pixels. Defaults to the stage size.
36
+ *
37
+ * The backend scales its own content inside the box; the element's transform (position, zoom,
38
+ * scale, rotation) applies on top of it, exactly as it would to an image.
39
+ */
40
+ size: PuppetSize | null;
41
+ /**
42
+ * Class names for the box, applied to the element the transition wrapper renders — the one
43
+ * carrying the box's `position: relative` and its width and height.
44
+ *
45
+ * That is the **parent** of the container handed to
46
+ * {@link import("../../game/puppet/puppetBackend").PuppetBackend.mount}, not the container
47
+ * itself: the backend owns the inside of the box and the engine empties it on dispose, so
48
+ * anything styled here has to sit outside it. Note also that the wrapper above it — the one the
49
+ * transform is written to — is not this element, so a class that sets `transform` here will be
50
+ * overwritten frame by frame.
51
+ */
52
+ className?: string;
53
+ /** Layer of the puppet. */
54
+ layer?: Layer;
55
+ /** Initial motion. Part of the saved state, so it survives a save/load round trip. */
56
+ motion: string | null;
57
+ /** Initial expression. */
58
+ expression: string | null;
59
+ /** Initial skin. */
60
+ skin: string | null;
61
+ /** Initial numeric parameters. */
62
+ params: Record<string, number>;
63
+ /** Initial string slots. */
64
+ slots: Record<string, string | null>;
65
+ }
66
+ /** How the story treats a one-shot {@link Puppet.command}. */
67
+ export type PuppetCommandOptions = {
68
+ /**
69
+ * Wait for the backend to finish the command before the story moves on.
70
+ *
71
+ * Off by default. The engine cannot tell a motion worth a beat from a parameter nudge, and a
72
+ * backend that never resolves would otherwise park the story forever; opting in makes the wait
73
+ * the author's decision, and only where they meant it. A waiting command is skippable like any
74
+ * other timed action.
75
+ *
76
+ * @default false
77
+ */
78
+ await?: boolean;
79
+ };
80
+ export type PuppetDataRaw = {
81
+ state: Record<string, any>;
82
+ transformState: Record<string, any>;
83
+ };
84
+ /**
85
+ * A displayable whose interior is drawn by a backend the host registered.
86
+ *
87
+ * The engine gives a puppet everything a displayable has — a position on a layer, a transform, an
88
+ * opacity, an entry in the saved game — and nothing else. What appears inside its box is decided
89
+ * entirely by {@link import("../../game/puppet/puppetBackend").PuppetBackend}, which the engine
90
+ * neither ships nor understands.
91
+ *
92
+ * When no backend answers to `config.backend`, the element degrades quietly: it keeps its place,
93
+ * its transform and its state, warns once, and draws nothing.
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * const alice = new Puppet({
98
+ * backend: "my-renderer",
99
+ * src: "models/alice/alice.model.json",
100
+ * size: {width: 900, height: 1200},
101
+ * position: {xalign: 0.3},
102
+ * });
103
+ *
104
+ * scene.action([
105
+ * alice.show({duration: 400}),
106
+ * alice.setMotion("idle"),
107
+ * alice.setExpression("smile"),
108
+ * alice.command("playMotion", {id: "wave"}, {await: true}),
109
+ * ]);
110
+ * ```
111
+ */
112
+ export declare class Puppet extends Displayable<PuppetDataRaw, Puppet, TransformDefinitions.ImageTransformProps> implements EventfulDisplayable {
113
+ constructor(config: Partial<IPuppetUserConfig> & {
114
+ backend: string;
115
+ src: string;
116
+ });
117
+ /**
118
+ * Request a named motion — usually the loop the model settles into.
119
+ *
120
+ * This is persistent state, not a one-shot: it is saved, and re-applied in full the next time
121
+ * the model mounts. Pass `null` to clear it. A motion meant to play once and end belongs in
122
+ * {@link Puppet.command}.
123
+ *
124
+ * The story does not wait for the backend to take the pose.
125
+ * @chainable
126
+ * @example
127
+ * ```ts
128
+ * alice.setMotion("idle");
129
+ * ```
130
+ */
131
+ setMotion(motion: string | null): Proxied<Puppet, Chained<LogicAction.Actions>>;
132
+ /**
133
+ * Request a named expression, or `null` to clear it. Persistent state, like the motion.
134
+ * @chainable
135
+ * @example
136
+ * ```ts
137
+ * alice.setExpression("smile");
138
+ * ```
139
+ */
140
+ setExpression(expression: string | null): Proxied<Puppet, Chained<LogicAction.Actions>>;
141
+ /**
142
+ * Request a named skin or costume, or `null` to clear it. Persistent state, like the motion.
143
+ * @chainable
144
+ * @example
145
+ * ```ts
146
+ * alice.setSkin("winter");
147
+ * ```
148
+ */
149
+ setSkin(skin: string | null): Proxied<Puppet, Chained<LogicAction.Actions>>;
150
+ /**
151
+ * Set one numeric parameter, leaving every other parameter as it stands.
152
+ *
153
+ * What an id means is the backend's business — a rig parameter, a bone override, a blend weight.
154
+ * The engine only remembers it, saves it, and hands the whole map back on a load.
155
+ * @chainable
156
+ * @example
157
+ * ```ts
158
+ * alice.setParam("ParamAngleX", 12);
159
+ * ```
160
+ */
161
+ setParam(id: string, value: number): Proxied<Puppet, Chained<LogicAction.Actions>>;
162
+ /**
163
+ * Set one free string slot, leaving every other slot as it stands. `null` clears that slot.
164
+ *
165
+ * Slots are for the named things `motion` / `expression` / `skin` do not cover — an attachment
166
+ * point, a swapped-in prop, whatever a particular renderer calls its own.
167
+ * @chainable
168
+ * @example
169
+ * ```ts
170
+ * alice.setSlot("prop", "umbrella");
171
+ * ```
172
+ */
173
+ setSlot(id: string, value: string | null): Proxied<Puppet, Chained<LogicAction.Actions>>;
174
+ /**
175
+ * Send the backend a command the engine neither models nor interprets.
176
+ *
177
+ * `name` and `payload` are forwarded verbatim. This is the escape hatch for everything
178
+ * {@link import("../../game/puppet/puppetBackend").PuppetState} deliberately leaves out — a
179
+ * motion that plays once and ends, a hit test, lip sync. None of it is saved, so a command is
180
+ * not restored by a load and not taken back by an undo; anything that has to survive either
181
+ * belongs in the state, through the `set*` methods above.
182
+ *
183
+ * **The story does not wait unless it is asked to.** See {@link PuppetCommandOptions}.
184
+ * @chainable
185
+ * @example
186
+ * ```ts
187
+ * alice.command("playMotion", {id: "wave"}); // the story moves straight on
188
+ * alice.command("playMotion", {id: "bow"}, {await: true}); // ...and here it waits for it
189
+ * ```
190
+ */
191
+ command(name: string, payload?: unknown, options?: PuppetCommandOptions): Proxied<Puppet, Chained<LogicAction.Actions>>;
192
+ /**
193
+ * What the backend drawing this puppet is currently doing.
194
+ *
195
+ * Two of the five are worth acting on. `"missing-backend"` means nothing answers to
196
+ * `config.backend`, and `"error"` means the backend threw or the model failed to load; in both
197
+ * cases the element is still on stage, still transforming and still saving — it is simply not
198
+ * being drawn. The engine cannot decide what that should mean for a game, so it reports rather
199
+ * than intervenes.
200
+ *
201
+ * The status describes the live instance and is not part of the saved game: a load re-mounts,
202
+ * and the status starts over from `"unmounted"`.
203
+ * @example
204
+ * ```ts
205
+ * if (alice.getStatus() === "missing-backend") {
206
+ * // the renderer this project depends on was never registered
207
+ * }
208
+ * ```
209
+ */
210
+ getStatus(): PuppetStatus;
211
+ /**
212
+ * Listen for this puppet's status changing, receiving the new status.
213
+ *
214
+ * A backend fails asynchronously — the element mounts, then the model does or does not load — so
215
+ * {@link Puppet.getStatus} alone cannot answer "did my renderer come up". Subscribe to be told.
216
+ * Dispose the returned token to stop listening.
217
+ * @example
218
+ * ```ts
219
+ * const token = alice.onStatusChange((status) => {
220
+ * if (status === "error") console.warn("Alice is not being drawn");
221
+ * });
222
+ * ```
223
+ */
224
+ onStatusChange(listener: (status: PuppetStatus) => void): LiveGameEventToken;
225
+ /**
226
+ * Override the layer used to render this puppet.
227
+ * @param layer - The layer to assign to the puppet.
228
+ */
229
+ useLayer(layer: Layer): this;
230
+ }
@@ -49,6 +49,10 @@ export interface ITextUserConfig extends TransformDefinitions.TextTransformProps
49
49
  */
50
50
  layer?: Layer;
51
51
  }
52
+ export type TextDataRaw = {
53
+ state: Record<string, any>;
54
+ transformState: Record<string, any>;
55
+ };
52
56
  export declare class Text extends Displayable<TextDataRaw, Text, TransformDefinitions.TextTransformProps> implements EventfulDisplayable {
53
57
  constructor(config: Partial<ITextUserConfig>);
54
58
  constructor(text: string, config?: Partial<ITextUserConfig>);
@@ -13,6 +13,10 @@ export interface ILayerUserConfig extends TransformDefinitions.ImageTransformPro
13
13
  */
14
14
  zIndex: number;
15
15
  }
16
+ export type LayerDataRaw = {
17
+ state: Record<string, any>;
18
+ transformState: Record<string, any>;
19
+ };
16
20
  export declare class Layer extends Displayable<LayerDataRaw, Layer, TransformDefinitions.ImageTransformProps> implements EventfulDisplayable {
17
21
  /**
18
22
  * Create a layer that can host displayables.
@@ -26,7 +26,18 @@ export type StorableRestore = {
26
26
  /** The namespace keys whose contents were replaced. */
27
27
  namespaces: string[];
28
28
  };
29
+ export type StorableEvents = {
30
+ "event:storable.change": [StorableChange];
31
+ "event:storable.restore": [StorableRestore];
32
+ };
29
33
  export declare class Namespace<T extends NameSpaceContent<keyof T>> {
34
+ /**
35
+ * Whether a value can be written to a save.
36
+ *
37
+ * Plain objects and arrays may nest freely; the leaves have to be a primitive, `null`,
38
+ * `undefined` or a `Date`. A value that refers back to itself, or one that nests past 64
39
+ * levels, is not serializable — both report `false` rather than recursing forever.
40
+ */
30
41
  static isSerializable(value: any): boolean;
31
42
  name: string;
32
43
  constructor(name: string, initContent: T, key?: string);
@@ -1,10 +1,52 @@
1
1
  export type StorableData<K extends string = string> = {
2
2
  [key in K]: number | boolean | string | StorableData | StorableData[] | undefined | null | Date;
3
3
  };
4
- export type StorableType = BaseStorableType | Record<string, BaseStorableType> | Array<BaseStorableType>;
4
+ /**
5
+ * A value that stands on its own, with nothing inside it: a JSON primitive, or a `Date`.
6
+ */
7
+ export type BaseStorableType = number | boolean | string | undefined | null | Date;
8
+ export type BaseStorableTypeName = "any" | "date";
9
+ /**
10
+ * Anything a namespace can hold.
11
+ *
12
+ * Plain objects and arrays nest freely — `{party: [{name: "yuko", metAt: new Date()}]}` is a
13
+ * single stored value, and a `Date` buried anywhere inside it comes back as a `Date`. Only the
14
+ * leaves are constrained, to {@link BaseStorableType}: a save file is JSON, and a class
15
+ * instance, a `Map`, a function or a symbol has no representation in it.
16
+ *
17
+ * Two limits are enforced when the value is written to a save rather than when it is assigned,
18
+ * because that is when they start to matter:
19
+ *
20
+ * - nesting is capped at 64 levels;
21
+ * - a value that refers back to itself is rejected outright. A save is a tree; a cycle has no
22
+ * place in one, and cutting the back-edge would silently save a different object graph than
23
+ * the one the author built.
24
+ *
25
+ * Reference identity is not part of the value. Storing the same object at two positions saves
26
+ * two copies, and loading produces two independent objects — the same bargain `JSON.stringify`
27
+ * makes.
28
+ */
29
+ export type StorableType = BaseStorableType | {
30
+ [key: string]: StorableType;
31
+ } | StorableType[];
32
+ /**
33
+ * A position inside a stored value: the property keys walked from its root. `[]` is the value
34
+ * itself, `["party", 0, "metAt"]` is the `metAt` of the first element of `party`.
35
+ *
36
+ * Array indices are written as numbers and object keys as strings, but both are read back with
37
+ * plain property access, so the distinction is presentational.
38
+ */
39
+ export type StorablePath = (string | number)[];
5
40
  /**
6
41
  * A single stored value as it appears in a saved game. Values are tagged on the way out so
7
- * that types JSON cannot express (currently `Date`) survive the round-trip.
42
+ * that types JSON cannot express (currently `Date`, and a nested `undefined`) survive the
43
+ * round-trip.
44
+ *
45
+ * `data` is plain JSON. The two types JSON loses are not encoded in-band — no sentinel object
46
+ * is inserted that a stored value could collide with — but named by position in `dates` and
47
+ * `undefineds`, which the loader walks to put the real values back. Both are absent when there
48
+ * is nothing to name, so a value holding neither serializes exactly as it did before this
49
+ * scheme existed, and a save written before it loads unchanged.
8
50
  *
9
51
  * This is part of the on-disk save format rather than an implementation detail: it is what
10
52
  * {@link SavedGame}'s `store` actually contains. Read it through `Namespace`, never by hand.
@@ -12,6 +54,10 @@ export type StorableType = BaseStorableType | Record<string, BaseStorableType> |
12
54
  export type WrappedStorableData<T extends StorableType = any> = {
13
55
  type: BaseStorableTypeName;
14
56
  data: T;
57
+ /** Positions in `data` that held a `Date`, stored as an ISO 8601 string. */
58
+ dates?: StorablePath[];
59
+ /** Positions in `data` that held `undefined`, stored as `null`. */
60
+ undefineds?: StorablePath[];
15
61
  };
16
62
  /**
17
63
  * One namespace's contents in a saved game: every value wrapped by {@link WrappedStorableData}.
@@ -19,3 +65,6 @@ export type WrappedStorableData<T extends StorableType = any> = {
19
65
  export type SerializedNamespaceData = {
20
66
  [key: string]: WrappedStorableData;
21
67
  };
68
+ export type NameSpaceContent<T extends string | number | symbol> = {
69
+ [K in T]?: StorableType;
70
+ };
@@ -1,9 +1,18 @@
1
1
  import { Actionable } from "../action/actionable";
2
+ import { StorableType } from "../elements/persistent/type";
3
+ import { Chained, Proxied } from "../action/chain";
4
+ import { LogicAction } from "../game";
2
5
  import { BooleanValueKeyOf, StringKeyOf } from "../../../util/data";
3
6
  import { Lambda } from "../elements/condition";
4
7
  import { Word } from "../elements/character/word";
5
8
  import { DynamicWord, DynamicWordResult } from "../elements/character/sentence";
6
9
  import { LambdaHandler } from "../elements/type";
10
+ export type PersistentContent = {
11
+ [K in string]: StorableType;
12
+ };
13
+ export type DynamicPersistentData = {
14
+ [K in string]: StorableType;
15
+ };
7
16
  export declare class Persistent<T extends PersistentContent> extends Actionable<null> {
8
17
  constructor(namespace: string, defaultContent: T);
9
18
  /**
@@ -13,15 +22,15 @@ export declare class Persistent<T extends PersistentContent> extends Actionable<
13
22
  * @param value - The value to set
14
23
  * @returns A chainable persistent action
15
24
  */
16
- set<K extends StringKeyOf<T>>(key: K, value: T[K]): ChainedPersistent<T>;
17
- set<K extends StringKeyOf<T>>(key: K, handler: (value: T[K]) => T[K]): ChainedPersistent<T>;
25
+ set<K extends StringKeyOf<T>>(key: K, value: T[K]): Proxied<Persistent<T>, Chained<LogicAction.Actions>>;
26
+ set<K extends StringKeyOf<T>>(key: K, handler: (value: T[K]) => T[K]): Proxied<Persistent<T>, Chained<LogicAction.Actions>>;
18
27
  /**
19
28
  * Create an action to assign a value to the persistent storage
20
29
  * @chainable
21
30
  * @param value - The value to assign
22
31
  * @returns A chainable persistent action
23
32
  */
24
- assign(value: Partial<T> | ((value: T) => Partial<T>)): ChainedPersistent<T>;
33
+ assign(value: Partial<T> | ((value: T) => Partial<T>)): Proxied<Persistent<T>, Chained<LogicAction.Actions>>;
25
34
  /**
26
35
  * Determine whether the values are equal, can be used in {@link Condition}
27
36
  * @example
@@ -37,6 +37,9 @@ export type JumpConfig = {
37
37
  };
38
38
  type ChainableAction = Proxied<LogicAction.GameElement, Chained<LogicAction.Actions>> | LogicAction.Actions;
39
39
  type ChainedScene = Proxied<Scene, Chained<LogicAction.Actions>>;
40
+ export type SceneDataRaw = {
41
+ state: Record<string, any>;
42
+ };
40
43
  export declare class Scene extends Constructable<LogicAction.Actions, Scene> {
41
44
  get local(): Persistent<any>;
42
45
  get background(): Image;
@@ -15,6 +15,7 @@ export interface ScriptCtx {
15
15
  $: NamespaceGetter;
16
16
  }
17
17
  type ScriptRun = (ctx: ScriptCtx) => ScriptCleaner | void;
18
+ export type ScriptCleaner = () => void;
18
19
  export declare class Script extends Actionable<object> {
19
20
  /**
20
21
  * Create a script action from a handler.
@@ -7,6 +7,9 @@ export declare enum SoundType {
7
7
  Bgm = "bgm",
8
8
  Sound = "sound"
9
9
  }
10
+ export type SoundDataRaw = {
11
+ state: Record<string, any>;
12
+ };
10
13
  export type VoiceIdMap = Record<string | number, string | Sound>;
11
14
  export type VoiceSrcGenerator = (id: string | number) => string | Sound;
12
15
  export interface ISoundUserConfig {
@@ -18,6 +18,7 @@ export interface IStoryConfig {
18
18
  */
19
19
  camera?: Camera;
20
20
  }
21
+ export type ElementStateRaw = Record<string, any>;
21
22
  export declare class Story extends Constructable<SceneAction<"scene:action">, Story> {
22
23
  constructor(name: string, config?: Partial<IStoryConfig>);
23
24
  /**
@@ -1,3 +1,4 @@
1
+ import { CSSProps } from "../../elements/transition/type";
1
2
  export declare enum CommonPositionType {
2
3
  Left = "left",
3
4
  Center = "center",
@@ -19,6 +20,12 @@ export type OffsetPosition = {
19
20
  xoffset: number;
20
21
  yoffset: number;
21
22
  };
23
+ export type D2Position<X = any, Y = any> = {
24
+ x: UnknownAble<X>;
25
+ y: UnknownAble<Y>;
26
+ xoffset: UnknownAble<number>;
27
+ yoffset: UnknownAble<number>;
28
+ };
22
29
  export type RawPosition = CommonPositionType | (Partial<Coord2DPosition> & {
23
30
  xalign?: never;
24
31
  yalign?: never;
@@ -28,6 +35,45 @@ export type RawPosition = CommonPositionType | (Partial<Coord2DPosition> & {
28
35
  });
29
36
  type Unknown = typeof PositionUtils.Unknown;
30
37
  type UnknownAble<T> = T | Unknown;
38
+ export declare class PositionUtils {
39
+ static readonly Unknown: unique symbol;
40
+ static isUnknown(arg: any): arg is typeof PositionUtils.Unknown;
41
+ static D2PositionToCSS(pos: D2Position, invertX?: boolean, invertY?: boolean, dimensions?: {
42
+ width: number;
43
+ height: number;
44
+ }): CSSProps;
45
+ /**
46
+ * Resolve a position component (base position + pixel offset) to a CSS length.
47
+ *
48
+ * When the design {@link dimension} (the game's base width or height for this axis) is
49
+ * known, the base position and its offset are folded into a single percentage of that
50
+ * dimension. This keeps offsets resolution-independent — they scale with the stage just
51
+ * like sizes do — and lets `motion` interpolate the result: a mixed `calc(% + px)` value
52
+ * cannot be animated on its percentage part, so the offset would otherwise be the only
53
+ * animatable piece and any align change would be silently dropped.
54
+ *
55
+ * Without a dimension it falls back to the legacy `calc(<pos> + <offset>px)` form.
56
+ */
57
+ static calc(pos: number | string, offset?: UnknownAble<number>, dimension?: number): string;
58
+ /**
59
+ * Express a position component as a percentage of the given design dimension.
60
+ * Accepts an existing percentage string (e.g. `"50%"`) or a pixel number, and returns
61
+ * `null` for any other form so the caller can fall back to the legacy representation.
62
+ */
63
+ static toPercent(pos: number | string, dimension: number): number | null;
64
+ static toCoord2D(pos: IPosition | D2Position): Coord2D;
65
+ static orUnknown<T>(arg: T | UnknownAble<T> | undefined): T | Unknown;
66
+ static mergePosition(a: IPosition, b: IPosition): Coord2D;
67
+ static serializePosition(pos: IPosition): D2Position;
68
+ static isRawCommonPositionType(arg: any): arg is CommonPositionType;
69
+ static isRawCoord2DPosition(arg: any): arg is Partial<Coord2DPosition>;
70
+ static isRawAlignPosition(arg: any): arg is Partial<AlignPosition>;
71
+ static isRawPosition(arg: any): arg is RawPosition;
72
+ static isPosition(arg: any): arg is IPosition;
73
+ static rawPositionToCoord2D(arg: any): Coord2D;
74
+ static tryParsePosition(arg: any): IPosition;
75
+ static wrap(def: CSSProps): CSSProps;
76
+ }
31
77
  export declare class CommonPosition implements IPosition {
32
78
  static Positions: typeof CommonPositionType;
33
79
  static isCommonPositionType(arg: any): arg is CommonPosition;
@@ -1,4 +1,6 @@
1
1
  import { Actionable } from "../action/actionable";
2
+ import { Chained, Proxied } from "../action/chain";
3
+ import { LogicAction } from "../game";
2
4
  import type { TransformDefinitions } from "../elements/transform/type";
3
5
  /**
4
6
  * How the overlay video is composited onto the stage.
@@ -25,6 +27,13 @@ export type VfxFadeOptions = {
25
27
  duration?: number;
26
28
  easing?: TransformDefinitions.EasingDefinition;
27
29
  };
30
+ export type VfxState = {
31
+ display: boolean;
32
+ paused: boolean;
33
+ };
34
+ export type VfxStateRaw = {
35
+ state: VfxState;
36
+ };
28
37
  /**
29
38
  * A full-screen looping video overlay for particle and ambience effects
30
39
  * (falling petals, light dust, rain, snow, fog, light flares).
@@ -55,7 +64,7 @@ export declare class Vfx extends Actionable<VfxStateRaw> {
55
64
  * already shown is idempotent (the fade-in is re-applied).
56
65
  * @chainable
57
66
  */
58
- show(options?: VfxFadeOptions): ChainedVfx;
67
+ show(options?: VfxFadeOptions): Proxied<Vfx, Chained<LogicAction.Actions>>;
59
68
  /**
60
69
  * Fade the overlay out, then stop playback and remove it from the stage.
61
70
  *
@@ -63,17 +72,17 @@ export declare class Vfx extends Actionable<VfxStateRaw> {
63
72
  * not shown is a no-op (a weak warning is logged).
64
73
  * @chainable
65
74
  */
66
- hide(options?: VfxFadeOptions): ChainedVfx;
75
+ hide(options?: VfxFadeOptions): Proxied<Vfx, Chained<LogicAction.Actions>>;
67
76
  /**
68
77
  * Freeze the overlay on its current frame.
69
78
  * @chainable
70
79
  */
71
- pause(): ChainedVfx;
80
+ pause(): Proxied<Vfx, Chained<LogicAction.Actions>>;
72
81
  /**
73
82
  * Continue playback from the current frame.
74
83
  * @chainable
75
84
  */
76
- resume(): ChainedVfx;
85
+ resume(): Proxied<Vfx, Chained<LogicAction.Actions>>;
77
86
  /**
78
87
  * Adjust the playback speed (e.g. `0.5` for slow drifting).
79
88
  *
@@ -81,5 +90,5 @@ export declare class Vfx extends Actionable<VfxStateRaw> {
81
90
  * returns to `config.playbackRate`.
82
91
  * @chainable
83
92
  */
84
- setPlaybackRate(rate: number): ChainedVfx;
93
+ setPlaybackRate(rate: number): Proxied<Vfx, Chained<LogicAction.Actions>>;
85
94
  }
@@ -1,8 +1,16 @@
1
1
  import { Actionable } from "../action/actionable";
2
+ import { Chained, Proxied } from "../action/chain";
3
+ import { LogicAction } from "../game";
2
4
  export type VideoConfig = {
3
5
  src: string;
4
6
  muted: boolean;
5
7
  };
8
+ export type VideoState = {
9
+ display: boolean;
10
+ };
11
+ export type VideoStateRaw = {
12
+ state: VideoState;
13
+ };
6
14
  export declare class Video extends Actionable<VideoStateRaw> {
7
15
  /**
8
16
  * Create a video element with source and optional mute flag.
@@ -17,12 +25,12 @@ export declare class Video extends Actionable<VideoStateRaw> {
17
25
  * Show the video element.
18
26
  * @chainable
19
27
  */
20
- show(): ChainedVideo;
28
+ show(): Proxied<Video, Chained<LogicAction.Actions>>;
21
29
  /**
22
30
  * Hide the video element.
23
31
  * @chainable
24
32
  */
25
- hide(): ChainedVideo;
33
+ hide(): Proxied<Video, Chained<LogicAction.Actions>>;
26
34
  /**
27
35
  * Play the video and wait until it finishes.
28
36
  * @chainable
@@ -31,24 +39,24 @@ export declare class Video extends Actionable<VideoStateRaw> {
31
39
  * video.play();
32
40
  * ```
33
41
  */
34
- play(): ChainedVideo;
42
+ play(): Proxied<Video, Chained<LogicAction.Actions>>;
35
43
  /**
36
44
  * Pause the video, keeping its current position.
37
45
  * @chainable
38
46
  */
39
- pause(): ChainedVideo;
47
+ pause(): Proxied<Video, Chained<LogicAction.Actions>>;
40
48
  /**
41
49
  * Resume playback from the current position.
42
50
  *
43
51
  * Unlike {@link play}, this does not wait for the video to finish.
44
52
  * @chainable
45
53
  */
46
- resume(): ChainedVideo;
54
+ resume(): Proxied<Video, Chained<LogicAction.Actions>>;
47
55
  /**
48
56
  * Stop the video: pause it and end any pending {@link play} so the story continues.
49
57
  * @chainable
50
58
  */
51
- stop(): ChainedVideo;
59
+ stop(): Proxied<Video, Chained<LogicAction.Actions>>;
52
60
  /**
53
61
  * Seek to a specific time (in seconds).
54
62
  * @chainable
@@ -57,5 +65,5 @@ export declare class Video extends Actionable<VideoStateRaw> {
57
65
  * video.seek(3);
58
66
  * ```
59
67
  */
60
- seek(time: number): ChainedVideo;
68
+ seek(time: number): Proxied<Video, Chained<LogicAction.Actions>>;
61
69
  }
@@ -1,3 +1,5 @@
1
+ import { Character } from "../elements/character";
2
+ import { Sentence } from "../elements/character/sentence";
1
3
  import { Storable } from "../elements/persistent/storable";
2
4
  import { Story } from "../elements/story";
3
5
  import { Game } from "../game";
@@ -9,6 +11,51 @@ import { EventDispatcher } from "../../../util/data";
9
11
  import { GameState } from "../../player/gameState";
10
12
  import { GameHistory } from "../action/gameHistory";
11
13
  import { StackModel, StackSnapshot } from "../action/stackModel";
14
+ export type LiveGameEvent = {
15
+ "event:character.prompt": [
16
+ {
17
+ /**
18
+ * The character who says the sentence
19
+ */
20
+ character: Character | null;
21
+ /**
22
+ * The sentence said by the character
23
+ */
24
+ sentence: Sentence;
25
+ /**
26
+ * The text of the sentence
27
+ */
28
+ text: string;
29
+ }
30
+ ];
31
+ "event:menu.choose": [
32
+ {
33
+ /**
34
+ * The sentence selected by the player
35
+ */
36
+ sentence: Sentence;
37
+ /**
38
+ * The text of the sentence
39
+ */
40
+ text: string;
41
+ }
42
+ ];
43
+ "event:action.current": [
44
+ {
45
+ /**
46
+ * The id of the action that just began executing (as assigned by the story compiler),
47
+ * or null for an action with no id. Fires for every executed action, including those
48
+ * inside parallel/async branches — subscribers that only care about top-level lines
49
+ * should filter by their own id set.
50
+ */
51
+ actionId: string | null;
52
+ /**
53
+ * The action's type (e.g. `"character:say"`).
54
+ */
55
+ actionType: string | null;
56
+ }
57
+ ];
58
+ };
12
59
  export declare class LiveGame {
13
60
  static DefaultNamespaces: {
14
61
  game: {};