@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,455 @@
1
+ ---
2
+ name: game-level-content-design
3
+ description: Level metrics, greyboxing standards, flow and pacing, streaming strategies, encounter design, procedural generation, and difficulty curves
4
+ topics: [game-dev, level-design, world-design, procedural, streaming]
5
+ ---
6
+
7
+ Level design is the discipline of building the spaces that players inhabit and the experiences they have within those spaces. It bridges game design, environment art, and engineering — a level designer must understand player movement metrics (how high can they jump, how fast do they run, how wide is their collision capsule), pacing principles (tension-release cycles, difficulty ramps), and technical constraints (streaming budgets, draw call limits, memory footprints). Good level design is invisible: the player feels guided without feeling railroaded, challenged without feeling frustrated, and rewarded without feeling manipulated.
8
+
9
+ ## Summary
10
+
11
+ ### Player Movement Metrics
12
+
13
+ Every level must be designed around precise, measured player capabilities. These metrics are established during prototyping and become the dimensional constants of level construction.
14
+
15
+ **Core metrics to define and document:**
16
+ - **Player capsule dimensions**: Width (diameter) and height — determines minimum corridor width and door height
17
+ - **Walk speed**: Meters per second at normal movement
18
+ - **Run/sprint speed**: Meters per second at maximum movement
19
+ - **Jump height**: Maximum vertical reach from standing (and running if different)
20
+ - **Jump distance**: Maximum horizontal gap clearable at sprint speed
21
+ - **Mantle height**: Maximum ledge height the player can grab and climb over
22
+ - **Crouch height**: Reduced capsule height for crawl spaces
23
+ - **Camera height**: Eye level relative to ground — affects sightlines and cover design
24
+
25
+ **Typical metric ranges (scale in meters, 1 unit = 1 meter):**
26
+ - Corridor width: player width x 2.5 minimum (to prevent claustrophobic feel), 3–4m for comfortable traversal
27
+ - Door width: player width x 2 minimum, 1.5–2m typical
28
+ - Door height: player height x 1.3 minimum, 2.4–3m typical
29
+ - Stair step height: 0.15–0.25m (match player step-up threshold)
30
+ - Railing/cover height: 0.8–1.2m (must block standing camera but allow aim-over)
31
+ - Jump gap: max jump distance minus 20% safety margin
32
+ - Ceiling height: 3–4m for interiors, creates comfortable proportion
33
+
34
+ ### Greyboxing Standards
35
+
36
+ Greyboxing (also called blockout or whiteboxing) is the practice of building levels with simple geometric shapes to validate layout, flow, and gameplay before investing in environment art.
37
+
38
+ **Greybox rules:**
39
+ - Use untextured or single-color primitives (boxes, cylinders, planes)
40
+ - Build to exact player metrics — every jump, every door, every cover piece must be precisely measured
41
+ - Include gameplay-critical elements: spawn points, objective locations, AI patrol paths, cover positions, item pickups
42
+ - Playtest the greybox before any art pass — fix layout problems when the cost of change is zero
43
+ - Color-code greybox elements by function: grey for static geometry, blue for interactable, red for hazards, green for objectives, yellow for spawns
44
+ - The greybox IS the level — art replaces the geometry but does not change the layout
45
+
46
+ ### Flow and Pacing Principles
47
+
48
+ Level flow describes the intended path and experience arc of the player through a space. Pacing is the rhythm of intensity — alternating between high-action moments and rest/exploration moments.
49
+
50
+ **Flow patterns:**
51
+ - **Linear corridor**: Player moves from A to B through a series of connected spaces. Easiest to pace, lowest replayability. Used in narrative-driven games.
52
+ - **Hub and spoke**: Central area with branches leading to objectives. Player chooses order. Provides agency while maintaining structure.
53
+ - **Open arena**: Large space with multiple traversal options and objective points. Used for combat encounters, boss fights, multiplayer maps.
54
+ - **Metroidvania loop**: Interconnected rooms that loop back on themselves, gated by ability acquisition. High exploration satisfaction, complex to design.
55
+ - **Open world**: Player-driven exploration with points of interest distributed across a large map. Requires streaming, landmark navigation, and density management.
56
+
57
+ **Pacing rhythm (tension curve):**
58
+ 1. Introduction — safe space, establish new mechanic or environment
59
+ 2. Rising tension — encounters escalate in difficulty or complexity
60
+ 3. Climax — peak challenge (mini-boss, puzzle climax, setpiece)
61
+ 4. Release — reward, safe space, narrative payoff
62
+ 5. Repeat with escalation
63
+
64
+ ### Streaming Strategies
65
+
66
+ Large levels and open worlds exceed memory budgets. Streaming loads and unloads content as the player moves through the world.
67
+
68
+ **Approaches:**
69
+ - **Unreal World Partition**: Automatic grid-based streaming. World divided into cells loaded/unloaded based on player distance. Recommended for Unreal open worlds.
70
+ - **Unity Addressable Scenes**: Additive scene loading with reference-counted asset bundles. Manual streaming control via scene triggers or distance checks.
71
+ - **Godot scene loading**: `ResourceLoader.load_threaded_request()` for async loading, manual additive scene management.
72
+ - **Chunk-based**: World divided into fixed-size chunks (like Minecraft). Simple to implement, predictable memory budget per chunk, natural for voxel or grid-based games.
73
+
74
+ ## Deep Guidance
75
+
76
+ ### Level Metrics Reference Sheet
77
+
78
+ Every project should maintain a metrics reference sheet that all level designers use. This ensures consistency across levels built by different designers.
79
+
80
+ ```yaml
81
+ # level_metrics.yaml — Player capability reference for level construction
82
+ # All values in meters unless otherwise noted
83
+ # Update these values when player controller tuning changes
84
+
85
+ player:
86
+ capsule:
87
+ radius: 0.35
88
+ standing_height: 1.8
89
+ crouch_height: 1.0
90
+ prone_height: 0.5 # if applicable
91
+
92
+ movement:
93
+ walk_speed: 3.5 # m/s
94
+ run_speed: 6.0 # m/s
95
+ sprint_speed: 8.5 # m/s (if sprint is separate from run)
96
+ crouch_speed: 1.5 # m/s
97
+ swim_speed: 3.0 # m/s
98
+
99
+ jump:
100
+ standing_height: 1.2 # m — max vertical from standing
101
+ running_height: 1.4 # m — slightly higher with momentum
102
+ standing_distance: 2.5 # m — horizontal from standing
103
+ running_distance: 5.0 # m — horizontal at sprint speed
104
+ double_jump_height: 2.5 # m — if applicable
105
+ wall_jump_height: 2.0 # m — if applicable
106
+
107
+ traversal:
108
+ mantle_height: 2.0 # m — max ledge grab height
109
+ step_up_height: 0.35 # m — auto-step over small obstacles
110
+ slide_under_height: 1.0 # m — gap that slide can pass through
111
+ ladder_speed: 2.0 # m/s — vertical climbing speed
112
+ zipline_speed: 10.0 # m/s — if applicable
113
+
114
+ camera:
115
+ eye_height_standing: 1.65 # m from ground
116
+ eye_height_crouching: 0.85
117
+ fov_horizontal: 90 # degrees (adjustable in settings)
118
+
119
+ # Level construction guides derived from player metrics
120
+ construction:
121
+ doors:
122
+ min_width: 1.0 # player diameter * 1.4 rounded up
123
+ standard_width: 1.5
124
+ double_door_width: 2.5
125
+ min_height: 2.2 # player height * 1.2
126
+ standard_height: 2.5
127
+
128
+ corridors:
129
+ min_width: 1.5 # feels claustrophobic — use intentionally
130
+ standard_width: 3.0 # comfortable single-lane movement
131
+ wide_width: 5.0 # allows two players side-by-side
132
+ min_height: 2.5
133
+ standard_height: 3.5
134
+
135
+ stairs:
136
+ step_height: 0.2 # within step_up threshold
137
+ step_depth: 0.3 # comfortable foot placement
138
+ width: 1.5 # standard corridor width
139
+ landing_depth: 2.0 # turning landing for U-stairs
140
+
141
+ cover:
142
+ low_cover_height: 1.0 # player can aim over when standing
143
+ high_cover_height: 1.8 # player cannot aim over, must peek around
144
+ cover_width: 1.5 # min width to fully hide player capsule
145
+ peek_gap: 0.3 # space between cover pieces for peeking
146
+
147
+ jumps:
148
+ safe_gap: 3.5 # running jump distance * 0.7 safety margin
149
+ max_gap: 4.5 # running jump distance * 0.9 — expert-only
150
+ safe_height: 1.0 # standing jump height * 0.83
151
+ max_height: 1.2 # standing jump height — requires precision
152
+
153
+ sightlines:
154
+ engagement_close: 10 # m — shotgun/melee range
155
+ engagement_mid: 30 # m — assault rifle optimal
156
+ engagement_long: 80 # m — sniper/marksman range
157
+ max_render: 500 # m — LOD and fog limit visibility beyond this
158
+ ```
159
+
160
+ ### Greyboxing Workflow
161
+
162
+ A disciplined greyboxing workflow ensures levels are gameplay-validated before art investment.
163
+
164
+ **Phase 1: Paper design (1–2 days)**
165
+ - Top-down sketch of the level layout on paper or whiteboard
166
+ - Mark critical path, secondary paths, secret areas
167
+ - Note encounter locations with enemy counts and types
168
+ - Note pickup locations with item types
169
+ - Review with design lead before building
170
+
171
+ **Phase 2: Blockout in engine (2–5 days)**
172
+ - Build the level using primitive shapes at exact player metrics
173
+ - Place player start, objectives, enemy spawners, item pickups
174
+ - Implement basic AI navigation (navmesh bake) and pathfinding
175
+ - Add temporary lighting (bright, even, functional — not artistic)
176
+ - No art assets, no textures, no decorative geometry
177
+
178
+ **Phase 3: Internal playtest (1 day)**
179
+ - All level designers play each other's greyboxes
180
+ - Evaluate: flow (does the path feel natural?), pacing (are encounters spaced well?), readability (does the player know where to go?), fun (is it enjoyable?)
181
+ - Document issues by location and priority
182
+ - Iterate on blockout based on feedback
183
+
184
+ **Phase 4: Art pass begins only after greybox approval**
185
+ - Environment artists replace primitives with final geometry
186
+ - Keep collision volumes from the greybox — do not let art meshes change collision
187
+ - If art requires layout changes, re-validate with a greybox-only playtest
188
+
189
+ ### Encounter Design
190
+
191
+ Encounters are designed gameplay moments — typically combat, but also puzzles, traversal challenges, or narrative beats. Each encounter exists within a defined space and has a designed experience arc.
192
+
193
+ **Combat encounter anatomy:**
194
+
195
+ 1. **Approach** — Player sees or anticipates the encounter space before engaging. The space telegraphs what is coming: cover placement suggests a firefight, elevation suggests a sniper, tight corridors suggest close-quarters.
196
+
197
+ 2. **Engagement** — Combat begins. The encounter should have a designed "shape":
198
+ - **Wave encounters**: Enemies arrive in groups with brief pauses between waves. Each wave escalates (more enemies, tougher types, flanking positions).
199
+ - **Arena encounters**: Fixed set of enemies in an open space. Player chooses engagement order and positioning. Boss fights are a specialized arena encounter.
200
+ - **Gauntlet encounters**: Player moves through a space while enemies attack continuously. Tests movement and prioritization.
201
+
202
+ 3. **Resolution** — Combat ends with a clear signal (music change, door opens, loot drops). Give the player a moment to breathe before the next encounter.
203
+
204
+ **Encounter spacing:**
205
+ - Minimum 30 seconds of non-combat traversal between combat encounters (prevents fatigue)
206
+ - Major encounters (mini-boss, setpiece) should be preceded by 1–2 minutes of low-intensity gameplay
207
+ - After a climactic encounter, provide a rest area with ambient storytelling, loot, or narrative content
208
+ - The ratio of combat time to non-combat time depends on genre: action games ~60/40, narrative games ~20/80, survival horror ~30/70
209
+
210
+ ### Procedural Generation Rulesets
211
+
212
+ Procedural generation creates level content algorithmically rather than by hand. It requires explicit rulesets to produce coherent, playable results.
213
+
214
+ **Room-based dungeon generation (roguelike pattern):**
215
+
216
+ ```python
217
+ # dungeon_generator.py — Rule-based procedural dungeon layout
218
+ # Generates a graph of rooms connected by corridors
219
+
220
+ import random
221
+ from dataclasses import dataclass, field
222
+ from enum import Enum, auto
223
+
224
+ class RoomType(Enum):
225
+ SPAWN = auto()
226
+ COMBAT = auto()
227
+ TREASURE = auto()
228
+ SHOP = auto()
229
+ BOSS = auto()
230
+ SECRET = auto()
231
+ REST = auto() # Safe room with no enemies
232
+
233
+ @dataclass
234
+ class Room:
235
+ id: int
236
+ room_type: RoomType
237
+ width: float # meters
238
+ height: float # meters
239
+ connections: list[int] = field(default_factory=list)
240
+
241
+ @dataclass
242
+ class DungeonConfig:
243
+ """Configuration for dungeon generation rules."""
244
+ total_rooms: int = 15
245
+ min_room_size: float = 8.0 # meters
246
+ max_room_size: float = 25.0 # meters
247
+ boss_room_size: float = 30.0 # boss room is always large
248
+ min_combat_rooms: int = 5
249
+ max_combat_rooms: int = 8
250
+ treasure_rooms: int = 2
251
+ shop_rooms: int = 1
252
+ rest_rooms: int = 2
253
+ secret_room_chance: float = 0.3 # 30% chance to add a secret room
254
+ min_rooms_before_boss: int = 8 # minimum path length to boss
255
+ max_connections_per_room: int = 4
256
+
257
+ class DungeonGenerator:
258
+ def __init__(self, config: DungeonConfig, seed: int | None = None):
259
+ self.config = config
260
+ self.rng = random.Random(seed)
261
+ self.rooms: list[Room] = []
262
+
263
+ def generate(self) -> list[Room]:
264
+ self._place_rooms()
265
+ self._connect_rooms()
266
+ self._assign_types()
267
+ self._validate()
268
+ return self.rooms
269
+
270
+ def _place_rooms(self):
271
+ """Create rooms with random sizes within budget."""
272
+ for i in range(self.config.total_rooms):
273
+ size = self.rng.uniform(
274
+ self.config.min_room_size,
275
+ self.config.max_room_size,
276
+ )
277
+ self.rooms.append(Room(
278
+ id=i,
279
+ room_type=RoomType.COMBAT, # placeholder, assigned later
280
+ width=size,
281
+ height=size * self.rng.uniform(0.7, 1.3),
282
+ ))
283
+
284
+ def _connect_rooms(self):
285
+ """Build a spanning tree, then add extra connections for loops."""
286
+ # Spanning tree ensures all rooms are reachable
287
+ unconnected = list(range(1, len(self.rooms)))
288
+ connected = [0]
289
+ while unconnected:
290
+ from_room = self.rng.choice(connected)
291
+ to_room = self.rng.choice(unconnected)
292
+ self.rooms[from_room].connections.append(to_room)
293
+ self.rooms[to_room].connections.append(from_room)
294
+ connected.append(to_room)
295
+ unconnected.remove(to_room)
296
+
297
+ # Add extra connections for loops (optional paths)
298
+ extra = self.rng.randint(2, 5)
299
+ for _ in range(extra):
300
+ a = self.rng.randint(0, len(self.rooms) - 1)
301
+ b = self.rng.randint(0, len(self.rooms) - 1)
302
+ if (a != b
303
+ and b not in self.rooms[a].connections
304
+ and len(self.rooms[a].connections) < self.config.max_connections_per_room):
305
+ self.rooms[a].connections.append(b)
306
+ self.rooms[b].connections.append(a)
307
+
308
+ def _assign_types(self):
309
+ """Assign room types following generation rules."""
310
+ # Room 0 is always spawn
311
+ self.rooms[0].room_type = RoomType.SPAWN
312
+ self.rooms[0].width = self.config.min_room_size
313
+ self.rooms[0].height = self.config.min_room_size
314
+
315
+ # Last room is always boss
316
+ boss_idx = len(self.rooms) - 1
317
+ self.rooms[boss_idx].room_type = RoomType.BOSS
318
+ self.rooms[boss_idx].width = self.config.boss_room_size
319
+ self.rooms[boss_idx].height = self.config.boss_room_size
320
+
321
+ # Room before boss is always rest (save point)
322
+ if boss_idx > 1:
323
+ pre_boss = self.rooms[boss_idx].connections[0]
324
+ self.rooms[pre_boss].room_type = RoomType.REST
325
+
326
+ # Distribute remaining types
327
+ available = [i for i in range(1, boss_idx)
328
+ if self.rooms[i].room_type == RoomType.COMBAT]
329
+ self.rng.shuffle(available)
330
+
331
+ idx = 0
332
+ for _ in range(self.config.treasure_rooms):
333
+ if idx < len(available):
334
+ self.rooms[available[idx]].room_type = RoomType.TREASURE
335
+ idx += 1
336
+ for _ in range(self.config.shop_rooms):
337
+ if idx < len(available):
338
+ self.rooms[available[idx]].room_type = RoomType.SHOP
339
+ idx += 1
340
+ for _ in range(self.config.rest_rooms - 1): # -1 for pre-boss rest
341
+ if idx < len(available):
342
+ self.rooms[available[idx]].room_type = RoomType.REST
343
+ idx += 1
344
+ # Remaining rooms stay as COMBAT
345
+
346
+ # Secret room (chance-based, added as branch off existing room)
347
+ if self.rng.random() < self.config.secret_room_chance:
348
+ secret = Room(
349
+ id=len(self.rooms),
350
+ room_type=RoomType.SECRET,
351
+ width=self.config.min_room_size,
352
+ height=self.config.min_room_size,
353
+ )
354
+ attach_to = self.rng.choice(
355
+ [r for r in self.rooms if r.room_type == RoomType.COMBAT]
356
+ )
357
+ secret.connections.append(attach_to.id)
358
+ attach_to.connections.append(secret.id)
359
+ self.rooms.append(secret)
360
+
361
+ def _validate(self):
362
+ """Verify generation rules are satisfied."""
363
+ combat_count = sum(
364
+ 1 for r in self.rooms if r.room_type == RoomType.COMBAT
365
+ )
366
+ assert combat_count >= self.config.min_combat_rooms, (
367
+ f"Too few combat rooms: {combat_count}"
368
+ )
369
+ # Verify connectivity (BFS from spawn)
370
+ visited = set()
371
+ queue = [0]
372
+ while queue:
373
+ current = queue.pop(0)
374
+ if current in visited:
375
+ continue
376
+ visited.add(current)
377
+ queue.extend(self.rooms[current].connections)
378
+ assert len(visited) == len(self.rooms), "Not all rooms are reachable"
379
+ ```
380
+
381
+ ### Open-World POI Distribution
382
+
383
+ Points of Interest (POIs) in open worlds must be distributed to maintain a consistent density of discoverable content without feeling repetitive or overwhelming.
384
+
385
+ **Distribution rules:**
386
+ - **Minimum spacing**: No two POIs of the same type within 200m of each other (prevents clustering)
387
+ - **Maximum spacing**: No point in the traversable world should be more than 60 seconds of travel from the nearest POI (prevents empty stretches)
388
+ - **Density gradient**: Higher POI density near hubs and main paths, lower density in wilderness areas. The player should always see at least one undiscovered POI from any high vantage point.
389
+ - **Type variety**: Within any 500m radius, the player should encounter at least 3 different POI types (camp, landmark, puzzle, combat challenge, resource node, etc.)
390
+ - **Landmark visibility**: Major POIs should be visible from 300m+ to serve as navigation landmarks. Use vertical elements (towers, distinctive trees, rock formations) that stand above the terrain horizon.
391
+
392
+ **POI placement workflow:**
393
+ 1. Place major landmarks first (towns, dungeons, geographic features) — these anchor the world
394
+ 2. Place main quest locations relative to landmarks — ensure the critical path visits diverse biomes
395
+ 3. Fill with secondary POIs using a Poisson disk sampling algorithm (guarantees minimum spacing while feeling natural)
396
+ 4. Playtest by traversing every major route — if any 2-minute stretch feels empty, add content
397
+
398
+ ### Difficulty Curves Within Levels
399
+
400
+ Difficulty within a single level should follow a shaped curve, not a flat line or monotonic increase.
401
+
402
+ **Intra-level difficulty patterns:**
403
+
404
+ - **Ramp**: Starts easy, steadily increases. Good for tutorial levels and the early game. Risk: becomes predictable.
405
+ - **Sawtooth**: Alternating peaks and valleys. Each peak is slightly higher than the last. The valleys provide recovery and reward. Most common and effective pattern for sustained engagement.
406
+ - **Plateau**: Moderate difficulty with a sharp spike at the end (boss encounter). Effective for levels that build toward a climactic moment.
407
+ - **Inverted U**: Difficulty peaks in the middle of the level, then eases toward the end. Used when the level's narrative arc has a mid-point climax with a falling-action resolution.
408
+
409
+ **Difficulty levers available to level designers:**
410
+ - Enemy count and composition (more enemies, tougher enemy types)
411
+ - Arena size and cover density (less cover = harder)
412
+ - Resource availability (fewer health pickups = harder)
413
+ - Time pressure (timed sections, advancing hazards)
414
+ - Sightline length (longer sightlines favor ranged players, shorter favor melee)
415
+ - Verticality (enemies at different elevations are harder to deal with simultaneously)
416
+ - Environmental hazards (fire, pits, moving platforms)
417
+ - Checkpoint frequency (fewer checkpoints = higher stakes per encounter)
418
+
419
+ ### World Streaming Implementation
420
+
421
+ Open worlds require streaming subsystems that load and unload content based on player position.
422
+
423
+ **Streaming budget management:**
424
+ - Define a "streaming radius" around the player — all content within this radius must be loaded
425
+ - The streaming radius must account for maximum player speed (if the player can travel 100m/s in a vehicle, the streaming radius must be at least 100m * load-time-seconds ahead)
426
+ - Memory budget: streaming pool size = total memory budget minus persistent content (UI, player, audio banks, core systems)
427
+ - Priority loading: always load terrain and collision first, then large landmarks, then detail objects (foliage, debris, decals)
428
+
429
+ **Level-of-detail streaming:**
430
+ - Distance band 0 (0–50m): Full detail geometry, full-resolution textures, all physics bodies active
431
+ - Distance band 1 (50–200m): LOD1 geometry, half-resolution textures, simplified physics (or no physics)
432
+ - Distance band 2 (200–500m): LOD2 geometry, quarter-resolution textures, no physics, impostor rendering for trees
433
+ - Distance band 3 (500m+): Billboard impostors, terrain-only, atmosphere/fog handles the rest
434
+
435
+ **Transition management:**
436
+ - Cross-fade between LOD levels over 0.5–1.0 seconds to hide pop-in
437
+ - Use noise-based dithering during LOD transitions (perceptually smoother than alpha fade)
438
+ - Stream loading should never cause a hitch — if a load is taking too long, the player should see simplified content rather than nothing (empty space or T-poses are certification failures)
439
+ - Budget loading I/O bandwidth: on HDD-based platforms, reserve 50% of disk bandwidth for audio streaming, 50% for asset streaming. On SSD, this constraint is relaxed.
440
+
441
+ ### Level Design Documentation Template
442
+
443
+ Every level should have a design document before construction begins.
444
+
445
+ **Essential sections:**
446
+ - **Overview**: Level name, position in the game's progression, estimated play time, primary gameplay focus
447
+ - **Narrative context**: What story events occur here? What is the player's goal? What do they learn?
448
+ - **Map layout**: Top-down sketch with critical path marked, secondary paths, and secret areas
449
+ - **Encounter list**: Each encounter with enemy types, count, intended difficulty (1–10 scale), designed player strategy
450
+ - **Metrics compliance**: Confirmation that all jumps, doors, and corridors match the project metrics sheet
451
+ - **Streaming plan**: How the level is divided into streaming cells, estimated memory per cell, transition points
452
+ - **Art direction notes**: Mood, lighting intent, color palette, reference images
453
+ - **Audio direction notes**: Ambient soundscape, music transitions, key audio events
454
+ - **Unique mechanics**: Any level-specific mechanics (vehicles, zero-gravity, underwater) with design notes
455
+ - **Dependencies**: What player abilities are required? What story prerequisites must be met?