narraleaf-react 0.9.1 → 0.10.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/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,9 +3,13 @@ import { DeepPartial, Hooks, StringKeyOf } from "../../util/data";
3
3
  import { LogicAction } from "./action/logicAction";
4
4
  import { LiveGame } from "./game/liveGame";
5
5
  import { Preference } from "./game/preference";
6
+ import { GameState } from "../player/gameState";
6
7
  import { Plugins, IGamePluginRegistry } from "./game/plugin/plugin";
7
8
  import { LayoutRouter } from "../player/lib/PageRouter/router";
8
9
  import { KeyMap } from "./game/keyMap";
10
+ import type { Storable } from "./elements/persistent/storable";
11
+ import type { Scene } from "./elements/scene";
12
+ import type { LiveGameEventHandler, LiveGameEventToken } from "./types";
9
13
  declare enum GameSettingsNamespace {
10
14
  game = "game"
11
15
  }
@@ -34,6 +38,17 @@ export type GameHooks = {
34
38
  */
35
39
  "afterRestore": [];
36
40
  };
41
+ export type GameLifecycleEventContext = {
42
+ game: Game;
43
+ gameState: GameState;
44
+ liveGame: LiveGame;
45
+ storable: Storable;
46
+ scene: Scene | null;
47
+ };
48
+ export type GameLifecycleEvents = {
49
+ "event:game.preloadComplete": [ctx: GameLifecycleEventContext];
50
+ "event:game.firstSceneReady": [ctx: GameLifecycleEventContext];
51
+ };
37
52
  export declare class Game {
38
53
  static GameSettingsNamespace: typeof GameSettingsNamespace;
39
54
  readonly hooks: Hooks<GameHooks>;
@@ -45,11 +60,17 @@ export declare class Game {
45
60
  * Game key bindings
46
61
  */
47
62
  keyMap: KeyMap;
63
+ static LifecycleEventTypes: {
64
+ [K in keyof GameLifecycleEvents]: K;
65
+ };
48
66
  /**
49
67
  * Plugin registry
50
68
  */
51
69
  plugins: Plugins;
52
70
  router: LayoutRouter;
71
+ private readonly lifecycleEvents;
72
+ private preloadCompleteContext;
73
+ private firstSceneReadyContext;
53
74
  /**
54
75
  * Create a new game
55
76
  * @param config - Game configuration
@@ -78,6 +99,45 @@ export declare class Game {
78
99
  * @param plugin - The plugin to use
79
100
  */
80
101
  use(plugin: IGamePluginRegistry): this;
102
+ /**
103
+ * Listen for the initial preload pass completing.
104
+ *
105
+ * This is the point where the initial preload pass has actually finished.
106
+ * Use {@link whenPreloadComplete} if the listener may be registered after the event has fired.
107
+ */
108
+ onPreloadComplete(fc: LiveGameEventHandler<GameLifecycleEvents["event:game.preloadComplete"]>): LiveGameEventToken;
109
+ /**
110
+ * Listen once for the initial preload pass completing.
111
+ */
112
+ oncePreloadComplete(fc: LiveGameEventHandler<GameLifecycleEvents["event:game.preloadComplete"]>): LiveGameEventToken;
113
+ /**
114
+ * Resolve when the initial preload pass has completed.
115
+ */
116
+ whenPreloadComplete(): Promise<GameLifecycleEventContext>;
117
+ /**
118
+ * Whether the initial preload pass has completed.
119
+ */
120
+ isPreloadComplete(): boolean;
121
+ /**
122
+ * Listen for the first scene being fully ready.
123
+ *
124
+ * This fires after the initial preload pass has actually finished, after the first
125
+ * scene component is mounted, and after the browser has had a frame to render it.
126
+ * Use {@link whenFirstSceneReady} if the listener may be registered after the event has fired.
127
+ */
128
+ onFirstSceneReady(fc: LiveGameEventHandler<GameLifecycleEvents["event:game.firstSceneReady"]>): LiveGameEventToken;
129
+ /**
130
+ * Listen once for the first scene being fully ready.
131
+ */
132
+ onceFirstSceneReady(fc: LiveGameEventHandler<GameLifecycleEvents["event:game.firstSceneReady"]>): LiveGameEventToken;
133
+ /**
134
+ * Resolve when the first scene is fully ready.
135
+ */
136
+ whenFirstSceneReady(): Promise<GameLifecycleEventContext>;
137
+ /**
138
+ * Whether the first scene is fully ready.
139
+ */
140
+ isFirstSceneReady(): boolean;
81
141
  getLiveGame(): LiveGame;
82
142
  /**
83
143
  * Dispose the game and all its resources
@@ -8,7 +8,7 @@ import { GuardConfig } from "../player/guard";
8
8
  import React from "react";
9
9
  import { StackModel, StackModelRawData } from "./action/stackModel";
10
10
  import { MenuComponent, NotificationComponent, NvlDialogComponent, SayComponent } from "./common/player";
11
- import { Color, LiveGameEventToken } from "./types";
11
+ import { LiveGameEventToken } from "./types";
12
12
  export interface SavedGameMetaData {
13
13
  /**
14
14
  * The timestamp of when the game was created
@@ -251,16 +251,6 @@ export type GameConfig = {
251
251
  * @default false
252
252
  */
253
253
  allowSkipVideo: boolean;
254
- /**
255
- * The default text color for the dialog
256
- * @default "#000"
257
- */
258
- defaultTextColor: Color;
259
- /**
260
- * The default text color for the character nametag
261
- * @default "#000"
262
- */
263
- defaultNametagColor: Color;
264
254
  /**
265
255
  * The component to use for the notification
266
256
  * @default DefaultNotification
@@ -310,36 +300,11 @@ export type GameConfig = {
310
300
  */
311
301
  guard: GuardConfig;
312
302
  };
313
- /**
314
- * Default font size for the game
315
- * @default "16px"
316
- */
317
- fontSize: React.CSSProperties["fontSize"];
318
- /**
319
- * Default font weight for the game
320
- * @default 400
321
- */
322
- fontWeight: number;
323
- /**
324
- * Default font weight for the game
325
- * @default 700
326
- */
327
- fontWeightBold: number;
328
- /**
329
- * Default font family for the game
330
- * @default "sans-serif"
331
- */
332
- fontFamily: React.CSSProperties["fontFamily"];
333
303
  /**
334
304
  * Override the default stage
335
305
  * @default null
336
306
  */
337
307
  stage: React.ReactNode | null;
338
- /**
339
- * The default color for the menu choices
340
- * @default "#000"
341
- */
342
- defaultMenuChoiceColor: Color;
343
308
  /**
344
309
  * The maximum number of times a stack model can loop
345
310
  * @default 1000
@@ -1,4 +1,4 @@
1
1
  import "client-only";
2
2
  import { PlayerProps } from "../elements/type";
3
3
  import React from "react";
4
- export default function Player({ story, width, height, className, onReady, onPreloadedReady, onEnd, onError, children, active, }: Readonly<PlayerProps>): React.JSX.Element;
4
+ export default function Player({ story, width, height, className, onReady, onPreloadComplete, onPreloadedReady, onFirstSceneReady, onEnd, onError, children, active, }: Readonly<PlayerProps>): React.JSX.Element;
@@ -1,5 +1,6 @@
1
+ import { type TextAppearanceProps } from "../../../elements/say/Sentence";
1
2
  import React from "react";
2
- export interface ItemProps {
3
+ export interface ItemProps extends TextAppearanceProps {
3
4
  className?: string;
4
5
  style?: React.CSSProperties;
5
6
  /**
@@ -9,4 +10,4 @@ export interface ItemProps {
9
10
  */
10
11
  bindKey?: string;
11
12
  }
12
- export default function Item({ className, style, bindKey }: ItemProps): React.JSX.Element;
13
+ export default function Item({ className, style, bindKey, defaultColor, fontSize, fontWeight, fontWeightBold, fontFamily, }: ItemProps): React.JSX.Element;
@@ -1,9 +1,12 @@
1
1
  import React from "react";
2
2
  import type { Character } from "../../../nlcore/elements/character";
3
3
  import type { NvlDialogEntry } from "../../gameState";
4
- type NametagProps = React.HTMLAttributes<HTMLDivElement> & {
4
+ import type { Color } from "../../../../game/nlcore/types";
5
+ export type NametagProps = Omit<React.HTMLAttributes<HTMLDivElement>, "children" | "color"> & {
5
6
  entry?: NvlDialogEntry;
6
7
  character?: Character | null;
8
+ name?: React.ReactNode;
9
+ color?: Color;
10
+ children?: React.ReactNode;
7
11
  };
8
- export default function Nametag({ entry, character, ...props }: Readonly<NametagProps>): React.JSX.Element;
9
- export {};
12
+ export default function Nametag({ entry, character, name, color, children, style, ...props }: Readonly<NametagProps>): React.JSX.Element;
@@ -4,14 +4,19 @@ import { Word } from "../../../nlcore/elements/character/word";
4
4
  import { GameState } from "../../../../game/nlcore/common/game";
5
5
  import { Color } from "../../../../game/nlcore/types";
6
6
  import React from "react";
7
- import { DialogElementProps } from "./type";
8
7
  import { DialogState } from "./UIDialog";
9
8
  import type { NvlDialogEntry } from "../../gameState";
10
- type BaseTextsProps = {
9
+ export type TextAppearanceProps = {
11
10
  /**
12
11
  * The default color of the text
13
12
  */
14
13
  defaultColor?: Color;
14
+ fontSize?: React.CSSProperties["fontSize"];
15
+ fontWeight?: React.CSSProperties["fontWeight"];
16
+ fontWeightBold?: React.CSSProperties["fontWeight"];
17
+ fontFamily?: React.CSSProperties["fontFamily"];
18
+ };
19
+ export type BaseTextsProps = TextAppearanceProps & {
15
20
  className?: string;
16
21
  style?: React.CSSProperties;
17
22
  dialog?: DialogState;
@@ -84,19 +89,6 @@ export interface TextsPreviewProps extends Omit<React.HTMLAttributes<HTMLDivElem
84
89
  fontFamily?: React.CSSProperties["fontFamily"];
85
90
  onCompleted?: () => void;
86
91
  }
87
- /**
88
- * Props-based wrapper component
89
- * Provides a clean interface for direct prop usage
90
- */
91
- export interface TextsProps extends DialogElementProps {
92
- sentence: Sentence;
93
- gameState: GameState;
94
- useTypeEffect?: boolean;
95
- onCompleted?: () => void;
96
- finished?: boolean;
97
- count?: number;
98
- words?: Word<Pausing | string>[];
99
- }
100
92
  export type EntryTextsProps = BaseTextsProps & {
101
93
  entry: NvlDialogEntry;
102
94
  gameState: GameState;
@@ -105,10 +97,12 @@ export type EntryTextsProps = BaseTextsProps & {
105
97
  isActive: boolean;
106
98
  };
107
99
  export declare function TextsPreview({ text, sentence, words, useTypeEffect, loop, restartDelay, cps, gameSpeed, pauseDuration, defaultColor, className, style, fontSize, fontWeight, fontWeightBold, fontFamily, onCompleted, ...props }: TextsPreviewProps): React.JSX.Element;
100
+ export type RawTextsProps = BaseTextsProps;
108
101
  export declare function RawTexts(props: BaseTextsProps): React.JSX.Element;
109
102
  /**
110
103
  * Context-based wrapper component
111
104
  * Provides integration with the sentence context
112
105
  */
106
+ export type TextsProps = BaseTextsProps | EntryTextsProps;
113
107
  export declare function Texts(props: BaseTextsProps | EntryTextsProps): React.JSX.Element;
114
108
  export default Texts;
@@ -3,7 +3,7 @@ import { IDialogProps, SayElementProps } from "../elements/say/type";
3
3
  import { IUserMenuProps, MenuElementProps } from "../elements/menu/type";
4
4
  import { Story } from "../../nlcore/elements/story";
5
5
  import clsx from "clsx";
6
- import { Game } from "../../nlcore/game";
6
+ import { Game, type GameLifecycleEventContext } from "../../nlcore/game";
7
7
  import { GameState } from "../gameState";
8
8
  import { Storable } from "../../nlcore/elements/persistent/storable";
9
9
  import { LiveGame } from "../../nlcore/game/liveGame";
@@ -28,23 +28,42 @@ export type PlayerEventContext = {
28
28
  liveGame: LiveGame;
29
29
  storable: Storable;
30
30
  };
31
+ export type PlayerLifecycleEventContext = GameLifecycleEventContext;
31
32
  export interface PlayerProps {
32
33
  story?: Story;
33
34
  width?: string | number;
34
35
  height?: string | number;
35
36
  className?: clsx.ClassValue;
36
37
  /**
37
- * Once the game is ready to be played
38
+ * Once the Player is initialized.
39
+ *
40
+ * This is not a preload or first-render guarantee. Use
41
+ * {@link PlayerProps.onPreloadComplete} or {@link PlayerProps.onFirstSceneReady}
42
+ * when you need those exact lifecycle points.
38
43
  *
39
44
  * only called each lifecycle once
40
45
  */
41
46
  onReady?: (ctx: PlayerEventContext) => void;
47
+ /**
48
+ * Once the initial preload pass has actually completed.
49
+ *
50
+ * This fires before the first scene is guaranteed to be rendered.
51
+ */
52
+ onPreloadComplete?: (ctx: PlayerLifecycleEventContext) => void;
42
53
  /**
43
54
  * Once the internal preload pass is ready and the Player has committed that state.
44
55
  *
45
56
  * only called each lifecycle once
57
+ *
58
+ * @deprecated Use {@link PlayerProps.onPreloadComplete}.
46
59
  */
47
60
  onPreloadedReady?: (ctx: PlayerEventContext) => void;
61
+ /**
62
+ * Once the first scene has mounted and the browser has had a frame to render it.
63
+ *
64
+ * This is the most direct signal that the game is visually ready for the player.
65
+ */
66
+ onFirstSceneReady?: (ctx: PlayerLifecycleEventContext) => void;
48
67
  /**
49
68
  * Once the game is ended
50
69
  *