narraleaf-react 0.23.1 → 0.24.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.
@@ -15,6 +15,23 @@ export declare class CharacterAction<T extends typeof CharacterActionTypes[keyof
15
15
  };
16
16
  static getVoice(state: GameState, sentence: Sentence): Sound | null;
17
17
  private static endVoiceWithPreference;
18
+ /**
19
+ * The line voice still running past the end of its own sentence, per game.
20
+ *
21
+ * Only `voiceEndMode: "none"` ever leaves one - the other two modes stop the clip at line end.
22
+ * A WeakMap rather than a field on `GameState` because this is bookkeeping between two
23
+ * consecutive `say`s, not state a host or a save has any business seeing.
24
+ */
25
+ private static readonly trailingVoice;
26
+ /**
27
+ * Cut whatever is still playing from an earlier line before this one's voice starts.
28
+ *
29
+ * "Let it play on" means the clip outlives its own sentence - it does not mean two actors talk
30
+ * at once. Without this, advancing through voiced lines under that mode layered every clip over
31
+ * the last one, and a player clicking quickly could stack three or four. Unvoiced lines pass by
32
+ * without cutting anything, which is the whole point of the mode.
33
+ */
34
+ static cutTrailingVoice(gameState: GameState, next: Sound | null): void;
18
35
  executeAction(gameState: GameState, injection: ActionExecutionInjection): ExecutedActionResult;
19
36
  stringify(_story: Story, _seen: Set<LogicAction.Actions>, _strict: boolean): string;
20
37
  }
@@ -9,7 +9,17 @@ type GameHistoryAction = {
9
9
  export type GameElementHistory = {
10
10
  type: "say";
11
11
  text: string;
12
+ /** Resolved clip URL of the line's voice, if any. */
12
13
  voice: string | null;
14
+ /**
15
+ * The line's `Sentence.config.voiceId` - the key its take is filed under, not a URL.
16
+ *
17
+ * A backlog UI that wants a replay button needs an id it can hand back to the host, because
18
+ * the host addresses audio by id (asset, voice unit) and a resolved URL is not one of those.
19
+ * Absent on entries recorded before this field existed, and on a line voiced through the
20
+ * inline `config.voice` rather than the scene's voice map.
21
+ */
22
+ voiceId?: string | number | null;
13
23
  character: string | null;
14
24
  } | {
15
25
  type: "menu";
@@ -41,6 +41,8 @@ export type SceneDataRaw = {
41
41
  state: Record<string, any>;
42
42
  };
43
43
  export declare class Scene extends Constructable<LogicAction.Actions, Scene> {
44
+ /** Resolved voice src -> the one `Sound` that plays it. See {@link Scene.getVoice}. */
45
+ private readonly voiceCache;
44
46
  get local(): Persistent<any>;
45
47
  get background(): Image;
46
48
  get backgroundLayer(): Layer;
@@ -268,6 +268,9 @@ export type GameConfig = {
268
268
  /**
269
269
  * The delay in milliseconds before the game automatically shows the next sentence
270
270
  *
271
+ * Counted from the end of the line: the text has finished typing AND the line's voice, if any,
272
+ * has finished playing. A voiced line therefore waits out its clip and then this delay.
273
+ *
271
274
  * Only works when the player preference "autoForward" is enabled
272
275
  * @default 3000
273
276
  */
@@ -42,6 +42,8 @@ export declare class DialogState {
42
42
  private _idle;
43
43
  private _active;
44
44
  private autoForwardScheduler;
45
+ /** Drops the listeners on a voice clip auto-forward is currently waiting out. */
46
+ private voiceWaitDisposer;
45
47
  constructor(config: DialogStateConfig);
46
48
  get state(): DialogStateType;
47
49
  get deps(): React.DependencyList;
@@ -78,7 +80,22 @@ export declare class DialogState {
78
80
  emitFlush(): this;
79
81
  onFlush(listener: () => void): EventToken;
80
82
  safeEmit(event: keyof DialogEvents, ...args: DialogEvents[keyof DialogEvents]): this;
83
+ /**
84
+ * Auto-forward waits for the line's voice before it starts counting.
85
+ *
86
+ * Typing finishing and the voice finishing are unrelated events - a fully-typed line whose actor
87
+ * is still mid-sentence is the normal case, not an edge one. Counting `autoForwardDelay` from the
88
+ * typing meant auto mode talked over the cast on every line longer than the delay, which is the
89
+ * one thing auto mode exists to avoid. The delay still applies afterwards, so the pause a player
90
+ * configured is a pause *after* the line rather than a race against it.
91
+ *
92
+ * A line with no voice, or one whose clip has already ended, schedules exactly as before.
93
+ */
81
94
  private scheduleAutoForward;
95
+ private scheduleAutoForwardDelay;
96
+ /** The token of this line's voice while it is still playing, or null - no voice, or already done. */
97
+ private getPlayingVoiceToken;
98
+ private releaseVoiceWait;
82
99
  }
83
100
  export default function PlayerDialog({ action, onFinished, useTypeEffect, gameState, active, }: Readonly<SayElementProps>): React.JSX.Element;
84
101
  export {};