@patterkit/model 0.17.0 → 0.19.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.cjs +37 -0
- package/dist/index.d.cts +45 -5
- package/dist/index.d.ts +45 -5
- package/dist/index.js +33 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -57,13 +57,17 @@ __export(index_exports, {
|
|
|
57
57
|
gameIdify: () => gameIdify,
|
|
58
58
|
isCaseOnlyPropertyName: () => import_expr.isCaseOnlyPropertyName,
|
|
59
59
|
isContentlessBeat: () => isContentlessBeat,
|
|
60
|
+
isDialogueScene: () => isDialogueScene,
|
|
60
61
|
isValidGameId: () => isValidGameId,
|
|
61
62
|
isValidPropertyName: () => import_expr.isValidPropertyName,
|
|
62
63
|
projectLayout: () => projectLayout,
|
|
63
64
|
projectQualifiers: () => projectQualifiers,
|
|
64
65
|
propertyNameify: () => import_expr.propertyNameify,
|
|
65
66
|
qualifierStringKey: () => qualifierStringKey,
|
|
67
|
+
resolveSceneRef: () => resolveSceneRef,
|
|
68
|
+
sceneAddressIndex: () => sceneAddressIndex,
|
|
66
69
|
speakerLabelKey: () => speakerLabelKey,
|
|
70
|
+
textIsAction: () => textIsAction,
|
|
67
71
|
usedQualifiers: () => usedQualifiers,
|
|
68
72
|
usedSpeakerPairs: () => usedSpeakerPairs,
|
|
69
73
|
walkNodes: () => walkNodes
|
|
@@ -94,6 +98,14 @@ function effectiveGameId(entity) {
|
|
|
94
98
|
const g = entity.gameId?.trim();
|
|
95
99
|
return g ? g : gameIdify(entity.name);
|
|
96
100
|
}
|
|
101
|
+
function sceneAddressIndex(scenes) {
|
|
102
|
+
const byAddress = /* @__PURE__ */ new Map();
|
|
103
|
+
for (const [id, scene] of Object.entries(scenes)) byAddress.set(effectiveGameId(scene), id);
|
|
104
|
+
return byAddress;
|
|
105
|
+
}
|
|
106
|
+
function resolveSceneRef(scenes, ref, byAddress) {
|
|
107
|
+
return (byAddress ?? sceneAddressIndex(scenes)).get(ref) ?? (Object.hasOwn(scenes, ref) ? ref : void 0);
|
|
108
|
+
}
|
|
97
109
|
var COMMON_GENDERS = ["male", "female", "neuter"];
|
|
98
110
|
var DEFAULT_QUALIFIERS = [
|
|
99
111
|
{ gameId: "vo", name: "V.O.", description: "Voice-over: the character isn't in the scene (a thought, narration, a voice in the ear)." },
|
|
@@ -141,6 +153,27 @@ function usedSpeakerPairs(scenes) {
|
|
|
141
153
|
}
|
|
142
154
|
return out;
|
|
143
155
|
}
|
|
156
|
+
function isDialogueScene(scene) {
|
|
157
|
+
let found = false;
|
|
158
|
+
for (const block of scene.blocks) {
|
|
159
|
+
walkNodes(block.children, (node) => {
|
|
160
|
+
if (found) return;
|
|
161
|
+
if (node.type === "group") {
|
|
162
|
+
if (node.prompt?.kind === "line" && node.prompt.character) found = true;
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
for (const beat of node.beats ?? []) if (beat.kind === "line" && beat.character) {
|
|
166
|
+
found = true;
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
if (found) return true;
|
|
171
|
+
}
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
function textIsAction(project, scene) {
|
|
175
|
+
return !project.localiseDialogueText && isDialogueScene(scene);
|
|
176
|
+
}
|
|
144
177
|
var DEFAULT_PAD_AFTER = 0.6;
|
|
145
178
|
var PAD_AFTER_MIN = -10;
|
|
146
179
|
var PAD_AFTER_MAX = 60;
|
|
@@ -258,13 +291,17 @@ var UNRESOLVED_KEY = "unresolved";
|
|
|
258
291
|
gameIdify,
|
|
259
292
|
isCaseOnlyPropertyName,
|
|
260
293
|
isContentlessBeat,
|
|
294
|
+
isDialogueScene,
|
|
261
295
|
isValidGameId,
|
|
262
296
|
isValidPropertyName,
|
|
263
297
|
projectLayout,
|
|
264
298
|
projectQualifiers,
|
|
265
299
|
propertyNameify,
|
|
266
300
|
qualifierStringKey,
|
|
301
|
+
resolveSceneRef,
|
|
302
|
+
sceneAddressIndex,
|
|
267
303
|
speakerLabelKey,
|
|
304
|
+
textIsAction,
|
|
268
305
|
usedQualifiers,
|
|
269
306
|
usedSpeakerPairs,
|
|
270
307
|
walkNodes
|
package/dist/index.d.cts
CHANGED
|
@@ -43,7 +43,7 @@ interface LineBeat {
|
|
|
43
43
|
tags?: string[];
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
*
|
|
46
|
+
* Text - speaker-less prose (spec §2). Never voiced; its
|
|
47
47
|
* localised text always permits inline `{@name}` interpolation (spec §16). This
|
|
48
48
|
* is the on-screen-text role (e.g. "A door slams!") - distinct from a game-event
|
|
49
49
|
* beat, which is a pure engine instruction with no localised content.
|
|
@@ -63,6 +63,11 @@ interface TextBeat {
|
|
|
63
63
|
extensions?: NodeExtensions;
|
|
64
64
|
/** Author tags (#215). See LineBeat.tags. */
|
|
65
65
|
tags?: string[];
|
|
66
|
+
/** Bundle only: this text beat is ACTION, a direction to the people staging the scene that the player
|
|
67
|
+
* never sees (design/proposals/action-text.md). Set by the compiler on every text beat of a dialogue scene
|
|
68
|
+
* (`isDialogueScene`) when the project's `localiseDialogueText` is off; its text is then the source in
|
|
69
|
+
* every locale. Absent = shown text. Never in source. */
|
|
70
|
+
action?: true;
|
|
66
71
|
}
|
|
67
72
|
/**
|
|
68
73
|
* A GAME EVENT (spec §2): a pure engine instruction with no player-facing text - just `gameData` the host
|
|
@@ -252,6 +257,25 @@ declare function effectiveGameId(entity: {
|
|
|
252
257
|
gameId?: string;
|
|
253
258
|
name: string;
|
|
254
259
|
}): string;
|
|
260
|
+
/** A bundle's scenes by their address (effective gameId), for `resolveSceneRef` to look up in. */
|
|
261
|
+
declare function sceneAddressIndex(scenes: Readonly<Record<string, {
|
|
262
|
+
gameId?: string;
|
|
263
|
+
name: string;
|
|
264
|
+
}>>): Map<string, string>;
|
|
265
|
+
/**
|
|
266
|
+
* THE rule for resolving a scene reference to its internal id: its address (the effective gameId, the
|
|
267
|
+
* host-facing name, spec §6) first, then its internal id. Undefined when neither names a scene.
|
|
268
|
+
*
|
|
269
|
+
* One rule for the runtime's openFlow, goto and every engine lookup, and for every tool that has to land
|
|
270
|
+
* where the game will (the Storylet Engine's Board and pairing check, Patterpad's Show Card). Each used to
|
|
271
|
+
* keep a copy, and the copies tried the internal id first, so where one scene's id was another's gameId
|
|
272
|
+
* they picked a different scene from the one the game opened (family parity item 1). Pass `byAddress`
|
|
273
|
+
* (from `sceneAddressIndex`) to look up many references in one bundle without rebuilding it.
|
|
274
|
+
*/
|
|
275
|
+
declare function resolveSceneRef(scenes: Readonly<Record<string, {
|
|
276
|
+
gameId?: string;
|
|
277
|
+
name: string;
|
|
278
|
+
}>>, ref: string, byAddress?: ReadonlyMap<string, string>): string | undefined;
|
|
255
279
|
type PropertyType = "boolean" | "number" | "string" | "flags" | "enum" | "quality";
|
|
256
280
|
interface PropertyDecl {
|
|
257
281
|
name: string;
|
|
@@ -394,6 +418,12 @@ declare function usedSpeakerPairs(scenes: Scene[]): {
|
|
|
394
418
|
character: string;
|
|
395
419
|
qualifier: string;
|
|
396
420
|
}[];
|
|
421
|
+
/** A DIALOGUE scene (design/proposals/action-text.md): one with at least one line beat that names a
|
|
422
|
+
* character, an option's prompt included. Any other scene is a TEXT scene. */
|
|
423
|
+
declare function isDialogueScene(scene: Scene): boolean;
|
|
424
|
+
/** Whether a scene's text beats are ACTION: a dialogue scene, in a project that doesn't localise dialogue
|
|
425
|
+
* scenes' text (`localiseDialogueText` off, the default). Its option prompts never are. */
|
|
426
|
+
declare function textIsAction(project: Pick<ProjectFile, "localiseDialogueText">, scene: Scene): boolean;
|
|
397
427
|
/** The built-in `padAfter`, in seconds, for a project that sets no default of its own: the same on every runtime
|
|
398
428
|
* and in Patterpad's Play window (design/proposals/line-padding.md section 4). */
|
|
399
429
|
declare const DEFAULT_PAD_AFTER = 0.6;
|
|
@@ -412,7 +442,7 @@ interface BundleQualifier {
|
|
|
412
442
|
* the bundle; this type states the resulting contract for anyone reading a bundle. */
|
|
413
443
|
type BundleCastMember = Omit<CastMember, "notes" | "actor" | "gender">;
|
|
414
444
|
/** A node TYPE that can carry author-defined gameData fields (the gameData schema, project-level).
|
|
415
|
-
* Beat kinds map straight through: dialogue = `line`,
|
|
445
|
+
* Beat kinds map straight through: dialogue = `line`, text = `text`, game event = `gameEvent`.
|
|
416
446
|
* `option` is a choice's option: a group that is a direct child of a `choice` group, whose gameData the
|
|
417
447
|
* host reads off the option `getChoices` hands it. Any other group's gameData stays undeclared. */
|
|
418
448
|
type GameDataNodeKind = "scene" | "block" | "snippet" | "line" | "text" | "gameEvent" | "option";
|
|
@@ -589,7 +619,7 @@ interface ProjectFile {
|
|
|
589
619
|
* opt-in even for a voiced project (a voiced story may want voice scripts without tracking recording status). */
|
|
590
620
|
trackAudioStatus?: boolean;
|
|
591
621
|
/**
|
|
592
|
-
* Inline text formatting. When true, authors can mark dialogue /
|
|
622
|
+
* Inline text formatting. When true, authors can mark dialogue / text / direction /
|
|
593
623
|
* choice-prompt text bold, italic, or bold+italic; it is stored INSIDE the localised strings
|
|
594
624
|
* (and the flow's `direction`) as `<b>…</b>`, `<i>…</i>`, `<bi>…</bi>`, with literal `<`, `>`,
|
|
595
625
|
* `&` escaped to `<` / `>` / `&`. The runtime treats the string as opaque - it is the
|
|
@@ -662,6 +692,11 @@ interface ProjectFile {
|
|
|
662
692
|
/** The project's default `padAfter` for every line and text beat that sets none and has no default above it.
|
|
663
693
|
* Absent = `DEFAULT_PAD_AFTER`. */
|
|
664
694
|
padAfterDefault?: number;
|
|
695
|
+
/** Localise text lines in dialogue scenes (design/proposals/action-text.md). Off (absent) by default: a
|
|
696
|
+
* dialogue scene's text beats (`isDialogueScene`) are then ACTION, left out of the loc files and the
|
|
697
|
+
* written word counts, and compiled with `action: true`. On: they're localised and shown as a text
|
|
698
|
+
* scene's are. A text scene is localised whatever this says, and an option's prompt always is. */
|
|
699
|
+
localiseDialogueText?: boolean;
|
|
665
700
|
gameDataFields?: GameDataFields;
|
|
666
701
|
/**
|
|
667
702
|
* The Patter extensions this project takes, by id (ruled 2026-10-18: the project opts in), each pinned to a
|
|
@@ -707,6 +742,11 @@ interface LocaleFile {
|
|
|
707
742
|
scene: string;
|
|
708
743
|
locale: string;
|
|
709
744
|
default?: boolean;
|
|
745
|
+
/** A translated shard only: its scene's text beats were action (`textIsAction`) when loc import last wrote
|
|
746
|
+
* it, so they aren't in it. Loc export and `patter validate` compare this with the scene now, to report
|
|
747
|
+
* text that has dropped out of the loc files or come into them. Absent = shown text, or a shard written
|
|
748
|
+
* before the setting existed. */
|
|
749
|
+
textAction?: true;
|
|
710
750
|
/** beatId -> text. */
|
|
711
751
|
strings: Record<string, string>;
|
|
712
752
|
}
|
|
@@ -919,7 +959,7 @@ interface HandoffFile {
|
|
|
919
959
|
}
|
|
920
960
|
/** An editable line as sent. */
|
|
921
961
|
interface HandoffLine {
|
|
922
|
-
/** The beat id (a line, a
|
|
962
|
+
/** The beat id (a line, a text beat, or an option prompt). */
|
|
923
963
|
id: string;
|
|
924
964
|
kind: "line" | "narration" | "option";
|
|
925
965
|
/** The speaker, speaker qualifier (`gameId`), and direction as sent (spoken lines only). */
|
|
@@ -1362,4 +1402,4 @@ interface ExtensionFieldDecl {
|
|
|
1362
1402
|
/** A node's extension values in a bundle: extension id -> field -> value, raw. */
|
|
1363
1403
|
type NodeExtensions = Record<string, Record<string, unknown>>;
|
|
1364
1404
|
|
|
1365
|
-
export { AUTHORING_SCHEMA, type AuthoringFile, type Beat, type Block, type Bundle, type BundleCastMember, type BundleExtension, type BundleQualifier, COMMON_GENDERS, type CaptionDelimiters, type CastMember, type Comment, type CommentMessage, type CommentRange, type CompiledBlock, type CompiledEffect, type CompiledGroup, type CompiledScene, type CompiledSnippet, type CoverageDriver, DEFAULT_CAPTION_CHARACTER, DEFAULT_CAPTION_DELIMITERS, DEFAULT_DOCUMENTATION_CLASSES, DEFAULT_LAYOUT, DEFAULT_PAD_AFTER, DEFAULT_QUALIFIERS, DEFAULT_RECORDING_STATUSES, DEFAULT_SPEAKER_PATTERN, DEFAULT_WRITING_STATUSES, type DocLine, type DocumentationClass, EXTENSIONS_DIR, EXTENSION_SCHEMA, EXTENSION_SHARD, type EditRecord, type Effect, type EngineSave, type EstimatingConfig, type Expression, type ExtensionFieldDecl, type ExtensionShard, FLOW_SCHEMA, type FlowCursor, type FlowFile, type FlowNode, type FlowSnapshot, type FlowSnapshotV2, type FlowState, type FlowValues, type GameData, type GameDataField, type GameDataFieldType, type GameDataFields, type GameDataNodeKind, type GameEventBeat, type GrammaticalGender, type Group, HANDOFF_SCHEMA, type HandoffFile, type HandoffImport, type HandoffLine, type HandoffRow, type HostScopeDecl, type HostScopeRegistry, type HostScopeSpec, type Jump, type JumpTarget, type LineBeat, type LocaleFile, MANIFEST_EXTENSION, type NodeExtensions, PAD_AFTER_MAX, PAD_AFTER_MIN, PROJECT_EXTENSION_STEM, PROJECT_LOCALE_SCENE, PROJECT_SCHEMA, type ProjectDictionary, type ProjectExtension, type ProjectFile, type ProjectLayout, type PromptBeat, type PropertyDecl, type PropertyType, RERECORD_STATUS, RERECORD_STATUS_DECL, type RecordingFolder, type RecordingStatusDecl, SAVE_SCHEMA, SAVE_VERSION, SPEAKER_PATTERN_KEY, STRINGS_SCHEMA, type SaveEnvelope, type SaveGame, type SaveGameV2, type SavedChoice, type SavedChoiceOption, type SavedChoicePrompt, type ScalarValue, type Scene, type Selector, type SelectorExhaust, type SelectorOrder, type SelectorSnapshot, type SequenceOptions, type Snippet, type SpeakerQualifier, type StackFrame, type Suggestion, type SuggestionSource, type TextBeat, UNRESOLVED_KEY, type VcsKind, type WritingStatusDecl, castStringKey, deriveRecordingFolders, effectiveGameId, formatSpeakerLabel, gameIdify, isContentlessBeat, isValidGameId, projectLayout, projectQualifiers, qualifierStringKey, speakerLabelKey, usedQualifiers, usedSpeakerPairs, walkNodes };
|
|
1405
|
+
export { AUTHORING_SCHEMA, type AuthoringFile, type Beat, type Block, type Bundle, type BundleCastMember, type BundleExtension, type BundleQualifier, COMMON_GENDERS, type CaptionDelimiters, type CastMember, type Comment, type CommentMessage, type CommentRange, type CompiledBlock, type CompiledEffect, type CompiledGroup, type CompiledScene, type CompiledSnippet, type CoverageDriver, DEFAULT_CAPTION_CHARACTER, DEFAULT_CAPTION_DELIMITERS, DEFAULT_DOCUMENTATION_CLASSES, DEFAULT_LAYOUT, DEFAULT_PAD_AFTER, DEFAULT_QUALIFIERS, DEFAULT_RECORDING_STATUSES, DEFAULT_SPEAKER_PATTERN, DEFAULT_WRITING_STATUSES, type DocLine, type DocumentationClass, EXTENSIONS_DIR, EXTENSION_SCHEMA, EXTENSION_SHARD, type EditRecord, type Effect, type EngineSave, type EstimatingConfig, type Expression, type ExtensionFieldDecl, type ExtensionShard, FLOW_SCHEMA, type FlowCursor, type FlowFile, type FlowNode, type FlowSnapshot, type FlowSnapshotV2, type FlowState, type FlowValues, type GameData, type GameDataField, type GameDataFieldType, type GameDataFields, type GameDataNodeKind, type GameEventBeat, type GrammaticalGender, type Group, HANDOFF_SCHEMA, type HandoffFile, type HandoffImport, type HandoffLine, type HandoffRow, type HostScopeDecl, type HostScopeRegistry, type HostScopeSpec, type Jump, type JumpTarget, type LineBeat, type LocaleFile, MANIFEST_EXTENSION, type NodeExtensions, PAD_AFTER_MAX, PAD_AFTER_MIN, PROJECT_EXTENSION_STEM, PROJECT_LOCALE_SCENE, PROJECT_SCHEMA, type ProjectDictionary, type ProjectExtension, type ProjectFile, type ProjectLayout, type PromptBeat, type PropertyDecl, type PropertyType, RERECORD_STATUS, RERECORD_STATUS_DECL, type RecordingFolder, type RecordingStatusDecl, SAVE_SCHEMA, SAVE_VERSION, SPEAKER_PATTERN_KEY, STRINGS_SCHEMA, type SaveEnvelope, type SaveGame, type SaveGameV2, type SavedChoice, type SavedChoiceOption, type SavedChoicePrompt, type ScalarValue, type Scene, type Selector, type SelectorExhaust, type SelectorOrder, type SelectorSnapshot, type SequenceOptions, type Snippet, type SpeakerQualifier, type StackFrame, type Suggestion, type SuggestionSource, type TextBeat, UNRESOLVED_KEY, type VcsKind, type WritingStatusDecl, castStringKey, deriveRecordingFolders, effectiveGameId, formatSpeakerLabel, gameIdify, isContentlessBeat, isDialogueScene, isValidGameId, projectLayout, projectQualifiers, qualifierStringKey, resolveSceneRef, sceneAddressIndex, speakerLabelKey, textIsAction, usedQualifiers, usedSpeakerPairs, walkNodes };
|
package/dist/index.d.ts
CHANGED
|
@@ -43,7 +43,7 @@ interface LineBeat {
|
|
|
43
43
|
tags?: string[];
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
*
|
|
46
|
+
* Text - speaker-less prose (spec §2). Never voiced; its
|
|
47
47
|
* localised text always permits inline `{@name}` interpolation (spec §16). This
|
|
48
48
|
* is the on-screen-text role (e.g. "A door slams!") - distinct from a game-event
|
|
49
49
|
* beat, which is a pure engine instruction with no localised content.
|
|
@@ -63,6 +63,11 @@ interface TextBeat {
|
|
|
63
63
|
extensions?: NodeExtensions;
|
|
64
64
|
/** Author tags (#215). See LineBeat.tags. */
|
|
65
65
|
tags?: string[];
|
|
66
|
+
/** Bundle only: this text beat is ACTION, a direction to the people staging the scene that the player
|
|
67
|
+
* never sees (design/proposals/action-text.md). Set by the compiler on every text beat of a dialogue scene
|
|
68
|
+
* (`isDialogueScene`) when the project's `localiseDialogueText` is off; its text is then the source in
|
|
69
|
+
* every locale. Absent = shown text. Never in source. */
|
|
70
|
+
action?: true;
|
|
66
71
|
}
|
|
67
72
|
/**
|
|
68
73
|
* A GAME EVENT (spec §2): a pure engine instruction with no player-facing text - just `gameData` the host
|
|
@@ -252,6 +257,25 @@ declare function effectiveGameId(entity: {
|
|
|
252
257
|
gameId?: string;
|
|
253
258
|
name: string;
|
|
254
259
|
}): string;
|
|
260
|
+
/** A bundle's scenes by their address (effective gameId), for `resolveSceneRef` to look up in. */
|
|
261
|
+
declare function sceneAddressIndex(scenes: Readonly<Record<string, {
|
|
262
|
+
gameId?: string;
|
|
263
|
+
name: string;
|
|
264
|
+
}>>): Map<string, string>;
|
|
265
|
+
/**
|
|
266
|
+
* THE rule for resolving a scene reference to its internal id: its address (the effective gameId, the
|
|
267
|
+
* host-facing name, spec §6) first, then its internal id. Undefined when neither names a scene.
|
|
268
|
+
*
|
|
269
|
+
* One rule for the runtime's openFlow, goto and every engine lookup, and for every tool that has to land
|
|
270
|
+
* where the game will (the Storylet Engine's Board and pairing check, Patterpad's Show Card). Each used to
|
|
271
|
+
* keep a copy, and the copies tried the internal id first, so where one scene's id was another's gameId
|
|
272
|
+
* they picked a different scene from the one the game opened (family parity item 1). Pass `byAddress`
|
|
273
|
+
* (from `sceneAddressIndex`) to look up many references in one bundle without rebuilding it.
|
|
274
|
+
*/
|
|
275
|
+
declare function resolveSceneRef(scenes: Readonly<Record<string, {
|
|
276
|
+
gameId?: string;
|
|
277
|
+
name: string;
|
|
278
|
+
}>>, ref: string, byAddress?: ReadonlyMap<string, string>): string | undefined;
|
|
255
279
|
type PropertyType = "boolean" | "number" | "string" | "flags" | "enum" | "quality";
|
|
256
280
|
interface PropertyDecl {
|
|
257
281
|
name: string;
|
|
@@ -394,6 +418,12 @@ declare function usedSpeakerPairs(scenes: Scene[]): {
|
|
|
394
418
|
character: string;
|
|
395
419
|
qualifier: string;
|
|
396
420
|
}[];
|
|
421
|
+
/** A DIALOGUE scene (design/proposals/action-text.md): one with at least one line beat that names a
|
|
422
|
+
* character, an option's prompt included. Any other scene is a TEXT scene. */
|
|
423
|
+
declare function isDialogueScene(scene: Scene): boolean;
|
|
424
|
+
/** Whether a scene's text beats are ACTION: a dialogue scene, in a project that doesn't localise dialogue
|
|
425
|
+
* scenes' text (`localiseDialogueText` off, the default). Its option prompts never are. */
|
|
426
|
+
declare function textIsAction(project: Pick<ProjectFile, "localiseDialogueText">, scene: Scene): boolean;
|
|
397
427
|
/** The built-in `padAfter`, in seconds, for a project that sets no default of its own: the same on every runtime
|
|
398
428
|
* and in Patterpad's Play window (design/proposals/line-padding.md section 4). */
|
|
399
429
|
declare const DEFAULT_PAD_AFTER = 0.6;
|
|
@@ -412,7 +442,7 @@ interface BundleQualifier {
|
|
|
412
442
|
* the bundle; this type states the resulting contract for anyone reading a bundle. */
|
|
413
443
|
type BundleCastMember = Omit<CastMember, "notes" | "actor" | "gender">;
|
|
414
444
|
/** A node TYPE that can carry author-defined gameData fields (the gameData schema, project-level).
|
|
415
|
-
* Beat kinds map straight through: dialogue = `line`,
|
|
445
|
+
* Beat kinds map straight through: dialogue = `line`, text = `text`, game event = `gameEvent`.
|
|
416
446
|
* `option` is a choice's option: a group that is a direct child of a `choice` group, whose gameData the
|
|
417
447
|
* host reads off the option `getChoices` hands it. Any other group's gameData stays undeclared. */
|
|
418
448
|
type GameDataNodeKind = "scene" | "block" | "snippet" | "line" | "text" | "gameEvent" | "option";
|
|
@@ -589,7 +619,7 @@ interface ProjectFile {
|
|
|
589
619
|
* opt-in even for a voiced project (a voiced story may want voice scripts without tracking recording status). */
|
|
590
620
|
trackAudioStatus?: boolean;
|
|
591
621
|
/**
|
|
592
|
-
* Inline text formatting. When true, authors can mark dialogue /
|
|
622
|
+
* Inline text formatting. When true, authors can mark dialogue / text / direction /
|
|
593
623
|
* choice-prompt text bold, italic, or bold+italic; it is stored INSIDE the localised strings
|
|
594
624
|
* (and the flow's `direction`) as `<b>…</b>`, `<i>…</i>`, `<bi>…</bi>`, with literal `<`, `>`,
|
|
595
625
|
* `&` escaped to `<` / `>` / `&`. The runtime treats the string as opaque - it is the
|
|
@@ -662,6 +692,11 @@ interface ProjectFile {
|
|
|
662
692
|
/** The project's default `padAfter` for every line and text beat that sets none and has no default above it.
|
|
663
693
|
* Absent = `DEFAULT_PAD_AFTER`. */
|
|
664
694
|
padAfterDefault?: number;
|
|
695
|
+
/** Localise text lines in dialogue scenes (design/proposals/action-text.md). Off (absent) by default: a
|
|
696
|
+
* dialogue scene's text beats (`isDialogueScene`) are then ACTION, left out of the loc files and the
|
|
697
|
+
* written word counts, and compiled with `action: true`. On: they're localised and shown as a text
|
|
698
|
+
* scene's are. A text scene is localised whatever this says, and an option's prompt always is. */
|
|
699
|
+
localiseDialogueText?: boolean;
|
|
665
700
|
gameDataFields?: GameDataFields;
|
|
666
701
|
/**
|
|
667
702
|
* The Patter extensions this project takes, by id (ruled 2026-10-18: the project opts in), each pinned to a
|
|
@@ -707,6 +742,11 @@ interface LocaleFile {
|
|
|
707
742
|
scene: string;
|
|
708
743
|
locale: string;
|
|
709
744
|
default?: boolean;
|
|
745
|
+
/** A translated shard only: its scene's text beats were action (`textIsAction`) when loc import last wrote
|
|
746
|
+
* it, so they aren't in it. Loc export and `patter validate` compare this with the scene now, to report
|
|
747
|
+
* text that has dropped out of the loc files or come into them. Absent = shown text, or a shard written
|
|
748
|
+
* before the setting existed. */
|
|
749
|
+
textAction?: true;
|
|
710
750
|
/** beatId -> text. */
|
|
711
751
|
strings: Record<string, string>;
|
|
712
752
|
}
|
|
@@ -919,7 +959,7 @@ interface HandoffFile {
|
|
|
919
959
|
}
|
|
920
960
|
/** An editable line as sent. */
|
|
921
961
|
interface HandoffLine {
|
|
922
|
-
/** The beat id (a line, a
|
|
962
|
+
/** The beat id (a line, a text beat, or an option prompt). */
|
|
923
963
|
id: string;
|
|
924
964
|
kind: "line" | "narration" | "option";
|
|
925
965
|
/** The speaker, speaker qualifier (`gameId`), and direction as sent (spoken lines only). */
|
|
@@ -1362,4 +1402,4 @@ interface ExtensionFieldDecl {
|
|
|
1362
1402
|
/** A node's extension values in a bundle: extension id -> field -> value, raw. */
|
|
1363
1403
|
type NodeExtensions = Record<string, Record<string, unknown>>;
|
|
1364
1404
|
|
|
1365
|
-
export { AUTHORING_SCHEMA, type AuthoringFile, type Beat, type Block, type Bundle, type BundleCastMember, type BundleExtension, type BundleQualifier, COMMON_GENDERS, type CaptionDelimiters, type CastMember, type Comment, type CommentMessage, type CommentRange, type CompiledBlock, type CompiledEffect, type CompiledGroup, type CompiledScene, type CompiledSnippet, type CoverageDriver, DEFAULT_CAPTION_CHARACTER, DEFAULT_CAPTION_DELIMITERS, DEFAULT_DOCUMENTATION_CLASSES, DEFAULT_LAYOUT, DEFAULT_PAD_AFTER, DEFAULT_QUALIFIERS, DEFAULT_RECORDING_STATUSES, DEFAULT_SPEAKER_PATTERN, DEFAULT_WRITING_STATUSES, type DocLine, type DocumentationClass, EXTENSIONS_DIR, EXTENSION_SCHEMA, EXTENSION_SHARD, type EditRecord, type Effect, type EngineSave, type EstimatingConfig, type Expression, type ExtensionFieldDecl, type ExtensionShard, FLOW_SCHEMA, type FlowCursor, type FlowFile, type FlowNode, type FlowSnapshot, type FlowSnapshotV2, type FlowState, type FlowValues, type GameData, type GameDataField, type GameDataFieldType, type GameDataFields, type GameDataNodeKind, type GameEventBeat, type GrammaticalGender, type Group, HANDOFF_SCHEMA, type HandoffFile, type HandoffImport, type HandoffLine, type HandoffRow, type HostScopeDecl, type HostScopeRegistry, type HostScopeSpec, type Jump, type JumpTarget, type LineBeat, type LocaleFile, MANIFEST_EXTENSION, type NodeExtensions, PAD_AFTER_MAX, PAD_AFTER_MIN, PROJECT_EXTENSION_STEM, PROJECT_LOCALE_SCENE, PROJECT_SCHEMA, type ProjectDictionary, type ProjectExtension, type ProjectFile, type ProjectLayout, type PromptBeat, type PropertyDecl, type PropertyType, RERECORD_STATUS, RERECORD_STATUS_DECL, type RecordingFolder, type RecordingStatusDecl, SAVE_SCHEMA, SAVE_VERSION, SPEAKER_PATTERN_KEY, STRINGS_SCHEMA, type SaveEnvelope, type SaveGame, type SaveGameV2, type SavedChoice, type SavedChoiceOption, type SavedChoicePrompt, type ScalarValue, type Scene, type Selector, type SelectorExhaust, type SelectorOrder, type SelectorSnapshot, type SequenceOptions, type Snippet, type SpeakerQualifier, type StackFrame, type Suggestion, type SuggestionSource, type TextBeat, UNRESOLVED_KEY, type VcsKind, type WritingStatusDecl, castStringKey, deriveRecordingFolders, effectiveGameId, formatSpeakerLabel, gameIdify, isContentlessBeat, isValidGameId, projectLayout, projectQualifiers, qualifierStringKey, speakerLabelKey, usedQualifiers, usedSpeakerPairs, walkNodes };
|
|
1405
|
+
export { AUTHORING_SCHEMA, type AuthoringFile, type Beat, type Block, type Bundle, type BundleCastMember, type BundleExtension, type BundleQualifier, COMMON_GENDERS, type CaptionDelimiters, type CastMember, type Comment, type CommentMessage, type CommentRange, type CompiledBlock, type CompiledEffect, type CompiledGroup, type CompiledScene, type CompiledSnippet, type CoverageDriver, DEFAULT_CAPTION_CHARACTER, DEFAULT_CAPTION_DELIMITERS, DEFAULT_DOCUMENTATION_CLASSES, DEFAULT_LAYOUT, DEFAULT_PAD_AFTER, DEFAULT_QUALIFIERS, DEFAULT_RECORDING_STATUSES, DEFAULT_SPEAKER_PATTERN, DEFAULT_WRITING_STATUSES, type DocLine, type DocumentationClass, EXTENSIONS_DIR, EXTENSION_SCHEMA, EXTENSION_SHARD, type EditRecord, type Effect, type EngineSave, type EstimatingConfig, type Expression, type ExtensionFieldDecl, type ExtensionShard, FLOW_SCHEMA, type FlowCursor, type FlowFile, type FlowNode, type FlowSnapshot, type FlowSnapshotV2, type FlowState, type FlowValues, type GameData, type GameDataField, type GameDataFieldType, type GameDataFields, type GameDataNodeKind, type GameEventBeat, type GrammaticalGender, type Group, HANDOFF_SCHEMA, type HandoffFile, type HandoffImport, type HandoffLine, type HandoffRow, type HostScopeDecl, type HostScopeRegistry, type HostScopeSpec, type Jump, type JumpTarget, type LineBeat, type LocaleFile, MANIFEST_EXTENSION, type NodeExtensions, PAD_AFTER_MAX, PAD_AFTER_MIN, PROJECT_EXTENSION_STEM, PROJECT_LOCALE_SCENE, PROJECT_SCHEMA, type ProjectDictionary, type ProjectExtension, type ProjectFile, type ProjectLayout, type PromptBeat, type PropertyDecl, type PropertyType, RERECORD_STATUS, RERECORD_STATUS_DECL, type RecordingFolder, type RecordingStatusDecl, SAVE_SCHEMA, SAVE_VERSION, SPEAKER_PATTERN_KEY, STRINGS_SCHEMA, type SaveEnvelope, type SaveGame, type SaveGameV2, type SavedChoice, type SavedChoiceOption, type SavedChoicePrompt, type ScalarValue, type Scene, type Selector, type SelectorExhaust, type SelectorOrder, type SelectorSnapshot, type SequenceOptions, type Snippet, type SpeakerQualifier, type StackFrame, type Suggestion, type SuggestionSource, type TextBeat, UNRESOLVED_KEY, type VcsKind, type WritingStatusDecl, castStringKey, deriveRecordingFolders, effectiveGameId, formatSpeakerLabel, gameIdify, isContentlessBeat, isDialogueScene, isValidGameId, projectLayout, projectQualifiers, qualifierStringKey, resolveSceneRef, sceneAddressIndex, speakerLabelKey, textIsAction, usedQualifiers, usedSpeakerPairs, walkNodes };
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,14 @@ function effectiveGameId(entity) {
|
|
|
29
29
|
const g = entity.gameId?.trim();
|
|
30
30
|
return g ? g : gameIdify(entity.name);
|
|
31
31
|
}
|
|
32
|
+
function sceneAddressIndex(scenes) {
|
|
33
|
+
const byAddress = /* @__PURE__ */ new Map();
|
|
34
|
+
for (const [id, scene] of Object.entries(scenes)) byAddress.set(effectiveGameId(scene), id);
|
|
35
|
+
return byAddress;
|
|
36
|
+
}
|
|
37
|
+
function resolveSceneRef(scenes, ref, byAddress) {
|
|
38
|
+
return (byAddress ?? sceneAddressIndex(scenes)).get(ref) ?? (Object.hasOwn(scenes, ref) ? ref : void 0);
|
|
39
|
+
}
|
|
32
40
|
var COMMON_GENDERS = ["male", "female", "neuter"];
|
|
33
41
|
var DEFAULT_QUALIFIERS = [
|
|
34
42
|
{ gameId: "vo", name: "V.O.", description: "Voice-over: the character isn't in the scene (a thought, narration, a voice in the ear)." },
|
|
@@ -76,6 +84,27 @@ function usedSpeakerPairs(scenes) {
|
|
|
76
84
|
}
|
|
77
85
|
return out;
|
|
78
86
|
}
|
|
87
|
+
function isDialogueScene(scene) {
|
|
88
|
+
let found = false;
|
|
89
|
+
for (const block of scene.blocks) {
|
|
90
|
+
walkNodes(block.children, (node) => {
|
|
91
|
+
if (found) return;
|
|
92
|
+
if (node.type === "group") {
|
|
93
|
+
if (node.prompt?.kind === "line" && node.prompt.character) found = true;
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
for (const beat of node.beats ?? []) if (beat.kind === "line" && beat.character) {
|
|
97
|
+
found = true;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
if (found) return true;
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
function textIsAction(project, scene) {
|
|
106
|
+
return !project.localiseDialogueText && isDialogueScene(scene);
|
|
107
|
+
}
|
|
79
108
|
var DEFAULT_PAD_AFTER = 0.6;
|
|
80
109
|
var PAD_AFTER_MIN = -10;
|
|
81
110
|
var PAD_AFTER_MAX = 60;
|
|
@@ -192,13 +221,17 @@ export {
|
|
|
192
221
|
gameIdify,
|
|
193
222
|
isCaseOnlyPropertyName,
|
|
194
223
|
isContentlessBeat,
|
|
224
|
+
isDialogueScene,
|
|
195
225
|
isValidGameId,
|
|
196
226
|
isValidPropertyName,
|
|
197
227
|
projectLayout,
|
|
198
228
|
projectQualifiers,
|
|
199
229
|
propertyNameify,
|
|
200
230
|
qualifierStringKey,
|
|
231
|
+
resolveSceneRef,
|
|
232
|
+
sceneAddressIndex,
|
|
201
233
|
speakerLabelKey,
|
|
234
|
+
textIsAction,
|
|
202
235
|
usedQualifiers,
|
|
203
236
|
usedSpeakerPairs,
|
|
204
237
|
walkNodes
|
package/package.json
CHANGED