narraleaf-react 0.17.0 → 0.18.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.
package/README.md CHANGED
@@ -1,165 +1,165 @@
1
- <picture>
2
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/NarraLeaf/.github/refs/heads/master/doc/banner-md-transparent.png">
3
- <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/NarraLeaf/.github/refs/heads/master/doc/banner-md-light.png">
4
- <img alt="NarraLeaf Logo" src="https://raw.githubusercontent.com/NarraLeaf/.github/refs/heads/master/doc/banner-md-light.png">
5
- </picture>
6
-
7
- <h1 align="center">NarraLeaf-React</h1>
8
-
9
- <h4 align="center">A React visual novel player framework</h4>
10
-
11
- <p align="center">English | <a href="docs/README.zh-CN.md">简体中文</a></p>
12
-
13
-
14
- ## What is NarraLeaf-React?
15
-
16
- NarraLeaf-React is a lightweight front-end visual novel player.
17
- NL focuses on visual novel playing, so the user interface can be customized very easily.
18
-
19
- It doesn't use any rendering libraries and can be used on any web platform (e.g. Electron)
20
-
21
- ## Why NarraLeaf-React?
22
-
23
- - **Lightweight**: NarraLeaf-React is a front-end framework, and it doesn't use any rendering libraries.
24
- - **Customizable**: You can customize the UI as you like, even replace the whole components.
25
- - **Easy to use**: It is easy to use and has a simple API that is built for developers. Based on OOP principles.
26
-
27
- ### Scripting
28
-
29
- NarraLeaf-React uses TypeScript for all scripting, so you don't have to learn a whole new language to use it.
30
-
31
- It also has a highly abstracted and easy-to-use API, for example:
32
-
33
- ```typescript
34
- import {Character, Menu, Scene, c, b} from "narraleaf-react";
35
- ```
36
-
37
- ```typescript
38
- const scene1 = new Scene("Scene1: Hello World", {
39
- background: "/link/to/background.jpg",
40
- });
41
-
42
- const jS = new Character("John Smith");
43
- const jD = new Character("John Doe");
44
-
45
- scene1.action([
46
- jS`Hello, world!`,
47
- jS`This is my first ${b("NarraLeaf")} story.`,
48
- jS`Start editing ${c("src/story.js", "#00f")} and enjoy the journey!`,
49
-
50
- jD`Also, don't forget to check out the ${c("documentation", "#00f")}!`,
51
-
52
- "By the way, the documentation is available on https://www.narraleaf.com/docs/narraleaf-react",
53
- "You can also visit the website for demo and more information.",
54
-
55
- Menu.prompt("Start the journey")
56
-
57
- .choose("Yes I will!", [
58
- jS`Great! Let's start the journey!`,
59
- jS`You can open issues on GitHub if you have any questions.`
60
- ])
61
-
62
- .choose("No, I'm going to check the documentation", [
63
- jS`Sure! Take your time!`
64
- ])
65
- ]);
66
- ```
67
-
68
- For more information, please visit the [NarraLeaf-React documentation](https://www.narraleaf.com/docs/narraleaf-react).
69
-
70
- ## Get Started
71
-
72
- ### Install
73
-
74
- ```bash
75
- npm install narraleaf-react
76
- ```
77
-
78
- ### Documentation
79
-
80
- - [Introduction](https://www.narraleaf.com/docs/narraleaf-react)
81
- - [Quick Start](https://www.narraleaf.com/docs/narraleaf-react/quick-start)
82
- - [Installation](https://www.narraleaf.com/docs/narraleaf-react/installation)
83
- - [Basic](https://www.narraleaf.com/docs/narraleaf-react/basic)
84
- - [Create a Scene](https://www.narraleaf.com/docs/narraleaf-react/basic/create-scene)
85
- - [Add Actions](https://www.narraleaf.com/docs/narraleaf-react/basic/add-actions)
86
- - [Show Dialog](https://www.narraleaf.com/docs/narraleaf-react/basic/show-dialog)
87
- - [Show Image](https://www.narraleaf.com/docs/narraleaf-react/basic/show-image)
88
- - [Play Story](https://www.narraleaf.com/docs/narraleaf-react/basic/play-story)
89
- - [Make Choices](https://www.narraleaf.com/docs/narraleaf-react/basic/make-choices)
90
- - [Play Sound](https://www.narraleaf.com/docs/narraleaf-react/basic/sound)
91
- - [Store Data](https://www.narraleaf.com/docs/narraleaf-react/basic/store-data)
92
- - [Conditional](https://www.narraleaf.com/docs/narraleaf-react/basic/conditional)
93
- - [Voice](https://www.narraleaf.com/docs/narraleaf-react/basic/voice)
94
- - [Manage Preferences](https://www.narraleaf.com/docs/narraleaf-react/basic/manage-preferences)
95
- - [Solutions](https://www.narraleaf.com/docs/narraleaf-react/solutions)
96
- - [Customizing the Font](https://www.narraleaf.com/docs/narraleaf-react/solutions/font)
97
- - [Migration from Ren'Py](https://www.narraleaf.com/docs/narraleaf-react/solutions/from-renpy)
98
- - [Quick Menu](https://www.narraleaf.com/docs/narraleaf-react/solutions/quick-menu)
99
- - [Dialog Avatar](https://www.narraleaf.com/docs/narraleaf-react/solutions/dialog-avatar)
100
- - [Custom Dialog](https://www.narraleaf.com/docs/narraleaf-react/solutions/custom-dialog)
101
- - [Custom NVL Dialog](https://www.narraleaf.com/docs/narraleaf-react/solutions/custom-nvl-dialog)
102
- - [Custom Menu](https://www.narraleaf.com/docs/narraleaf-react/solutions/custom-menu)
103
- - [Page Overlay Settings](https://www.narraleaf.com/docs/narraleaf-react/solutions/page-overlay-settings)
104
- - [Save System with localStorage](https://www.narraleaf.com/docs/narraleaf-react/solutions/save-system-localstorage)
105
- - [Custom Notification](https://www.narraleaf.com/docs/narraleaf-react/solutions/custom-notification)
106
- - [Gallery Service with localStorage](https://www.narraleaf.com/docs/narraleaf-react/solutions/gallery-service-localstorage)
107
- - [Core](https://www.narraleaf.com/docs/narraleaf-react/core)
108
- - [Elements](https://www.narraleaf.com/docs/narraleaf-react/core/elements)
109
- - [Scene](https://www.narraleaf.com/docs/narraleaf-react/core/elements/scene)
110
- - [Character](https://www.narraleaf.com/docs/narraleaf-react/core/elements/character)
111
- - [Sentence](https://www.narraleaf.com/docs/narraleaf-react/core/elements/character/sentence)
112
- - [Word](https://www.narraleaf.com/docs/narraleaf-react/core/elements/character/word)
113
- - [Pause](https://www.narraleaf.com/docs/narraleaf-react/core/elements/character/pause)
114
- - [Image](https://www.narraleaf.com/docs/narraleaf-react/core/elements/image)
115
- - [Sound](https://www.narraleaf.com/docs/narraleaf-react/core/elements/sound)
116
- - [Menu](https://www.narraleaf.com/docs/narraleaf-react/core/elements/menu)
117
- - [Script](https://www.narraleaf.com/docs/narraleaf-react/core/elements/script)
118
- - [Condition](https://www.narraleaf.com/docs/narraleaf-react/core/elements/condition)
119
- - [Control](https://www.narraleaf.com/docs/narraleaf-react/core/elements/control)
120
- - [Text](https://www.narraleaf.com/docs/narraleaf-react/core/elements/text)
121
- - [Persistent](https://www.narraleaf.com/docs/narraleaf-react/core/elements/persistent)
122
- - [Story](https://www.narraleaf.com/docs/narraleaf-react/core/elements/story)
123
- - [Displayable](https://www.narraleaf.com/docs/narraleaf-react/core/elements/displayable)
124
- - [Layer](https://www.narraleaf.com/docs/narraleaf-react/core/elements/layer)
125
- - [Service](https://www.narraleaf.com/docs/narraleaf-react/core/elements/service)
126
- - [Video](https://www.narraleaf.com/docs/narraleaf-react/core/elements/video)
127
- - [Built-in Gallery](https://www.narraleaf.com/docs/narraleaf-react/core/elements/built-in/gallery)
128
- - [Animation](https://www.narraleaf.com/docs/narraleaf-react/core/animation)
129
- - [Transform](https://www.narraleaf.com/docs/narraleaf-react/core/animation/transform)
130
- - [Transitions](https://www.narraleaf.com/docs/narraleaf-react/core/animation/transition)
131
- - [Game](https://www.narraleaf.com/docs/narraleaf-react/core/game)
132
- - [LiveGame](https://www.narraleaf.com/docs/narraleaf-react/core/game/live-game)
133
- - [Storable](https://www.narraleaf.com/docs/narraleaf-react/core/game/storable)
134
- - [Preference](https://www.narraleaf.com/docs/narraleaf-react/core/game/preference/preference)
135
- - [Key Map](https://www.narraleaf.com/docs/narraleaf-react/core/game/key-map)
136
- - [Hooks](https://www.narraleaf.com/docs/narraleaf-react/core/game/hooks)
137
- - [Plugin](https://www.narraleaf.com/docs/narraleaf-react/core/plugin)
138
- - [Utils](https://www.narraleaf.com/docs/narraleaf-react/core/utils)
139
- - [Player](https://www.narraleaf.com/docs/narraleaf-react/player)
140
- - [Player](https://www.narraleaf.com/docs/narraleaf-react/player/player)
141
- - [FixedAspectRatioContainer](https://www.narraleaf.com/docs/narraleaf-react/player/fixed-aspect-ratio-container)
142
- - [GameProviders](https://www.narraleaf.com/docs/narraleaf-react/player/game-providers)
143
- - [Hooks](https://www.narraleaf.com/docs/narraleaf-react/player/hooks)
144
- - [LayoutRouter](https://www.narraleaf.com/docs/narraleaf-react/player/page-router)
145
- - [Dialog](https://www.narraleaf.com/docs/narraleaf-react/player/dialog)
146
- - [Notification](https://www.narraleaf.com/docs/narraleaf-react/player/notification)
147
- - [Menu](https://www.narraleaf.com/docs/narraleaf-react/player/menu)
148
- - [NvlContainer](https://www.narraleaf.com/docs/narraleaf-react/player/nvl-container)
149
- - About
150
- - [License](https://www.narraleaf.com/docs/narraleaf-react/info/license)
151
- - [Incompatible Changes](https://www.narraleaf.com/docs/narraleaf-react/info/incompatible-changes)
152
-
153
- Read more in the [NarraLeaf-React documentation](https://www.narraleaf.com/docs/narraleaf-react).
154
-
155
- ## License
156
-
157
- > NarraLeaf-React is licensed under the MPL-2.0 License.
158
- >
159
- > We updated the license to MPL-2.0 on 2024-9-24.
160
-
161
- ## Contributing
162
-
163
- We welcome all contributions.
164
- If you have any ideas, just open an issue or a pull request.
165
-
1
+ <picture>
2
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/NarraLeaf/.github/refs/heads/master/doc/banner-md-transparent.png">
3
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/NarraLeaf/.github/refs/heads/master/doc/banner-md-light.png">
4
+ <img alt="NarraLeaf Logo" src="https://raw.githubusercontent.com/NarraLeaf/.github/refs/heads/master/doc/banner-md-light.png">
5
+ </picture>
6
+
7
+ <h1 align="center">NarraLeaf-React</h1>
8
+
9
+ <h4 align="center">A React visual novel player framework</h4>
10
+
11
+ <p align="center">English | <a href="docs/README.zh-CN.md">简体中文</a></p>
12
+
13
+
14
+ ## What is NarraLeaf-React?
15
+
16
+ NarraLeaf-React is a lightweight front-end visual novel player.
17
+ NL focuses on visual novel playing, so the user interface can be customized very easily.
18
+
19
+ It doesn't use any rendering libraries and can be used on any web platform (e.g. Electron)
20
+
21
+ ## Why NarraLeaf-React?
22
+
23
+ - **Lightweight**: NarraLeaf-React is a front-end framework, and it doesn't use any rendering libraries.
24
+ - **Customizable**: You can customize the UI as you like, even replace the whole components.
25
+ - **Easy to use**: It is easy to use and has a simple API that is built for developers. Based on OOP principles.
26
+
27
+ ### Scripting
28
+
29
+ NarraLeaf-React uses TypeScript for all scripting, so you don't have to learn a whole new language to use it.
30
+
31
+ It also has a highly abstracted and easy-to-use API, for example:
32
+
33
+ ```typescript
34
+ import {Character, Menu, Scene, c, b} from "narraleaf-react";
35
+ ```
36
+
37
+ ```typescript
38
+ const scene1 = new Scene("Scene1: Hello World", {
39
+ background: "/link/to/background.jpg",
40
+ });
41
+
42
+ const jS = new Character("John Smith");
43
+ const jD = new Character("John Doe");
44
+
45
+ scene1.action([
46
+ jS`Hello, world!`,
47
+ jS`This is my first ${b("NarraLeaf")} story.`,
48
+ jS`Start editing ${c("src/story.js", "#00f")} and enjoy the journey!`,
49
+
50
+ jD`Also, don't forget to check out the ${c("documentation", "#00f")}!`,
51
+
52
+ "By the way, the documentation is available on https://www.narraleaf.com/docs/narraleaf-react",
53
+ "You can also visit the website for demo and more information.",
54
+
55
+ Menu.prompt("Start the journey")
56
+
57
+ .choose("Yes I will!", [
58
+ jS`Great! Let's start the journey!`,
59
+ jS`You can open issues on GitHub if you have any questions.`
60
+ ])
61
+
62
+ .choose("No, I'm going to check the documentation", [
63
+ jS`Sure! Take your time!`
64
+ ])
65
+ ]);
66
+ ```
67
+
68
+ For more information, please visit the [NarraLeaf-React documentation](https://www.narraleaf.com/docs/narraleaf-react).
69
+
70
+ ## Get Started
71
+
72
+ ### Install
73
+
74
+ ```bash
75
+ npm install narraleaf-react
76
+ ```
77
+
78
+ ### Documentation
79
+
80
+ - [Introduction](https://www.narraleaf.com/docs/narraleaf-react)
81
+ - [Quick Start](https://www.narraleaf.com/docs/narraleaf-react/quick-start)
82
+ - [Installation](https://www.narraleaf.com/docs/narraleaf-react/installation)
83
+ - [Basic](https://www.narraleaf.com/docs/narraleaf-react/basic)
84
+ - [Create a Scene](https://www.narraleaf.com/docs/narraleaf-react/basic/create-scene)
85
+ - [Add Actions](https://www.narraleaf.com/docs/narraleaf-react/basic/add-actions)
86
+ - [Show Dialog](https://www.narraleaf.com/docs/narraleaf-react/basic/show-dialog)
87
+ - [Show Image](https://www.narraleaf.com/docs/narraleaf-react/basic/show-image)
88
+ - [Play Story](https://www.narraleaf.com/docs/narraleaf-react/basic/play-story)
89
+ - [Make Choices](https://www.narraleaf.com/docs/narraleaf-react/basic/make-choices)
90
+ - [Play Sound](https://www.narraleaf.com/docs/narraleaf-react/basic/sound)
91
+ - [Store Data](https://www.narraleaf.com/docs/narraleaf-react/basic/store-data)
92
+ - [Conditional](https://www.narraleaf.com/docs/narraleaf-react/basic/conditional)
93
+ - [Voice](https://www.narraleaf.com/docs/narraleaf-react/basic/voice)
94
+ - [Manage Preferences](https://www.narraleaf.com/docs/narraleaf-react/basic/manage-preferences)
95
+ - [Solutions](https://www.narraleaf.com/docs/narraleaf-react/solutions)
96
+ - [Customizing the Font](https://www.narraleaf.com/docs/narraleaf-react/solutions/font)
97
+ - [Migration from Ren'Py](https://www.narraleaf.com/docs/narraleaf-react/solutions/from-renpy)
98
+ - [Quick Menu](https://www.narraleaf.com/docs/narraleaf-react/solutions/quick-menu)
99
+ - [Dialog Avatar](https://www.narraleaf.com/docs/narraleaf-react/solutions/dialog-avatar)
100
+ - [Custom Dialog](https://www.narraleaf.com/docs/narraleaf-react/solutions/custom-dialog)
101
+ - [Custom NVL Dialog](https://www.narraleaf.com/docs/narraleaf-react/solutions/custom-nvl-dialog)
102
+ - [Custom Menu](https://www.narraleaf.com/docs/narraleaf-react/solutions/custom-menu)
103
+ - [Page Overlay Settings](https://www.narraleaf.com/docs/narraleaf-react/solutions/page-overlay-settings)
104
+ - [Save System with localStorage](https://www.narraleaf.com/docs/narraleaf-react/solutions/save-system-localstorage)
105
+ - [Custom Notification](https://www.narraleaf.com/docs/narraleaf-react/solutions/custom-notification)
106
+ - [Gallery Service with localStorage](https://www.narraleaf.com/docs/narraleaf-react/solutions/gallery-service-localstorage)
107
+ - [Core](https://www.narraleaf.com/docs/narraleaf-react/core)
108
+ - [Elements](https://www.narraleaf.com/docs/narraleaf-react/core/elements)
109
+ - [Scene](https://www.narraleaf.com/docs/narraleaf-react/core/elements/scene)
110
+ - [Character](https://www.narraleaf.com/docs/narraleaf-react/core/elements/character)
111
+ - [Sentence](https://www.narraleaf.com/docs/narraleaf-react/core/elements/character/sentence)
112
+ - [Word](https://www.narraleaf.com/docs/narraleaf-react/core/elements/character/word)
113
+ - [Pause](https://www.narraleaf.com/docs/narraleaf-react/core/elements/character/pause)
114
+ - [Image](https://www.narraleaf.com/docs/narraleaf-react/core/elements/image)
115
+ - [Sound](https://www.narraleaf.com/docs/narraleaf-react/core/elements/sound)
116
+ - [Menu](https://www.narraleaf.com/docs/narraleaf-react/core/elements/menu)
117
+ - [Script](https://www.narraleaf.com/docs/narraleaf-react/core/elements/script)
118
+ - [Condition](https://www.narraleaf.com/docs/narraleaf-react/core/elements/condition)
119
+ - [Control](https://www.narraleaf.com/docs/narraleaf-react/core/elements/control)
120
+ - [Text](https://www.narraleaf.com/docs/narraleaf-react/core/elements/text)
121
+ - [Persistent](https://www.narraleaf.com/docs/narraleaf-react/core/elements/persistent)
122
+ - [Story](https://www.narraleaf.com/docs/narraleaf-react/core/elements/story)
123
+ - [Displayable](https://www.narraleaf.com/docs/narraleaf-react/core/elements/displayable)
124
+ - [Layer](https://www.narraleaf.com/docs/narraleaf-react/core/elements/layer)
125
+ - [Service](https://www.narraleaf.com/docs/narraleaf-react/core/elements/service)
126
+ - [Video](https://www.narraleaf.com/docs/narraleaf-react/core/elements/video)
127
+ - [Built-in Gallery](https://www.narraleaf.com/docs/narraleaf-react/core/elements/built-in/gallery)
128
+ - [Animation](https://www.narraleaf.com/docs/narraleaf-react/core/animation)
129
+ - [Transform](https://www.narraleaf.com/docs/narraleaf-react/core/animation/transform)
130
+ - [Transitions](https://www.narraleaf.com/docs/narraleaf-react/core/animation/transition)
131
+ - [Game](https://www.narraleaf.com/docs/narraleaf-react/core/game)
132
+ - [LiveGame](https://www.narraleaf.com/docs/narraleaf-react/core/game/live-game)
133
+ - [Storable](https://www.narraleaf.com/docs/narraleaf-react/core/game/storable)
134
+ - [Preference](https://www.narraleaf.com/docs/narraleaf-react/core/game/preference/preference)
135
+ - [Key Map](https://www.narraleaf.com/docs/narraleaf-react/core/game/key-map)
136
+ - [Hooks](https://www.narraleaf.com/docs/narraleaf-react/core/game/hooks)
137
+ - [Plugin](https://www.narraleaf.com/docs/narraleaf-react/core/plugin)
138
+ - [Utils](https://www.narraleaf.com/docs/narraleaf-react/core/utils)
139
+ - [Player](https://www.narraleaf.com/docs/narraleaf-react/player)
140
+ - [Player](https://www.narraleaf.com/docs/narraleaf-react/player/player)
141
+ - [FixedAspectRatioContainer](https://www.narraleaf.com/docs/narraleaf-react/player/fixed-aspect-ratio-container)
142
+ - [GameProviders](https://www.narraleaf.com/docs/narraleaf-react/player/game-providers)
143
+ - [Hooks](https://www.narraleaf.com/docs/narraleaf-react/player/hooks)
144
+ - [LayoutRouter](https://www.narraleaf.com/docs/narraleaf-react/player/page-router)
145
+ - [Dialog](https://www.narraleaf.com/docs/narraleaf-react/player/dialog)
146
+ - [Notification](https://www.narraleaf.com/docs/narraleaf-react/player/notification)
147
+ - [Menu](https://www.narraleaf.com/docs/narraleaf-react/player/menu)
148
+ - [NvlContainer](https://www.narraleaf.com/docs/narraleaf-react/player/nvl-container)
149
+ - About
150
+ - [License](https://www.narraleaf.com/docs/narraleaf-react/info/license)
151
+ - [Incompatible Changes](https://www.narraleaf.com/docs/narraleaf-react/info/incompatible-changes)
152
+
153
+ Read more in the [NarraLeaf-React documentation](https://www.narraleaf.com/docs/narraleaf-react).
154
+
155
+ ## License
156
+
157
+ > NarraLeaf-React is licensed under the MPL-2.0 License.
158
+ >
159
+ > We updated the license to MPL-2.0 on 2024-9-24.
160
+
161
+ ## Contributing
162
+
163
+ We welcome all contributions.
164
+ If you have any ideas, just open an issue or a pull request.
165
+
@@ -3,6 +3,7 @@ import { Chained, Proxied } from "../../action/chain";
3
3
  import { GameState } from "../../common/game";
4
4
  import { LogicAction } from "../../game";
5
5
  import type { LiveGameEventToken } from "../../types";
6
+ import { Image } from "../displayable/image";
6
7
  import { Layer } from "../layer";
7
8
  import { DynamicPersistent, Persistent } from "../persistent";
8
9
  import { Scene } from "../scene";
@@ -23,6 +24,15 @@ export declare class DevTools {
23
24
  static wrapAction(action: LogicAction.Actions[] | Proxied<LogicAction.GameElement, Chained<LogicAction.Actions>>): ControlAction;
24
25
  static getNamespaceName(persistent: Persistent<any>): string;
25
26
  static getCurrentScene(gameState: GameState): Scene | null;
27
+ /**
28
+ * The src of each of a layered image's layers, bottom to top, for the given tags (the image's
29
+ * current ones when omitted). `null` entries are layers that draw nothing; a non-layered image
30
+ * yields an empty array.
31
+ *
32
+ * A layered image has no single src to read — it is a stack — so an editor host that renders
33
+ * its own thumbnail of an on-stage element has to composite these itself, in order.
34
+ */
35
+ static getLayerSrcs(image: Image, tags?: string[]): (string | null)[];
26
36
  /**
27
37
  * Register a displayable into a scene's render tree without emitting a `displayable:init`
28
38
  * action. The element renders immediately at its constructor-config transform state
@@ -49,10 +49,21 @@ export type TagSrcResolver<T extends TagGroupDefinition> = (...tags: SelectEleme
49
49
  * A set of mutually exclusive variants for one layer, keyed by tag.
50
50
  *
51
51
  * `null` means the layer draws nothing for that tag.
52
+ *
53
+ * The tag set is the group's identity: every layer offering the *same* set of tags is driven by
54
+ * one group, which is how a single `char(["angry"])` moves the brows, the eyes and the mouth at
55
+ * once. To follow a group, repeat its whole tag set on the layer and use `null` for the tags
56
+ * where that layer draws nothing. Offering only part of a set instead declares a *different*
57
+ * group, and the shared tags then collide.
52
58
  */
53
59
  export type LayerVariants = Record<string, string | null>;
54
60
  /**
55
61
  * Derives a layer's src from the currently active tags. Declares no tags of its own.
62
+ *
63
+ * A resolver is opaque, so the srcs it can return are invisible to the preloader and are fetched
64
+ * on first use. Prefer {@link LayerVariants} — including for a layer that follows another layer's
65
+ * group, which no longer needs a resolver — and keep resolvers for sources that genuinely cannot
66
+ * be enumerated.
56
67
  */
57
68
  export type LayerResolver = (tags: ReadonlySet<string>) => string | null;
58
69
  /**
@@ -74,7 +85,8 @@ export type LayeredDefinition<L extends LayerGroupDefinition = LayerGroupDefinit
74
85
  */
75
86
  layers: L;
76
87
  /**
77
- * One tag per variant layer, in any order.
88
+ * One tag per group, in any order. Layers that offer the same tag set share a group and so
89
+ * share that one default.
78
90
  */
79
91
  defaults: readonly LayerTagsOf<L>[];
80
92
  };
@@ -88,10 +100,14 @@ export declare class Image<Tags extends TagGroupDefinition | null = TagGroupDefi
88
100
  * src: {
89
101
  * layers: [
90
102
  * "body.png",
91
- * {happy: "happy.png", sad: "sad.png"},
92
103
  * {shirt: "shirt.png", coat: "coat.png"},
104
+ * // Both layers offer {happy, sad}, so one group drives them together.
105
+ * {happy: "brows_happy.png", sad: "brows_sad.png"},
106
+ * {happy: "mouth_happy.png", sad: "mouth_sad.png"},
107
+ * // Follows the same group, and draws nothing while happy.
108
+ * {happy: null, sad: "tears.png"},
93
109
  * ],
94
- * defaults: ["happy", "shirt"],
110
+ * defaults: ["shirt", "happy"],
95
111
  * }
96
112
  * });
97
113
  * ```
@@ -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, in-flight transitions are settled immediately, and timed pauses (`Control.sleep`,
96
- * auto-forward) resolve at once. It stops as soon as a menu is waiting for a choice, so the
97
- * choice itself is always left to the player.
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), or `"maxSteps"`. When an `actionId` target was requested, `reachedTarget`
118
- * is also set (`true` only for reason `"action"`).
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;