@yagejs-addons/dialogue 0.1.0 → 0.2.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/dist/DialogueController-BMeNLi0v.d.cts +1204 -0
- package/dist/DialogueController-Cs5IUc-u.d.ts +1204 -0
- package/dist/chunk-7QVYU63E.js +7 -0
- package/dist/chunk-7QVYU63E.js.map +1 -0
- package/dist/chunk-CU47RPEB.js +410 -0
- package/dist/chunk-CU47RPEB.js.map +1 -0
- package/dist/chunk-GJQKZCOL.js +983 -0
- package/dist/chunk-GJQKZCOL.js.map +1 -0
- package/dist/index.cjs +3441 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +591 -0
- package/dist/index.d.ts +591 -0
- package/dist/index.js +2048 -0
- package/dist/index.js.map +1 -0
- package/dist/presenters.cjs +3149 -0
- package/dist/presenters.cjs.map +1 -0
- package/dist/presenters.d.cts +1817 -0
- package/dist/presenters.d.ts +1817 -0
- package/dist/presenters.js +2920 -0
- package/dist/presenters.js.map +1 -0
- package/dist/types-DSbBSlh7.d.cts +375 -0
- package/dist/types-DSbBSlh7.d.ts +375 -0
- package/dist/yaml.cjs +726 -0
- package/dist/yaml.cjs.map +1 -0
- package/dist/yaml.d.cts +23 -0
- package/dist/yaml.d.ts +23 -0
- package/dist/yaml.js +37 -0
- package/dist/yaml.js.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine-agnostic dialogue model. Nothing in this folder imports `@yagejs/*`
|
|
3
|
+
* — it's plain TypeScript so it can be unit-tested headless and lifted into a
|
|
4
|
+
* standalone `@yagejs/dialogue` package later. Engine/UI/i18n touch points all
|
|
5
|
+
* live behind adapters (see ../chrome, ../render, ../avatar, ./i18n).
|
|
6
|
+
*/
|
|
7
|
+
type NodeId = string;
|
|
8
|
+
type SpeakerId = string;
|
|
9
|
+
/**
|
|
10
|
+
* A side effect attached to a step or a choice. The runner handles a couple of
|
|
11
|
+
* built-ins (`set` mutates branching vars, `goto` jumps) and surfaces the rest
|
|
12
|
+
* to the host via the command event, so the game decides what `give-item` or
|
|
13
|
+
* `play-sfx` actually mean. Keep it a flat tagged record so scripts stay JSON.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* When a command attached to a `say` line fires, relative to its reveal:
|
|
17
|
+
* `show` (as the line appears — default), `afterReveal` (once fully typed), or
|
|
18
|
+
* `advance` (as the player leaves the line). Ignored for `command`/choice
|
|
19
|
+
* commands, which fire inline. Skipping fires everything at show-time.
|
|
20
|
+
*/
|
|
21
|
+
type CommandTiming = "show" | "afterReveal" | "advance";
|
|
22
|
+
interface Command {
|
|
23
|
+
readonly type: string;
|
|
24
|
+
/**
|
|
25
|
+
* If true, a handler that returns a promise *pauses* the conversation until it
|
|
26
|
+
* resolves (the runner enters its `awaiting-command` wait-state). Use for
|
|
27
|
+
* cinematic sequencing — "wait for the NPC to walk off, then continue". A
|
|
28
|
+
* non-blocking handler's promise is fire-and-forget.
|
|
29
|
+
*/
|
|
30
|
+
readonly blocking?: boolean;
|
|
31
|
+
/** Reveal-relative firing time for a `say`-line command. Default `show`. */
|
|
32
|
+
readonly at?: CommandTiming;
|
|
33
|
+
readonly [key: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
/** Whether the runner is playing normally or fast-forwarding through a skip. */
|
|
36
|
+
type RunMode = "play" | "skip";
|
|
37
|
+
/** Context handed to every command handler. */
|
|
38
|
+
interface CommandContext {
|
|
39
|
+
readonly mode: RunMode;
|
|
40
|
+
/**
|
|
41
|
+
* Write a variable through the conversation's {@link VariableStorage} — the
|
|
42
|
+
* skill-check seam: a result a blocking command computes (`ctx.setVar("passed",
|
|
43
|
+
* true)`) is read by a later condition. Routes through the same guarded write
|
|
44
|
+
* as the `set` built-in, so a read-only `cells` accessor throws. A stale ctx
|
|
45
|
+
* (after stop/replay) no-ops.
|
|
46
|
+
*/
|
|
47
|
+
setVar(name: string, value: VarValue): void;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A command handler. Return a promise from a `blocking` command to pause the
|
|
51
|
+
* conversation until it resolves (cinematic sequencing). Handlers are installed
|
|
52
|
+
* on the controller (`commands` map + optional `fallbackCommand`), with optional
|
|
53
|
+
* per-`play()` overrides.
|
|
54
|
+
*/
|
|
55
|
+
type CommandHandler = (command: Command, ctx: CommandContext) => void | Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* A boolean guard on a choice or step. Resolved against the conversation's
|
|
58
|
+
* {@link VariableStorage} + installed functions:
|
|
59
|
+
*
|
|
60
|
+
* - a bare name (`"greeted"`) → truthy check on that variable;
|
|
61
|
+
* - an atomic comparison `{ var, op, value }` (the degenerate one-level tree);
|
|
62
|
+
* - a full {@link Expr} tree (`and`/`or`, arithmetic, `has_item("key")`, …);
|
|
63
|
+
* - a `(vars) => boolean` predicate — TS-only, receives a materialized snapshot
|
|
64
|
+
* of the readable variables (doesn't survive JSON).
|
|
65
|
+
*/
|
|
66
|
+
type Condition = string | {
|
|
67
|
+
readonly var: string;
|
|
68
|
+
readonly op: CompareOp;
|
|
69
|
+
readonly value: unknown;
|
|
70
|
+
} | Expr | ((vars: VarMap) => boolean);
|
|
71
|
+
/** Operators for the atomic `{ var, op, value }` condition (the degenerate
|
|
72
|
+
* comparison tree). Full expression trees use {@link BinaryOp}/{@link UnaryOp}. */
|
|
73
|
+
type CompareOp = "==" | "!=" | ">" | ">=" | "<" | "<=" | "truthy" | "falsy";
|
|
74
|
+
type VarValue = string | number | boolean | null;
|
|
75
|
+
type VarMap = Record<string, VarValue>;
|
|
76
|
+
/** Comparison operators (symbol + Yarn word forms). `is`/`eq` ≡ `==`. */
|
|
77
|
+
type ComparisonOp = "==" | "!=" | ">" | "<" | ">=" | "<=" | "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "is";
|
|
78
|
+
/** Boolean operators (symbol + word forms). */
|
|
79
|
+
type LogicalOp = "and" | "&&" | "or" | "||" | "xor" | "^";
|
|
80
|
+
/** Arithmetic operators. `+` concatenates when either operand is a string. */
|
|
81
|
+
type ArithmeticOp = "+" | "-" | "*" | "/" | "%";
|
|
82
|
+
type BinaryOp = ComparisonOp | LogicalOp | ArithmeticOp;
|
|
83
|
+
/** Unary operators: logical negation (`not`/`!`) and numeric negation (`-`). */
|
|
84
|
+
type UnaryOp = "not" | "!" | "-";
|
|
85
|
+
/** An expression node. Evaluates to a {@link VarValue} against an eval scope
|
|
86
|
+
* (variable reads + installed functions). */
|
|
87
|
+
type Expr = {
|
|
88
|
+
readonly kind: "literal";
|
|
89
|
+
readonly value: VarValue;
|
|
90
|
+
} | {
|
|
91
|
+
readonly kind: "varRef";
|
|
92
|
+
readonly name: string;
|
|
93
|
+
} | {
|
|
94
|
+
readonly kind: "call";
|
|
95
|
+
readonly fn: string;
|
|
96
|
+
readonly args?: readonly Expr[];
|
|
97
|
+
} | {
|
|
98
|
+
readonly kind: "unary";
|
|
99
|
+
readonly op: UnaryOp;
|
|
100
|
+
readonly operand: Expr;
|
|
101
|
+
} | {
|
|
102
|
+
readonly kind: "binary";
|
|
103
|
+
readonly op: BinaryOp;
|
|
104
|
+
readonly left: Expr;
|
|
105
|
+
readonly right: Expr;
|
|
106
|
+
} | {
|
|
107
|
+
readonly kind: "group";
|
|
108
|
+
readonly expr: Expr;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* The read/write bridge between a conversation and game state (Yarn's
|
|
112
|
+
* `VariableStorage` shape). Names are **opaque** — the runtime imposes no
|
|
113
|
+
* meaning on a name's characters; scoping/prefixing/nesting is the host's
|
|
114
|
+
* policy. The addon ships a zero-config {@link MemoryVariableStorage}; a host
|
|
115
|
+
* can supply its own or {@link compose} several (a {@link cells} accessor over
|
|
116
|
+
* game state, an in-memory default for dialogue-locals + seeds, …). Storage
|
|
117
|
+
* **persists** across `play()`s.
|
|
118
|
+
*/
|
|
119
|
+
interface VariableStorage {
|
|
120
|
+
/** Read a variable, or `undefined` if absent. */
|
|
121
|
+
get(name: string): VarValue | undefined;
|
|
122
|
+
/** Write a variable. A read-only accessor (a `cells` getter without a setter)
|
|
123
|
+
* throws. */
|
|
124
|
+
set(name: string, value: VarValue): void;
|
|
125
|
+
/** Whether the storage currently holds `name` (drives seed-if-absent). */
|
|
126
|
+
has(name: string): boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Enumerate the readable `(name, value)` pairs — backs `{token}` interpolation
|
|
129
|
+
* params, `handle.getVars()`, and the `(vars) => boolean` predicate. A fully
|
|
130
|
+
* opaque game store may enumerate fewer names; those then won't interpolate or
|
|
131
|
+
* appear in `getVars()`, but direct `get`/`set`/`has` still work.
|
|
132
|
+
*/
|
|
133
|
+
entries(): Iterable<readonly [string, VarValue]>;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* A pure, argument-capable read installed on the controller (`functions`). The
|
|
137
|
+
* read-only counterpart to a `command`: `has_item("rusty-key")` in a condition.
|
|
138
|
+
* Zero-arg reads need no function — a bare name reads {@link VariableStorage}.
|
|
139
|
+
* MUST be cheap + side-effect-free (called on every condition test).
|
|
140
|
+
*/
|
|
141
|
+
type DialogueFunction = (...args: VarValue[]) => VarValue;
|
|
142
|
+
/**
|
|
143
|
+
* Per-`play()` overrides, layered over the controller-installed
|
|
144
|
+
* storage/functions/commands for entity-specifics. `storage` replaces the
|
|
145
|
+
* controller's (use {@link compose} to layer); `functions`/`commands` merge
|
|
146
|
+
* key-by-key with the call site winning; `fallbackCommand` wins when set.
|
|
147
|
+
*/
|
|
148
|
+
interface DialoguePlayOptions {
|
|
149
|
+
readonly storage?: VariableStorage | undefined;
|
|
150
|
+
readonly functions?: Readonly<Record<string, DialogueFunction>> | undefined;
|
|
151
|
+
readonly commands?: Readonly<Record<string, CommandHandler>> | undefined;
|
|
152
|
+
readonly fallbackCommand?: CommandHandler | undefined;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The typed, per-conversation handle returned by `play()`. Lets the host poke
|
|
156
|
+
* variables live (`setVar`) and read them back (`getVars`) without growing
|
|
157
|
+
* string-keyed methods on the controller. Generation-stamped: after
|
|
158
|
+
* `stop()`/replay a stale handle no-ops (`setVar`) / returns an empty snapshot
|
|
159
|
+
* (`getVars`).
|
|
160
|
+
*/
|
|
161
|
+
interface DialogueHandle<Vars extends VarMap = VarMap> {
|
|
162
|
+
/** Write a variable through the conversation's storage (guarded). On the
|
|
163
|
+
* {@link defineScript} path both the name AND the value are typed to the
|
|
164
|
+
* script's declared variables — a wrong-typed value is a compile error.
|
|
165
|
+
* (`ctx.setVar` stays loosely typed: command handlers are installed on the
|
|
166
|
+
* controller, not bound to any one script's variable types.) */
|
|
167
|
+
setVar<K extends keyof Vars & string>(name: K, value: Vars[K]): void;
|
|
168
|
+
/** Snapshot of the storage's enumerable variables. */
|
|
169
|
+
getVars(): Readonly<Vars>;
|
|
170
|
+
}
|
|
171
|
+
/** A single line of dialogue spoken by an optional speaker. */
|
|
172
|
+
interface SayStep {
|
|
173
|
+
readonly kind: "say";
|
|
174
|
+
readonly speaker?: SpeakerId;
|
|
175
|
+
/** Literal text (default-locale), and/or an i18n `key`. Markup allowed. */
|
|
176
|
+
readonly text: string;
|
|
177
|
+
readonly key?: string;
|
|
178
|
+
/** Expression variant for the speaker's avatar (e.g. "happy", "angry"). */
|
|
179
|
+
readonly expression?: string;
|
|
180
|
+
/** Reveal-speed multiplier for this whole line (1 = base). */
|
|
181
|
+
readonly speed?: number;
|
|
182
|
+
/** If set, the line auto-advances after this many ms once fully revealed. */
|
|
183
|
+
readonly autoAdvanceMs?: number;
|
|
184
|
+
readonly commands?: readonly Command[];
|
|
185
|
+
/** Opaque preset name for per-line layout/variant (presenter interprets). */
|
|
186
|
+
readonly view?: string;
|
|
187
|
+
/** Opaque per-line hint bag (presenter/chrome interprets). */
|
|
188
|
+
readonly meta?: Readonly<Record<string, unknown>>;
|
|
189
|
+
/** Voice-clip id (audio handler interprets; reveal may sync to it). */
|
|
190
|
+
readonly voice?: string;
|
|
191
|
+
}
|
|
192
|
+
interface ChoiceOption {
|
|
193
|
+
readonly text: string;
|
|
194
|
+
readonly key?: string;
|
|
195
|
+
/** Node to jump to when picked. Omit to just continue the current node. */
|
|
196
|
+
readonly target?: NodeId;
|
|
197
|
+
readonly condition?: Condition;
|
|
198
|
+
/** Hide this option once it has been picked. Tracked as per-conversation
|
|
199
|
+
* cursor state (resets on a fresh `play()`; the future save cursor captures
|
|
200
|
+
* it), NOT in the variable storage. */
|
|
201
|
+
readonly once?: boolean;
|
|
202
|
+
/**
|
|
203
|
+
* What to do when this option's {@link condition} is **false**. Default
|
|
204
|
+
* `"hidden"` (the option is filtered out). `"disabled"` keeps it on screen as
|
|
205
|
+
* a non-selectable, greyed-out row (the Disco-Elysium "[Strength 8] Force the
|
|
206
|
+
* door" pattern — the player learns the gate exists). Governs condition
|
|
207
|
+
* failures only: a spent `once` option is **always** hidden regardless. A step
|
|
208
|
+
* whose only-enabled count drops to zero is skipped, so a disabled row never
|
|
209
|
+
* causes a soft-lock.
|
|
210
|
+
*/
|
|
211
|
+
readonly presentation?: "hidden" | "disabled";
|
|
212
|
+
/** Short reason shown beside a `"disabled"` row where the layout allows (e.g.
|
|
213
|
+
* "Requires the rusty key"). Resolved through the i18n adapter, so `{token}`s
|
|
214
|
+
* interpolate; there is no separate i18n `key` for it. */
|
|
215
|
+
readonly disabledReason?: string;
|
|
216
|
+
readonly commands?: readonly Command[];
|
|
217
|
+
/** Opaque per-choice hint bag (tone/icon/position for fancy choice UIs). */
|
|
218
|
+
readonly meta?: Readonly<Record<string, unknown>>;
|
|
219
|
+
}
|
|
220
|
+
interface ChoiceStep {
|
|
221
|
+
readonly kind: "choice";
|
|
222
|
+
/** Optional prompt shown above the options. */
|
|
223
|
+
readonly text?: string;
|
|
224
|
+
readonly key?: string;
|
|
225
|
+
readonly speaker?: SpeakerId;
|
|
226
|
+
readonly options: readonly ChoiceOption[];
|
|
227
|
+
/** Presentation preset for the prompt/chrome (e.g. "box"/"bubble"), like a
|
|
228
|
+
* say's `view` — lets a composite chrome route the choice the same way. */
|
|
229
|
+
readonly view?: string;
|
|
230
|
+
readonly meta?: Readonly<Record<string, unknown>>;
|
|
231
|
+
}
|
|
232
|
+
/** Fire commands without showing anything (set a var, emit a game event). */
|
|
233
|
+
interface CommandStep {
|
|
234
|
+
readonly kind: "command";
|
|
235
|
+
readonly commands: readonly Command[];
|
|
236
|
+
/** Optional conditional jump; if `condition` passes, jump to `target`. */
|
|
237
|
+
readonly condition?: Condition;
|
|
238
|
+
readonly target?: NodeId;
|
|
239
|
+
}
|
|
240
|
+
/** Unconditional jump to another node. */
|
|
241
|
+
interface GotoStep {
|
|
242
|
+
readonly kind: "goto";
|
|
243
|
+
readonly target: NodeId;
|
|
244
|
+
}
|
|
245
|
+
/** Ends the conversation immediately. */
|
|
246
|
+
interface EndStep {
|
|
247
|
+
readonly kind: "end";
|
|
248
|
+
}
|
|
249
|
+
type Step = SayStep | ChoiceStep | CommandStep | GotoStep | EndStep;
|
|
250
|
+
interface DialogueNode {
|
|
251
|
+
readonly id: NodeId;
|
|
252
|
+
readonly steps: readonly Step[];
|
|
253
|
+
}
|
|
254
|
+
/** How a speaker's avatar is presented (the presenter implementation decides). */
|
|
255
|
+
interface AvatarRef {
|
|
256
|
+
/** "portrait" → a sprite beside the box; "scene" → an existing world entity. */
|
|
257
|
+
readonly kind: "portrait" | "scene";
|
|
258
|
+
/** Presenter-specific handle: a texture id for portraits, an entity name for scene. */
|
|
259
|
+
readonly ref: string;
|
|
260
|
+
/** Map of expression id → presenter-specific variant (texture/frame/anim). */
|
|
261
|
+
readonly expressions?: Record<string, string>;
|
|
262
|
+
/** Side the portrait sits on. Default "left". */
|
|
263
|
+
readonly side?: "left" | "right";
|
|
264
|
+
}
|
|
265
|
+
interface SpeakerDef {
|
|
266
|
+
readonly id: SpeakerId;
|
|
267
|
+
/** Display name (literal). */
|
|
268
|
+
readonly name: string;
|
|
269
|
+
/** i18n key for the name. */
|
|
270
|
+
readonly nameKey?: string;
|
|
271
|
+
/** Name-plate tint (0xRRGGBB). */
|
|
272
|
+
readonly color?: number;
|
|
273
|
+
readonly avatar?: AvatarRef;
|
|
274
|
+
}
|
|
275
|
+
interface DialogueScript {
|
|
276
|
+
readonly id: string;
|
|
277
|
+
readonly start: NodeId;
|
|
278
|
+
readonly nodes: Record<NodeId, DialogueNode>;
|
|
279
|
+
readonly speakers?: Record<SpeakerId, SpeakerDef>;
|
|
280
|
+
/**
|
|
281
|
+
* Declared variable **defaults** (Yarn `<<declare>>` / `InitialValues`). On
|
|
282
|
+
* `play()`, each applies **only if the installed storage doesn't already
|
|
283
|
+
* `has` the name** (seed-if-absent) — a game-linked value always wins, the
|
|
284
|
+
* addon never clobbers. The default's value also fixes the variable's inferred
|
|
285
|
+
* type on the {@link defineScript} path. Variables **persist** in storage
|
|
286
|
+
* across plays (cycling-NPC counters, quest progress); a script re-inits a
|
|
287
|
+
* value explicitly to reset it. (A choice's `once` flag is per-conversation
|
|
288
|
+
* cursor state, not a stored variable — see {@link ChoiceOption.once}.)
|
|
289
|
+
*/
|
|
290
|
+
readonly declare?: VarMap;
|
|
291
|
+
}
|
|
292
|
+
interface RunStyle {
|
|
293
|
+
readonly bold?: boolean;
|
|
294
|
+
readonly italic?: boolean;
|
|
295
|
+
/** 0xRRGGBB. */
|
|
296
|
+
readonly color?: number;
|
|
297
|
+
/**
|
|
298
|
+
* Animated effect applied to the whole run — an **open vocabulary** the
|
|
299
|
+
* presenter interprets, like an inline marker name. The bundled text presenter
|
|
300
|
+
* animates the {@link BuiltinEffectId}s; a custom text channel can animate any
|
|
301
|
+
* name; an effect a presenter doesn't recognize renders as plain styled text.
|
|
302
|
+
* `bold`/`italic`/`color`/`speed` are the typed, universal set — `effect` is
|
|
303
|
+
* the one open dimension.
|
|
304
|
+
*/
|
|
305
|
+
readonly effect?: string;
|
|
306
|
+
/** Reveal-speed multiplier for characters in this run. */
|
|
307
|
+
readonly speed?: number;
|
|
308
|
+
}
|
|
309
|
+
/** The text effects the bundled renderer presenter animates out of the box.
|
|
310
|
+
* {@link RunStyle.effect} is an open string; these are just the built-ins — a
|
|
311
|
+
* documented reference, not a closed set the parser enforces. */
|
|
312
|
+
type BuiltinEffectId = "wave" | "shake" | "pulse" | "rainbow";
|
|
313
|
+
/** A contiguous span of text sharing one style. */
|
|
314
|
+
interface TextRun {
|
|
315
|
+
readonly text: string;
|
|
316
|
+
readonly style: RunStyle;
|
|
317
|
+
/**
|
|
318
|
+
* Number of graphemes (user-perceived characters) in `text` — NOT
|
|
319
|
+
* `text.length`. All reveal bookkeeping counts graphemes, because that is
|
|
320
|
+
* the unit the renderer splits into glyph nodes (one per grapheme), so an
|
|
321
|
+
* emoji / ZWJ sequence / combining mark counts as 1.
|
|
322
|
+
*/
|
|
323
|
+
readonly graphemeCount: number;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* A self-closing `[pause=600/]` token — a zero-width timing hold the reveal
|
|
327
|
+
* arms when the cursor reaches its offset. One member of the unified
|
|
328
|
+
* {@link RevealToken} stream; `kind` discriminates it from a {@link MarkerToken}.
|
|
329
|
+
*/
|
|
330
|
+
interface PauseToken {
|
|
331
|
+
readonly kind: "pause";
|
|
332
|
+
/** Grapheme index into the flattened text where the pause occurs. */
|
|
333
|
+
readonly atChar: number;
|
|
334
|
+
/** Hold duration in ms (always > 0; a non-positive `[pause=0/]` emits no token). */
|
|
335
|
+
readonly ms: number;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* A self-closing inline marker (`[name k=v/]`) that fires as a **reveal event**
|
|
339
|
+
* when the typewriter cursor reaches its char offset — the sibling of
|
|
340
|
+
* {@link PauseToken}, but a one-shot consequence rather than a timing hold. The
|
|
341
|
+
* canonical use is positional SFX (`[sfx=ding/]`) and a mid-line face change
|
|
342
|
+
* (`[expression=happy/]`); the addon interprets none of the names (the avatar
|
|
343
|
+
* channel reads `[expression]`, the host reads the rest). The Yarn self-named
|
|
344
|
+
* shortcut `[name=val/]` ≡ `[name name=val/]`, so it composes with explicit
|
|
345
|
+
* props (`[shake=500 amount=3/]` → `{ shake: "500", amount: "3" }`).
|
|
346
|
+
*/
|
|
347
|
+
interface MarkerToken {
|
|
348
|
+
readonly kind: "marker";
|
|
349
|
+
/** Grapheme index into the flattened text where the marker fires. */
|
|
350
|
+
readonly atChar: number;
|
|
351
|
+
/** Marker name (lower-cased), e.g. `expression`, `sfx`, `shake`. */
|
|
352
|
+
readonly name: string;
|
|
353
|
+
/** Parsed `key=value` props (all string-valued). `[expression=happy/]` →
|
|
354
|
+
* `{ expression: "happy" }` via the self-named shortcut. */
|
|
355
|
+
readonly props: Readonly<Record<string, string>>;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* One inline control token interleaved between text runs during reveal — a
|
|
359
|
+
* timing {@link PauseToken} or a fire-and-forget {@link MarkerToken}. They share
|
|
360
|
+
* one ordered stream on {@link ParsedText.tokens}, so **source order is drain
|
|
361
|
+
* order**: `[pause=600/][shake/]` holds then fires; `[shake/][pause=600/]` fires
|
|
362
|
+
* then holds.
|
|
363
|
+
*/
|
|
364
|
+
type RevealToken = PauseToken | MarkerToken;
|
|
365
|
+
/** Result of parsing one line's markup. */
|
|
366
|
+
interface ParsedText {
|
|
367
|
+
readonly runs: readonly TextRun[];
|
|
368
|
+
/** Inline pause + marker tokens in source (left-to-right) order — the order
|
|
369
|
+
* the reveal drains them. Empty when the line has none. */
|
|
370
|
+
readonly tokens: readonly RevealToken[];
|
|
371
|
+
/** Total grapheme count across all runs (the reveal denominator). */
|
|
372
|
+
readonly length: number;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export type { ArithmeticOp as A, BinaryOp as B, Condition as C, DialogueScript as D, Expr as E, GotoStep as G, LogicalOp as L, MarkerToken as M, NodeId as N, ParsedText as P, RunMode as R, SayStep as S, TextRun as T, UnaryOp as U, VarValue as V, VariableStorage as a, VarMap as b, DialogueFunction as c, SpeakerDef as d, ChoiceStep as e, ChoiceOption as f, Command as g, CommandContext as h, AvatarRef as i, BuiltinEffectId as j, CommandHandler as k, CommandStep as l, CommandTiming as m, CompareOp as n, ComparisonOp as o, DialogueHandle as p, DialogueNode as q, DialoguePlayOptions as r, EndStep as s, PauseToken as t, RevealToken as u, RunStyle as v, SpeakerId as w, Step as x };
|