@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,242 @@
1
+ ---
2
+ name: game-engine-selection
3
+ description: Engine evaluation framework, Unity vs Unreal vs Godot comparison, middleware selection, and platform considerations
4
+ topics: [game-dev, engine, unity, unreal, godot, middleware]
5
+ ---
6
+
7
+ Choosing a game engine is the single most consequential technical decision in game development. It determines your rendering capabilities, supported platforms, available middleware, hiring pool, and long-term maintenance cost. Unlike web framework selection where migration is painful but possible, switching game engines mid-project is effectively starting over. This decision must be made deliberately, with explicit tradeoff acknowledgment, and documented as an ADR.
8
+
9
+ ## Summary
10
+
11
+ ### Engine Evaluation Framework
12
+
13
+ Evaluate engines across seven dimensions, weighted by project priorities:
14
+
15
+ 1. **Target Platform Fit** — Does the engine support all required platforms natively? Mobile, console, PC, VR/AR, and web each have different engine strengths. Console SDK access requires platform holder approval and some engines handle this better than others.
16
+
17
+ 2. **Rendering Capabilities** — Does the engine's rendering pipeline match the game's visual target? A stylized 2D game does not need ray tracing. A photorealistic open-world game needs advanced LOD, streaming, and global illumination.
18
+
19
+ 3. **Team Expertise** — What does the team already know? A team of C# developers will be more productive in Unity or Godot (C#) than Unreal (C++). Ramp-up time is real cost.
20
+
21
+ 4. **Ecosystem & Marketplace** — Asset stores, plugin ecosystems, and community tools dramatically accelerate development. Evaluate the quantity and quality of available assets, plugins, and community resources.
22
+
23
+ 5. **Licensing & Revenue Model** — Upfront cost, royalty structures, runtime fees, and source code access all factor in. A free engine with a 5% royalty above $1M revenue is different economics than a subscription model.
24
+
25
+ 6. **Tooling & Workflow** — Editor quality, iteration speed (compile times, hot reload), debugging tools, profiling tools, and version control integration affect daily productivity.
26
+
27
+ 7. **Scalability & Performance** — Maximum scene complexity, entity counts, physics performance, networking architecture, and memory management capabilities set upper bounds on what the game can do.
28
+
29
+ ### Key Decision Factors
30
+
31
+ The most common selection mistakes come from over-weighting one dimension:
32
+
33
+ - **Do not choose Unreal just for graphics** — if your game is a 2D puzzle game, Unreal's rendering capabilities are wasted and its complexity is a liability
34
+ - **Do not choose Unity just for market share** — if your game requires advanced rendering or large open worlds, Unity's default pipeline may require extensive custom work
35
+ - **Do not choose Godot just because it is free** — if your game requires console publishing, Godot's console support is limited and requires third-party porting
36
+ - **Do not choose a custom engine unless you have engine programmers** — building an engine is a multi-year investment that delays game development
37
+
38
+ ### Middleware Categories
39
+
40
+ No engine does everything well. Middleware fills the gaps:
41
+
42
+ - **Physics**: Havok, PhysX (built into Unity/Unreal), Jolt, Box2D
43
+ - **Audio**: FMOD, Wwise, Criware ADX2
44
+ - **Networking**: Photon, Mirror (Unity), Steam Networking, EOS
45
+ - **UI**: Coherent Gameface, NoesisGUI, Dear ImGui (debug), engine-native UI
46
+ - **Animation**: Morpheme, engine-native state machines, procedural IK solutions
47
+ - **AI**: custom behavior trees and utility AI are more common than middleware in this space
48
+
49
+ ## Deep Guidance
50
+
51
+ ### Engine Comparison Matrix
52
+
53
+ ```yaml
54
+ # Engine Decision Matrix — score each 1-5, multiply by weight
55
+ # Adjust weights to match your project priorities
56
+
57
+ criteria:
58
+ - name: "Target Platform Fit"
59
+ weight: 5
60
+ unity: 5 # Best cross-platform support, all major platforms
61
+ unreal: 4 # Excellent console/PC, weaker mobile/web
62
+ godot: 3 # Good PC/mobile, limited console, decent web
63
+ custom: 2 # Only what you build
64
+
65
+ - name: "2D Capability"
66
+ weight: 3 # Adjust: 5 for 2D games, 1 for 3D-only
67
+ unity: 4 # Solid 2D tools, Tilemap, SpriteRenderer
68
+ unreal: 2 # Paper2D exists but is underprioritized
69
+ godot: 5 # Best-in-class 2D with dedicated node types
70
+ custom: 3 # Depends on implementation
71
+
72
+ - name: "3D Rendering Quality"
73
+ weight: 4 # Adjust: 5 for AAA visual target
74
+ unity: 3 # URP adequate, HDRP approaching Unreal
75
+ unreal: 5 # Industry-leading Nanite, Lumen, MetaHumans
76
+ godot: 2 # Improving rapidly but behind on advanced features
77
+ custom: 1 # Years of investment required
78
+
79
+ - name: "Team Ramp-Up (C# team)"
80
+ weight: 4 # Adjust based on team language background
81
+ unity: 5 # Native C#
82
+ unreal: 1 # C++ with Blueprints; steep curve for C# devs
83
+ godot: 4 # GDScript is easy; C# support is stable
84
+ custom: 2 # Depends on language choice
85
+
86
+ - name: "Asset Marketplace"
87
+ weight: 3
88
+ unity: 5 # Largest asset store by volume
89
+ unreal: 4 # Smaller but high quality, many free monthly assets
90
+ godot: 2 # Growing but still limited
91
+ custom: 1 # No marketplace
92
+
93
+ - name: "Source Code Access"
94
+ weight: 2
95
+ unity: 2 # Reference source available, not modifiable freely
96
+ unreal: 4 # Full source on GitHub with license
97
+ godot: 5 # Fully open source (MIT)
98
+ custom: 5 # You own it all
99
+
100
+ - name: "Build & Iteration Speed"
101
+ weight: 4
102
+ unity: 4 # Hot reload improving, reasonable compile times
103
+ unreal: 2 # C++ compilation is slow; Blueprints iterate faster
104
+ godot: 5 # Fastest iteration cycle, near-instant scene reload
105
+ custom: 3 # Depends on build system
106
+
107
+ - name: "License Cost"
108
+ weight: 2
109
+ unity: 3 # Free tier, then subscription; runtime fee (post-2024)
110
+ unreal: 4 # Free until $1M revenue, then 5% royalty
111
+ godot: 5 # MIT license, completely free forever
112
+ custom: 5 # No license cost (but massive dev cost)
113
+
114
+ # Scoring: Sum of (score * weight) per engine
115
+ # Do NOT let the matrix make the decision — it structures the conversation
116
+ ```
117
+
118
+ ### Unity In Depth
119
+
120
+ **Strengths:**
121
+ - Broadest platform support in the industry (mobile, console, PC, VR, AR, WebGL)
122
+ - Largest asset store — thousands of ready-made solutions for common problems
123
+ - C# is accessible to a wide talent pool; lower barrier to entry than C++
124
+ - Strong 2D tooling alongside capable 3D
125
+ - Extensive documentation and tutorial ecosystem
126
+
127
+ **Weaknesses:**
128
+ - Rendering quality historically trails Unreal for AAA-grade visuals (HDRP narrows this gap)
129
+ - Runtime fee model introduced uncertainty (Unity responded to backlash but trust was damaged)
130
+ - Legacy code and architectural debt in some subsystems (old Input System, UI systems, networking)
131
+ - DOTS/ECS is powerful but has had a long and unstable development path
132
+
133
+ **Best for:** Mobile games, indie/AA multi-platform titles, VR/AR applications, 2D games that need cross-platform, rapid prototyping.
134
+
135
+ **Avoid for:** Games that require Unreal-grade visual fidelity without extensive custom rendering work.
136
+
137
+ ### Unreal Engine In Depth
138
+
139
+ **Strengths:**
140
+ - Industry-leading rendering: Nanite (virtualized geometry), Lumen (global illumination), MetaHumans
141
+ - Full C++ source code access enables deep engine customization
142
+ - Blueprint visual scripting allows designers and artists to prototype gameplay without code
143
+ - Mature networking and replication system for multiplayer
144
+ - Excellent large-world support (World Partition, level streaming)
145
+
146
+ **Weaknesses:**
147
+ - C++ compilation times are slow; iteration speed suffers for gameplay programming
148
+ - Steep learning curve — the engine is enormous and documentation can lag behind features
149
+ - Binary asset format makes version control painful (requires Perforce or Git LFS)
150
+ - Mobile support exists but is secondary to console/PC
151
+ - Royalty model takes 5% above $1M, which is significant for successful indie titles
152
+
153
+ **Best for:** AAA/AA 3D games, photorealistic visuals, large open worlds, multiplayer shooters, cinematic experiences.
154
+
155
+ **Avoid for:** Small 2D games, solo developers without C++ experience, projects where iteration speed is more important than visual fidelity.
156
+
157
+ ### Godot In Depth
158
+
159
+ **Strengths:**
160
+ - Fully open source (MIT license) — no royalties, no fees, no restrictions
161
+ - Best-in-class 2D engine with dedicated 2D physics, rendering, and node types
162
+ - GDScript is purpose-built for game development and extremely approachable
163
+ - Fastest iteration speed of any major engine — scene changes are near-instant
164
+ - Lightweight: the full engine editor is under 100MB
165
+ - Scene composition model (everything is a scene/node tree) is elegant and intuitive
166
+
167
+ **Weaknesses:**
168
+ - 3D rendering is functional but trails Unity and Unreal significantly
169
+ - Console export requires third-party porting services (no official console SDK support in open source)
170
+ - Smaller asset marketplace and plugin ecosystem
171
+ - Smaller community means fewer tutorials, fewer Stack Overflow answers, fewer ready-made solutions
172
+ - C# support is stable but GDScript is the first-class citizen; documentation and examples favor GDScript
173
+
174
+ **Best for:** 2D games, solo developers, small indie teams, game jams, projects where open source matters, educational contexts.
175
+
176
+ **Avoid for:** AAA 3D games, projects requiring guaranteed console support from day one, teams that need extensive middleware ecosystem.
177
+
178
+ ### Custom Engine Considerations
179
+
180
+ Building a custom engine is justified only when:
181
+ - The game requires capabilities no existing engine provides (novel rendering techniques, extreme performance requirements)
182
+ - The team has dedicated engine programmers with years of experience
183
+ - The studio plans to ship multiple titles on this engine, amortizing the investment
184
+ - Learning and IP ownership are explicit business goals
185
+
186
+ Building a custom engine is NOT justified when:
187
+ - The team wants to "learn how engines work" during a production project
188
+ - A single game feature is hard in an existing engine (solve that one feature, do not rebuild everything)
189
+ - The team is small and the game is on a tight timeline
190
+
191
+ ### Middleware Selection Guide
192
+
193
+ **Audio middleware (FMOD vs Wwise):**
194
+ - FMOD: Simpler API, generous indie licensing, good Unity/Unreal integration, lower learning curve
195
+ - Wwise: More powerful spatial audio and interactive music features, industry standard for AAA, steeper learning curve, more complex licensing
196
+ - Rule of thumb: FMOD for indie/AA, Wwise for AAA or games where adaptive audio is a pillar
197
+
198
+ **Networking middleware:**
199
+ - Photon: Managed servers, good for casual multiplayer, per-CCU pricing
200
+ - Mirror (Unity): Free, community-driven, server-authoritative, self-hosted
201
+ - Steam Networking: Free for Steam-published games, P2P with relay fallback
202
+ - EOS (Epic Online Services): Free, cross-platform, accounts/matchmaking/lobbies
203
+ - Rule of thumb: prototype with the simplest option, migrate to a production solution when you know your scale requirements
204
+
205
+ **Physics middleware:**
206
+ - PhysX: Built into Unity and Unreal; adequate for most games
207
+ - Havok: Premium physics with better large-world and destruction support; used in many AAA titles
208
+ - Jolt: Modern, open-source alternative gaining traction; good performance characteristics
209
+ - Box2D: The standard for 2D physics; built into most 2D engines
210
+
211
+ ### Rendering API Considerations
212
+
213
+ The choice of rendering API is usually dictated by the engine and target platform:
214
+
215
+ - **Vulkan**: Cross-platform (PC, Android, Switch via NVN/Vulkan-like), low-level, maximum control, highest learning curve
216
+ - **DirectX 12**: Windows and Xbox only, low-level like Vulkan, best Windows-specific optimization
217
+ - **Metal**: Apple platforms only (iOS, macOS), required for iOS/macOS, good performance
218
+ - **OpenGL/OpenGL ES**: Legacy but still relevant for web (WebGL) and older mobile devices
219
+ - **WebGPU**: Emerging standard for browser-based 3D, successor to WebGL
220
+
221
+ For most projects using an established engine, the engine abstracts the rendering API. Rendering API selection becomes critical only for custom engines or when writing custom render passes/shaders within an engine.
222
+
223
+ ### Platform SDK Requirements
224
+
225
+ Console development requires platform holder approval and NDA-protected SDK access:
226
+
227
+ - **PlayStation**: Must apply to Sony's PlayStation Partners Program, receive DevKit hardware, and sign NDA. Unity and Unreal handle PS SDK integration; Godot requires third-party porting.
228
+ - **Xbox**: Microsoft's ID@Xbox program for indie developers. Unity and Unreal have integrated GDK support. Somewhat more accessible than PlayStation for smaller studios.
229
+ - **Nintendo Switch**: Most restrictive approval process. Must apply to Nintendo Developer Portal. Unity and Unreal support Switch natively. Godot requires third-party porting services.
230
+
231
+ Console SDK access should be secured early in development — approval processes can take weeks to months, and DevKit hardware has lead times.
232
+
233
+ ### Decision Documentation Template
234
+
235
+ Every engine decision should be recorded as an Architecture Decision Record:
236
+
237
+ - **Context**: What kind of game, target platforms, team composition, timeline
238
+ - **Options Considered**: List each engine evaluated with weighted matrix scores
239
+ - **Decision**: Which engine was chosen
240
+ - **Rationale**: Which weights drove the decision, which tradeoffs were accepted
241
+ - **Consequences**: What capabilities are gained, what limitations are accepted
242
+ - **Revisit Triggers**: Under what conditions this decision should be reconsidered (e.g., "if we add VR support," "if the team grows beyond 20 engineers")
@@ -0,0 +1,357 @@
1
+ ---
2
+ name: game-input-systems
3
+ description: Input abstraction patterns, action mapping, dead zones, aim assist, haptic feedback, cross-play fairness, and accessibility
4
+ topics: [game-dev, input, controls, rebinding, haptics, accessibility]
5
+ ---
6
+
7
+ The input system is the player's sole interface with the game world. Every millisecond of input latency, every unintuitive binding, and every inaccessible control scheme directly erodes the player's experience. A well-designed input system abstracts hardware differences behind a unified action layer, supports rebinding without code changes, handles device hotswap gracefully, and provides accessibility options that let every player engage with the game. Input systems are deceptively complex — the gap between "reading a button press" and "shipping a polished, accessible, cross-platform input system" is enormous.
8
+
9
+ ## Summary
10
+
11
+ ### Input Abstraction Architecture
12
+
13
+ Never read hardware inputs directly in gameplay code. Instead, build a three-layer abstraction:
14
+
15
+ 1. **Hardware Layer**: Reads raw input from devices (keyboard, mouse, gamepad, touch, motion). This is the only layer that knows about specific hardware APIs (XInput, DirectInput, HID, touchscreen events).
16
+
17
+ 2. **Action Mapping Layer**: Maps raw inputs to semantic actions. "Press A button" or "Press Space bar" both map to the action "Jump." This layer handles rebinding, combo detection, input buffering, and modifier keys. Actions are defined in data (config files), not code.
18
+
19
+ 3. **Gameplay Layer**: Reads only actions, never raw inputs. Gameplay code asks "is the Jump action active?" not "is the space bar pressed?" This separation means the same gameplay code works across all input devices without modification.
20
+
21
+ ### Dead Zones and Sensitivity
22
+
23
+ Analog sticks have manufacturing variance — they may not return exactly (0,0) at rest. Dead zones prevent this drift from causing unwanted input.
24
+
25
+ - **Axial dead zone**: Apply dead zone independently to each axis. Simple but creates a diamond-shaped dead zone that can eat diagonal input near the center.
26
+ - **Radial dead zone**: Apply dead zone to the magnitude of the stick vector. Creates a circular dead zone that preserves diagonal input direction. Preferred for most games.
27
+ - **Default inner dead zone**: 0.15–0.25 (15–25% of stick range). Too small = stick drift; too large = lost precision near center.
28
+ - **Outer dead zone**: 0.90–0.95. Analog sticks rarely reach perfect 1.0 at the edge. The outer dead zone maps the usable range to 0.0–1.0 so players can achieve maximum input.
29
+
30
+ After applying dead zones, **rescale** the remaining range to 0.0–1.0 so gameplay code receives the full input range.
31
+
32
+ Sensitivity curves (response curves) map the rescaled stick input to gameplay speed:
33
+ - **Linear**: Output = Input. Simple, predictable, but may feel too fast near the edge.
34
+ - **Quadratic**: Output = Input^2. Slower near center for precision aiming, faster at edge. Most common default.
35
+ - **Custom curve**: Expose a curve editor in settings for players who want fine control.
36
+
37
+ ### Aim Assist and Aim Friction
38
+
39
+ Controller players in shooters need aim assist to compete with mouse precision. Aim assist is not "cheating" — it compensates for the physical limitations of thumbsticks.
40
+
41
+ **Aim assist types:**
42
+ - **Bullet magnetism**: Shots that miss by a small margin are redirected to hit the target. Invisible to the player. Typically 2–5 degrees of correction.
43
+ - **Reticle friction / aim slowdown**: Sensitivity decreases when the reticle is near a valid target, making it easier to track. The player feels like they are aiming well.
44
+ - **Target snap / aim lock**: Briefly snaps the reticle toward a target when aiming down sights. Used sparingly — too aggressive feels like the game is playing itself.
45
+ - **Rotation assist**: Slightly rotates the player's view to track a moving target that passes through the reticle area.
46
+
47
+ **Tuning rules:**
48
+ - Aim assist should be strongest on controller and weakest (or absent) on mouse
49
+ - Never apply aim assist to mouse input — mouse players perceive it as interference
50
+ - Scale aim assist with difficulty level (higher assist on easier difficulties)
51
+ - Disable or reduce aim assist in competitive multiplayer when fairness matters more than accessibility
52
+ - Expose aim assist strength as a player setting (0–100%)
53
+
54
+ ### Cross-Play Input Fairness
55
+
56
+ When keyboard/mouse and controller players compete in the same lobby, input disparity creates balance problems. Mouse has superior precision; controller has aim assist compensation.
57
+
58
+ **Strategies:**
59
+ - **Input-based matchmaking**: Match controller players with controller players and KB/M with KB/M by default. Allow opt-in to mixed lobbies.
60
+ - **Input detection**: Detect input device changes mid-match (player switches from controller to KB/M). Either lock the detected input type for the match or adjust aim assist immediately.
61
+ - **Separate leaderboards**: Maintain input-type-specific rankings when input method significantly affects competitive performance.
62
+ - **Asymmetric aim assist**: Controller players receive aim assist; KB/M players do not. This is the standard approach in cross-play shooters.
63
+
64
+ ## Deep Guidance
65
+
66
+ ### Action Mapping System
67
+
68
+ ```typescript
69
+ // Input abstraction: Hardware -> Action Mapping -> Gameplay
70
+
71
+ // --- Action Definitions (data-driven) ---
72
+
73
+ enum ActionType {
74
+ Button, // Discrete: pressed, released, held
75
+ Axis1D, // Continuous scalar: -1 to 1 (triggers, single stick axis)
76
+ Axis2D, // Continuous vector: { x, y } (stick, mouse delta)
77
+ }
78
+
79
+ interface ActionBinding {
80
+ action: string; // "Jump", "Move", "Fire", "AimDirection"
81
+ type: ActionType;
82
+ bindings: InputBinding[]; // Multiple bindings per action (KB + gamepad)
83
+ modifiers?: string[]; // Required modifier actions (e.g., "Sprint" + "Jump")
84
+ }
85
+
86
+ interface InputBinding {
87
+ device: "keyboard" | "mouse" | "gamepad" | "touch";
88
+ input: string; // "Space", "ButtonSouth", "LeftStick", etc.
89
+ scale?: number; // For axis inversion: -1 inverts
90
+ deadZone?: number; // Override per-binding dead zone
91
+ }
92
+
93
+ // Example action map (would be loaded from JSON/YAML config)
94
+ const defaultActionMap: ActionBinding[] = [
95
+ {
96
+ action: "Move",
97
+ type: ActionType.Axis2D,
98
+ bindings: [
99
+ { device: "gamepad", input: "LeftStick" },
100
+ // WASD mapped to 2D axis via composite
101
+ { device: "keyboard", input: "Composite:W,S,A,D" },
102
+ ],
103
+ },
104
+ {
105
+ action: "Jump",
106
+ type: ActionType.Button,
107
+ bindings: [
108
+ { device: "gamepad", input: "ButtonSouth" }, // A on Xbox, X on PS
109
+ { device: "keyboard", input: "Space" },
110
+ ],
111
+ },
112
+ {
113
+ action: "Fire",
114
+ type: ActionType.Button,
115
+ bindings: [
116
+ { device: "gamepad", input: "RightTrigger" },
117
+ { device: "mouse", input: "LeftButton" },
118
+ ],
119
+ },
120
+ {
121
+ action: "AimDirection",
122
+ type: ActionType.Axis2D,
123
+ bindings: [
124
+ { device: "gamepad", input: "RightStick" },
125
+ { device: "mouse", input: "Delta" },
126
+ ],
127
+ },
128
+ ];
129
+
130
+ // --- Input System Core ---
131
+
132
+ class InputSystem {
133
+ private actionMap: ActionBinding[];
134
+ private actionStates: Map<string, ActionState> = new Map();
135
+ private rebinds: Map<string, InputBinding[]> = new Map();
136
+
137
+ constructor(actionMap: ActionBinding[]) {
138
+ this.actionMap = actionMap;
139
+ for (const binding of actionMap) {
140
+ this.actionStates.set(binding.action, {
141
+ pressed: false,
142
+ released: false,
143
+ held: false,
144
+ value: 0,
145
+ axis2D: { x: 0, y: 0 },
146
+ });
147
+ }
148
+ }
149
+
150
+ // Called once per frame before gameplay update
151
+ update(rawInputs: RawInputSnapshot): void {
152
+ for (const binding of this.actionMap) {
153
+ const state = this.actionStates.get(binding.action)!;
154
+ const effectiveBindings = this.rebinds.get(binding.action)
155
+ ?? binding.bindings;
156
+
157
+ // Evaluate all bindings; take the one with highest magnitude
158
+ let bestValue = 0;
159
+ let bestAxis2D = { x: 0, y: 0 };
160
+
161
+ for (const b of effectiveBindings) {
162
+ const raw = rawInputs.get(b.device, b.input);
163
+ if (raw === undefined) continue;
164
+
165
+ if (binding.type === ActionType.Axis2D) {
166
+ const vec = raw as { x: number; y: number };
167
+ const deadZoned = this.applyRadialDeadZone(
168
+ vec, b.deadZone ?? 0.2
169
+ );
170
+ if (magnitude(deadZoned) > magnitude(bestAxis2D)) {
171
+ bestAxis2D = deadZoned;
172
+ }
173
+ } else {
174
+ const val = (raw as number) * (b.scale ?? 1);
175
+ if (Math.abs(val) > Math.abs(bestValue)) {
176
+ bestValue = val;
177
+ }
178
+ }
179
+ }
180
+
181
+ // Update state transitions
182
+ const wasHeld = state.held;
183
+ state.held = binding.type === ActionType.Axis2D
184
+ ? magnitude(bestAxis2D) > 0.01
185
+ : Math.abs(bestValue) > 0.5;
186
+ state.pressed = state.held && !wasHeld;
187
+ state.released = !state.held && wasHeld;
188
+ state.value = bestValue;
189
+ state.axis2D = bestAxis2D;
190
+ }
191
+ }
192
+
193
+ // Gameplay code reads actions, never raw inputs
194
+ isPressed(action: string): boolean {
195
+ return this.actionStates.get(action)?.pressed ?? false;
196
+ }
197
+
198
+ isHeld(action: string): boolean {
199
+ return this.actionStates.get(action)?.held ?? false;
200
+ }
201
+
202
+ getAxis2D(action: string): { x: number; y: number } {
203
+ return this.actionStates.get(action)?.axis2D ?? { x: 0, y: 0 };
204
+ }
205
+
206
+ // Runtime rebinding
207
+ rebind(action: string, newBindings: InputBinding[]): void {
208
+ this.rebinds.set(action, newBindings);
209
+ this.saveRebinds(); // Persist to player prefs
210
+ }
211
+
212
+ private applyRadialDeadZone(
213
+ input: { x: number; y: number },
214
+ deadZone: number
215
+ ): { x: number; y: number } {
216
+ const mag = magnitude(input);
217
+ if (mag < deadZone) return { x: 0, y: 0 };
218
+ // Rescale remaining range to 0-1
219
+ const rescaled = (mag - deadZone) / (1 - deadZone);
220
+ const normalized = { x: input.x / mag, y: input.y / mag };
221
+ return {
222
+ x: normalized.x * rescaled,
223
+ y: normalized.y * rescaled,
224
+ };
225
+ }
226
+
227
+ private saveRebinds(): void { /* persist to localStorage/file */ }
228
+ }
229
+
230
+ interface ActionState {
231
+ pressed: boolean;
232
+ released: boolean;
233
+ held: boolean;
234
+ value: number;
235
+ axis2D: { x: number; y: number };
236
+ }
237
+
238
+ interface RawInputSnapshot {
239
+ get(device: string, input: string): number | { x: number; y: number } | undefined;
240
+ }
241
+
242
+ function magnitude(v: { x: number; y: number }): number {
243
+ return Math.sqrt(v.x * v.x + v.y * v.y);
244
+ }
245
+ ```
246
+
247
+ ### Input Buffering
248
+
249
+ Input buffering accepts player inputs slightly before they would be valid and executes them at the first valid opportunity. This forgives imprecise timing and makes controls feel responsive.
250
+
251
+ **How it works:**
252
+ - When a player presses Jump while still in the air (e.g., 100 ms before landing), the input is stored in a buffer
253
+ - When the character lands, the buffer is checked — if a Jump input exists within the buffer window, the character immediately jumps
254
+ - Buffer window: typically 100–200 ms (6–12 frames at 60 fps)
255
+
256
+ **Where to apply buffering:**
257
+ - **Combat combos**: Buffer the next attack input during the current attack animation. Player presses "attack" during the swing of the first hit, and the second hit fires immediately when the first hit's recovery ends.
258
+ - **Platforming**: Buffer jump input during landing animation. Buffer wall-jump input during wall slide.
259
+ - **Dodge/roll**: Buffer dodge during attack recovery or hitstun.
260
+ - **Interaction**: Buffer "interact" input while walking toward an interactable object.
261
+
262
+ **Where NOT to apply buffering:**
263
+ - Menu navigation (buffer causes double-selection)
264
+ - Aim (buffered aim inputs create jittery movement)
265
+ - Anything where the "was this intentional?" ambiguity outweighs the responsiveness benefit
266
+
267
+ ### Haptic Feedback Design
268
+
269
+ Modern controllers (DualSense, Switch Joy-Cons, Xbox Impulse Triggers) provide nuanced haptic feedback beyond simple rumble.
270
+
271
+ **DualSense (PS5) advanced haptics:**
272
+ - **Adaptive triggers**: Variable resistance on L2/R2. Simulate bowstring tension, trigger pull weight, brake resistance, mud/sand resistance.
273
+ - **HD haptics**: High-fidelity vibration motors that can simulate textures, impacts, and environmental feedback through the controller. Walking on gravel feels different from walking on metal.
274
+ - **Speaker**: The controller has a built-in speaker for close-proximity sound effects (walkie-talkie chatter, weapon click, UI confirmation).
275
+
276
+ **Nintendo Switch HD Rumble:**
277
+ - Linear resonant actuators provide frequency-specific vibration
278
+ - Can simulate the feeling of ice cubes in a glass, rolling a ball, or counting objects by feel
279
+ - Lower fidelity than DualSense but still far beyond binary rumble
280
+
281
+ **Haptic design principles:**
282
+ - Haptics should reinforce, not replace, visual and audio feedback
283
+ - Every player action that has a physical analog should have a haptic response (firing a weapon, landing from a jump, taking damage)
284
+ - Environmental haptics add immersion: rain, vehicle engine vibration, walking surface texture
285
+ - Intensity should scale with gameplay intensity — constant high-intensity rumble causes fatigue and numbness
286
+ - Always provide an option to disable haptics entirely and to adjust intensity (0–100%)
287
+ - Test haptic design with the controller in hand, not just as parameter values on screen
288
+
289
+ ### Controller Disconnect Handling
290
+
291
+ Players disconnect controllers during gameplay (battery dies, cable pulled, Bluetooth interference). The game must handle this gracefully.
292
+
293
+ **Required behaviors:**
294
+ 1. **Pause immediately**: When a controller disconnects during single-player gameplay, pause the game and display a reconnection prompt. Never let gameplay continue without input — the player will take damage, fall off ledges, or lose progress.
295
+ 2. **Reconnect seamlessly**: When the controller reconnects, resume gameplay from the paused state. Do not require navigating a menu.
296
+ 3. **Player identification**: In local multiplayer, track which controller belongs to which player. When controller 2 disconnects and reconnects, it must re-associate with player 2, not become a new player.
297
+ 4. **Battery warning**: Display a low-battery warning before disconnection occurs. Platform APIs provide battery level (iOS: `UIDevice.batteryLevel`, Android: `BatteryManager`, PlayStation/Xbox SDK battery APIs).
298
+ 5. **Save protection**: If the game auto-saves on a timer, do not auto-save during a disconnect state — the player may be in an invalid position (falling, taking damage).
299
+
300
+ ### IME and Text Input
301
+
302
+ Text input in games is complex because it must handle hardware keyboards, on-screen keyboards, and Input Method Editors (IME) for CJK (Chinese, Japanese, Korean) languages.
303
+
304
+ **Keyboard text input:**
305
+ - Use the platform's text input API, not raw key events. Raw key events do not handle dead keys (accents), compose sequences, or IME.
306
+ - Support clipboard paste (Ctrl+V / Cmd+V) in all text fields.
307
+ - Handle key repeat rate (initial delay + repeat interval) for held keys in text fields.
308
+
309
+ **On-screen keyboards:**
310
+ - Mobile and console games must trigger the platform's on-screen keyboard when a text field is focused.
311
+ - Adjust the UI layout to prevent the on-screen keyboard from covering the active text field.
312
+ - Specify keyboard type per field: default, email, numeric, URL, password.
313
+
314
+ **IME support:**
315
+ - IME is required for CJK language input. The player types phonetic characters that are composed into ideographs through a candidate selection process.
316
+ - Display the IME composition string (the in-progress text) inline in the text field.
317
+ - Display the candidate list (possible character choices) near the text field.
318
+ - Do not consume keyboard events that the IME is processing — let the IME handle composition before the game receives the final character.
319
+ - Test IME input with native speakers — broken IME support is immediately obvious and blocks the game for millions of players in East Asian markets.
320
+
321
+ ### Accessibility in Input Design
322
+
323
+ Accessible input design is a legal requirement in some markets (CVAA in the US for communication features, European Accessibility Act) and a moral imperative everywhere.
324
+
325
+ **Minimum accessibility requirements:**
326
+ - **Full rebinding**: Every action must be rebindable to any key/button. No hardcoded bindings.
327
+ - **One-handed play**: Provide control schemes that work with only the left or right side of the controller/keyboard.
328
+ - **Hold vs toggle**: Every "hold to sprint/aim/crouch" input must have a toggle alternative.
329
+ - **Stick sensitivity**: Expose dead zone size, sensitivity curve, and axis inversion as player settings.
330
+ - **Button mashing alternatives**: Replace button-mash QTEs with hold-to-fill or automatic alternatives.
331
+ - **Auto-aim**: Provide a strong auto-aim option for players who cannot use fine analog control.
332
+ - **Sequential inputs**: Allow combo inputs to be performed sequentially (one press at a time) rather than requiring simultaneous button presses.
333
+ - **Touch target size**: On mobile, interactive touch targets must be at least 44x44 points (Apple HIG) or 48x48 dp (Material Design).
334
+
335
+ **Beyond minimum:**
336
+ - Copilot mode: Two controllers control the same character (one player assists another)
337
+ - Switch/adaptive controller support: Ensure the game works with accessibility controllers (Xbox Adaptive Controller)
338
+ - Eye tracking input: Support Tobii and similar eye tracking devices as input sources
339
+ - Voice input: Support voice commands for basic actions (requires platform speech-to-text API)
340
+
341
+ ### Input Latency Measurement
342
+
343
+ Input latency is the time from the player pressing a button to the corresponding visual change on screen. For competitive games, this must be as low as possible.
344
+
345
+ **Latency sources (cumulative):**
346
+ - Input polling: 0–8 ms (depends on polling rate: 1000 Hz USB = 1 ms, Bluetooth = 4–8 ms)
347
+ - Game simulation: 0–16.67 ms (depends on where in the frame the input is processed)
348
+ - Render pipeline: 16.67–33.33 ms (1–2 frames of render-ahead buffering)
349
+ - Display: 1–20 ms (monitor response time + display processing)
350
+ - Total typical: 40–80 ms (target < 60 ms for competitive games)
351
+
352
+ **Reducing input latency:**
353
+ - Poll input as late as possible in the frame (just before simulation, not at frame start)
354
+ - Minimize render-ahead buffers (trade GPU utilization for latency)
355
+ - Use "late latch" techniques: update camera/aim after the final input poll, just before GPU submission
356
+ - On PC, support NVIDIA Reflex / AMD Anti-Lag for driver-level latency reduction
357
+ - Measure with a high-speed camera (240+ fps) pointed at the display while pressing a button connected to an LED — count frames between LED and screen change