@jgengine/shell 0.10.0 → 0.12.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 (286) hide show
  1. package/CHANGELOG.md +39 -2
  2. package/LICENSE +203 -661
  3. package/README.md +1 -1
  4. package/dist/CombatPresentation.d.ts +5 -0
  5. package/dist/CombatPresentation.js +8 -0
  6. package/dist/GameHost.d.ts +25 -1
  7. package/dist/GameHost.js +60 -4
  8. package/dist/GamePhaseStamp.d.ts +1 -0
  9. package/dist/GamePhaseStamp.js +9 -0
  10. package/dist/GamePlayer.d.ts +5 -0
  11. package/dist/GamePlayer.js +5 -0
  12. package/dist/GamePlayerShell.d.ts +5 -12
  13. package/dist/GamePlayerShell.js +67 -1332
  14. package/dist/GameUiPreview.js +3 -2
  15. package/dist/Shell3dPresentation.d.ts +63 -0
  16. package/dist/Shell3dPresentation.js +302 -0
  17. package/dist/ShellChrome.d.ts +51 -0
  18. package/dist/ShellChrome.js +51 -0
  19. package/dist/ShellHudPresentation.d.ts +41 -0
  20. package/dist/ShellHudPresentation.js +22 -0
  21. package/dist/audio/audioEngine.d.ts +4 -0
  22. package/dist/audio/audioEngine.js +128 -21
  23. package/dist/audio/audioWire.d.ts +40 -0
  24. package/dist/audio/audioWire.js +62 -0
  25. package/dist/audio/loopParams.d.ts +20 -0
  26. package/dist/audio/loopParams.js +28 -0
  27. package/dist/behaviour.d.ts +2 -1
  28. package/dist/behaviour.js +2 -1
  29. package/dist/behaviourAttach.d.ts +1 -0
  30. package/dist/behaviourAttach.js +1 -0
  31. package/dist/behaviourDriver.d.ts +1 -0
  32. package/dist/behaviourDriver.js +1 -0
  33. package/dist/boundActionDispatch.d.ts +13 -0
  34. package/dist/boundActionDispatch.js +37 -0
  35. package/dist/camera/GameCameraRig.d.ts +5 -2
  36. package/dist/camera/GameCameraRig.js +8 -3
  37. package/dist/camera/GameFirstPersonCamera.d.ts +9 -2
  38. package/dist/camera/GameFirstPersonCamera.js +8 -3
  39. package/dist/camera/GameInspectionCamera.d.ts +1 -1
  40. package/dist/camera/GameInspectionCamera.js +2 -2
  41. package/dist/camera/GameOrbitCamera.js +24 -9
  42. package/dist/camera/cameraBlendMath.d.ts +3 -0
  43. package/dist/camera/cameraBlendMath.js +3 -0
  44. package/dist/camera/cameraRigs.d.ts +3 -1
  45. package/dist/camera/cameraRigs.js +21 -3
  46. package/dist/camera/fovPreference.d.ts +6 -1
  47. package/dist/camera/fovPreference.js +6 -1
  48. package/dist/camera/index.d.ts +4 -7
  49. package/dist/camera/index.js +4 -7
  50. package/dist/camera/inspectionCameraMath.d.ts +7 -2
  51. package/dist/camera/inspectionCameraMath.js +7 -2
  52. package/dist/camera/orbitCameraMath.d.ts +36 -6
  53. package/dist/camera/orbitCameraMath.js +56 -6
  54. package/dist/camera/rigMath.d.ts +114 -24
  55. package/dist/camera/rigMath.js +129 -24
  56. package/dist/camera/rigResolve.d.ts +4 -2
  57. package/dist/camera/rigResolve.js +4 -2
  58. package/dist/camera/shakeChannel.d.ts +6 -2
  59. package/dist/camera/shakeChannel.js +6 -2
  60. package/dist/camera/shakeChannelMath.d.ts +1 -0
  61. package/dist/camera/shakeChannelMath.js +1 -0
  62. package/dist/commandSink.d.ts +8 -3
  63. package/dist/commandSink.js +8 -3
  64. package/dist/defineGame.d.ts +15 -1
  65. package/dist/defineGame.js +50 -9
  66. package/dist/devtools/ColPanel.d.ts +1 -0
  67. package/dist/devtools/ColPanel.js +14 -0
  68. package/dist/devtools/DevtoolsOverlay.d.ts +11 -7
  69. package/dist/devtools/DevtoolsOverlay.js +47 -462
  70. package/dist/devtools/KeysPanel.d.ts +4 -0
  71. package/dist/devtools/KeysPanel.js +31 -0
  72. package/dist/devtools/LogsPanel.d.ts +1 -0
  73. package/dist/devtools/LogsPanel.js +12 -0
  74. package/dist/devtools/NetPanel.d.ts +4 -0
  75. package/dist/devtools/NetPanel.js +10 -0
  76. package/dist/devtools/PerfPanel.d.ts +4 -0
  77. package/dist/devtools/PerfPanel.js +53 -0
  78. package/dist/devtools/TunePanel.d.ts +3 -0
  79. package/dist/devtools/TunePanel.js +309 -0
  80. package/dist/devtools/agentBridge.d.ts +41 -0
  81. package/dist/devtools/agentBridge.js +266 -0
  82. package/dist/devtools/collisionDebug.d.ts +6 -0
  83. package/dist/devtools/collisionDebug.js +6 -0
  84. package/dist/devtools/collisionDebugMath.d.ts +8 -2
  85. package/dist/devtools/collisionDebugMath.js +24 -5
  86. package/dist/devtools/devtoolsOverrides.d.ts +6 -0
  87. package/dist/devtools/devtoolsOverrides.js +48 -0
  88. package/dist/devtools/panelAtoms.d.ts +9 -0
  89. package/dist/devtools/panelAtoms.js +10 -0
  90. package/dist/devtools/perfDiagnose.d.ts +2 -0
  91. package/dist/devtools/perfDiagnose.js +43 -0
  92. package/dist/diagnostics/RuntimeDiagnostics.d.ts +36 -0
  93. package/dist/diagnostics/RuntimeDiagnostics.js +80 -0
  94. package/dist/drivers/FrameDriver.d.ts +37 -0
  95. package/dist/drivers/FrameDriver.js +232 -0
  96. package/dist/drivers/HudOnlyDriver.d.ts +16 -0
  97. package/dist/drivers/HudOnlyDriver.js +60 -0
  98. package/dist/environment/Daylight.d.ts +23 -7
  99. package/dist/environment/Daylight.js +106 -13
  100. package/dist/environment/EnvironmentScene.js +44 -9
  101. package/dist/environment/VolumetricClouds.d.ts +17 -0
  102. package/dist/environment/VolumetricClouds.js +202 -0
  103. package/dist/environment/daylightCycle.d.ts +3 -1
  104. package/dist/environment/daylightCycle.js +3 -1
  105. package/dist/environment/groundPadMath.d.ts +3 -0
  106. package/dist/environment/groundPadMath.js +3 -0
  107. package/dist/environment/index.d.ts +1 -0
  108. package/dist/environment/index.js +1 -0
  109. package/dist/environment/skyLightingPolicy.d.ts +2 -0
  110. package/dist/environment/skyLightingPolicy.js +2 -0
  111. package/dist/environment/terrainGroundColor.d.ts +9 -0
  112. package/dist/environment/terrainGroundColor.js +22 -0
  113. package/dist/gameKit.d.ts +27 -0
  114. package/dist/gameKit.js +29 -0
  115. package/dist/hotbarActions.d.ts +26 -0
  116. package/dist/hotbarActions.js +27 -0
  117. package/dist/inputSink.d.ts +16 -4
  118. package/dist/inputSink.js +57 -7
  119. package/dist/map/MapMarkerBeacons.d.ts +3 -2
  120. package/dist/materialOverride.d.ts +10 -0
  121. package/dist/materialOverride.js +15 -3
  122. package/dist/multiplayer.js +8 -2
  123. package/dist/postfx/PostProcessing.d.ts +9 -1
  124. package/dist/postfx/PostProcessing.js +56 -11
  125. package/dist/postfx/gradeShader.js +9 -1
  126. package/dist/presentationResolve.d.ts +35 -0
  127. package/dist/presentationResolve.js +51 -0
  128. package/dist/registry.d.ts +4 -2
  129. package/dist/render/EnvironmentLighting.d.ts +10 -0
  130. package/dist/render/EnvironmentLighting.js +34 -0
  131. package/dist/render/SceneLighting.d.ts +7 -0
  132. package/dist/render/SceneLighting.js +18 -0
  133. package/dist/render/SceneModels.d.ts +14 -0
  134. package/dist/render/SceneModels.js +337 -0
  135. package/dist/render/assetBase.d.ts +17 -0
  136. package/dist/render/assetBase.js +35 -0
  137. package/dist/render/defaultSurface.d.ts +29 -0
  138. package/dist/render/defaultSurface.js +101 -0
  139. package/dist/render/modelLoad.d.ts +24 -0
  140. package/dist/render/modelLoad.js +76 -0
  141. package/dist/render/modelRender.d.ts +11 -0
  142. package/dist/render/modelRender.js +15 -0
  143. package/dist/render/resolveModel.d.ts +54 -3
  144. package/dist/render/resolveModel.js +116 -4
  145. package/dist/render/useEntityRenderCues.d.ts +13 -0
  146. package/dist/render/useEntityRenderCues.js +62 -0
  147. package/dist/scatter/InstancedScatter.d.ts +24 -0
  148. package/dist/scatter/InstancedScatter.js +135 -0
  149. package/dist/scatter/scatterModels.d.ts +25 -0
  150. package/dist/scatter/scatterModels.js +61 -0
  151. package/dist/scatter/scatterProxies.d.ts +6 -0
  152. package/dist/scatter/scatterProxies.js +118 -0
  153. package/dist/scatter.d.ts +1 -0
  154. package/dist/scatter.js +1 -0
  155. package/dist/scene/AuthoredScene.d.ts +84 -0
  156. package/dist/scene/AuthoredScene.js +178 -0
  157. package/dist/scene/CityRenderer.d.ts +2 -0
  158. package/dist/scene/CityRenderer.js +1031 -0
  159. package/dist/scene/GeneratedAssetRenderer.d.ts +14 -0
  160. package/dist/scene/GeneratedAssetRenderer.js +59 -0
  161. package/dist/scene/GrassFieldRenderer.d.ts +2 -0
  162. package/dist/scene/GrassFieldRenderer.js +73 -0
  163. package/dist/scene/PoleLineRenderer.d.ts +2 -0
  164. package/dist/scene/PoleLineRenderer.js +287 -0
  165. package/dist/scene/SoilPatchRenderer.d.ts +2 -0
  166. package/dist/scene/SoilPatchRenderer.js +84 -0
  167. package/dist/scene/StudioStage.d.ts +37 -0
  168. package/dist/scene/StudioStage.js +42 -0
  169. package/dist/scene/WaterRenderer.d.ts +2 -0
  170. package/dist/scene/WaterRenderer.js +61 -0
  171. package/dist/scene/builtinSceneKindRenderers.d.ts +2 -0
  172. package/dist/scene/builtinSceneKindRenderers.js +26 -0
  173. package/dist/scene/cityWindowMaterial.d.ts +16 -0
  174. package/dist/scene/cityWindowMaterial.js +81 -0
  175. package/dist/scene/sceneKindRenderers.d.ts +30 -0
  176. package/dist/scene/sceneKindRenderers.js +17 -0
  177. package/dist/scene.d.ts +1 -0
  178. package/dist/scene.js +1 -0
  179. package/dist/settings/appliedSettings.d.ts +7 -1
  180. package/dist/settings/appliedSettings.js +13 -2
  181. package/dist/settings/settingsController.d.ts +2 -0
  182. package/dist/settings/settingsController.js +22 -1
  183. package/dist/shellConstants.d.ts +4 -0
  184. package/dist/shellConstants.js +4 -0
  185. package/dist/shellMovement.d.ts +8 -0
  186. package/dist/shellMovement.js +11 -0
  187. package/dist/shellPointer.d.ts +20 -0
  188. package/dist/shellPointer.js +28 -0
  189. package/dist/structures/PlacementGhost.d.ts +4 -0
  190. package/dist/structures/PlacementGhost.js +4 -0
  191. package/dist/structures/TransformGizmo.d.ts +53 -0
  192. package/dist/structures/TransformGizmo.js +59 -0
  193. package/dist/structures/index.d.ts +1 -0
  194. package/dist/structures/index.js +1 -0
  195. package/dist/terrain/GrassField.d.ts +11 -3
  196. package/dist/terrain/GrassField.js +16 -6
  197. package/dist/terrain/TerraformBrushCursor.js +3 -0
  198. package/dist/terrain/grassBudget.d.ts +11 -2
  199. package/dist/terrain/grassBudget.js +20 -4
  200. package/dist/terrain/grassGeometry.d.ts +35 -0
  201. package/dist/terrain/grassGeometry.js +85 -20
  202. package/dist/terrain/grassMaterial.d.ts +20 -0
  203. package/dist/terrain/grassMaterial.js +68 -13
  204. package/dist/terrain/heightfieldGeometry.d.ts +34 -0
  205. package/dist/terrain/heightfieldGeometry.js +109 -0
  206. package/dist/terrain/index.d.ts +1 -0
  207. package/dist/terrain/index.js +1 -0
  208. package/dist/terrain/random.d.ts +3 -0
  209. package/dist/terrain/random.js +3 -0
  210. package/dist/terrain/soilPatchMaterial.d.ts +23 -0
  211. package/dist/terrain/soilPatchMaterial.js +147 -0
  212. package/dist/terrain/terrainDetailMaterial.d.ts +19 -2
  213. package/dist/terrain/terrainDetailMaterial.js +87 -7
  214. package/dist/terrain/terrainMath.d.ts +8 -1
  215. package/dist/terrain/terrainMath.js +8 -1
  216. package/dist/touch/TouchControlsOverlay.d.ts +9 -5
  217. package/dist/touch/TouchControlsOverlay.js +201 -22
  218. package/dist/useShellMultiplayerSync.d.ts +9 -0
  219. package/dist/useShellMultiplayerSync.js +98 -0
  220. package/dist/visibility/CullingProvider.js +1 -1
  221. package/dist/water/Ocean.d.ts +7 -1
  222. package/dist/water/Ocean.js +16 -3
  223. package/dist/water/OceanConfig.d.ts +11 -0
  224. package/dist/water/OceanConfig.js +8 -0
  225. package/dist/water/OceanMaterial.d.ts +12 -0
  226. package/dist/water/OceanMaterial.js +9 -0
  227. package/dist/water/OceanShader.d.ts +2 -2
  228. package/dist/water/OceanShader.js +78 -10
  229. package/dist/weather/fireSpreadPose.d.ts +1 -0
  230. package/dist/weather/fireSpreadPose.js +1 -0
  231. package/dist/weather/weatherGeometry.d.ts +1 -0
  232. package/dist/weather/weatherGeometry.js +1 -0
  233. package/dist/weather/weatherMath.d.ts +3 -0
  234. package/dist/weather/weatherMath.js +3 -0
  235. package/dist/weather/weatherUniforms.d.ts +3 -0
  236. package/dist/weather/weatherUniforms.js +3 -0
  237. package/dist/world/PlaceScene.d.ts +11 -0
  238. package/dist/world/PlaceScene.js +27 -0
  239. package/dist/world/RetainedVfx.d.ts +10 -0
  240. package/dist/world/RetainedVfx.js +136 -0
  241. package/dist/world/WorldHud.d.ts +49 -2
  242. package/dist/world/WorldHud.js +87 -2
  243. package/dist/world/WorldScene.d.ts +21 -0
  244. package/dist/world/WorldScene.js +186 -0
  245. package/dist/world/WorldVfx.d.ts +9 -0
  246. package/dist/world/WorldVfx.js +184 -0
  247. package/dist/world/entityPose.d.ts +2 -0
  248. package/dist/world/entityPose.js +2 -0
  249. package/dist/world/floatTextStyle.d.ts +1 -0
  250. package/dist/world/floatTextStyle.js +1 -0
  251. package/dist/world/telegraphPulse.d.ts +1 -0
  252. package/dist/world/telegraphPulse.js +1 -0
  253. package/dist/world/worldBarSamples.d.ts +25 -0
  254. package/dist/world/worldBarSamples.js +38 -0
  255. package/dist/worldSky.d.ts +11 -0
  256. package/dist/worldSky.js +21 -0
  257. package/dist/worldSync.d.ts +2 -1
  258. package/dist/worldSync.js +2 -1
  259. package/package.json +6 -6
  260. package/skills/game-design/SKILL.md +28 -0
  261. package/skills/game-design/agents/openai.yaml +4 -0
  262. package/skills/game-design/references/application-playbook.md +170 -0
  263. package/skills/game-design/references/field-guide.md +288 -0
  264. package/skills/jgengine/SKILL.md +54 -0
  265. package/skills/jgengine/api.md +527 -0
  266. package/skills/jgengine/capabilities.md +131 -0
  267. package/skills/jgengine/recipes/minimal-game.md +88 -0
  268. package/skills/jgengine-ui/SKILL.md +41 -0
  269. package/skills/jgengine-ui/api.md +2007 -0
  270. package/skills/jgengine-ui/capabilities.md +211 -0
  271. package/skills/jgengine-ui/recipes/portable-minimap.md +150 -0
  272. package/skills/jgengine-ui/reference.md +513 -0
  273. package/skills/jgengine-ui/references/visual-scorecard.md +73 -0
  274. package/skills/jgengine-world/SKILL.md +51 -0
  275. package/skills/jgengine-world/api.md +3056 -0
  276. package/skills/jgengine-world/capabilities.md +476 -0
  277. package/skills/jgengine-world/recipes/commanding-entities.md +128 -0
  278. package/skills/jgengine-world/reference.md +261 -0
  279. package/skills/level-design/SKILL.md +54 -0
  280. package/skills/level-design/agents/openai.yaml +4 -0
  281. package/skills/level-design/references/application-playbook.md +192 -0
  282. package/skills/level-design/references/field-guide.md +337 -0
  283. package/skills/level-design/references/live-editor-loop.md +179 -0
  284. package/dist/cartridge.d.ts +0 -145
  285. package/dist/cartridge.js +0 -246
  286. package/llms.txt +0 -2761
@@ -6,12 +6,19 @@ export interface CameraPose {
6
6
  lookAt: Vec3;
7
7
  fov: number;
8
8
  }
9
+ /** @internal */
9
10
  export declare function rtsPanKeysConflict(input: ActionCodesMap | undefined): boolean;
11
+ /** @internal */
10
12
  export declare function clamp(value: number, min: number, max: number): number;
13
+ /** @internal */
11
14
  export declare function lerp(from: number, to: number, blend: number): number;
15
+ /** @internal */
12
16
  export declare function smoothstep(t: number): number;
17
+ /** @internal */
13
18
  export declare function forwardVector(yaw: number): Vec3;
14
- /** Screen-right of a yaw: `forward × up` with up = +Y. */
19
+ /** Screen-right of a yaw: `forward × up` with up = +Y.
20
+ * @internal
21
+ */
15
22
  export declare function rightVector(yaw: number): Vec3;
16
23
  export interface ResolvedTopDown {
17
24
  height: number;
@@ -20,15 +27,19 @@ export interface ResolvedTopDown {
20
27
  offset: Vec3;
21
28
  followSmoothing: number;
22
29
  }
30
+ /** @internal */
23
31
  export declare function resolveTopDown(config: TopDownCameraConfig | undefined): ResolvedTopDown;
24
32
  /**
25
33
  * Camera pose for a fixed top-down / isometric rig. `pitch` is the elevation of
26
34
  * the camera→target ray above the ground (PI/2 = straight down); `yaw` is the
27
35
  * fixed azimuth (PI/4 reads isometric). Height sets zoom; horizontal boom is
28
36
  * derived so the look angle stays constant as height changes.
29
- */
37
+ * @internal
38
+ */
30
39
  export declare function topDownPose(follow: Vec3, resolved: ResolvedTopDown, fov: number): CameraPose;
31
- /** Exponential spring-arm approach toward a desired point (frame-rate independent). */
40
+ /** Exponential spring-arm approach toward a desired point (frame-rate independent).
41
+ * @internal
42
+ */
32
43
  export declare function springArmStep(current: Vec3, desired: Vec3, damping: number, dt: number): Vec3;
33
44
  export interface ResolvedSideScroll {
34
45
  axis: "x" | "z";
@@ -37,26 +48,38 @@ export interface ResolvedSideScroll {
37
48
  lookHeight: number;
38
49
  followSmoothing: number;
39
50
  }
51
+ /** @internal */
40
52
  export declare function resolveSideScroll(config: SideScrollCameraConfig | undefined): ResolvedSideScroll;
41
- /** Frame-rate independent follow blend for the side-scroll rig; `followSmoothing <= 0` hard-locks (blend 1) instead of freezing. */
53
+ /** Frame-rate independent follow blend for the side-scroll rig; `followSmoothing <= 0` hard-locks (blend 1) instead of freezing.
54
+ * @internal
55
+ */
42
56
  export declare function sideScrollFollowBlend(followSmoothing: number, dt: number): number;
43
57
  /**
44
58
  * Fixed lateral 2.5D follow pose: the camera sits perpendicular to the travel
45
59
  * axis at `distance`, above the entity by `height`, and looks at the entity
46
60
  * raised by `lookHeight`. Axis "x" watches from +z; axis "z" watches from +x.
47
- */
61
+ * @internal
62
+ */
48
63
  export declare function resolveSideScrollPose(entityPos: Vec3, resolved: ResolvedSideScroll, fov: number): CameraPose;
49
- /** Speed→FOV curve: FOV climbs from base to max as speed rises to `speedForMax`. */
64
+ /** Speed→FOV curve: FOV climbs from base to max as speed rises to `speedForMax`.
65
+ * @internal
66
+ */
50
67
  export declare function speedToFov(speed: number, curve: {
51
68
  base?: number;
52
69
  max?: number;
53
70
  speedForMax?: number;
54
71
  } | undefined): number;
55
- /** Yaw that points from `from` toward `to` on the XZ plane (matches shell forward = (sin, cos)). */
72
+ /** Yaw that points from `from` toward `to` on the XZ plane (matches shell forward = (sin, cos)).
73
+ * @internal
74
+ */
56
75
  export declare function yawTo(from: Vec3, to: Vec3): number;
57
- /** Shortest signed angular delta from `a` to `b`, wrapped to (-PI, PI]. */
76
+ /** Shortest signed angular delta from `a` to `b`, wrapped to (-PI, PI].
77
+ * @internal
78
+ */
58
79
  export declare function angleDelta(a: number, b: number): number;
59
- /** Exponential yaw smoothing that respects wrap-around. */
80
+ /** Exponential yaw smoothing that respects wrap-around.
81
+ * @internal
82
+ */
60
83
  export declare function smoothYaw(current: number, desired: number, speed: number, dt: number): number;
61
84
  export interface ResolvedShoulder {
62
85
  shoulderOffset: number;
@@ -64,20 +87,25 @@ export interface ResolvedShoulder {
64
87
  distance: number;
65
88
  fov: number;
66
89
  }
90
+ /** @internal */
67
91
  export declare function resolveShoulder(config: ShoulderCameraConfig | undefined, aiming: boolean): ResolvedShoulder;
68
- /** Blend two shoulder framings by an ADS factor in [0,1]. */
92
+ /** Blend two shoulder framings by an ADS factor in [0,1].
93
+ * @internal
94
+ */
69
95
  export declare function blendShoulder(hip: ResolvedShoulder, ads: ResolvedShoulder, t: number): ResolvedShoulder;
70
96
  /**
71
97
  * Over-the-shoulder camera pose. The boom sits behind the follow point along
72
98
  * `yaw`, raised by `heightOffset`, and pushed sideways by `shoulderOffset`
73
99
  * (sign set by `sideSign`: +1 right, -1 left). `pitch` tilts the look point.
74
- */
100
+ * @internal
101
+ */
75
102
  export declare function shoulderPose(follow: Vec3, yaw: number, pitch: number, sideSign: number, shoulder: ResolvedShoulder): CameraPose;
76
103
  /**
77
104
  * Lock-on pose: camera sits behind the player along the player→target vector so
78
105
  * the target stays framed. The look point is biased between player and target
79
106
  * by `framingBias`.
80
- */
107
+ * @internal
108
+ */
81
109
  export declare function lockOnPose(player: Vec3, target: Vec3, config: LockOnCameraConfig | undefined, fov: number): {
82
110
  pose: CameraPose;
83
111
  yaw: number;
@@ -93,11 +121,22 @@ export interface ResolvedChase {
93
121
  bankPerYawRate: number;
94
122
  bankMax: number;
95
123
  bankDamping: number;
124
+ /** Max fraction of the slip angle the anchor yaw follows toward velocity; 0 = drift-lag off (#1051). */
125
+ velocityYawBlend: number;
126
+ /** Below this planar speed the drift-lag feature is fully off. */
127
+ velocityYawMinSpeed: number;
128
+ /** Exponential smoothing rate toward the blended anchor yaw (1-exp(-response*dt)). */
129
+ velocityYawResponse: number;
96
130
  }
131
+ /** @internal */
97
132
  export declare function resolveChase(config: ChaseCameraConfig | undefined): ResolvedChase;
98
- /** Velocity-lead the follow point (#286.9): aim `leadTime` seconds along the target's frame velocity, clamped to `leadMax`. */
133
+ /** Velocity-lead the follow point (#286.9): aim `leadTime` seconds along the target's frame velocity, clamped to `leadMax`.
134
+ * @internal
135
+ */
99
136
  export declare function leadFollowPoint(follow: Vec3, previous: Vec3, dt: number, resolved: ResolvedChase): Vec3;
100
- /** One smoothing step of the chase rig's turn-bank roll (#286.10): roll opposes yaw rate, clamped and exponentially damped. */
137
+ /** One smoothing step of the chase rig's turn-bank roll (#286.10): roll opposes yaw rate, clamped and exponentially damped.
138
+ * @internal
139
+ */
101
140
  export declare function bankRollStep(currentRoll: number, yaw: number, previousYaw: number, dt: number, resolved: ResolvedChase): number;
102
141
  export interface ResolvedObserver {
103
142
  distance: number;
@@ -105,14 +144,37 @@ export interface ResolvedObserver {
105
144
  lookHeight: number;
106
145
  orbitSpeed: number;
107
146
  }
147
+ /** @internal */
108
148
  export declare function resolveObserver(config: ObserverCameraConfig | undefined): ResolvedObserver;
109
- /** Detached spectator pose: orbits `subject` at a fixed distance/height, never reading player input. */
149
+ /** Detached spectator pose: orbits `subject` at a fixed distance/height, never reading player input.
150
+ * @internal
151
+ */
110
152
  export declare function observerPose(subject: Vec3, angle: number, resolved: ResolvedObserver, fov: number): CameraPose;
111
- /** Desired chase-camera position behind a vehicle facing `yaw` (before spring smoothing). */
153
+ /** Desired chase-camera position behind a vehicle facing `yaw` (before spring smoothing).
154
+ * @internal
155
+ */
112
156
  export declare function chaseDesiredPosition(follow: Vec3, yaw: number, resolved: ResolvedChase): Vec3;
113
- /** Look point ahead of / above a chased vehicle. */
157
+ /** Look point ahead of / above a chased vehicle.
158
+ * @internal
159
+ */
114
160
  export declare function chaseLookAt(follow: Vec3, yaw: number, resolved: ResolvedChase): Vec3;
115
- /** World-space seat pose (cockpit/hood/rear) rigidly attached to the vehicle. */
161
+ /**
162
+ * Drift-lag (#1051): the yaw the chase anchor should aim before temporal
163
+ * smoothing. When the target slides, its planar `velocity` diverges from its
164
+ * `heading`; this rotates the anchor from heading partway toward the velocity
165
+ * direction so the camera reveals the car's side while travel stays framed. The
166
+ * traversed fraction is `velocityYawBlend` scaled by how far the slip angle has
167
+ * opened (0 at straight-line travel, full at a 90° slide), so ordinary driving
168
+ * is untouched. Returns the raw heading — no swing — when the feature is off,
169
+ * when planar speed is below `velocityYawMinSpeed`, or when the target is
170
+ * reversing (velocity opposed to heading forward). Blending is shortest-arc, so
171
+ * it stays correct across the ±PI wrap seam.
172
+ * @internal
173
+ */
174
+ export declare function velocityYawTarget(heading: number, velocity: Vec3, resolved: ResolvedChase): number;
175
+ /** World-space seat pose (cockpit/hood/rear) rigidly attached to the vehicle.
176
+ * @internal
177
+ */
116
178
  export declare function seatPose(follow: Vec3, yaw: number, local: {
117
179
  x?: number;
118
180
  y?: number;
@@ -122,10 +184,15 @@ export interface TraumaState {
122
184
  trauma: number;
123
185
  time: number;
124
186
  }
187
+ /** @internal */
125
188
  export declare function createTrauma(): TraumaState;
126
- /** Add trauma (0..1) and clamp; larger hits raise the ceiling toward 1. */
189
+ /** Add trauma (0..1) and clamp; larger hits raise the ceiling toward 1.
190
+ * @internal
191
+ */
127
192
  export declare function addTrauma(state: TraumaState, amount: number): void;
128
- /** Decay trauma linearly toward 0 and advance the shake clock. */
193
+ /** Decay trauma linearly toward 0 and advance the shake clock.
194
+ * @internal
195
+ */
129
196
  export declare function stepTrauma(state: TraumaState, decayPerSecond: number, dt: number): void;
130
197
  export interface ShakeOffset {
131
198
  x: number;
@@ -136,14 +203,35 @@ export interface ShakeOffset {
136
203
  * Positional + roll shake for the current trauma. Shake magnitude is
137
204
  * `trauma^exponent` so small hits stay subtle; the oscillation is deterministic
138
205
  * per-seed pseudo-noise (no per-frame RNG, so identical inputs reproduce).
139
- */
206
+ * @internal
207
+ */
140
208
  export declare function shakeOffset(state: TraumaState, config: {
141
209
  maxOffset?: number;
142
210
  maxRoll?: number;
143
211
  exponent?: number;
144
212
  frequency?: number;
145
213
  } | undefined): ShakeOffset;
146
- /** Linear cross-fade between two full camera poses (position, lookAt, fov). */
214
+ /** Calibrated trauma decay for `traumaShake`/`impactPresets` (trauma/second). */
215
+ export declare const CALIBRATED_TRAUMA_SHAKE_DECAY_PER_SECOND = 1.4;
216
+ /** Calibrated positional shake amplitude at full trauma (world units) for `traumaShake`. */
217
+ export declare const CALIBRATED_TRAUMA_SHAKE_MAX_OFFSET = 0.55;
218
+ /** Calibrated rotational shake amplitude at full trauma (radians) for `traumaShake`. */
219
+ export declare const CALIBRATED_TRAUMA_SHAKE_MAX_ROLL = 0.1;
220
+ /** Calibrated shake noise frequency (Hz) for `traumaShake`. */
221
+ export declare const CALIBRATED_TRAUMA_SHAKE_FREQUENCY = 32;
222
+ /**
223
+ * Calibrated trauma² camera shake: offset scales with `trauma` squared using
224
+ * game-feel defaults (decay 1.4/s, max offset 0.55, max roll 0.1 rad, noise
225
+ * freq 32×t) — the curve `impactPresets` trauma values are calibrated
226
+ * against, so an impact "just looks right" without hand-tuning `shakeOffset`.
227
+ *
228
+ * @capability camera-shake calibrated trauma² camera kick with zero tuning
229
+ * @internal
230
+ */
231
+ export declare function traumaShake(trauma: number, time?: number): ShakeOffset;
232
+ /** Linear cross-fade between two full camera poses (position, lookAt, fov).
233
+ * @internal
234
+ */
147
235
  export declare function crossfadePose(from: CameraPose, to: CameraPose, t: number): CameraPose;
148
236
  export interface DirectorCameraValues {
149
237
  /** `undefined` = no runtime override (fall back to static); `null` = explicitly follow nothing. */
@@ -164,7 +252,8 @@ export interface ResolvedDirectedCamera {
164
252
  * (#196.2). `director` omitted, or its fields `undefined`/`null`, is a pure
165
253
  * passthrough to `staticConfig` so mounting a director with no active override
166
254
  * changes nothing.
167
- */
255
+ * @internal
256
+ */
168
257
  export declare function resolveDirectedCamera(director: DirectorCameraValues | undefined, staticConfig: StaticCameraValues): ResolvedDirectedCamera;
169
258
  export interface CinematicSample {
170
259
  pose: CameraPose;
@@ -175,5 +264,6 @@ export interface CinematicSample {
175
264
  * travel time from the previous keyframe into it; segment easing is per the
176
265
  * destination keyframe. Reports `done` once past the final keyframe (unless
177
266
  * looping, which wraps `elapsed` into the total path duration).
178
- */
267
+ * @internal
268
+ */
179
269
  export declare function cinematicSample(keyframes: readonly CameraKeyframe[], elapsed: number, loop: boolean, fallbackFov: number): CinematicSample;
@@ -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,
@@ -213,9 +242,14 @@ export function resolveChase(config) {
213
242
  bankPerYawRate: config?.bank?.perYawRate ?? 0,
214
243
  bankMax: config?.bank?.max ?? 0.35,
215
244
  bankDamping: config?.bank?.damping ?? 8,
245
+ velocityYawBlend: config?.velocityYaw === undefined ? 0 : config.velocityYaw.blend ?? 0.65,
246
+ velocityYawMinSpeed: config?.velocityYaw?.minSpeed ?? 4,
247
+ velocityYawResponse: config?.velocityYaw?.response ?? 6,
216
248
  };
217
249
  }
218
- /** Velocity-lead the follow point (#286.9): aim `leadTime` seconds along the target's frame velocity, clamped to `leadMax`. */
250
+ /** Velocity-lead the follow point (#286.9): aim `leadTime` seconds along the target's frame velocity, clamped to `leadMax`.
251
+ * @internal
252
+ */
219
253
  export function leadFollowPoint(follow, previous, dt, resolved) {
220
254
  if (resolved.leadTime <= 0 || dt <= 0)
221
255
  return follow;
@@ -236,7 +270,9 @@ function wrapAngle(angle) {
236
270
  wrapped += Math.PI * 2;
237
271
  return wrapped;
238
272
  }
239
- /** One smoothing step of the chase rig's turn-bank roll (#286.10): roll opposes yaw rate, clamped and exponentially damped. */
273
+ /** One smoothing step of the chase rig's turn-bank roll (#286.10): roll opposes yaw rate, clamped and exponentially damped.
274
+ * @internal
275
+ */
240
276
  export function bankRollStep(currentRoll, yaw, previousYaw, dt, resolved) {
241
277
  if (resolved.bankPerYawRate <= 0)
242
278
  return 0;
@@ -244,6 +280,7 @@ export function bankRollStep(currentRoll, yaw, previousYaw, dt, resolved) {
244
280
  const target = clamp(-yawRate * resolved.bankPerYawRate, -resolved.bankMax, resolved.bankMax);
245
281
  return currentRoll + (target - currentRoll) * Math.min(1, resolved.bankDamping * dt);
246
282
  }
283
+ /** @internal */
247
284
  export function resolveObserver(config) {
248
285
  return {
249
286
  distance: config?.distance ?? 8,
@@ -252,7 +289,9 @@ export function resolveObserver(config) {
252
289
  orbitSpeed: config?.orbitSpeed ?? 0.2,
253
290
  };
254
291
  }
255
- /** Detached spectator pose: orbits `subject` at a fixed distance/height, never reading player input. */
292
+ /** Detached spectator pose: orbits `subject` at a fixed distance/height, never reading player input.
293
+ * @internal
294
+ */
256
295
  export function observerPose(subject, angle, resolved, fov) {
257
296
  const position = {
258
297
  x: subject.x + Math.sin(angle) * resolved.distance,
@@ -265,7 +304,9 @@ export function observerPose(subject, angle, resolved, fov) {
265
304
  fov,
266
305
  };
267
306
  }
268
- /** Desired chase-camera position behind a vehicle facing `yaw` (before spring smoothing). */
307
+ /** Desired chase-camera position behind a vehicle facing `yaw` (before spring smoothing).
308
+ * @internal
309
+ */
269
310
  export function chaseDesiredPosition(follow, yaw, resolved) {
270
311
  const back = forwardVector(yaw);
271
312
  return {
@@ -274,7 +315,9 @@ export function chaseDesiredPosition(follow, yaw, resolved) {
274
315
  z: follow.z - back.z * resolved.distance,
275
316
  };
276
317
  }
277
- /** Look point ahead of / above a chased vehicle. */
318
+ /** Look point ahead of / above a chased vehicle.
319
+ * @internal
320
+ */
278
321
  export function chaseLookAt(follow, yaw, resolved) {
279
322
  const forward = forwardVector(yaw);
280
323
  return {
@@ -283,7 +326,35 @@ export function chaseLookAt(follow, yaw, resolved) {
283
326
  z: follow.z + forward.z * 2,
284
327
  };
285
328
  }
286
- /** World-space seat pose (cockpit/hood/rear) rigidly attached to the vehicle. */
329
+ /**
330
+ * Drift-lag (#1051): the yaw the chase anchor should aim before temporal
331
+ * smoothing. When the target slides, its planar `velocity` diverges from its
332
+ * `heading`; this rotates the anchor from heading partway toward the velocity
333
+ * direction so the camera reveals the car's side while travel stays framed. The
334
+ * traversed fraction is `velocityYawBlend` scaled by how far the slip angle has
335
+ * opened (0 at straight-line travel, full at a 90° slide), so ordinary driving
336
+ * is untouched. Returns the raw heading — no swing — when the feature is off,
337
+ * when planar speed is below `velocityYawMinSpeed`, or when the target is
338
+ * reversing (velocity opposed to heading forward). Blending is shortest-arc, so
339
+ * it stays correct across the ±PI wrap seam.
340
+ * @internal
341
+ */
342
+ export function velocityYawTarget(heading, velocity, resolved) {
343
+ if (resolved.velocityYawBlend <= 0)
344
+ return heading;
345
+ const speed = Math.hypot(velocity.x, velocity.z);
346
+ if (speed < resolved.velocityYawMinSpeed)
347
+ return heading;
348
+ const forward = forwardVector(heading);
349
+ if (forward.x * velocity.x + forward.z * velocity.z < 0)
350
+ return heading;
351
+ const slip = angleDelta(heading, Math.atan2(velocity.x, velocity.z));
352
+ const slipFraction = clamp(Math.abs(slip) / (Math.PI / 2), 0, 1);
353
+ return heading + slip * resolved.velocityYawBlend * slipFraction;
354
+ }
355
+ /** World-space seat pose (cockpit/hood/rear) rigidly attached to the vehicle.
356
+ * @internal
357
+ */
287
358
  export function seatPose(follow, yaw, local, fov) {
288
359
  const forward = forwardVector(yaw);
289
360
  const right = rightVector(yaw);
@@ -301,14 +372,19 @@ export function seatPose(follow, yaw, local, fov) {
301
372
  fov,
302
373
  };
303
374
  }
375
+ /** @internal */
304
376
  export function createTrauma() {
305
377
  return { trauma: 0, time: 0 };
306
378
  }
307
- /** Add trauma (0..1) and clamp; larger hits raise the ceiling toward 1. */
379
+ /** Add trauma (0..1) and clamp; larger hits raise the ceiling toward 1.
380
+ * @internal
381
+ */
308
382
  export function addTrauma(state, amount) {
309
383
  state.trauma = clamp(state.trauma + amount, 0, 1);
310
384
  }
311
- /** Decay trauma linearly toward 0 and advance the shake clock. */
385
+ /** Decay trauma linearly toward 0 and advance the shake clock.
386
+ * @internal
387
+ */
312
388
  export function stepTrauma(state, decayPerSecond, dt) {
313
389
  state.time += dt;
314
390
  state.trauma = clamp(state.trauma - decayPerSecond * dt, 0, 1);
@@ -321,7 +397,8 @@ function hashNoise(seed, time, frequency) {
321
397
  * Positional + roll shake for the current trauma. Shake magnitude is
322
398
  * `trauma^exponent` so small hits stay subtle; the oscillation is deterministic
323
399
  * per-seed pseudo-noise (no per-frame RNG, so identical inputs reproduce).
324
- */
400
+ * @internal
401
+ */
325
402
  export function shakeOffset(state, config) {
326
403
  const maxOffset = config?.maxOffset ?? 0.5;
327
404
  const maxRoll = config?.maxRoll ?? 0.06;
@@ -336,7 +413,33 @@ export function shakeOffset(state, config) {
336
413
  roll: maxRoll * shake * hashNoise(3, state.time, frequency),
337
414
  };
338
415
  }
339
- /** Linear cross-fade between two full camera poses (position, lookAt, fov). */
416
+ /** Calibrated trauma decay for `traumaShake`/`impactPresets` (trauma/second). */
417
+ export const CALIBRATED_TRAUMA_SHAKE_DECAY_PER_SECOND = 1.4;
418
+ /** Calibrated positional shake amplitude at full trauma (world units) for `traumaShake`. */
419
+ export const CALIBRATED_TRAUMA_SHAKE_MAX_OFFSET = 0.55;
420
+ /** Calibrated rotational shake amplitude at full trauma (radians) for `traumaShake`. */
421
+ export const CALIBRATED_TRAUMA_SHAKE_MAX_ROLL = 0.1;
422
+ /** Calibrated shake noise frequency (Hz) for `traumaShake`. */
423
+ export const CALIBRATED_TRAUMA_SHAKE_FREQUENCY = 32;
424
+ /**
425
+ * Calibrated trauma² camera shake: offset scales with `trauma` squared using
426
+ * game-feel defaults (decay 1.4/s, max offset 0.55, max roll 0.1 rad, noise
427
+ * freq 32×t) — the curve `impactPresets` trauma values are calibrated
428
+ * against, so an impact "just looks right" without hand-tuning `shakeOffset`.
429
+ *
430
+ * @capability camera-shake calibrated trauma² camera kick with zero tuning
431
+ * @internal
432
+ */
433
+ export function traumaShake(trauma, time = 0) {
434
+ return shakeOffset({ trauma: clamp(trauma, 0, 1), time }, {
435
+ maxOffset: CALIBRATED_TRAUMA_SHAKE_MAX_OFFSET,
436
+ maxRoll: CALIBRATED_TRAUMA_SHAKE_MAX_ROLL,
437
+ frequency: CALIBRATED_TRAUMA_SHAKE_FREQUENCY,
438
+ });
439
+ }
440
+ /** Linear cross-fade between two full camera poses (position, lookAt, fov).
441
+ * @internal
442
+ */
340
443
  export function crossfadePose(from, to, t) {
341
444
  const blend = clamp(t, 0, 1);
342
445
  return {
@@ -350,7 +453,8 @@ export function crossfadePose(from, to, t) {
350
453
  * (#196.2). `director` omitted, or its fields `undefined`/`null`, is a pure
351
454
  * passthrough to `staticConfig` so mounting a director with no active override
352
455
  * changes nothing.
353
- */
456
+ * @internal
457
+ */
354
458
  export function resolveDirectedCamera(director, staticConfig) {
355
459
  const directedFollow = director?.followEntityId;
356
460
  const followEntityId = directedFollow === undefined ? staticConfig.followEntityId : directedFollow;
@@ -363,7 +467,8 @@ export function resolveDirectedCamera(director, staticConfig) {
363
467
  * travel time from the previous keyframe into it; segment easing is per the
364
468
  * destination keyframe. Reports `done` once past the final keyframe (unless
365
469
  * looping, which wraps `elapsed` into the total path duration).
366
- */
470
+ * @internal
471
+ */
367
472
  export function cinematicSample(keyframes, elapsed, loop, fallbackFov) {
368
473
  if (keyframes.length === 0) {
369
474
  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
  }