@zigrivers/scaffold 3.4.1 → 3.5.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.
Files changed (194) hide show
  1. package/README.md +91 -0
  2. package/content/knowledge/game/game-accessibility.md +328 -0
  3. package/content/knowledge/game/game-ai-patterns.md +542 -0
  4. package/content/knowledge/game/game-asset-pipeline.md +359 -0
  5. package/content/knowledge/game/game-audio-design.md +342 -0
  6. package/content/knowledge/game/game-binary-vcs-strategy.md +396 -0
  7. package/content/knowledge/game/game-design-document.md +260 -0
  8. package/content/knowledge/game/game-domain-patterns.md +297 -0
  9. package/content/knowledge/game/game-economy-design.md +355 -0
  10. package/content/knowledge/game/game-engine-selection.md +242 -0
  11. package/content/knowledge/game/game-input-systems.md +357 -0
  12. package/content/knowledge/game/game-level-content-design.md +455 -0
  13. package/content/knowledge/game/game-liveops-analytics.md +280 -0
  14. package/content/knowledge/game/game-localization.md +323 -0
  15. package/content/knowledge/game/game-milestone-definitions.md +337 -0
  16. package/content/knowledge/game/game-modding-ugc.md +390 -0
  17. package/content/knowledge/game/game-narrative-design.md +404 -0
  18. package/content/knowledge/game/game-networking.md +391 -0
  19. package/content/knowledge/game/game-performance-budgeting.md +378 -0
  20. package/content/knowledge/game/game-platform-certification.md +417 -0
  21. package/content/knowledge/game/game-project-structure.md +360 -0
  22. package/content/knowledge/game/game-save-systems.md +452 -0
  23. package/content/knowledge/game/game-testing-strategy.md +470 -0
  24. package/content/knowledge/game/game-ui-patterns.md +475 -0
  25. package/content/knowledge/game/game-vr-ar-design.md +313 -0
  26. package/content/knowledge/review/review-art-bible.md +305 -0
  27. package/content/knowledge/review/review-game-design.md +303 -0
  28. package/content/knowledge/review/review-game-economy.md +272 -0
  29. package/content/knowledge/review/review-netcode.md +280 -0
  30. package/content/knowledge/review/review-platform-cert.md +341 -0
  31. package/content/methodology/custom-defaults.yml +25 -0
  32. package/content/methodology/deep.yml +25 -0
  33. package/content/methodology/game-overlay.yml +145 -0
  34. package/content/methodology/mvp.yml +25 -0
  35. package/content/pipeline/architecture/ai-behavior-design.md +87 -0
  36. package/content/pipeline/architecture/netcode-spec.md +86 -0
  37. package/content/pipeline/architecture/review-netcode.md +78 -0
  38. package/content/pipeline/foundation/performance-budgets.md +91 -0
  39. package/content/pipeline/modeling/narrative-bible.md +84 -0
  40. package/content/pipeline/pre/game-design-document.md +89 -0
  41. package/content/pipeline/pre/review-gdd.md +74 -0
  42. package/content/pipeline/quality/analytics-telemetry.md +98 -0
  43. package/content/pipeline/quality/live-ops-plan.md +99 -0
  44. package/content/pipeline/quality/platform-cert-prep.md +129 -0
  45. package/content/pipeline/quality/playtest-plan.md +83 -0
  46. package/content/pipeline/specification/art-bible.md +87 -0
  47. package/content/pipeline/specification/audio-design.md +96 -0
  48. package/content/pipeline/specification/content-structure-design.md +141 -0
  49. package/content/pipeline/specification/economy-design.md +104 -0
  50. package/content/pipeline/specification/game-accessibility.md +82 -0
  51. package/content/pipeline/specification/game-ui-spec.md +97 -0
  52. package/content/pipeline/specification/input-controls-spec.md +81 -0
  53. package/content/pipeline/specification/localization-plan.md +113 -0
  54. package/content/pipeline/specification/modding-ugc-spec.md +116 -0
  55. package/content/pipeline/specification/online-services-spec.md +104 -0
  56. package/content/pipeline/specification/review-economy.md +87 -0
  57. package/content/pipeline/specification/review-game-ui.md +73 -0
  58. package/content/pipeline/specification/save-system-spec.md +116 -0
  59. package/dist/cli/commands/adopt.d.ts.map +1 -1
  60. package/dist/cli/commands/adopt.js +25 -0
  61. package/dist/cli/commands/adopt.js.map +1 -1
  62. package/dist/cli/commands/adopt.test.js +28 -1
  63. package/dist/cli/commands/adopt.test.js.map +1 -1
  64. package/dist/cli/commands/build.test.js +3 -0
  65. package/dist/cli/commands/build.test.js.map +1 -1
  66. package/dist/cli/commands/init.d.ts +1 -0
  67. package/dist/cli/commands/init.d.ts.map +1 -1
  68. package/dist/cli/commands/init.js +6 -0
  69. package/dist/cli/commands/init.js.map +1 -1
  70. package/dist/cli/commands/init.test.js +12 -1
  71. package/dist/cli/commands/init.test.js.map +1 -1
  72. package/dist/cli/commands/knowledge.test.js +8 -0
  73. package/dist/cli/commands/knowledge.test.js.map +1 -1
  74. package/dist/cli/commands/next.d.ts.map +1 -1
  75. package/dist/cli/commands/next.js +19 -5
  76. package/dist/cli/commands/next.js.map +1 -1
  77. package/dist/cli/commands/next.test.js +56 -0
  78. package/dist/cli/commands/next.test.js.map +1 -1
  79. package/dist/cli/commands/rework.d.ts.map +1 -1
  80. package/dist/cli/commands/rework.js +11 -2
  81. package/dist/cli/commands/rework.js.map +1 -1
  82. package/dist/cli/commands/rework.test.js +5 -0
  83. package/dist/cli/commands/rework.test.js.map +1 -1
  84. package/dist/cli/commands/run.d.ts.map +1 -1
  85. package/dist/cli/commands/run.js +54 -4
  86. package/dist/cli/commands/run.js.map +1 -1
  87. package/dist/cli/commands/run.test.js +384 -0
  88. package/dist/cli/commands/run.test.js.map +1 -1
  89. package/dist/cli/commands/skip.test.js +3 -0
  90. package/dist/cli/commands/skip.test.js.map +1 -1
  91. package/dist/cli/commands/status.d.ts.map +1 -1
  92. package/dist/cli/commands/status.js +16 -3
  93. package/dist/cli/commands/status.js.map +1 -1
  94. package/dist/cli/commands/status.test.js +55 -0
  95. package/dist/cli/commands/status.test.js.map +1 -1
  96. package/dist/cli/output/auto.d.ts +3 -0
  97. package/dist/cli/output/auto.d.ts.map +1 -1
  98. package/dist/cli/output/auto.js +9 -0
  99. package/dist/cli/output/auto.js.map +1 -1
  100. package/dist/cli/output/context.d.ts +6 -0
  101. package/dist/cli/output/context.d.ts.map +1 -1
  102. package/dist/cli/output/context.js.map +1 -1
  103. package/dist/cli/output/context.test.js +87 -0
  104. package/dist/cli/output/context.test.js.map +1 -1
  105. package/dist/cli/output/error-display.test.js +3 -0
  106. package/dist/cli/output/error-display.test.js.map +1 -1
  107. package/dist/cli/output/interactive.d.ts +3 -0
  108. package/dist/cli/output/interactive.d.ts.map +1 -1
  109. package/dist/cli/output/interactive.js +76 -0
  110. package/dist/cli/output/interactive.js.map +1 -1
  111. package/dist/cli/output/json.d.ts +3 -0
  112. package/dist/cli/output/json.d.ts.map +1 -1
  113. package/dist/cli/output/json.js +9 -0
  114. package/dist/cli/output/json.js.map +1 -1
  115. package/dist/config/loader.d.ts.map +1 -1
  116. package/dist/config/loader.js +3 -2
  117. package/dist/config/loader.js.map +1 -1
  118. package/dist/config/schema.d.ts +641 -15
  119. package/dist/config/schema.d.ts.map +1 -1
  120. package/dist/config/schema.js +26 -1
  121. package/dist/config/schema.js.map +1 -1
  122. package/dist/config/schema.test.js +192 -1
  123. package/dist/config/schema.test.js.map +1 -1
  124. package/dist/core/assembly/overlay-loader.d.ts +24 -0
  125. package/dist/core/assembly/overlay-loader.d.ts.map +1 -0
  126. package/dist/core/assembly/overlay-loader.js +190 -0
  127. package/dist/core/assembly/overlay-loader.js.map +1 -0
  128. package/dist/core/assembly/overlay-loader.test.d.ts +2 -0
  129. package/dist/core/assembly/overlay-loader.test.d.ts.map +1 -0
  130. package/dist/core/assembly/overlay-loader.test.js +106 -0
  131. package/dist/core/assembly/overlay-loader.test.js.map +1 -0
  132. package/dist/core/assembly/overlay-resolver.d.ts +15 -0
  133. package/dist/core/assembly/overlay-resolver.d.ts.map +1 -0
  134. package/dist/core/assembly/overlay-resolver.js +58 -0
  135. package/dist/core/assembly/overlay-resolver.js.map +1 -0
  136. package/dist/core/assembly/overlay-resolver.test.d.ts +2 -0
  137. package/dist/core/assembly/overlay-resolver.test.d.ts.map +1 -0
  138. package/dist/core/assembly/overlay-resolver.test.js +246 -0
  139. package/dist/core/assembly/overlay-resolver.test.js.map +1 -0
  140. package/dist/core/assembly/overlay-state-resolver.d.ts +26 -0
  141. package/dist/core/assembly/overlay-state-resolver.d.ts.map +1 -0
  142. package/dist/core/assembly/overlay-state-resolver.js +63 -0
  143. package/dist/core/assembly/overlay-state-resolver.js.map +1 -0
  144. package/dist/core/assembly/overlay-state-resolver.test.d.ts +2 -0
  145. package/dist/core/assembly/overlay-state-resolver.test.d.ts.map +1 -0
  146. package/dist/core/assembly/overlay-state-resolver.test.js +256 -0
  147. package/dist/core/assembly/overlay-state-resolver.test.js.map +1 -0
  148. package/dist/core/assembly/preset-loader.d.ts +1 -0
  149. package/dist/core/assembly/preset-loader.d.ts.map +1 -1
  150. package/dist/core/assembly/preset-loader.js +2 -0
  151. package/dist/core/assembly/preset-loader.js.map +1 -1
  152. package/dist/core/dependency/eligibility.test.js +3 -0
  153. package/dist/core/dependency/eligibility.test.js.map +1 -1
  154. package/dist/e2e/game-pipeline.test.d.ts +10 -0
  155. package/dist/e2e/game-pipeline.test.d.ts.map +1 -0
  156. package/dist/e2e/game-pipeline.test.js +298 -0
  157. package/dist/e2e/game-pipeline.test.js.map +1 -0
  158. package/dist/e2e/init.test.js +3 -0
  159. package/dist/e2e/init.test.js.map +1 -1
  160. package/dist/project/adopt.d.ts +3 -1
  161. package/dist/project/adopt.d.ts.map +1 -1
  162. package/dist/project/adopt.js +29 -1
  163. package/dist/project/adopt.js.map +1 -1
  164. package/dist/project/adopt.test.js +51 -1
  165. package/dist/project/adopt.test.js.map +1 -1
  166. package/dist/types/config.d.ts +50 -4
  167. package/dist/types/config.d.ts.map +1 -1
  168. package/dist/types/config.test.d.ts +2 -0
  169. package/dist/types/config.test.d.ts.map +1 -0
  170. package/dist/types/config.test.js +97 -0
  171. package/dist/types/config.test.js.map +1 -0
  172. package/dist/utils/eligible.d.ts +3 -2
  173. package/dist/utils/eligible.d.ts.map +1 -1
  174. package/dist/utils/eligible.js +18 -4
  175. package/dist/utils/eligible.js.map +1 -1
  176. package/dist/utils/errors.d.ts +4 -0
  177. package/dist/utils/errors.d.ts.map +1 -1
  178. package/dist/utils/errors.js +31 -0
  179. package/dist/utils/errors.js.map +1 -1
  180. package/dist/utils/errors.test.js +4 -1
  181. package/dist/utils/errors.test.js.map +1 -1
  182. package/dist/wizard/questions.d.ts +4 -0
  183. package/dist/wizard/questions.d.ts.map +1 -1
  184. package/dist/wizard/questions.js +59 -1
  185. package/dist/wizard/questions.js.map +1 -1
  186. package/dist/wizard/questions.test.js +178 -4
  187. package/dist/wizard/questions.test.js.map +1 -1
  188. package/dist/wizard/wizard.d.ts +1 -0
  189. package/dist/wizard/wizard.d.ts.map +1 -1
  190. package/dist/wizard/wizard.js +4 -1
  191. package/dist/wizard/wizard.js.map +1 -1
  192. package/dist/wizard/wizard.test.js +102 -4
  193. package/dist/wizard/wizard.test.js.map +1 -1
  194. package/package.json +1 -1
@@ -0,0 +1,404 @@
1
+ ---
2
+ name: game-narrative-design
3
+ description: Dialogue tree patterns, branching narrative frameworks, lore bible structure, environmental storytelling, and localization hooks
4
+ topics: [game-dev, narrative, dialogue, branching, lore, worldbuilding]
5
+ ---
6
+
7
+ Game narrative design is the discipline of telling stories through interactive systems. Unlike film or literature, game narrative must account for player agency — the story adapts to player choices, pacing varies with player skill, and narrative is delivered through gameplay mechanics as much as through dialogue. The narrative designer's job is to create systems that deliver story, not just write scripts. This requires understanding dialogue tree architectures, branching frameworks, environmental storytelling techniques, and the technical infrastructure that supports narrative at scale.
8
+
9
+ ## Summary
10
+
11
+ ### Dialogue Trees
12
+
13
+ Dialogue trees are the most common narrative delivery mechanism in games. A dialogue tree is a directed graph where nodes are lines of dialogue or narration and edges are player choices or conditions. The complexity spectrum ranges from simple linear sequences (visual novels) to deeply branching graphs with state-dependent paths (RPGs).
14
+
15
+ **Key concepts:**
16
+ - **Nodes**: Individual dialogue lines, narration blocks, or action beats
17
+ - **Choices**: Player-selectable options that branch the conversation
18
+ - **Conditions**: Logic gates that show/hide choices or redirect flow based on game state (quest progress, reputation, inventory)
19
+ - **Hub-and-spoke**: A central node with multiple conversation topics the player can explore in any order, converging back to the hub — the dominant pattern in modern RPGs
20
+ - **Barks**: Short, contextual lines triggered by gameplay events (combat, discovery, idle) rather than conversation — technically distinct from dialogue trees but managed by the same systems
21
+
22
+ ### Branching Narrative Frameworks
23
+
24
+ The technical infrastructure for branching narrative has matured significantly. Three dominant authoring tools exist:
25
+
26
+ - **ink (Inkle Studios)**: A scripting language for interactive narrative. Text-first with inline logic. Compiles to a runtime that integrates with any engine. Used in 80 Days, Heaven's Vault, Slay the Spire (narrative events).
27
+ - **Yarn Spinner**: A dialogue scripting tool designed for Unity (with Godot and Unreal ports). Node-based visual editor plus text scripting. Used in Night in the Woods, A Short Hike.
28
+ - **Twine**: A hypertext-based tool for branching stories. Exports to HTML or integrates via custom formats. More suited to prototyping and narrative design than production game integration.
29
+
30
+ ### Lore Bible Structure
31
+
32
+ A lore bible is the single source of truth for a game's world, history, characters, and rules. It prevents continuity errors, enables consistent writing across a team, and serves as a reference for localization teams.
33
+
34
+ ### Environmental Storytelling
35
+
36
+ Environmental storytelling conveys narrative through the game world itself: architecture, object placement, visual details, and ambient audio. It respects player agency because it rewards observation without interrupting gameplay. Players who explore find richer story; players who do not are not blocked.
37
+
38
+ ### Localization Hooks
39
+
40
+ Narrative content must be localization-ready from the start. Retrofitting localization into a narrative system is extremely expensive. Key requirements: externalized strings (never hardcode text), context annotations for translators, gendered/pluralized text support, and cultural adaptation flags for content that may need regional changes.
41
+
42
+ ## Deep Guidance
43
+
44
+ ### Dialogue System Architecture
45
+
46
+ A production dialogue system needs more than just a tree. It needs state tracking, condition evaluation, variable management, and integration points with the game's other systems.
47
+
48
+ ```typescript
49
+ // Dialogue system core architecture
50
+
51
+ interface DialogueNode {
52
+ id: string;
53
+ speaker: string; // Character ID, maps to portrait/voice
54
+ text: string; // Localization key, NOT raw text
55
+ voiceClip?: string; // Audio asset reference
56
+ animation?: string; // Character animation to play during line
57
+ duration?: number; // Auto-advance after N seconds (for barks)
58
+ onEnter?: GameAction[]; // Actions triggered when this node displays
59
+ onExit?: GameAction[]; // Actions triggered when leaving this node
60
+ choices?: DialogueChoice[]; // Player options (empty = auto-advance)
61
+ next?: string; // Next node if no choices (linear flow)
62
+ tags?: string[]; // Metadata: "main_quest", "humor", "lore"
63
+ }
64
+
65
+ interface DialogueChoice {
66
+ text: string; // Localization key for choice label
67
+ targetNodeId: string; // Where this choice leads
68
+ conditions?: Condition[]; // Show only if ALL conditions are true
69
+ consequences?: GameAction[]; // Immediate effects of choosing this
70
+ skillCheck?: SkillCheck; // Optional skill gate
71
+ tone?: string; // UI hint: "friendly", "aggressive", "sarcastic"
72
+ }
73
+
74
+ interface Condition {
75
+ type: "quest_state" | "has_item" | "reputation" | "stat_check" | "flag";
76
+ key: string; // Quest ID, item ID, faction name, flag name
77
+ operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "has" | "not_has";
78
+ value: string | number | boolean;
79
+ }
80
+
81
+ interface SkillCheck {
82
+ skill: string; // "persuasion", "intimidation", "lockpick"
83
+ difficulty: number; // Target value
84
+ showDifficulty: boolean; // Show the DC to the player?
85
+ failNodeId?: string; // Where to go if the check fails
86
+ }
87
+
88
+ interface GameAction {
89
+ type: "set_flag" | "add_item" | "remove_item" | "change_reputation"
90
+ | "start_quest" | "advance_quest" | "play_animation" | "trigger_event";
91
+ parameters: Record<string, string | number | boolean>;
92
+ }
93
+
94
+ // --- Dialogue Runner ---
95
+
96
+ class DialogueRunner {
97
+ private currentNode: DialogueNode | null = null;
98
+ private variables: Map<string, string | number | boolean> = new Map();
99
+ private visitedNodes: Set<string> = new Set();
100
+
101
+ startConversation(startNodeId: string, graph: Map<string, DialogueNode>): void {
102
+ this.currentNode = graph.get(startNodeId) ?? null;
103
+ if (!this.currentNode) return;
104
+
105
+ this.visitedNodes.add(startNodeId);
106
+ this.executeActions(this.currentNode.onEnter);
107
+ this.displayNode(this.currentNode);
108
+ }
109
+
110
+ getAvailableChoices(): DialogueChoice[] {
111
+ if (!this.currentNode?.choices) return [];
112
+
113
+ return this.currentNode.choices.filter(choice => {
114
+ if (!choice.conditions) return true;
115
+ return choice.conditions.every(cond => this.evaluateCondition(cond));
116
+ });
117
+ }
118
+
119
+ selectChoice(choiceIndex: number, graph: Map<string, DialogueNode>): void {
120
+ const choices = this.getAvailableChoices();
121
+ const choice = choices[choiceIndex];
122
+ if (!choice) return;
123
+
124
+ this.executeActions(this.currentNode?.onExit);
125
+ this.executeActions(choice.consequences);
126
+
127
+ // Handle skill check
128
+ if (choice.skillCheck) {
129
+ const passed = this.performSkillCheck(choice.skillCheck);
130
+ const targetId = passed ? choice.targetNodeId : choice.skillCheck.failNodeId;
131
+ if (targetId) {
132
+ this.currentNode = graph.get(targetId) ?? null;
133
+ }
134
+ } else {
135
+ this.currentNode = graph.get(choice.targetNodeId) ?? null;
136
+ }
137
+
138
+ if (this.currentNode) {
139
+ this.visitedNodes.add(this.currentNode.id);
140
+ this.executeActions(this.currentNode.onEnter);
141
+ this.displayNode(this.currentNode);
142
+ }
143
+ }
144
+
145
+ private evaluateCondition(cond: Condition): boolean {
146
+ // Delegate to game state manager
147
+ return true; // Placeholder
148
+ }
149
+
150
+ private performSkillCheck(check: SkillCheck): boolean {
151
+ // Roll against player stat
152
+ return true; // Placeholder
153
+ }
154
+
155
+ private executeActions(actions?: GameAction[]): void {
156
+ if (!actions) return;
157
+ for (const action of actions) {
158
+ // Dispatch to game systems
159
+ }
160
+ }
161
+
162
+ private displayNode(node: DialogueNode): void {
163
+ // Send to UI system for rendering
164
+ }
165
+ }
166
+ ```
167
+
168
+ ### Bark Systems
169
+
170
+ Barks are short, contextual dialogue lines triggered by gameplay events rather than conversations. They are critical for making NPCs and companions feel alive.
171
+
172
+ **Bark trigger categories:**
173
+ - **Combat**: Taking damage, defeating an enemy, low health, ally down, using ability
174
+ - **Exploration**: Entering a new area, discovering a secret, idle too long, seeing a landmark
175
+ - **Reaction**: Witnessing an explosion, hearing a sound, noticing the weather change
176
+ - **Relationship**: Reacting to player choices, commenting on another NPC's action, responding to player gift
177
+ - **Contextual**: Near a quest objective, carrying a relevant item, time of day
178
+
179
+ **Bark management rules:**
180
+ - Barks have cooldowns per category — prevent the same line from playing repeatedly
181
+ - Priority system: combat barks override idle barks; story barks override ambient barks
182
+ - Track which barks have been heard — avoid repetition across a session
183
+ - Barks should be short (under 5 seconds of audio) — they must not interrupt gameplay flow
184
+ - Companion barks should reference game state: "That door is locked — maybe there's a key nearby" only triggers when the player has interacted with a locked door
185
+
186
+ ### Lore Bible Structure
187
+
188
+ ```yaml
189
+ # Lore bible document structure
190
+ lore_bible:
191
+ world:
192
+ overview: "One-page world summary (elevator pitch for the setting)"
193
+ history:
194
+ - era: "Age of Foundation"
195
+ period: "0-500"
196
+ key_events: ["Event A", "Event B"]
197
+ tone: "Hope and expansion"
198
+ - era: "Age of Fracture"
199
+ period: "500-800"
200
+ key_events: ["Event C", "Event D"]
201
+ tone: "Conflict and division"
202
+ geography:
203
+ regions:
204
+ - name: "The Ashlands"
205
+ climate: "Volcanic, arid"
206
+ inhabitants: ["Faction X", "Creature Y"]
207
+ narrative_role: "Mid-game conflict zone"
208
+ rules_of_the_world:
209
+ magic_system: "Description of magic rules and limitations"
210
+ technology_level: "What tech exists, what does not"
211
+ social_structures: "How societies are organized"
212
+
213
+ factions:
214
+ - name: "The Iron Covenant"
215
+ alignment: "Lawful, authoritarian"
216
+ goals: "Unify the continent under one government"
217
+ key_figures: ["Commander Hale", "Archivist Venn"]
218
+ player_relationship: "Starts neutral, can become ally or enemy"
219
+ reputation_thresholds:
220
+ hostile: -50
221
+ neutral: [-49, 49]
222
+ friendly: 50
223
+ allied: 80
224
+
225
+ characters:
226
+ - name: "Elena Vasquez"
227
+ role: "Companion, quest giver"
228
+ personality: "Pragmatic, dry humor, fiercely loyal once trusted"
229
+ arc: "From cynical mercenary to committed idealist"
230
+ voice_direction: "Mid-30s, confident, slight fatigue"
231
+ key_relationships:
232
+ - character: "Commander Hale"
233
+ nature: "Former mentor, now adversary"
234
+ dialogue_rules:
235
+ - "Never uses contractions when angry (formal speech = danger sign)"
236
+ - "Deflects emotional topics with humor"
237
+ - "Refers to the player by callsign, not name, until reputation > 60"
238
+
239
+ terminology:
240
+ glossary:
241
+ - term: "The Fracture"
242
+ definition: "The cataclysmic event that split the continent"
243
+ usage: "Always capitalized; characters reference it with reverence or fear"
244
+ - term: "Aetherweaving"
245
+ definition: "The practice of manipulating ambient magical energy"
246
+ usage: "A skill, not an innate ability; requires training"
247
+ ```
248
+
249
+ ### Branching Narrative Patterns
250
+
251
+ **The Funnel Pattern:**
252
+ Branches diverge at choice points and reconverge at key story beats. This is the most practical pattern for production games because it limits the exponential content growth of true branching. Players feel agency at choice points, but the story returns to shared narrative infrastructure.
253
+
254
+ **The Waterfall Pattern:**
255
+ Branches separate permanently, creating distinct story paths that do not rejoin. Produces maximum replayability but requires writing and implementing multiple complete story threads. Only viable for shorter games or games with small narrative scope per path.
256
+
257
+ **The Modular Pattern:**
258
+ Self-contained narrative modules can be encountered in any order. Each module is complete on its own but references shared world state. Used in open-world games where the player can discover stories in any sequence. Modules can check prerequisites (quest state, level, items) to control availability.
259
+
260
+ **The State-Driven Pattern:**
261
+ Rather than explicit branches, the narrative adapts based on accumulated game state. The same conversation might have different dialogue depending on 20 different flags and variables. This creates the illusion of deep branching with fewer distinct paths. Used heavily in immersive sims (Deus Ex, Dishonored).
262
+
263
+ ### Environmental Storytelling Techniques
264
+
265
+ Environmental storytelling is narrative delivered through the game world without explicit dialogue or text.
266
+
267
+ **Visual narrative:**
268
+ - Object placement tells a story: a table set for two with only one chair used, a child's toy next to a broken window, medicine bottles on a nightstand
269
+ - Graffiti and signs convey faction presence, social dynamics, or warnings
270
+ - Architecture tells history: a cathedral converted to a fortress, a skyscraper reclaimed by nature
271
+
272
+ **Audio narrative:**
273
+ - Ambient audio sets mood and implies events: distant explosions, birdsong in a peaceful area, industrial noise
274
+ - Environmental audio logs (when diegetic — a recording device the player finds) deliver exposition without breaking immersion
275
+ - Music shifts to signal narrative transitions (entering enemy territory, approaching a revelation)
276
+
277
+ **Spatial narrative:**
278
+ - Level layout guides the player's attention: sight lines to important objects, lighting that draws the eye, paths that lead to discoveries
279
+ - Locked doors and blocked paths imply what happened before the player arrived
280
+ - Progression through spaces mirrors narrative arcs: tight corridors opening to vistas for revelations, descending into darkness for tension
281
+
282
+ ### Narrative-Level Design Integration
283
+
284
+ Narrative designers and level designers must collaborate early. Story beats need physical spaces, and spaces need narrative justification.
285
+
286
+ **Integration points:**
287
+ - Every major story beat needs a "stage" — a location designed for that moment (sightlines, acoustics, player positioning)
288
+ - Quest objective locations should be interesting spaces, not generic rooms
289
+ - Critical path encounters should teach the player through the environment before demanding skill
290
+ - Optional content (lore items, audio logs, environmental puzzles) should be placed along natural exploration paths, not hidden behind obscure routes
291
+
292
+ ### Localization Infrastructure
293
+
294
+ ```typescript
295
+ // Localization-ready dialogue string structure
296
+
297
+ interface LocalizedString {
298
+ key: string; // Unique identifier: "quest_01_elena_greeting_01"
299
+ source: string; // English source text (for translator reference)
300
+ context: string; // Translator context: "Elena greets player at camp,
301
+ // tone is friendly but tired. 'Commander' is a rank."
302
+ maxLength?: number; // Character limit for UI constraints
303
+ gender?: GenderVariants; // For languages with grammatical gender
304
+ plural?: PluralVariants; // For countable nouns
305
+ voiceActed: boolean; // If true, text changes require re-recording
306
+ tags: string[]; // "main_quest", "humor", "formal"
307
+ }
308
+
309
+ interface GenderVariants {
310
+ masculine: string;
311
+ feminine: string;
312
+ neutral?: string;
313
+ }
314
+
315
+ interface PluralVariants {
316
+ zero?: string;
317
+ one: string;
318
+ few?: string; // Used in Slavic languages (2-4)
319
+ many?: string; // Used in Slavic languages (5+)
320
+ other: string; // General plural
321
+ }
322
+
323
+ // BAD: Hardcoded concatenation
324
+ function badApproach(name: string, count: number): string {
325
+ return `${name} found ${count} item${count === 1 ? "" : "s"}`;
326
+ // Breaks in: German (word order), Japanese (no plurals),
327
+ // Arabic (dual form), Russian (complex plural rules)
328
+ }
329
+
330
+ // GOOD: Externalized with ICU MessageFormat
331
+ const goodApproach: LocalizedString = {
332
+ key: "ui_items_found",
333
+ source: "{playerName} found {count, plural, one {# item} other {# items}}",
334
+ context: "Displayed when player picks up items. {playerName} is the player's character name.",
335
+ maxLength: 60,
336
+ voiceActed: false,
337
+ tags: ["ui", "gameplay"],
338
+ };
339
+
340
+ // --- Localization pipeline rules ---
341
+ // 1. All player-visible text goes through the localization system — no exceptions
342
+ // 2. Never concatenate translated strings — use template parameters
343
+ // 3. Provide context for every string — translators need to understand usage
344
+ // 4. Account for text expansion: German is ~30% longer than English,
345
+ // Japanese/Chinese can be 50% shorter
346
+ // 5. Flag cultural adaptation needs early: jokes, idioms, gestures,
347
+ // colors with cultural significance
348
+ // 6. Voice-acted lines are expensive to change — lock script early for VO languages
349
+ // 7. Test with pseudo-localization during development (replace all text
350
+ // with accented versions to catch hardcoded strings)
351
+ ```
352
+
353
+ ### Narrative Tooling Patterns
354
+
355
+ **ink example (branching with state):**
356
+
357
+ ```
358
+ === elena_greeting ===
359
+ {met_elena_before:
360
+ Elena glances up from her map. "Back again? I was starting to think you'd gotten yourself killed."
361
+ - else:
362
+ A woman in battered armor looks up from a map spread across a crate. She sizes you up in a single glance.
363
+ "You must be the new recruit. I'm Elena. Try not to die on your first mission."
364
+ ~ met_elena_before = true
365
+ }
366
+
367
+ + [Ask about the mission] -> mission_briefing
368
+ + {has_item("iron_medal")} [Show the Iron Medal] -> iron_medal_reaction
369
+ + [Leave] -> elena_farewell
370
+ ```
371
+
372
+ ink's strength is inline conditional logic. The `{met_elena_before:}` block shows different text based on whether the player has met Elena before. The `{has_item("iron_medal")}` guard on a choice means that option only appears if the player has the item. This compiles to a compact runtime that any engine can embed.
373
+
374
+ **Yarn Spinner example (Unity-native):**
375
+
376
+ ```
377
+ title: ElenaGreeting
378
+ tags: companion camp
379
+ ---
380
+ <<if $met_elena_before>>
381
+ Elena: Back again? I was starting to think you'd gotten yourself killed.
382
+ <<else>>
383
+ Elena: You must be the new recruit. I'm Elena. Try not to die.
384
+ <<set $met_elena_before to true>>
385
+ <<endif>>
386
+
387
+ -> Ask about the mission
388
+ <<jump MissionBriefing>>
389
+ -> Show the Iron Medal <<if $has_iron_medal>>
390
+ <<jump IronMedalReaction>>
391
+ -> Leave
392
+ Elena: Watch your back out there.
393
+ ===
394
+ ```
395
+
396
+ Yarn Spinner's syntax is more accessible to non-programmers. It integrates directly with Unity's editor, showing nodes as a visual graph. The `<<if>>` blocks and `<<set>>` commands handle state. Custom commands (like `<<jump>>`) map to C# functions in the game.
397
+
398
+ ### Common Narrative Design Pitfalls
399
+
400
+ - **Ludo-narrative dissonance**: The story says one thing, gameplay says another (cutscene shows character devastated by violence; gameplay rewards mass violence). Design mechanics that reinforce narrative themes.
401
+ - **Choice without consequence**: Giving players choices that change nothing feels worse than no choice at all. If you present a choice, it must have visible consequences — even if the long-term path converges.
402
+ - **Info dumps**: Long exposition delivered through dialogue is exhausting. Distribute lore across environmental storytelling, optional conversations, and collectibles. Let curious players find depth; do not force it on everyone.
403
+ - **Orphaned content**: Branching narratives create content most players never see. Budget accordingly — the "hidden" branch still needs writing, voice acting, testing, and localization. If the branch is too expensive, it should not exist.
404
+ - **Late localization**: Starting localization after the script is "done" guarantees painful rework. Build localization infrastructure in month one, send text batches continuously, and lock voice scripts as early as possible.