@jgengine/shell 0.10.0 → 0.11.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 (234) hide show
  1. package/CHANGELOG.md +13 -2
  2. package/LICENSE +203 -661
  3. package/README.md +1 -1
  4. package/dist/GamePhaseStamp.d.ts +1 -0
  5. package/dist/GamePhaseStamp.js +9 -0
  6. package/dist/GamePlayerShell.d.ts +0 -12
  7. package/dist/GamePlayerShell.js +88 -1043
  8. package/dist/GameUiPreview.js +0 -2
  9. package/dist/audio/audioEngine.js +30 -8
  10. package/dist/audio/audioWire.d.ts +22 -0
  11. package/dist/audio/audioWire.js +19 -0
  12. package/dist/behaviour.d.ts +2 -1
  13. package/dist/behaviour.js +2 -1
  14. package/dist/behaviourAttach.d.ts +1 -0
  15. package/dist/behaviourAttach.js +1 -0
  16. package/dist/behaviourDriver.d.ts +1 -0
  17. package/dist/behaviourDriver.js +1 -0
  18. package/dist/boundActionDispatch.d.ts +13 -0
  19. package/dist/boundActionDispatch.js +37 -0
  20. package/dist/camera/GameCameraRig.d.ts +5 -2
  21. package/dist/camera/GameCameraRig.js +2 -2
  22. package/dist/camera/GameFirstPersonCamera.d.ts +9 -2
  23. package/dist/camera/GameFirstPersonCamera.js +8 -3
  24. package/dist/camera/GameInspectionCamera.d.ts +1 -1
  25. package/dist/camera/GameInspectionCamera.js +2 -2
  26. package/dist/camera/GameOrbitCamera.js +24 -9
  27. package/dist/camera/cameraBlendMath.d.ts +3 -0
  28. package/dist/camera/cameraBlendMath.js +3 -0
  29. package/dist/camera/fovPreference.d.ts +6 -1
  30. package/dist/camera/fovPreference.js +6 -1
  31. package/dist/camera/index.d.ts +4 -7
  32. package/dist/camera/index.js +4 -7
  33. package/dist/camera/inspectionCameraMath.d.ts +7 -2
  34. package/dist/camera/inspectionCameraMath.js +7 -2
  35. package/dist/camera/orbitCameraMath.d.ts +36 -6
  36. package/dist/camera/orbitCameraMath.js +56 -6
  37. package/dist/camera/rigMath.d.ts +94 -24
  38. package/dist/camera/rigMath.js +100 -24
  39. package/dist/camera/rigResolve.d.ts +4 -2
  40. package/dist/camera/rigResolve.js +4 -2
  41. package/dist/camera/shakeChannel.d.ts +6 -2
  42. package/dist/camera/shakeChannel.js +6 -2
  43. package/dist/camera/shakeChannelMath.d.ts +1 -0
  44. package/dist/camera/shakeChannelMath.js +1 -0
  45. package/dist/cartridge/runtime.d.ts +15 -0
  46. package/dist/cartridge/runtime.js +556 -0
  47. package/dist/cartridge/spec.d.ts +188 -0
  48. package/dist/cartridge/spec.js +19 -0
  49. package/dist/cartridge/validate.d.ts +2 -0
  50. package/dist/cartridge/validate.js +78 -0
  51. package/dist/cartridge.d.ts +1 -1
  52. package/dist/cartridge.js +3 -3
  53. package/dist/commandSink.d.ts +8 -3
  54. package/dist/commandSink.js +8 -3
  55. package/dist/defineGame.js +25 -6
  56. package/dist/devtools/ColPanel.d.ts +1 -0
  57. package/dist/devtools/ColPanel.js +14 -0
  58. package/dist/devtools/DevtoolsOverlay.d.ts +7 -3
  59. package/dist/devtools/DevtoolsOverlay.js +19 -450
  60. package/dist/devtools/KeysPanel.d.ts +4 -0
  61. package/dist/devtools/KeysPanel.js +31 -0
  62. package/dist/devtools/LogsPanel.d.ts +1 -0
  63. package/dist/devtools/LogsPanel.js +12 -0
  64. package/dist/devtools/NetPanel.d.ts +4 -0
  65. package/dist/devtools/NetPanel.js +10 -0
  66. package/dist/devtools/PerfPanel.d.ts +4 -0
  67. package/dist/devtools/PerfPanel.js +53 -0
  68. package/dist/devtools/TunePanel.d.ts +3 -0
  69. package/dist/devtools/TunePanel.js +309 -0
  70. package/dist/devtools/agentBridge.d.ts +41 -0
  71. package/dist/devtools/agentBridge.js +262 -0
  72. package/dist/devtools/collisionDebug.d.ts +6 -0
  73. package/dist/devtools/collisionDebug.js +6 -0
  74. package/dist/devtools/collisionDebugMath.d.ts +8 -2
  75. package/dist/devtools/collisionDebugMath.js +24 -5
  76. package/dist/devtools/devtoolsOverrides.d.ts +6 -0
  77. package/dist/devtools/devtoolsOverrides.js +48 -0
  78. package/dist/devtools/panelAtoms.d.ts +9 -0
  79. package/dist/devtools/panelAtoms.js +10 -0
  80. package/dist/devtools/perfDiagnose.d.ts +2 -0
  81. package/dist/devtools/perfDiagnose.js +43 -0
  82. package/dist/diagnostics/RuntimeDiagnostics.d.ts +29 -0
  83. package/dist/diagnostics/RuntimeDiagnostics.js +69 -0
  84. package/dist/drivers/FrameDriver.d.ts +37 -0
  85. package/dist/drivers/FrameDriver.js +232 -0
  86. package/dist/drivers/HudOnlyDriver.d.ts +16 -0
  87. package/dist/drivers/HudOnlyDriver.js +60 -0
  88. package/dist/environment/Daylight.d.ts +23 -7
  89. package/dist/environment/Daylight.js +106 -13
  90. package/dist/environment/EnvironmentScene.js +32 -6
  91. package/dist/environment/VolumetricClouds.d.ts +17 -0
  92. package/dist/environment/VolumetricClouds.js +202 -0
  93. package/dist/environment/daylightCycle.d.ts +3 -1
  94. package/dist/environment/daylightCycle.js +3 -1
  95. package/dist/environment/groundPadMath.d.ts +3 -0
  96. package/dist/environment/groundPadMath.js +3 -0
  97. package/dist/environment/index.d.ts +1 -0
  98. package/dist/environment/index.js +1 -0
  99. package/dist/environment/skyLightingPolicy.d.ts +2 -0
  100. package/dist/environment/skyLightingPolicy.js +2 -0
  101. package/dist/hotbarActions.d.ts +26 -0
  102. package/dist/hotbarActions.js +27 -0
  103. package/dist/inputSink.d.ts +16 -4
  104. package/dist/inputSink.js +57 -7
  105. package/dist/materialOverride.d.ts +10 -0
  106. package/dist/materialOverride.js +15 -3
  107. package/dist/multiplayer.js +8 -2
  108. package/dist/postfx/PostProcessing.js +47 -9
  109. package/dist/postfx/gradeShader.js +9 -1
  110. package/dist/registry.d.ts +3 -2
  111. package/dist/render/EnvironmentLighting.d.ts +10 -0
  112. package/dist/render/EnvironmentLighting.js +34 -0
  113. package/dist/render/SceneLighting.d.ts +7 -0
  114. package/dist/render/SceneLighting.js +18 -0
  115. package/dist/render/SceneModels.d.ts +14 -0
  116. package/dist/render/SceneModels.js +337 -0
  117. package/dist/render/defaultSurface.d.ts +29 -0
  118. package/dist/render/defaultSurface.js +101 -0
  119. package/dist/render/modelLoad.d.ts +24 -0
  120. package/dist/render/modelLoad.js +73 -0
  121. package/dist/render/modelRender.d.ts +11 -0
  122. package/dist/render/modelRender.js +15 -0
  123. package/dist/render/resolveModel.d.ts +39 -3
  124. package/dist/render/resolveModel.js +79 -2
  125. package/dist/render/useEntityRenderCues.d.ts +13 -0
  126. package/dist/render/useEntityRenderCues.js +62 -0
  127. package/dist/scatter/InstancedScatter.d.ts +24 -0
  128. package/dist/scatter/InstancedScatter.js +130 -0
  129. package/dist/scatter/scatterModels.d.ts +25 -0
  130. package/dist/scatter/scatterModels.js +61 -0
  131. package/dist/scatter/scatterProxies.d.ts +6 -0
  132. package/dist/scatter/scatterProxies.js +94 -0
  133. package/dist/scatter.d.ts +1 -0
  134. package/dist/scatter.js +1 -0
  135. package/dist/scene/AuthoredScene.d.ts +82 -0
  136. package/dist/scene/AuthoredScene.js +173 -0
  137. package/dist/scene/GeneratedAssetRenderer.d.ts +14 -0
  138. package/dist/scene/GeneratedAssetRenderer.js +59 -0
  139. package/dist/scene/GrassFieldRenderer.d.ts +2 -0
  140. package/dist/scene/GrassFieldRenderer.js +25 -0
  141. package/dist/scene/SoilPatchRenderer.d.ts +2 -0
  142. package/dist/scene/SoilPatchRenderer.js +21 -0
  143. package/dist/scene/StudioStage.d.ts +37 -0
  144. package/dist/scene/StudioStage.js +42 -0
  145. package/dist/scene/WaterRenderer.d.ts +2 -0
  146. package/dist/scene/WaterRenderer.js +37 -0
  147. package/dist/scene/builtinSceneKindRenderers.d.ts +2 -0
  148. package/dist/scene/builtinSceneKindRenderers.js +22 -0
  149. package/dist/scene/sceneKindRenderers.d.ts +28 -0
  150. package/dist/scene/sceneKindRenderers.js +17 -0
  151. package/dist/scene.d.ts +1 -0
  152. package/dist/scene.js +1 -0
  153. package/dist/settings/appliedSettings.d.ts +5 -0
  154. package/dist/settings/appliedSettings.js +9 -0
  155. package/dist/settings/settingsController.d.ts +2 -0
  156. package/dist/settings/settingsController.js +22 -1
  157. package/dist/shellConstants.d.ts +4 -0
  158. package/dist/shellConstants.js +4 -0
  159. package/dist/shellMovement.d.ts +8 -0
  160. package/dist/shellMovement.js +11 -0
  161. package/dist/shellPointer.d.ts +20 -0
  162. package/dist/shellPointer.js +28 -0
  163. package/dist/structures/PlacementGhost.d.ts +4 -0
  164. package/dist/structures/PlacementGhost.js +4 -0
  165. package/dist/structures/TransformGizmo.d.ts +43 -0
  166. package/dist/structures/TransformGizmo.js +55 -0
  167. package/dist/structures/index.d.ts +1 -0
  168. package/dist/structures/index.js +1 -0
  169. package/dist/terrain/GrassField.js +1 -1
  170. package/dist/terrain/TerraformBrushCursor.js +3 -0
  171. package/dist/terrain/grassBudget.d.ts +11 -2
  172. package/dist/terrain/grassBudget.js +20 -4
  173. package/dist/terrain/grassGeometry.d.ts +3 -0
  174. package/dist/terrain/grassGeometry.js +3 -0
  175. package/dist/terrain/grassMaterial.d.ts +2 -0
  176. package/dist/terrain/grassMaterial.js +2 -0
  177. package/dist/terrain/random.d.ts +3 -0
  178. package/dist/terrain/random.js +3 -0
  179. package/dist/terrain/soilPatchMaterial.d.ts +10 -0
  180. package/dist/terrain/soilPatchMaterial.js +109 -0
  181. package/dist/terrain/terrainDetailMaterial.d.ts +19 -2
  182. package/dist/terrain/terrainDetailMaterial.js +72 -5
  183. package/dist/terrain/terrainMath.d.ts +8 -1
  184. package/dist/terrain/terrainMath.js +8 -1
  185. package/dist/touch/TouchControlsOverlay.d.ts +9 -5
  186. package/dist/touch/TouchControlsOverlay.js +201 -22
  187. package/dist/useShellMultiplayerSync.d.ts +9 -0
  188. package/dist/useShellMultiplayerSync.js +98 -0
  189. package/dist/visibility/CullingProvider.js +1 -1
  190. package/dist/water/OceanConfig.d.ts +2 -0
  191. package/dist/water/OceanConfig.js +2 -0
  192. package/dist/weather/fireSpreadPose.d.ts +1 -0
  193. package/dist/weather/fireSpreadPose.js +1 -0
  194. package/dist/weather/weatherGeometry.d.ts +1 -0
  195. package/dist/weather/weatherGeometry.js +1 -0
  196. package/dist/weather/weatherMath.d.ts +3 -0
  197. package/dist/weather/weatherMath.js +3 -0
  198. package/dist/weather/weatherUniforms.d.ts +3 -0
  199. package/dist/weather/weatherUniforms.js +3 -0
  200. package/dist/world/RetainedVfx.d.ts +10 -0
  201. package/dist/world/RetainedVfx.js +136 -0
  202. package/dist/world/WorldHud.d.ts +49 -2
  203. package/dist/world/WorldHud.js +87 -2
  204. package/dist/world/WorldScene.d.ts +21 -0
  205. package/dist/world/WorldScene.js +159 -0
  206. package/dist/world/WorldVfx.d.ts +9 -0
  207. package/dist/world/WorldVfx.js +184 -0
  208. package/dist/world/entityPose.d.ts +2 -0
  209. package/dist/world/entityPose.js +2 -0
  210. package/dist/world/floatTextStyle.d.ts +1 -0
  211. package/dist/world/floatTextStyle.js +1 -0
  212. package/dist/world/telegraphPulse.d.ts +1 -0
  213. package/dist/world/telegraphPulse.js +1 -0
  214. package/dist/world/worldBarSamples.d.ts +25 -0
  215. package/dist/world/worldBarSamples.js +38 -0
  216. package/dist/worldSky.d.ts +5 -0
  217. package/dist/worldSky.js +11 -0
  218. package/dist/worldSync.d.ts +2 -1
  219. package/dist/worldSync.js +2 -1
  220. package/package.json +6 -6
  221. package/skills/jgengine/SKILL.md +51 -0
  222. package/skills/jgengine/api.md +434 -0
  223. package/skills/jgengine/capabilities.md +29 -0
  224. package/skills/jgengine/reference-cartridge.md +72 -0
  225. package/skills/jgengine-ui/SKILL.md +36 -0
  226. package/skills/jgengine-ui/api.md +1852 -0
  227. package/skills/jgengine-ui/capabilities.md +142 -0
  228. package/skills/jgengine-ui/reference.md +500 -0
  229. package/skills/jgengine-ui/references/visual-scorecard.md +73 -0
  230. package/skills/jgengine-world/SKILL.md +38 -0
  231. package/skills/jgengine-world/api.md +2652 -0
  232. package/skills/jgengine-world/capabilities.md +370 -0
  233. package/skills/jgengine-world/reference.md +222 -0
  234. package/llms.txt +0 -2761
@@ -6,28 +6,36 @@ function actionCodeList(codes) {
6
6
  const modes = codes;
7
7
  return [...(modes.hold ?? []), ...(modes.toggle ?? [])];
8
8
  }
9
+ /** @internal */
9
10
  export function rtsPanKeysConflict(input) {
10
11
  if (input === undefined)
11
12
  return false;
12
13
  return Object.values(input).some((codes) => actionCodeList(codes).some((code) => RTS_WASD_CODES.includes(code)));
13
14
  }
15
+ /** @internal */
14
16
  export function clamp(value, min, max) {
15
17
  return value < min ? min : value > max ? max : value;
16
18
  }
19
+ /** @internal */
17
20
  export function lerp(from, to, blend) {
18
21
  return from + (to - from) * blend;
19
22
  }
23
+ /** @internal */
20
24
  export function smoothstep(t) {
21
25
  const clamped = clamp(t, 0, 1);
22
26
  return clamped * clamped * (3 - 2 * clamped);
23
27
  }
28
+ /** @internal */
24
29
  export function forwardVector(yaw) {
25
30
  return { x: Math.sin(yaw), y: 0, z: Math.cos(yaw) };
26
31
  }
27
- /** Screen-right of a yaw: `forward × up` with up = +Y. */
32
+ /** Screen-right of a yaw: `forward × up` with up = +Y.
33
+ * @internal
34
+ */
28
35
  export function rightVector(yaw) {
29
36
  return { x: -Math.cos(yaw), y: 0, z: Math.sin(yaw) };
30
37
  }
38
+ /** @internal */
31
39
  export function resolveTopDown(config) {
32
40
  return {
33
41
  height: config?.height ?? 18,
@@ -46,7 +54,8 @@ export function resolveTopDown(config) {
46
54
  * the camera→target ray above the ground (PI/2 = straight down); `yaw` is the
47
55
  * fixed azimuth (PI/4 reads isometric). Height sets zoom; horizontal boom is
48
56
  * derived so the look angle stays constant as height changes.
49
- */
57
+ * @internal
58
+ */
50
59
  export function topDownPose(follow, resolved, fov) {
51
60
  const lookAt = {
52
61
  x: follow.x + resolved.offset.x,
@@ -65,10 +74,13 @@ export function topDownPose(follow, resolved, fov) {
65
74
  fov,
66
75
  };
67
76
  }
68
- /** Exponential spring-arm approach toward a desired point (frame-rate independent). */
77
+ /** Exponential spring-arm approach toward a desired point (frame-rate independent).
78
+ * @internal
79
+ */
69
80
  export function springArmStep(current, desired, damping, dt) {
70
81
  return lerpVec3(current, desired, smoothBlend(dt, damping));
71
82
  }
83
+ /** @internal */
72
84
  export function resolveSideScroll(config) {
73
85
  return {
74
86
  axis: config?.axis ?? "x",
@@ -78,7 +90,9 @@ export function resolveSideScroll(config) {
78
90
  followSmoothing: config?.followSmoothing ?? 8,
79
91
  };
80
92
  }
81
- /** Frame-rate independent follow blend for the side-scroll rig; `followSmoothing <= 0` hard-locks (blend 1) instead of freezing. */
93
+ /** Frame-rate independent follow blend for the side-scroll rig; `followSmoothing <= 0` hard-locks (blend 1) instead of freezing.
94
+ * @internal
95
+ */
82
96
  export function sideScrollFollowBlend(followSmoothing, dt) {
83
97
  return followSmoothing <= 0 ? 1 : smoothBlend(dt, followSmoothing);
84
98
  }
@@ -86,7 +100,8 @@ export function sideScrollFollowBlend(followSmoothing, dt) {
86
100
  * Fixed lateral 2.5D follow pose: the camera sits perpendicular to the travel
87
101
  * axis at `distance`, above the entity by `height`, and looks at the entity
88
102
  * raised by `lookHeight`. Axis "x" watches from +z; axis "z" watches from +x.
89
- */
103
+ * @internal
104
+ */
90
105
  export function resolveSideScrollPose(entityPos, resolved, fov) {
91
106
  const perpendicular = resolved.axis === "x" ? { x: 0, y: 0, z: 1 } : { x: 1, y: 0, z: 0 };
92
107
  return {
@@ -99,7 +114,9 @@ export function resolveSideScrollPose(entityPos, resolved, fov) {
99
114
  fov,
100
115
  };
101
116
  }
102
- /** Speed→FOV curve: FOV climbs from base to max as speed rises to `speedForMax`. */
117
+ /** Speed→FOV curve: FOV climbs from base to max as speed rises to `speedForMax`.
118
+ * @internal
119
+ */
103
120
  export function speedToFov(speed, curve) {
104
121
  const base = curve?.base ?? 55;
105
122
  const max = curve?.max ?? 78;
@@ -108,11 +125,15 @@ export function speedToFov(speed, curve) {
108
125
  return base;
109
126
  return lerp(base, max, clamp(speed / speedForMax, 0, 1));
110
127
  }
111
- /** Yaw that points from `from` toward `to` on the XZ plane (matches shell forward = (sin, cos)). */
128
+ /** Yaw that points from `from` toward `to` on the XZ plane (matches shell forward = (sin, cos)).
129
+ * @internal
130
+ */
112
131
  export function yawTo(from, to) {
113
132
  return Math.atan2(to.x - from.x, to.z - from.z);
114
133
  }
115
- /** Shortest signed angular delta from `a` to `b`, wrapped to (-PI, PI]. */
134
+ /** Shortest signed angular delta from `a` to `b`, wrapped to (-PI, PI].
135
+ * @internal
136
+ */
116
137
  export function angleDelta(a, b) {
117
138
  let delta = (b - a) % (Math.PI * 2);
118
139
  if (delta > Math.PI)
@@ -121,10 +142,13 @@ export function angleDelta(a, b) {
121
142
  delta += Math.PI * 2;
122
143
  return delta;
123
144
  }
124
- /** Exponential yaw smoothing that respects wrap-around. */
145
+ /** Exponential yaw smoothing that respects wrap-around.
146
+ * @internal
147
+ */
125
148
  export function smoothYaw(current, desired, speed, dt) {
126
149
  return current + angleDelta(current, desired) * smoothBlend(dt, speed);
127
150
  }
151
+ /** @internal */
128
152
  export function resolveShoulder(config, aiming) {
129
153
  const hip = {
130
154
  shoulderOffset: config?.shoulderOffset ?? 0.6,
@@ -142,7 +166,9 @@ export function resolveShoulder(config, aiming) {
142
166
  fov: ads?.fov ?? hip.fov * 0.75,
143
167
  };
144
168
  }
145
- /** Blend two shoulder framings by an ADS factor in [0,1]. */
169
+ /** Blend two shoulder framings by an ADS factor in [0,1].
170
+ * @internal
171
+ */
146
172
  export function blendShoulder(hip, ads, t) {
147
173
  return {
148
174
  shoulderOffset: lerp(hip.shoulderOffset, ads.shoulderOffset, t),
@@ -155,7 +181,8 @@ export function blendShoulder(hip, ads, t) {
155
181
  * Over-the-shoulder camera pose. The boom sits behind the follow point along
156
182
  * `yaw`, raised by `heightOffset`, and pushed sideways by `shoulderOffset`
157
183
  * (sign set by `sideSign`: +1 right, -1 left). `pitch` tilts the look point.
158
- */
184
+ * @internal
185
+ */
159
186
  export function shoulderPose(follow, yaw, pitch, sideSign, shoulder) {
160
187
  const forward = forwardVector(yaw);
161
188
  const right = rightVector(yaw);
@@ -181,7 +208,8 @@ export function shoulderPose(follow, yaw, pitch, sideSign, shoulder) {
181
208
  * Lock-on pose: camera sits behind the player along the player→target vector so
182
209
  * the target stays framed. The look point is biased between player and target
183
210
  * by `framingBias`.
184
- */
211
+ * @internal
212
+ */
185
213
  export function lockOnPose(player, target, config, fov) {
186
214
  const distance = config?.distance ?? 5;
187
215
  const height = config?.height ?? 2.4;
@@ -201,6 +229,7 @@ export function lockOnPose(player, target, config, fov) {
201
229
  };
202
230
  return { pose: { position, lookAt: focus, fov }, yaw };
203
231
  }
232
+ /** @internal */
204
233
  export function resolveChase(config) {
205
234
  return {
206
235
  distance: config?.distance ?? 6,
@@ -215,7 +244,9 @@ export function resolveChase(config) {
215
244
  bankDamping: config?.bank?.damping ?? 8,
216
245
  };
217
246
  }
218
- /** Velocity-lead the follow point (#286.9): aim `leadTime` seconds along the target's frame velocity, clamped to `leadMax`. */
247
+ /** Velocity-lead the follow point (#286.9): aim `leadTime` seconds along the target's frame velocity, clamped to `leadMax`.
248
+ * @internal
249
+ */
219
250
  export function leadFollowPoint(follow, previous, dt, resolved) {
220
251
  if (resolved.leadTime <= 0 || dt <= 0)
221
252
  return follow;
@@ -236,7 +267,9 @@ function wrapAngle(angle) {
236
267
  wrapped += Math.PI * 2;
237
268
  return wrapped;
238
269
  }
239
- /** One smoothing step of the chase rig's turn-bank roll (#286.10): roll opposes yaw rate, clamped and exponentially damped. */
270
+ /** One smoothing step of the chase rig's turn-bank roll (#286.10): roll opposes yaw rate, clamped and exponentially damped.
271
+ * @internal
272
+ */
240
273
  export function bankRollStep(currentRoll, yaw, previousYaw, dt, resolved) {
241
274
  if (resolved.bankPerYawRate <= 0)
242
275
  return 0;
@@ -244,6 +277,7 @@ export function bankRollStep(currentRoll, yaw, previousYaw, dt, resolved) {
244
277
  const target = clamp(-yawRate * resolved.bankPerYawRate, -resolved.bankMax, resolved.bankMax);
245
278
  return currentRoll + (target - currentRoll) * Math.min(1, resolved.bankDamping * dt);
246
279
  }
280
+ /** @internal */
247
281
  export function resolveObserver(config) {
248
282
  return {
249
283
  distance: config?.distance ?? 8,
@@ -252,7 +286,9 @@ export function resolveObserver(config) {
252
286
  orbitSpeed: config?.orbitSpeed ?? 0.2,
253
287
  };
254
288
  }
255
- /** Detached spectator pose: orbits `subject` at a fixed distance/height, never reading player input. */
289
+ /** Detached spectator pose: orbits `subject` at a fixed distance/height, never reading player input.
290
+ * @internal
291
+ */
256
292
  export function observerPose(subject, angle, resolved, fov) {
257
293
  const position = {
258
294
  x: subject.x + Math.sin(angle) * resolved.distance,
@@ -265,7 +301,9 @@ export function observerPose(subject, angle, resolved, fov) {
265
301
  fov,
266
302
  };
267
303
  }
268
- /** Desired chase-camera position behind a vehicle facing `yaw` (before spring smoothing). */
304
+ /** Desired chase-camera position behind a vehicle facing `yaw` (before spring smoothing).
305
+ * @internal
306
+ */
269
307
  export function chaseDesiredPosition(follow, yaw, resolved) {
270
308
  const back = forwardVector(yaw);
271
309
  return {
@@ -274,7 +312,9 @@ export function chaseDesiredPosition(follow, yaw, resolved) {
274
312
  z: follow.z - back.z * resolved.distance,
275
313
  };
276
314
  }
277
- /** Look point ahead of / above a chased vehicle. */
315
+ /** Look point ahead of / above a chased vehicle.
316
+ * @internal
317
+ */
278
318
  export function chaseLookAt(follow, yaw, resolved) {
279
319
  const forward = forwardVector(yaw);
280
320
  return {
@@ -283,7 +323,9 @@ export function chaseLookAt(follow, yaw, resolved) {
283
323
  z: follow.z + forward.z * 2,
284
324
  };
285
325
  }
286
- /** World-space seat pose (cockpit/hood/rear) rigidly attached to the vehicle. */
326
+ /** World-space seat pose (cockpit/hood/rear) rigidly attached to the vehicle.
327
+ * @internal
328
+ */
287
329
  export function seatPose(follow, yaw, local, fov) {
288
330
  const forward = forwardVector(yaw);
289
331
  const right = rightVector(yaw);
@@ -301,14 +343,19 @@ export function seatPose(follow, yaw, local, fov) {
301
343
  fov,
302
344
  };
303
345
  }
346
+ /** @internal */
304
347
  export function createTrauma() {
305
348
  return { trauma: 0, time: 0 };
306
349
  }
307
- /** Add trauma (0..1) and clamp; larger hits raise the ceiling toward 1. */
350
+ /** Add trauma (0..1) and clamp; larger hits raise the ceiling toward 1.
351
+ * @internal
352
+ */
308
353
  export function addTrauma(state, amount) {
309
354
  state.trauma = clamp(state.trauma + amount, 0, 1);
310
355
  }
311
- /** Decay trauma linearly toward 0 and advance the shake clock. */
356
+ /** Decay trauma linearly toward 0 and advance the shake clock.
357
+ * @internal
358
+ */
312
359
  export function stepTrauma(state, decayPerSecond, dt) {
313
360
  state.time += dt;
314
361
  state.trauma = clamp(state.trauma - decayPerSecond * dt, 0, 1);
@@ -321,7 +368,8 @@ function hashNoise(seed, time, frequency) {
321
368
  * Positional + roll shake for the current trauma. Shake magnitude is
322
369
  * `trauma^exponent` so small hits stay subtle; the oscillation is deterministic
323
370
  * per-seed pseudo-noise (no per-frame RNG, so identical inputs reproduce).
324
- */
371
+ * @internal
372
+ */
325
373
  export function shakeOffset(state, config) {
326
374
  const maxOffset = config?.maxOffset ?? 0.5;
327
375
  const maxRoll = config?.maxRoll ?? 0.06;
@@ -336,7 +384,33 @@ export function shakeOffset(state, config) {
336
384
  roll: maxRoll * shake * hashNoise(3, state.time, frequency),
337
385
  };
338
386
  }
339
- /** Linear cross-fade between two full camera poses (position, lookAt, fov). */
387
+ /** Calibrated trauma decay for `traumaShake`/`impactPresets` (trauma/second). */
388
+ export const CALIBRATED_TRAUMA_SHAKE_DECAY_PER_SECOND = 1.4;
389
+ /** Calibrated positional shake amplitude at full trauma (world units) for `traumaShake`. */
390
+ export const CALIBRATED_TRAUMA_SHAKE_MAX_OFFSET = 0.55;
391
+ /** Calibrated rotational shake amplitude at full trauma (radians) for `traumaShake`. */
392
+ export const CALIBRATED_TRAUMA_SHAKE_MAX_ROLL = 0.1;
393
+ /** Calibrated shake noise frequency (Hz) for `traumaShake`. */
394
+ export const CALIBRATED_TRAUMA_SHAKE_FREQUENCY = 32;
395
+ /**
396
+ * Calibrated trauma² camera shake: offset scales with `trauma` squared using
397
+ * game-feel defaults (decay 1.4/s, max offset 0.55, max roll 0.1 rad, noise
398
+ * freq 32×t) — the curve `impactPresets` trauma values are calibrated
399
+ * against, so an impact "just looks right" without hand-tuning `shakeOffset`.
400
+ *
401
+ * @capability camera-shake calibrated trauma² camera kick with zero tuning
402
+ * @internal
403
+ */
404
+ export function traumaShake(trauma, time = 0) {
405
+ return shakeOffset({ trauma: clamp(trauma, 0, 1), time }, {
406
+ maxOffset: CALIBRATED_TRAUMA_SHAKE_MAX_OFFSET,
407
+ maxRoll: CALIBRATED_TRAUMA_SHAKE_MAX_ROLL,
408
+ frequency: CALIBRATED_TRAUMA_SHAKE_FREQUENCY,
409
+ });
410
+ }
411
+ /** Linear cross-fade between two full camera poses (position, lookAt, fov).
412
+ * @internal
413
+ */
340
414
  export function crossfadePose(from, to, t) {
341
415
  const blend = clamp(t, 0, 1);
342
416
  return {
@@ -350,7 +424,8 @@ export function crossfadePose(from, to, t) {
350
424
  * (#196.2). `director` omitted, or its fields `undefined`/`null`, is a pure
351
425
  * passthrough to `staticConfig` so mounting a director with no active override
352
426
  * changes nothing.
353
- */
427
+ * @internal
428
+ */
354
429
  export function resolveDirectedCamera(director, staticConfig) {
355
430
  const directedFollow = director?.followEntityId;
356
431
  const followEntityId = directedFollow === undefined ? staticConfig.followEntityId : directedFollow;
@@ -363,7 +438,8 @@ export function resolveDirectedCamera(director, staticConfig) {
363
438
  * travel time from the previous keyframe into it; segment easing is per the
364
439
  * destination keyframe. Reports `done` once past the final keyframe (unless
365
440
  * looping, which wraps `elapsed` into the total path duration).
366
- */
441
+ * @internal
442
+ */
367
443
  export function cinematicSample(keyframes, elapsed, loop, fallbackFov) {
368
444
  if (keyframes.length === 0) {
369
445
  const zero = { x: 0, y: 0, z: 0 };
@@ -6,10 +6,12 @@ import type { CameraRigKind, GameCameraConfig } from "@jgengine/core/game/playab
6
6
  * of a rig's own config block selects that rig, checked in the fixed order below
7
7
  * (#207.8) so a config carrying more than one block resolves deterministically
8
8
  * instead of depending on object key order. Set `rig` explicitly to break a tie.
9
- */
9
+ * @internal
10
+ */
10
11
  export declare function resolveRigKind(config: GameCameraConfig | undefined): CameraRigKind;
11
12
  /**
12
13
  * The turntable rig is a flat facade over the observer's point-orbit mode: map
13
14
  * its `target`/`distance`/… onto an observer block so ObserverRig runs unchanged.
14
- */
15
+ * @internal
16
+ */
15
17
  export declare function turntableAsObserver(config: GameCameraConfig | undefined): GameCameraConfig;
@@ -5,7 +5,8 @@
5
5
  * of a rig's own config block selects that rig, checked in the fixed order below
6
6
  * (#207.8) so a config carrying more than one block resolves deterministically
7
7
  * instead of depending on object key order. Set `rig` explicitly to break a tie.
8
- */
8
+ * @internal
9
+ */
9
10
  export function resolveRigKind(config) {
10
11
  if (config?.rig !== undefined)
11
12
  return config.rig;
@@ -34,7 +35,8 @@ export function resolveRigKind(config) {
34
35
  /**
35
36
  * The turntable rig is a flat facade over the observer's point-orbit mode: map
36
37
  * its `target`/`distance`/… onto an observer block so ObserverRig runs unchanged.
37
- */
38
+ * @internal
39
+ */
38
40
  export function turntableAsObserver(config) {
39
41
  const t = config?.turntable;
40
42
  if (t === undefined)
@@ -8,8 +8,12 @@ export { createCameraShakeChannel } from "./shakeChannelMath.js";
8
8
  * default channel directly.
9
9
  */
10
10
  export declare const defaultCameraShakeChannel: CameraShakeChannel;
11
- /** Feed the default camera-shake channel from anywhere (see G7 hitstop cross-cut). */
11
+ /** Feed the default camera-shake channel from anywhere (see G7 hitstop cross-cut).
12
+ * @internal
13
+ */
12
14
  export declare function cameraShake(amplitude: number, decayPerSecond?: number): void;
13
15
  export declare const CameraShakeContext: import("react").Context<CameraShakeChannel>;
14
- /** The active rig's shake channel — call `.shake(...)` to add trauma from React UI. */
16
+ /** The active rig's shake channel — call `.shake(...)` to add trauma from React UI.
17
+ * @internal
18
+ */
15
19
  export declare function useCameraShake(): CameraShakeChannel;
@@ -8,12 +8,16 @@ export { createCameraShakeChannel } from "./shakeChannelMath.js";
8
8
  * default channel directly.
9
9
  */
10
10
  export const defaultCameraShakeChannel = createCameraShakeChannel();
11
- /** Feed the default camera-shake channel from anywhere (see G7 hitstop cross-cut). */
11
+ /** Feed the default camera-shake channel from anywhere (see G7 hitstop cross-cut).
12
+ * @internal
13
+ */
12
14
  export function cameraShake(amplitude, decayPerSecond) {
13
15
  defaultCameraShakeChannel.shake(amplitude, decayPerSecond);
14
16
  }
15
17
  export const CameraShakeContext = createContext(defaultCameraShakeChannel);
16
- /** The active rig's shake channel — call `.shake(...)` to add trauma from React UI. */
18
+ /** The active rig's shake channel — call `.shake(...)` to add trauma from React UI.
19
+ * @internal
20
+ */
17
21
  export function useCameraShake() {
18
22
  return useContext(CameraShakeContext);
19
23
  }
@@ -5,4 +5,5 @@ export interface CameraShakeChannel {
5
5
  sample(config?: Parameters<typeof shakeOffset>[1]): ShakeOffset;
6
6
  trauma(): number;
7
7
  }
8
+ /** @internal */
8
9
  export declare function createCameraShakeChannel(defaultDecayPerSecond?: number): CameraShakeChannel;
@@ -1,4 +1,5 @@
1
1
  import { addTrauma, createTrauma, shakeOffset, stepTrauma } from "./rigMath.js";
2
+ /** @internal */
2
3
  export function createCameraShakeChannel(defaultDecayPerSecond = 1.6) {
3
4
  const state = createTrauma();
4
5
  let decay = defaultDecayPerSecond;
@@ -0,0 +1,15 @@
1
+ import { type AbilityKit } from "@jgengine/core/combat/abilityKit";
2
+ import type { GameLoop } from "@jgengine/core/game/defineGame";
3
+ import type { GameContext, GameContextContent } from "@jgengine/core/runtime/gameContext";
4
+ import { type CartridgeRun, type CartridgeSpec } from "./spec.js";
5
+ export interface CartridgeRuntime {
6
+ content: GameContextContent;
7
+ loop: GameLoop<GameContext>;
8
+ run(ctx: GameContext): CartridgeRun;
9
+ weaponKit(ctx: GameContext): AbilityKit;
10
+ chooseUpgrade(ctx: GameContext, offerId: string): void;
11
+ begin(ctx: GameContext): void;
12
+ reset(ctx: GameContext): void;
13
+ spec: CartridgeSpec;
14
+ }
15
+ export declare function createCartridge(spec: CartridgeSpec): CartridgeRuntime;