@patterkit/runtime 0.21.0 → 0.23.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/index.d.cts CHANGED
@@ -2,7 +2,13 @@ import { ScalarValue } from '@wildwinter/expr';
2
2
  import { ScopeRegistry, PropertyBag, ScopeDeclaration, LogMount, ScopeResolver, PropertyRow } from '@wildwinter/scoperegistry';
3
3
  export { PropertyRow } from '@wildwinter/scoperegistry';
4
4
  import { GameData, Bundle, CompiledGroup, CompiledSnippet, CompiledBlock, FlowSnapshot, EngineSave, SaveGame, SaveGameV2, PropertyType, ScalarValue as ScalarValue$1, GameDataNodeKind, GameDataField } from '@patterkit/model';
5
- export { Bundle, EngineSave, FlowCursor, FlowSnapshot, SaveEnvelope, SaveGame, SavedChoice, SavedChoiceOption, SavedChoicePrompt, SelectorSnapshot, StackFrame } from '@patterkit/model';
5
+ export { Bundle, DEFAULT_PAD_AFTER, EngineSave, FlowCursor, FlowSnapshot, SaveEnvelope, SaveGame, SavedChoice, SavedChoiceOption, SavedChoicePrompt, SelectorSnapshot, StackFrame } from '@patterkit/model';
6
+
7
+ /** A beat's own `padAfter` (when it sets one) and its resolved one (always). */
8
+ interface BeatPad {
9
+ own?: number;
10
+ resolved: number;
11
+ }
6
12
 
7
13
  type SelectableNode = CompiledGroup | CompiledSnippet;
8
14
 
@@ -14,12 +20,16 @@ type StepResult = {
14
20
  character?: string;
15
21
  characterName?: string;
16
22
  direction?: string;
23
+ qualifier?: string;
24
+ qualifierName?: string;
25
+ padAfter: number;
17
26
  gameData?: GameData;
18
27
  tags?: string[];
19
28
  } | {
20
29
  type: "text";
21
30
  id: string;
22
31
  text: string;
32
+ padAfter: number;
23
33
  gameData?: GameData;
24
34
  tags?: string[];
25
35
  } | {
@@ -44,6 +54,15 @@ interface BeatInfo {
44
54
  characterName?: string;
45
55
  /** Performance direction (line only). */
46
56
  direction?: string;
57
+ /** Speaker qualifier `gameId` (line only), e.g. `vo`. */
58
+ qualifier?: string;
59
+ /** The qualifier's shown name (source locale), e.g. `V.O.`. */
60
+ qualifierName?: string;
61
+ /** The pause after this beat, in seconds, resolved from its own value and the defaults above it (line and
62
+ * text only; see line padding). What a delivered step carries. */
63
+ padAfter?: number;
64
+ /** The beat's own `padAfter`, when it sets one (line and text only). */
65
+ ownPadAfter?: number;
47
66
  /** Source text, un-interpolated (line / text). Omitted for gameEvent and IDs-only bundles. */
48
67
  text?: string;
49
68
  /** Author gameData overrides on this beat (raw, as the step carries them). Omitted when empty. */
@@ -111,6 +130,12 @@ interface ChoicePrompt {
111
130
  /** The speaker's resolved player-facing name (locale-aware; absent when the character has none). */
112
131
  characterName?: string;
113
132
  direction?: string;
133
+ /** The speaker qualifier's `gameId` (`vo`), and its resolved shown name (locale-aware). */
134
+ qualifier?: string;
135
+ qualifierName?: string;
136
+ /** The prompt's resolved pause, in seconds: when it is spoken (by `replayPromptOnChoose`, or by a game that
137
+ * voices it), the wait before the reply, negative to cut in on the question (line padding). */
138
+ padAfter: number;
114
139
  }
115
140
  /** A single option of a pending `choice` group. */
116
141
  interface ChoiceOption {
@@ -352,6 +377,8 @@ interface FlowHost {
352
377
  defaultStrings: Record<string, string>;
353
378
  /** Cast canonical name -> authoring `displayName` (the unlocalised fallback when no loc string exists). */
354
379
  castDisplay: Map<string, string>;
380
+ /** Speaker qualifier gameId -> authored name (the unlocalised fallback when no loc string exists). */
381
+ qualifierDisplay: Map<string, string>;
355
382
  nodeIndex: Map<string, SelectableNode>;
356
383
  blockIndex: Map<string, {
357
384
  sceneId: string;
@@ -363,6 +390,8 @@ interface FlowHost {
363
390
  blockGameIdToId: Map<string, Map<string, string>>;
364
391
  /** Author tags (#215): node id -> accumulated tags (own + every ancestor's, deduped). Built once. */
365
392
  tagIndex: Map<string, string[]>;
393
+ /** Every line and text beat's resolved pause (line padding), precomputed per bundle (pads.ts). */
394
+ padIndex: Map<string, BeatPad>;
366
395
  /** The game's one registry: `@patter` (the SHARED globals), host scopes, every instance bag. */
367
396
  registry: ScopeRegistry;
368
397
  /** True when the engine made the registry (a standalone game): `saveGame()` then carries its values. */
@@ -994,6 +1023,16 @@ declare class Flow {
994
1023
  * locale, else the authoring `displayName`. Undefined when the character has no display name at all
995
1024
  * (the host falls back to the `character` token itself). */
996
1025
  private resolveCharacterName;
1026
+ /** The resolved pause of the beat an option shows as its prompt (its authored prompt, else its first content
1027
+ * line), for a saved option that predates prompts carrying one. */
1028
+ private promptPadOf;
1029
+ /** A line or text beat's resolved pause (line padding): its own `padAfter`, else the nearest default above
1030
+ * it, else the project's, else the built-in one; clamped to zero on a snippet's last line. */
1031
+ private padOf;
1032
+ /** A speaker qualifier's shown name, resolved as a character's is: the `qualifier:<gameId>` string in the
1033
+ * active locale, else the default locale, else the authored name. Undefined in IDs-only mode (the game
1034
+ * maps the `qualifier` gameId itself). */
1035
+ private resolveQualifierName;
997
1036
  /** Split a ref into scope + name. Tokens: `@scene`, registered tokens, else `@patter` (incl. bare `@name`). */
998
1037
  private splitRef;
999
1038
  /** A fresh, unregistered bag for the NOT-shared `@patter` globals (the shared ones live on the host). */
package/dist/index.d.ts CHANGED
@@ -2,7 +2,13 @@ import { ScalarValue } from '@wildwinter/expr';
2
2
  import { ScopeRegistry, PropertyBag, ScopeDeclaration, LogMount, ScopeResolver, PropertyRow } from '@wildwinter/scoperegistry';
3
3
  export { PropertyRow } from '@wildwinter/scoperegistry';
4
4
  import { GameData, Bundle, CompiledGroup, CompiledSnippet, CompiledBlock, FlowSnapshot, EngineSave, SaveGame, SaveGameV2, PropertyType, ScalarValue as ScalarValue$1, GameDataNodeKind, GameDataField } from '@patterkit/model';
5
- export { Bundle, EngineSave, FlowCursor, FlowSnapshot, SaveEnvelope, SaveGame, SavedChoice, SavedChoiceOption, SavedChoicePrompt, SelectorSnapshot, StackFrame } from '@patterkit/model';
5
+ export { Bundle, DEFAULT_PAD_AFTER, EngineSave, FlowCursor, FlowSnapshot, SaveEnvelope, SaveGame, SavedChoice, SavedChoiceOption, SavedChoicePrompt, SelectorSnapshot, StackFrame } from '@patterkit/model';
6
+
7
+ /** A beat's own `padAfter` (when it sets one) and its resolved one (always). */
8
+ interface BeatPad {
9
+ own?: number;
10
+ resolved: number;
11
+ }
6
12
 
7
13
  type SelectableNode = CompiledGroup | CompiledSnippet;
8
14
 
@@ -14,12 +20,16 @@ type StepResult = {
14
20
  character?: string;
15
21
  characterName?: string;
16
22
  direction?: string;
23
+ qualifier?: string;
24
+ qualifierName?: string;
25
+ padAfter: number;
17
26
  gameData?: GameData;
18
27
  tags?: string[];
19
28
  } | {
20
29
  type: "text";
21
30
  id: string;
22
31
  text: string;
32
+ padAfter: number;
23
33
  gameData?: GameData;
24
34
  tags?: string[];
25
35
  } | {
@@ -44,6 +54,15 @@ interface BeatInfo {
44
54
  characterName?: string;
45
55
  /** Performance direction (line only). */
46
56
  direction?: string;
57
+ /** Speaker qualifier `gameId` (line only), e.g. `vo`. */
58
+ qualifier?: string;
59
+ /** The qualifier's shown name (source locale), e.g. `V.O.`. */
60
+ qualifierName?: string;
61
+ /** The pause after this beat, in seconds, resolved from its own value and the defaults above it (line and
62
+ * text only; see line padding). What a delivered step carries. */
63
+ padAfter?: number;
64
+ /** The beat's own `padAfter`, when it sets one (line and text only). */
65
+ ownPadAfter?: number;
47
66
  /** Source text, un-interpolated (line / text). Omitted for gameEvent and IDs-only bundles. */
48
67
  text?: string;
49
68
  /** Author gameData overrides on this beat (raw, as the step carries them). Omitted when empty. */
@@ -111,6 +130,12 @@ interface ChoicePrompt {
111
130
  /** The speaker's resolved player-facing name (locale-aware; absent when the character has none). */
112
131
  characterName?: string;
113
132
  direction?: string;
133
+ /** The speaker qualifier's `gameId` (`vo`), and its resolved shown name (locale-aware). */
134
+ qualifier?: string;
135
+ qualifierName?: string;
136
+ /** The prompt's resolved pause, in seconds: when it is spoken (by `replayPromptOnChoose`, or by a game that
137
+ * voices it), the wait before the reply, negative to cut in on the question (line padding). */
138
+ padAfter: number;
114
139
  }
115
140
  /** A single option of a pending `choice` group. */
116
141
  interface ChoiceOption {
@@ -352,6 +377,8 @@ interface FlowHost {
352
377
  defaultStrings: Record<string, string>;
353
378
  /** Cast canonical name -> authoring `displayName` (the unlocalised fallback when no loc string exists). */
354
379
  castDisplay: Map<string, string>;
380
+ /** Speaker qualifier gameId -> authored name (the unlocalised fallback when no loc string exists). */
381
+ qualifierDisplay: Map<string, string>;
355
382
  nodeIndex: Map<string, SelectableNode>;
356
383
  blockIndex: Map<string, {
357
384
  sceneId: string;
@@ -363,6 +390,8 @@ interface FlowHost {
363
390
  blockGameIdToId: Map<string, Map<string, string>>;
364
391
  /** Author tags (#215): node id -> accumulated tags (own + every ancestor's, deduped). Built once. */
365
392
  tagIndex: Map<string, string[]>;
393
+ /** Every line and text beat's resolved pause (line padding), precomputed per bundle (pads.ts). */
394
+ padIndex: Map<string, BeatPad>;
366
395
  /** The game's one registry: `@patter` (the SHARED globals), host scopes, every instance bag. */
367
396
  registry: ScopeRegistry;
368
397
  /** True when the engine made the registry (a standalone game): `saveGame()` then carries its values. */
@@ -994,6 +1023,16 @@ declare class Flow {
994
1023
  * locale, else the authoring `displayName`. Undefined when the character has no display name at all
995
1024
  * (the host falls back to the `character` token itself). */
996
1025
  private resolveCharacterName;
1026
+ /** The resolved pause of the beat an option shows as its prompt (its authored prompt, else its first content
1027
+ * line), for a saved option that predates prompts carrying one. */
1028
+ private promptPadOf;
1029
+ /** A line or text beat's resolved pause (line padding): its own `padAfter`, else the nearest default above
1030
+ * it, else the project's, else the built-in one; clamped to zero on a snippet's last line. */
1031
+ private padOf;
1032
+ /** A speaker qualifier's shown name, resolved as a character's is: the `qualifier:<gameId>` string in the
1033
+ * active locale, else the default locale, else the authored name. Undefined in IDs-only mode (the game
1034
+ * maps the `qualifier` gameId itself). */
1035
+ private resolveQualifierName;
997
1036
  /** Split a ref into scope + name. Tokens: `@scene`, registered tokens, else `@patter` (incl. bare `@name`). */
998
1037
  private splitRef;
999
1038
  /** A fresh, unregistered bag for the NOT-shared `@patter` globals (the shared ones live on the host). */
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { matchedSpecificity as scoreSpecificity } from "@wildwinter/expr-specifi
4
4
  import { ScopeRegistry } from "@wildwinter/scoperegistry";
5
5
  import { defaultFor, PropertyBag } from "@wildwinter/scoperegistry";
6
6
  import { patterDialect, interpolate, splitRef, stripCaptions } from "@patterkit/dialect";
7
- import { walkNodes, effectiveGameId, castStringKey, DEFAULT_CAPTION_DELIMITERS, DEFAULT_CAPTION_CHARACTER } from "@patterkit/model";
7
+ import { walkNodes, effectiveGameId, castStringKey, qualifierStringKey, DEFAULT_PAD_AFTER as DEFAULT_PAD_AFTER2, DEFAULT_CAPTION_DELIMITERS, DEFAULT_CAPTION_CHARACTER } from "@patterkit/model";
8
8
 
9
9
  // src/tags.ts
10
10
  function dedupe(tags) {
@@ -40,6 +40,45 @@ function buildTagIndex(bundle) {
40
40
  return index;
41
41
  }
42
42
 
43
+ // src/pads.ts
44
+ import { DEFAULT_PAD_AFTER } from "@patterkit/model";
45
+ var spoken = (b) => b.kind === "line" || b.kind === "text";
46
+ var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
47
+ function buildPadIndex(bundle) {
48
+ const index = /* @__PURE__ */ new Map();
49
+ const set = (beat, inherited, clamp) => {
50
+ const own = beat.kind === "gameEvent" ? void 0 : num(beat.padAfter);
51
+ let resolved = own ?? inherited;
52
+ if (clamp && resolved < 0) resolved = 0;
53
+ index.set(beat.id, own !== void 0 ? { own, resolved } : { resolved });
54
+ };
55
+ const visit = (node, inherited) => {
56
+ const def = num(node.padAfterDefault) ?? inherited;
57
+ if (node.type === "group") {
58
+ if (node.prompt) set(node.prompt, def, false);
59
+ for (const child of node.children) visit(child, def);
60
+ return;
61
+ }
62
+ const beats = node.beats ?? [];
63
+ let last = -1;
64
+ beats.forEach((b, i) => {
65
+ if (spoken(b)) last = i;
66
+ });
67
+ beats.forEach((b, i) => {
68
+ if (spoken(b)) set(b, def, i === last);
69
+ });
70
+ };
71
+ const projectDefault = num(bundle.padAfterDefault) ?? DEFAULT_PAD_AFTER;
72
+ for (const scene of Object.values(bundle.scenes)) {
73
+ const sceneDefault = num(scene.padAfterDefault) ?? projectDefault;
74
+ for (const block of scene.blocks) {
75
+ const blockDefault = num(block.padAfterDefault) ?? sceneDefault;
76
+ for (const child of block.children) visit(child, blockDefault);
77
+ }
78
+ }
79
+ return index;
80
+ }
81
+
43
82
  // src/engine.ts
44
83
  import { SAVE_VERSION } from "@patterkit/model";
45
84
  var astCache = /* @__PURE__ */ new WeakMap();
@@ -52,6 +91,15 @@ function tagIndexFor(bundle) {
52
91
  }
53
92
  return index;
54
93
  }
94
+ var padIndexCache = /* @__PURE__ */ new WeakMap();
95
+ function padIndexFor(bundle) {
96
+ let index = padIndexCache.get(bundle);
97
+ if (!index) {
98
+ index = buildPadIndex(bundle);
99
+ padIndexCache.set(bundle, index);
100
+ }
101
+ return index;
102
+ }
55
103
  function tagsOf(host, id) {
56
104
  return host.tagIndex.get(id)?.slice();
57
105
  }
@@ -117,6 +165,8 @@ var Engine = class _Engine {
117
165
  }
118
166
  const castDisplay = /* @__PURE__ */ new Map();
119
167
  for (const c of bundle.cast ?? []) if (c.displayName) castDisplay.set(c.name, c.displayName);
168
+ const qualifierDisplay = /* @__PURE__ */ new Map();
169
+ for (const q of bundle.qualifiers ?? []) if (q?.gameId) qualifierDisplay.set(q.gameId, q.name);
120
170
  this.defaultSeed = (options.seed ?? 2654435769) >>> 0;
121
171
  const nodeIndex = /* @__PURE__ */ new Map();
122
172
  const blockIndex = /* @__PURE__ */ new Map();
@@ -177,6 +227,7 @@ var Engine = class _Engine {
177
227
  strings,
178
228
  defaultStrings,
179
229
  castDisplay,
230
+ qualifierDisplay,
180
231
  nodeIndex,
181
232
  blockIndex,
182
233
  blockById,
@@ -184,6 +235,7 @@ var Engine = class _Engine {
184
235
  blockGameIdToId: this.blockGameIdToId,
185
236
  // same instances the engine resolves with
186
237
  tagIndex: tagIndexFor(bundle),
238
+ padIndex: padIndexFor(bundle),
187
239
  registry,
188
240
  ownsRegistry,
189
241
  patterBag,
@@ -581,8 +633,16 @@ var Engine = class _Engine {
581
633
  if (name !== void 0) info.characterName = name;
582
634
  }
583
635
  if (beat.direction !== void 0) info.direction = beat.direction;
636
+ if (beat.qualifier !== void 0) {
637
+ info.qualifier = beat.qualifier;
638
+ const name = this.host.defaultStrings[qualifierStringKey(beat.qualifier)] ?? this.host.qualifierDisplay.get(beat.qualifier);
639
+ if (name !== void 0) info.qualifierName = name;
640
+ }
584
641
  }
585
642
  if (beat.kind === "line" || beat.kind === "text") {
643
+ const pad = this.host.padIndex.get(beat.id);
644
+ info.padAfter = pad?.resolved ?? DEFAULT_PAD_AFTER2;
645
+ if (pad?.own !== void 0) info.ownPadAfter = pad.own;
586
646
  const source = this.host.defaultStrings[beat.id];
587
647
  if (source !== void 0) info.text = source;
588
648
  }
@@ -1376,7 +1436,8 @@ var Flow = class {
1376
1436
  const node = this.host.nodeIndex.get(o.id);
1377
1437
  if (!node) continue;
1378
1438
  byId.set(o.id, node);
1379
- options.push({ ...o });
1439
+ const { prompt: saved, ...rest } = o;
1440
+ options.push({ ...rest, ...saved ? { prompt: { ...saved, padAfter: saved.padAfter ?? this.promptPadOf(node) } } : {} });
1380
1441
  }
1381
1442
  if (options.length > 0) this.pendingChoice = { groupId: c.pendingChoice.groupId, options, byId };
1382
1443
  }
@@ -1385,7 +1446,7 @@ var Flow = class {
1385
1446
  if (this.pendingPromptOwnerId) {
1386
1447
  const owner = this.host.nodeIndex.get(this.pendingPromptOwnerId);
1387
1448
  const beat = owner ? this.authoredPromptOf(owner) : void 0;
1388
- if (beat) this.pendingPrompt = { beat, ...c.pendingPrompt ? { shown: { ...c.pendingPrompt } } : {} };
1449
+ if (beat) this.pendingPrompt = { beat, ...c.pendingPrompt ? { shown: { ...c.pendingPrompt, padAfter: c.pendingPrompt.padAfter ?? this.padOf(beat.id) } } : {} };
1389
1450
  else this.pendingPromptOwnerId = null;
1390
1451
  }
1391
1452
  }
@@ -1755,7 +1816,7 @@ var Flow = class {
1755
1816
  case "gameEvent":
1756
1817
  return { type: "gameEvent", id: beat.id, gameData: beat.gameData, ...withTags };
1757
1818
  case "text":
1758
- return { type: "text", id: beat.id, text: this.interpolate(this.resolveString(beat.id)), gameData: beat.gameData, ...withTags };
1819
+ return { type: "text", id: beat.id, text: this.interpolate(this.resolveString(beat.id)), padAfter: this.padOf(beat.id), gameData: beat.gameData, ...withTags };
1759
1820
  case "line": {
1760
1821
  const raw = this.resolveString(beat.id);
1761
1822
  const off = !this.host.captionsOn;
@@ -1769,6 +1830,10 @@ var Flow = class {
1769
1830
  character: silent ? void 0 : beat.character,
1770
1831
  characterName: silent ? void 0 : this.resolveCharacterName(beat.character),
1771
1832
  direction: silent ? void 0 : beat.direction,
1833
+ qualifier: silent ? void 0 : beat.qualifier,
1834
+ qualifierName: silent ? void 0 : this.resolveQualifierName(beat.qualifier),
1835
+ padAfter: this.padOf(beat.id),
1836
+ // a silent line still fires, so it still carries its pause
1772
1837
  gameData: beat.gameData,
1773
1838
  ...withTags
1774
1839
  };
@@ -1807,7 +1872,17 @@ var Flow = class {
1807
1872
  const beat = this.promptBeatOf(node);
1808
1873
  if (!beat) return void 0;
1809
1874
  const text = this.interpolate(this.resolveString(beat.id));
1810
- return beat.kind === "line" ? { kind: "line", text: this.captionLine(text), character: beat.character, characterName: this.resolveCharacterName(beat.character), direction: beat.direction } : { kind: "text", text };
1875
+ const padAfter = this.padOf(beat.id);
1876
+ return beat.kind === "line" ? {
1877
+ kind: "line",
1878
+ text: this.captionLine(text),
1879
+ character: beat.character,
1880
+ characterName: this.resolveCharacterName(beat.character),
1881
+ direction: beat.direction,
1882
+ qualifier: beat.qualifier,
1883
+ qualifierName: this.resolveQualifierName(beat.qualifier),
1884
+ padAfter
1885
+ } : { kind: "text", text, padAfter };
1811
1886
  }
1812
1887
  /** An option's AUTHORED prompt beat: an Option group's own `prompt`. The only prompt a replay speaks. */
1813
1888
  authoredPromptOf(node) {
@@ -1818,7 +1893,7 @@ var Flow = class {
1818
1893
  promptResult(beat, shown) {
1819
1894
  const tags = tagsOf(this.host, beat.id);
1820
1895
  const withTags = tags && tags.length ? { tags } : {};
1821
- if (shown.kind === "text") return { type: "text", id: beat.id, text: shown.text, gameData: beat.gameData, ...withTags };
1896
+ if (shown.kind === "text") return { type: "text", id: beat.id, text: shown.text, padAfter: this.padOf(beat.id), gameData: beat.gameData, ...withTags };
1822
1897
  return {
1823
1898
  type: "line",
1824
1899
  id: beat.id,
@@ -1826,6 +1901,9 @@ var Flow = class {
1826
1901
  character: shown.character,
1827
1902
  characterName: shown.characterName,
1828
1903
  direction: shown.direction,
1904
+ qualifier: shown.qualifier,
1905
+ qualifierName: shown.qualifierName,
1906
+ padAfter: this.padOf(beat.id),
1829
1907
  gameData: beat.gameData,
1830
1908
  ...withTags
1831
1909
  };
@@ -1862,6 +1940,26 @@ var Flow = class {
1862
1940
  const key = castStringKey(character);
1863
1941
  return this.host.strings[key] ?? this.host.defaultStrings[key] ?? this.host.castDisplay.get(character);
1864
1942
  }
1943
+ /** The resolved pause of the beat an option shows as its prompt (its authored prompt, else its first content
1944
+ * line), for a saved option that predates prompts carrying one. */
1945
+ promptPadOf(node) {
1946
+ const beat = this.promptBeatOf(node);
1947
+ return beat ? this.padOf(beat.id) : DEFAULT_PAD_AFTER2;
1948
+ }
1949
+ /** A line or text beat's resolved pause (line padding): its own `padAfter`, else the nearest default above
1950
+ * it, else the project's, else the built-in one; clamped to zero on a snippet's last line. */
1951
+ padOf(beatId) {
1952
+ return this.host.padIndex.get(beatId)?.resolved ?? DEFAULT_PAD_AFTER2;
1953
+ }
1954
+ /** A speaker qualifier's shown name, resolved as a character's is: the `qualifier:<gameId>` string in the
1955
+ * active locale, else the default locale, else the authored name. Undefined in IDs-only mode (the game
1956
+ * maps the `qualifier` gameId itself). */
1957
+ resolveQualifierName(qualifier) {
1958
+ if (qualifier === void 0) return void 0;
1959
+ if (this.host.emitIds) return void 0;
1960
+ const key = qualifierStringKey(qualifier);
1961
+ return this.host.strings[key] ?? this.host.defaultStrings[key] ?? this.host.qualifierDisplay.get(qualifier);
1962
+ }
1865
1963
  /** Split a ref into scope + name. Tokens: `@scene`, registered tokens, else `@patter` (incl. bare `@name`). */
1866
1964
  splitRef(ref) {
1867
1965
  return splitHostRef(this.host, ref);
@@ -1958,6 +2056,9 @@ function savedPrompt(p) {
1958
2056
  if (p.character !== void 0) out.character = p.character;
1959
2057
  if (p.characterName !== void 0) out.characterName = p.characterName;
1960
2058
  if (p.direction !== void 0) out.direction = p.direction;
2059
+ if (p.qualifier !== void 0) out.qualifier = p.qualifier;
2060
+ if (p.qualifierName !== void 0) out.qualifierName = p.qualifierName;
2061
+ if (typeof p.padAfter === "number") out.padAfter = p.padAfter;
1961
2062
  return out;
1962
2063
  }
1963
2064
  function serialiseSelectors(map) {
@@ -2048,6 +2149,9 @@ function truthy(v) {
2048
2149
  return v.length > 0;
2049
2150
  }
2050
2151
 
2152
+ // src/index.ts
2153
+ import { DEFAULT_PAD_AFTER as DEFAULT_PAD_AFTER3 } from "@patterkit/model";
2154
+
2051
2155
  // src/describe.ts
2052
2156
  import { effectiveGameId as effectiveGameId2 } from "@patterkit/model";
2053
2157
  var isShared = (d, scopeDefault) => d.shared ?? scopeDefault;
@@ -2170,6 +2274,7 @@ function effectiveGameData(fields, node) {
2170
2274
  }
2171
2275
  export {
2172
2276
  Checkpoint,
2277
+ DEFAULT_PAD_AFTER3 as DEFAULT_PAD_AFTER,
2173
2278
  Engine,
2174
2279
  Flow,
2175
2280
  buildTagIndex,