narraleaf-react 0.16.1 → 0.17.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.
- package/dist/game/nlcore/game/liveGame.d.ts +15 -6
- package/dist/game/player/elements/preload/preloadPlan.d.ts +34 -0
- package/dist/game/player/lib/AudioManager.d.ts +12 -0
- package/dist/game/player/lib/ImageCacheManager.d.ts +28 -1
- package/dist/main.js +37 -37
- package/dist/util/data.d.ts +4 -0
- package/package.json +1 -1
|
@@ -92,9 +92,13 @@ export declare class LiveGame {
|
|
|
92
92
|
*
|
|
93
93
|
* Every line in between is executed for real, so the backlog and its restore snapshots
|
|
94
94
|
* accumulate exactly as in normal play — only faster and silent. Audio is muted for the
|
|
95
|
-
* duration,
|
|
96
|
-
*
|
|
97
|
-
*
|
|
95
|
+
* duration, and timed pauses (`Control.sleep`, auto-forward) resolve at once. It stops as soon
|
|
96
|
+
* as a menu is waiting for a choice, so the choice itself is always left to the player.
|
|
97
|
+
*
|
|
98
|
+
* Skipping a line is a *request* to the renderer, not a synchronous state change: it is
|
|
99
|
+
* re-issued until the line settles. A line that never responds (an unskippable in-flight
|
|
100
|
+
* media/transition step) ends the run with `"stalled"` rather than hanging — this method always
|
|
101
|
+
* settles.
|
|
98
102
|
*
|
|
99
103
|
* Because history accumulates the whole way, {@link getHistory} and
|
|
100
104
|
* {@link restoreToHistory} cover the fast-forwarded span just like normal play.
|
|
@@ -113,9 +117,13 @@ export declare class LiveGame {
|
|
|
113
117
|
* unreachable / already-passed id from a successful jump.
|
|
114
118
|
* @param options.maxSteps - safety bound on the number of advance steps (defaults to the
|
|
115
119
|
* `maxStackModelLoop` config).
|
|
120
|
+
* @param options.stepTimeout - how long (ms) a single line is given to settle before the run
|
|
121
|
+
* reports `"stalled"`. Defaults to 10000. Raise it if the story
|
|
122
|
+
* fast-forwards through long unskippable media.
|
|
116
123
|
* @returns why it stopped: `"action"` (reached `until.actionId`), `"menu"`, `"end"` (the stack
|
|
117
|
-
* drained),
|
|
118
|
-
* is also set (`true` only for reason
|
|
124
|
+
* drained), `"maxSteps"`, or `"stalled"` (a line refused to settle). When an
|
|
125
|
+
* `actionId` target was requested, `reachedTarget` is also set (`true` only for reason
|
|
126
|
+
* `"action"`).
|
|
119
127
|
*
|
|
120
128
|
* Note: only the root execution stack is scanned for the target — an id buried inside an
|
|
121
129
|
* in-flight parallel (`Control.all`/`any`) or async branch is not a stop point.
|
|
@@ -125,8 +133,9 @@ export declare class LiveGame {
|
|
|
125
133
|
actionId: string;
|
|
126
134
|
};
|
|
127
135
|
maxSteps?: number;
|
|
136
|
+
stepTimeout?: number;
|
|
128
137
|
}): Promise<{
|
|
129
|
-
reason: "menu" | "end" | "maxSteps" | "action";
|
|
138
|
+
reason: "menu" | "end" | "maxSteps" | "action" | "stalled";
|
|
130
139
|
reachedTarget?: boolean;
|
|
131
140
|
}>;
|
|
132
141
|
private assertScreenshot;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Scene } from "../../../nlcore/elements/scene";
|
|
2
|
+
import type { Sound } from "../../../nlcore/elements/sound";
|
|
3
|
+
export type ScenePreloadPlan = {
|
|
4
|
+
/**
|
|
5
|
+
* Image urls the scene that is about to paint registers directly: its own backgrounds and
|
|
6
|
+
* images, plus the immediate background of any scene it jumps to. This tier is on the path to
|
|
7
|
+
* the first painted frame, so it is fetched unpaced and nothing is revealed until it is warm.
|
|
8
|
+
*/
|
|
9
|
+
critical: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Image urls belonging to the scenes reachable from here, minus anything already in
|
|
12
|
+
* {@link ScenePreloadPlan.critical}. Speculative: warmed after the critical tier, paced, and
|
|
13
|
+
* nothing waits for it.
|
|
14
|
+
*/
|
|
15
|
+
lookAhead: string[];
|
|
16
|
+
/** Every url in the plan, in order — the set the cache should keep for this scene. */
|
|
17
|
+
all: string[];
|
|
18
|
+
/**
|
|
19
|
+
* Sounds this scene registers. Warmed alongside the critical tier but never gated on: the
|
|
20
|
+
* audio context can be locked until the player interacts with the page (see
|
|
21
|
+
* `AudioManager.preload`), so waiting for these could wait forever.
|
|
22
|
+
*/
|
|
23
|
+
criticalAudio: Sound[];
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Split a scene's registered image sources into what must be warm before the scene paints and what
|
|
27
|
+
* is merely likely to be needed soon.
|
|
28
|
+
*
|
|
29
|
+
* The distinction matters because a scene's `srcManager` reaches transitively: `getFutureSrc()`
|
|
30
|
+
* carries the whole asset set of every scene this one can jump to. Treating that as one preload
|
|
31
|
+
* pass meant the first frame of a large story waited on assets from scenes the player had not
|
|
32
|
+
* reached yet.
|
|
33
|
+
*/
|
|
34
|
+
export declare function planScenePreload(scene: Scene): ScenePreloadPlan;
|
|
@@ -43,6 +43,18 @@ export declare class AudioManager {
|
|
|
43
43
|
fromData(data: AudioManagerDataRaw, elementMap: Map<string, LogicAction.GameElement>): this;
|
|
44
44
|
soundFromData(sound: SoundElement, data: AudioDataRaw): void;
|
|
45
45
|
isManaged(sound: SoundElement): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Fetch and decode a sound into the audio cache without playing it, so the first `play()` of
|
|
48
|
+
* this source starts on the same frame it is asked to instead of after a fetch and a decode.
|
|
49
|
+
*
|
|
50
|
+
* Deliberately **not** something to gate a loading screen on: the audio context only becomes
|
|
51
|
+
* ready once the browser's autoplay policy is satisfied by a user gesture, so this can sit
|
|
52
|
+
* pending indefinitely on a page nobody has interacted with yet. Start it and let it land —
|
|
53
|
+
* in practice the gesture that opens a menu unlocks the context long before the scene it
|
|
54
|
+
* belongs to is entered. Failures resolve quietly; the sound then loads on first play, exactly
|
|
55
|
+
* as it did before.
|
|
56
|
+
*/
|
|
57
|
+
preload(sound: SoundElement): Promise<void>;
|
|
46
58
|
reset(): void;
|
|
47
59
|
setGroupVolume(type: SoundType, volume: number): void;
|
|
48
60
|
setGlobalVolume(volume: number): void;
|
|
@@ -14,19 +14,46 @@ export declare class ImageCacheManager {
|
|
|
14
14
|
* the bytes are cached — the first reveal still pays the (async) decode cost and can paint
|
|
15
15
|
* a blank frame. Decode failures are ignored: the image then simply decodes lazily on
|
|
16
16
|
* first paint, exactly as before.
|
|
17
|
+
*
|
|
18
|
+
* Returns the element the decode ran on so callers can keep it alive (see
|
|
19
|
+
* {@link ImageCacheManager.preload}'s `retainDecoded`); `null` when the environment has no
|
|
20
|
+
* `Image` or no `decode()`.
|
|
17
21
|
*/
|
|
18
22
|
private static decodeImage;
|
|
19
23
|
private src;
|
|
20
24
|
private preloadTasks;
|
|
25
|
+
/**
|
|
26
|
+
* Decoded images held on purpose. A decoded bitmap only stays in the browser's cache while
|
|
27
|
+
* something still references it, so dropping the element right after `decode()` lets the
|
|
28
|
+
* bitmap be evicted and the reveal decodes all over again. Retention is opt-in per preload
|
|
29
|
+
* (`retainDecoded`) because a full-resolution bitmap costs width × height × 4 bytes — worth
|
|
30
|
+
* it for the scene that is about to paint, far too expensive for a whole reachable graph.
|
|
31
|
+
*/
|
|
32
|
+
private decoded;
|
|
21
33
|
constructor(game: Game);
|
|
22
34
|
has(name: string): boolean;
|
|
23
35
|
add(name: string, src: string): this;
|
|
24
36
|
remove(name: string): this;
|
|
25
37
|
get(name: string): string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Whether this source has been decoded and its decoded bitmap is still held, i.e. attaching
|
|
40
|
+
* it to an `<img>` can paint without an asynchronous decode first.
|
|
41
|
+
*/
|
|
42
|
+
isDecoded(name: string): boolean;
|
|
26
43
|
clear(): this;
|
|
27
44
|
size(): number;
|
|
28
45
|
isPreloading(src: string): boolean;
|
|
29
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Fetch `url`, cache it as a data URL and decode it, resolving the returned token's
|
|
48
|
+
* `onFinished` only once the decode has settled.
|
|
49
|
+
*
|
|
50
|
+
* @param options.retainDecoded keep the decoded bitmap alive until this source leaves the
|
|
51
|
+
* cache. Use it for the assets that are about to be revealed; leave it off for speculative
|
|
52
|
+
* look-ahead preloading, whose bitmaps would otherwise pile up in memory.
|
|
53
|
+
*/
|
|
54
|
+
preload(gameState: GameState, url: string, options?: {
|
|
55
|
+
retainDecoded?: boolean;
|
|
56
|
+
}): PreloadedToken;
|
|
30
57
|
abortAll(): void;
|
|
31
58
|
abort(src: string): void;
|
|
32
59
|
preloadedSrc(): string[];
|