@aura3d/engine 4.1.3 → 4.3.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 (281) hide show
  1. package/README.md +3 -3
  2. package/dist/aura3d-cli/cli-help.d.ts.map +1 -1
  3. package/dist/aura3d-cli/cli-help.js +4 -2
  4. package/dist/aura3d-cli/cli-help.js.map +1 -1
  5. package/dist/aura3d-cli/cli.d.ts.map +1 -1
  6. package/dist/aura3d-cli/cli.js +129 -19
  7. package/dist/aura3d-cli/cli.js.map +1 -1
  8. package/dist/aura3d-cli/commands/assets/index.js +2 -2
  9. package/dist/aura3d-cli/commands/assets/index.js.map +1 -1
  10. package/dist/aura3d-cli/commands/meshyLedger.d.ts +125 -14
  11. package/dist/aura3d-cli/commands/meshyLedger.d.ts.map +1 -1
  12. package/dist/aura3d-cli/commands/meshyLedger.js +262 -35
  13. package/dist/aura3d-cli/commands/meshyLedger.js.map +1 -1
  14. package/dist/aura3d-cli/commands/prd13/run.js +19 -16
  15. package/dist/aura3d-cli/commands/prd13/run.js.map +1 -1
  16. package/dist/aura3d-cli/index.d.ts +8 -0
  17. package/dist/aura3d-cli/index.d.ts.map +1 -1
  18. package/dist/aura3d-cli/index.js +12 -0
  19. package/dist/aura3d-cli/index.js.map +1 -1
  20. package/dist/aura3d-cli/pull-bridge/adapters.d.ts +9 -1
  21. package/dist/aura3d-cli/pull-bridge/adapters.d.ts.map +1 -1
  22. package/dist/aura3d-cli/pull-bridge/adapters.js +30 -7
  23. package/dist/aura3d-cli/pull-bridge/adapters.js.map +1 -1
  24. package/dist/aura3d-cli/pull-bridge/search.d.ts +5 -0
  25. package/dist/aura3d-cli/pull-bridge/search.d.ts.map +1 -1
  26. package/dist/aura3d-cli/pull-bridge/search.js +7 -1
  27. package/dist/aura3d-cli/pull-bridge/search.js.map +1 -1
  28. package/dist/aura3d-cli/pull-bridge.js +1 -1
  29. package/dist/aura3d-cli/pull-bridge.js.map +1 -1
  30. package/dist/aura3d-cli/resolve-ladder.d.ts +123 -0
  31. package/dist/aura3d-cli/resolve-ladder.d.ts.map +1 -0
  32. package/dist/aura3d-cli/resolve-ladder.js +410 -0
  33. package/dist/aura3d-cli/resolve-ladder.js.map +1 -0
  34. package/dist/aura3d-cli/skin/analysis.d.ts +137 -0
  35. package/dist/aura3d-cli/skin/analysis.d.ts.map +1 -0
  36. package/dist/aura3d-cli/skin/analysis.js +382 -0
  37. package/dist/aura3d-cli/skin/analysis.js.map +1 -0
  38. package/dist/aura3d-cli/skin/command.d.ts +71 -0
  39. package/dist/aura3d-cli/skin/command.d.ts.map +1 -0
  40. package/dist/aura3d-cli/skin/command.js +186 -0
  41. package/dist/aura3d-cli/skin/command.js.map +1 -0
  42. package/dist/aura3d-cli/skin/glbEdit.d.ts +14 -0
  43. package/dist/aura3d-cli/skin/glbEdit.d.ts.map +1 -0
  44. package/dist/aura3d-cli/skin/glbEdit.js +152 -0
  45. package/dist/aura3d-cli/skin/glbEdit.js.map +1 -0
  46. package/dist/aura3d-cli/skin/gltf.d.ts +159 -0
  47. package/dist/aura3d-cli/skin/gltf.d.ts.map +1 -0
  48. package/dist/aura3d-cli/skin/gltf.js +379 -0
  49. package/dist/aura3d-cli/skin/gltf.js.map +1 -0
  50. package/dist/aura3d-cli/skin/rebuildLimbs.d.ts +31 -0
  51. package/dist/aura3d-cli/skin/rebuildLimbs.d.ts.map +1 -0
  52. package/dist/aura3d-cli/skin/rebuildLimbs.js +326 -0
  53. package/dist/aura3d-cli/skin/rebuildLimbs.js.map +1 -0
  54. package/dist/aura3d-cli/skin/repair.d.ts +41 -0
  55. package/dist/aura3d-cli/skin/repair.d.ts.map +1 -0
  56. package/dist/aura3d-cli/skin/repair.js +180 -0
  57. package/dist/aura3d-cli/skin/repair.js.map +1 -0
  58. package/dist/create-aura3d/index.js +1 -1
  59. package/dist/debug/index.d.ts +2 -2
  60. package/dist/debug/index.d.ts.map +1 -1
  61. package/dist/debug/index.js +1 -1
  62. package/dist/debug/index.js.map +1 -1
  63. package/dist/debug/safety/frameBoundary.d.ts +33 -0
  64. package/dist/debug/safety/frameBoundary.d.ts.map +1 -0
  65. package/dist/debug/safety/frameBoundary.js +40 -0
  66. package/dist/debug/safety/frameBoundary.js.map +1 -0
  67. package/dist/debug/safety/index.d.ts +1 -0
  68. package/dist/debug/safety/index.d.ts.map +1 -1
  69. package/dist/debug/safety/index.js +1 -0
  70. package/dist/debug/safety/index.js.map +1 -1
  71. package/dist/engine/agent-api/app/actorBoneMatrixLookup.d.ts +22 -0
  72. package/dist/engine/agent-api/app/actorBoneMatrixLookup.d.ts.map +1 -0
  73. package/dist/engine/agent-api/app/actorBoneMatrixLookup.js +24 -0
  74. package/dist/engine/agent-api/app/actorBoneMatrixLookup.js.map +1 -0
  75. package/dist/engine/agent-api/app/canvas.d.ts +16 -0
  76. package/dist/engine/agent-api/app/canvas.d.ts.map +1 -1
  77. package/dist/engine/agent-api/app/canvas.js +15 -0
  78. package/dist/engine/agent-api/app/canvas.js.map +1 -1
  79. package/dist/engine/agent-api/app/createAuraApp.d.ts.map +1 -1
  80. package/dist/engine/agent-api/app/createAuraApp.js +21 -3
  81. package/dist/engine/agent-api/app/createAuraApp.js.map +1 -1
  82. package/dist/engine/agent-api/app/frameLoop.d.ts.map +1 -1
  83. package/dist/engine/agent-api/app/frameLoop.js +21 -3
  84. package/dist/engine/agent-api/app/frameLoop.js.map +1 -1
  85. package/dist/engine/agent-api/app/mountFailure.d.ts +6 -0
  86. package/dist/engine/agent-api/app/mountFailure.d.ts.map +1 -0
  87. package/dist/engine/agent-api/app/mountFailure.js +9 -0
  88. package/dist/engine/agent-api/app/mountFailure.js.map +1 -0
  89. package/dist/engine/agent-api/app/parentFit.d.ts +35 -0
  90. package/dist/engine/agent-api/app/parentFit.d.ts.map +1 -0
  91. package/dist/engine/agent-api/app/parentFit.js +36 -0
  92. package/dist/engine/agent-api/app/parentFit.js.map +1 -0
  93. package/dist/engine/agent-api/compiler/customMaterial.d.ts.map +1 -1
  94. package/dist/engine/agent-api/compiler/customMaterial.js +15 -3
  95. package/dist/engine/agent-api/compiler/customMaterial.js.map +1 -1
  96. package/dist/engine/agent-api/nodes/batched.d.ts +10 -0
  97. package/dist/engine/agent-api/nodes/batched.d.ts.map +1 -1
  98. package/dist/engine/agent-api/nodes/batched.js +7 -5
  99. package/dist/engine/agent-api/nodes/batched.js.map +1 -1
  100. package/dist/engine/agent-api/nodes/builder.d.ts +13 -0
  101. package/dist/engine/agent-api/nodes/builder.d.ts.map +1 -1
  102. package/dist/engine/agent-api/nodes/builder.js +7 -3
  103. package/dist/engine/agent-api/nodes/builder.js.map +1 -1
  104. package/dist/engine/agent-api/nodes/instancedMesh.d.ts +10 -0
  105. package/dist/engine/agent-api/nodes/instancedMesh.d.ts.map +1 -1
  106. package/dist/engine/agent-api/nodes/instancedMesh.js +7 -5
  107. package/dist/engine/agent-api/nodes/instancedMesh.js.map +1 -1
  108. package/dist/engine/agent-api/nodes/types.d.ts +6 -0
  109. package/dist/engine/agent-api/nodes/types.d.ts.map +1 -1
  110. package/dist/engine/lanes/prd06.d.ts.map +1 -1
  111. package/dist/engine/lanes/prd06.js +1 -16
  112. package/dist/engine/lanes/prd06.js.map +1 -1
  113. package/dist/engine/qa/fixedStepLoop.d.ts +2 -0
  114. package/dist/engine/qa/fixedStepLoop.d.ts.map +1 -1
  115. package/dist/engine/qa/fixedStepLoop.js +3 -0
  116. package/dist/engine/qa/fixedStepLoop.js.map +1 -1
  117. package/dist/game/evidence/textureStatus.d.ts +24 -0
  118. package/dist/game/evidence/textureStatus.d.ts.map +1 -0
  119. package/dist/game/evidence/textureStatus.js +27 -0
  120. package/dist/game/evidence/textureStatus.js.map +1 -0
  121. package/dist/game/index.d.ts +5 -0
  122. package/dist/game/index.d.ts.map +1 -1
  123. package/dist/game/index.js +3 -0
  124. package/dist/game/index.js.map +1 -1
  125. package/dist/game/motion/boneAttach.d.ts +42 -0
  126. package/dist/game/motion/boneAttach.d.ts.map +1 -0
  127. package/dist/game/motion/boneAttach.js +166 -0
  128. package/dist/game/motion/boneAttach.js.map +1 -0
  129. package/dist/game/motion/cameraClear.d.ts +35 -0
  130. package/dist/game/motion/cameraClear.d.ts.map +1 -0
  131. package/dist/game/motion/cameraClear.js +64 -0
  132. package/dist/game/motion/cameraClear.js.map +1 -0
  133. package/dist/game/motion/doubleFrame.d.ts +37 -0
  134. package/dist/game/motion/doubleFrame.d.ts.map +1 -0
  135. package/dist/game/motion/doubleFrame.js +59 -0
  136. package/dist/game/motion/doubleFrame.js.map +1 -0
  137. package/dist/game/motion/footSlide.d.ts +32 -0
  138. package/dist/game/motion/footSlide.d.ts.map +1 -0
  139. package/dist/game/motion/footSlide.js +59 -0
  140. package/dist/game/motion/footSlide.js.map +1 -0
  141. package/dist/game/motion/handBounce.d.ts +206 -0
  142. package/dist/game/motion/handBounce.d.ts.map +1 -0
  143. package/dist/game/motion/handBounce.js +267 -0
  144. package/dist/game/motion/handBounce.js.map +1 -0
  145. package/dist/game/motion/impact.d.ts +113 -0
  146. package/dist/game/motion/impact.d.ts.map +1 -0
  147. package/dist/game/motion/impact.js +233 -0
  148. package/dist/game/motion/impact.js.map +1 -0
  149. package/dist/game/motion/index.d.ts +21 -0
  150. package/dist/game/motion/index.d.ts.map +1 -0
  151. package/dist/game/motion/index.js +11 -0
  152. package/dist/game/motion/index.js.map +1 -0
  153. package/dist/game/motion/locomotion.d.ts +55 -0
  154. package/dist/game/motion/locomotion.d.ts.map +1 -0
  155. package/dist/game/motion/locomotion.js +107 -0
  156. package/dist/game/motion/locomotion.js.map +1 -0
  157. package/dist/game/motion/motionGate.d.ts +41 -0
  158. package/dist/game/motion/motionGate.d.ts.map +1 -0
  159. package/dist/game/motion/motionGate.js +71 -0
  160. package/dist/game/motion/motionGate.js.map +1 -0
  161. package/dist/game/motion/presenter.d.ts +37 -0
  162. package/dist/game/motion/presenter.d.ts.map +1 -0
  163. package/dist/game/motion/presenter.js +72 -0
  164. package/dist/game/motion/presenter.js.map +1 -0
  165. package/dist/game/motion/smoothing.d.ts +34 -0
  166. package/dist/game/motion/smoothing.d.ts.map +1 -0
  167. package/dist/game/motion/smoothing.js +92 -0
  168. package/dist/game/motion/smoothing.js.map +1 -0
  169. package/dist/game/session/warmPrograms.d.ts +75 -0
  170. package/dist/game/session/warmPrograms.d.ts.map +1 -0
  171. package/dist/game/session/warmPrograms.js +80 -0
  172. package/dist/game/session/warmPrograms.js.map +1 -0
  173. package/dist/physics/ensure.d.ts +2 -0
  174. package/dist/physics/ensure.d.ts.map +1 -0
  175. package/dist/physics/ensure.js +4 -0
  176. package/dist/physics/ensure.js.map +1 -0
  177. package/dist/physics/index.d.ts +1 -0
  178. package/dist/physics/index.d.ts.map +1 -1
  179. package/dist/physics/index.js +1 -0
  180. package/dist/physics/index.js.map +1 -1
  181. package/dist/physics/world.d.ts +1 -0
  182. package/dist/physics/world.d.ts.map +1 -1
  183. package/dist/physics/world.js +1 -0
  184. package/dist/physics/world.js.map +1 -1
  185. package/dist/physics-rapier/index.d.ts +2 -0
  186. package/dist/physics-rapier/index.d.ts.map +1 -1
  187. package/dist/physics-rapier/index.js +12 -10
  188. package/dist/physics-rapier/index.js.map +1 -1
  189. package/dist/physics-rapier/rapierInit.d.ts +6 -0
  190. package/dist/physics-rapier/rapierInit.d.ts.map +1 -0
  191. package/dist/physics-rapier/rapierInit.js +12 -0
  192. package/dist/physics-rapier/rapierInit.js.map +1 -0
  193. package/dist/physics-rapier/rapierInit.lazy.d.ts +6 -0
  194. package/dist/physics-rapier/rapierInit.lazy.d.ts.map +1 -0
  195. package/dist/physics-rapier/rapierInit.lazy.js +19 -0
  196. package/dist/physics-rapier/rapierInit.lazy.js.map +1 -0
  197. package/dist/rendering/DepthPass.d.ts.map +1 -1
  198. package/dist/rendering/DepthPass.js +30 -8
  199. package/dist/rendering/DepthPass.js.map +1 -1
  200. package/dist/rendering/ForwardPass.d.ts.map +1 -1
  201. package/dist/rendering/ForwardPass.js +7 -0
  202. package/dist/rendering/ForwardPass.js.map +1 -1
  203. package/dist/rendering/Renderer.d.ts +0 -2
  204. package/dist/rendering/Renderer.d.ts.map +1 -1
  205. package/dist/rendering/Renderer.js +6 -16
  206. package/dist/rendering/Renderer.js.map +1 -1
  207. package/dist/rendering/contracts/output.d.ts +9 -1
  208. package/dist/rendering/contracts/output.d.ts.map +1 -1
  209. package/dist/rendering/contracts/output.js.map +1 -1
  210. package/dist/rendering/environment/EnvironmentCache.d.ts.map +1 -1
  211. package/dist/rendering/environment/EnvironmentCache.js +6 -1
  212. package/dist/rendering/environment/EnvironmentCache.js.map +1 -1
  213. package/dist/rendering/environment/neutralEmbedded.d.ts +5 -0
  214. package/dist/rendering/environment/neutralEmbedded.d.ts.map +1 -0
  215. package/dist/rendering/environment/neutralEmbedded.js +1118 -0
  216. package/dist/rendering/environment/neutralEmbedded.js.map +1 -0
  217. package/dist/rendering/environment/neutralEmbeddedLoader.d.ts +5 -0
  218. package/dist/rendering/environment/neutralEmbeddedLoader.d.ts.map +1 -0
  219. package/dist/rendering/environment/neutralEmbeddedLoader.js +32 -0
  220. package/dist/rendering/environment/neutralEmbeddedLoader.js.map +1 -0
  221. package/dist/rendering/output/OutputPass.d.ts +2 -0
  222. package/dist/rendering/output/OutputPass.d.ts.map +1 -1
  223. package/dist/rendering/output/OutputPass.js +26 -3
  224. package/dist/rendering/output/OutputPass.js.map +1 -1
  225. package/dist/rendering/output/ToneMappingOperators.glsl.d.ts +3 -1
  226. package/dist/rendering/output/ToneMappingOperators.glsl.d.ts.map +1 -1
  227. package/dist/rendering/output/ToneMappingOperators.glsl.js +19 -1
  228. package/dist/rendering/output/ToneMappingOperators.glsl.js.map +1 -1
  229. package/dist/rendering/post/v2Stages.d.ts +2 -7
  230. package/dist/rendering/post/v2Stages.d.ts.map +1 -1
  231. package/dist/rendering/post/v2Stages.js +2 -17
  232. package/dist/rendering/post/v2Stages.js.map +1 -1
  233. package/dist/rendering/post/vignetteColor.d.ts +8 -0
  234. package/dist/rendering/post/vignetteColor.d.ts.map +1 -0
  235. package/dist/rendering/post/vignetteColor.js +18 -0
  236. package/dist/rendering/post/vignetteColor.js.map +1 -0
  237. package/dist/rendering/renderer/PostprocessExecution.d.ts +10 -0
  238. package/dist/rendering/renderer/PostprocessExecution.d.ts.map +1 -1
  239. package/dist/rendering/renderer/PostprocessExecution.js +38 -38
  240. package/dist/rendering/renderer/PostprocessExecution.js.map +1 -1
  241. package/dist/rendering/renderer/coreOutputPostRoute.d.ts +25 -17
  242. package/dist/rendering/renderer/coreOutputPostRoute.d.ts.map +1 -1
  243. package/dist/rendering/renderer/coreOutputPostRoute.js +27 -18
  244. package/dist/rendering/renderer/coreOutputPostRoute.js.map +1 -1
  245. package/dist/rendering/renderer/qrSubFlags.d.ts +1 -1
  246. package/dist/rendering/renderer/qrSubFlags.d.ts.map +1 -1
  247. package/dist/rendering/renderer/qrSubFlags.js +2 -8
  248. package/dist/rendering/renderer/qrSubFlags.js.map +1 -1
  249. package/dist/rendering/shaders/chunks/author/index.d.ts.map +1 -1
  250. package/dist/rendering/shaders/chunks/author/index.js +7 -0
  251. package/dist/rendering/shaders/chunks/author/index.js.map +1 -1
  252. package/dist/rendering/shaders/chunks/author/shadow.glsl.d.ts +11 -0
  253. package/dist/rendering/shaders/chunks/author/shadow.glsl.d.ts.map +1 -0
  254. package/dist/rendering/shaders/chunks/author/shadow.glsl.js +57 -0
  255. package/dist/rendering/shaders/chunks/author/shadow.glsl.js.map +1 -0
  256. package/dist/rendering/shadows/DirectionalCascadeFitter.d.ts +20 -0
  257. package/dist/rendering/shadows/DirectionalCascadeFitter.d.ts.map +1 -1
  258. package/dist/rendering/shadows/DirectionalCascadeFitter.js +80 -7
  259. package/dist/rendering/shadows/DirectionalCascadeFitter.js.map +1 -1
  260. package/dist/rendering/shadows/Prd02DepthShaderLibrary.d.ts.map +1 -1
  261. package/dist/rendering/shadows/Prd02DepthShaderLibrary.js +9 -1
  262. package/dist/rendering/shadows/Prd02DepthShaderLibrary.js.map +1 -1
  263. package/dist/rendering/shadows/ShadowSystem.d.ts.map +1 -1
  264. package/dist/rendering/shadows/ShadowSystem.js +7 -2
  265. package/dist/rendering/shadows/ShadowSystem.js.map +1 -1
  266. package/dist/rendering/webgl2/LdrPostprocessShader.d.ts +2 -0
  267. package/dist/rendering/webgl2/LdrPostprocessShader.d.ts.map +1 -1
  268. package/dist/rendering/webgl2/LdrPostprocessShader.js +25 -3
  269. package/dist/rendering/webgl2/LdrPostprocessShader.js.map +1 -1
  270. package/dist/rendering/webgl2/LegacyPost.d.ts +11 -2
  271. package/dist/rendering/webgl2/LegacyPost.d.ts.map +1 -1
  272. package/dist/rendering/webgl2/LegacyPost.js +191 -16
  273. package/dist/rendering/webgl2/LegacyPost.js.map +1 -1
  274. package/package.json +33 -26
  275. package/templates/cinematic-scene/package.json +2 -2
  276. package/templates/mini-game/package.json +2 -2
  277. package/templates/product-viewer/package.json +2 -2
  278. package/templates/production-asset-inspector/package.json +1 -1
  279. package/templates/production-material-studio/package.json +1 -1
  280. package/templates/production-product-configurator/package.json +1 -1
  281. package/templates/production-product-viewer/package.json +1 -1
@@ -0,0 +1,267 @@
1
+ import { resolveBone } from "./boneAttach.js";
2
+ const lerp = (a, b, t) => a + (b - a) * t;
3
+ const smoothstep = (t) => (t <= 0 ? 0 : t >= 1 ? 1 : t * t * (3 - 2 * t));
4
+ export function resolveHandBounceConfig(options = {}) {
5
+ const ballRadius = options.ballRadius ?? 0.13;
6
+ const floorY = options.floorY ?? 0;
7
+ return {
8
+ hand: options.hand ?? "right",
9
+ ballRadius,
10
+ floorY,
11
+ armReach: options.armReach ?? 0.55,
12
+ ballGap: options.ballGap ?? 0.09,
13
+ standing: { period: 0.46, palmTop: 1.02, palmPush: 0.62, ...options.standing },
14
+ running: { period: 0.3, palmTop: 0.92, palmPush: 0.6, ...options.running },
15
+ runSpeed: options.runSpeed ?? 0.45,
16
+ phases: { rideEnd: 0.35, palmTurn: 0.6, floorAt: 0.66, catchFrom: 0.92, ...options.phases },
17
+ floorBallY: floorY + ballRadius
18
+ };
19
+ }
20
+ /** Palm height, ball height and body effort for phase `t` (0..1). `shoulderY` is the live world Y of the dribbling shoulder. */
21
+ export function handBounceCycle(config, t, shoulderY, moving = false) {
22
+ const gait = moving ? config.running : config.standing;
23
+ const { rideEnd, palmTurn, floorAt } = config.phases;
24
+ const top = Math.min(config.floorY + gait.palmTop, shoulderY - 0.3);
25
+ const push = Math.max(config.floorY + gait.palmPush, shoulderY - config.armReach);
26
+ const low = push - 0.04;
27
+ let palmY;
28
+ let effort;
29
+ if (t < rideEnd) {
30
+ const s = t / rideEnd;
31
+ effort = Math.pow(s, 1.6);
32
+ palmY = lerp(top, push, effort);
33
+ }
34
+ else if (t < palmTurn) {
35
+ const s = (t - rideEnd) / (palmTurn - rideEnd);
36
+ effort = 1;
37
+ palmY = lerp(push, low, 1 - (1 - s) * (1 - s));
38
+ }
39
+ else {
40
+ const s = (t - palmTurn) / (1 - palmTurn);
41
+ effort = t < floorAt ? 1 : 1 - smoothstep((t - floorAt) / (1 - floorAt));
42
+ palmY = lerp(low, top, smoothstep(s));
43
+ }
44
+ return { palmY, ballY: handBounceBallY(config, t, palmY, push - config.ballGap, top - config.ballGap), effort };
45
+ }
46
+ /**
47
+ * Ball centre height for phase `t`. `palmY` is the palm the ball rides while in contact (pass the RENDERED palm so the ball
48
+ * cannot leave a hand that could not follow its target); `releaseY` is the ball height when it leaves the palm and `catchY`
49
+ * the height of the palm that receives it. In the air the ball falls to the floor and rebounds, so the bounce point is always
50
+ * `config.floorBallY`.
51
+ */
52
+ export function handBounceBallY(config, t, palmY, releaseY, catchY) {
53
+ const { rideEnd, floorAt, catchFrom } = config.phases;
54
+ if (t < rideEnd)
55
+ return palmY - config.ballGap;
56
+ if (t < floorAt) {
57
+ const s = (t - rideEnd) / (floorAt - rideEnd);
58
+ return lerp(releaseY, config.floorBallY, Math.pow(s, 1.2));
59
+ }
60
+ if (t >= catchFrom)
61
+ return palmY - config.ballGap;
62
+ const s = (t - floorAt) / (catchFrom - floorAt);
63
+ return lerp(config.floorBallY, catchY, 1 - Math.pow(1 - s, 1.7));
64
+ }
65
+ /**
66
+ * 1 while the palm is on the ball (riding down, and the catch at the top), 0 while the ball is free in the air. Anything that
67
+ * offsets the ball from the palm (stride lead, outward nudge) is scaled by `1 - weight`, so the ball is glued to the palm at the
68
+ * contact points however fast the handler runs.
69
+ */
70
+ export function handBounceContactWeight(config, phase) {
71
+ const { rideEnd, floorAt, catchFrom } = config.phases;
72
+ const t = ((phase % 1) + 1) % 1;
73
+ if (t < rideEnd)
74
+ return 1;
75
+ if (t < floorAt)
76
+ return 1 - smoothstep((t - rideEnd) / 0.1);
77
+ if (t < catchFrom)
78
+ return smoothstep((t - floorAt - 0.1) / (catchFrom - floorAt - 0.1));
79
+ return 1;
80
+ }
81
+ /** Horizontal ball position: on the palm at contact, drifting ahead with the handler's stride only while the ball is in the air. */
82
+ export function handBounceBallXZ(config, palm, holder, phase) {
83
+ const free = 1 - handBounceContactWeight(config, phase);
84
+ const ox = palm[0] - holder.x;
85
+ const oz = palm[2] - holder.z;
86
+ const olen = Math.hypot(ox, oz) || 1;
87
+ return {
88
+ x: palm[0] + (ox / olen) * 0.02 * free + holder.vx * 0.04 * free,
89
+ z: palm[2] + (oz / olen) * 0.02 * free + holder.vz * 0.04 * free
90
+ };
91
+ }
92
+ /** Clamp a palm target into the arm's reach sphere around the shoulder (a target the arm cannot reach makes the hand miss the ball). */
93
+ export function clampPalmReach(shoulder, target, reach) {
94
+ const dx = target[0] - shoulder[0];
95
+ const dy = target[1] - shoulder[1];
96
+ const dz = target[2] - shoulder[2];
97
+ const d = Math.hypot(dx, dy, dz);
98
+ if (d <= reach || d < 1e-9)
99
+ return [target[0], target[1], target[2]];
100
+ const k = reach / d;
101
+ return [shoulder[0] + dx * k, shoulder[1] + dy * k, shoulder[2] + dz * k];
102
+ }
103
+ /** Upper-body pitch angles (radians, forward positive) for a handler bouncing the ball: stationary handlers crouch into the push, runners bend at the waist. */
104
+ export function handBounceOverlayAngles(effort, moving, leanScale = 1) {
105
+ if (moving) {
106
+ const lean = (1.28 + 0.77 * effort) * leanScale;
107
+ return { spine: lean * 0.55, chest: lean * 0.45, head: -lean * 0.6 };
108
+ }
109
+ return { spine: (0.2 + 0.3 * effort) * leanScale, chest: (0.12 + 0.2 * effort) * leanScale, head: -0.22 };
110
+ }
111
+ const SIDE_PREFIX = { left: "left", right: "right" };
112
+ export function createHandBounce(options = {}) {
113
+ const config = resolveHandBounceConfig(options);
114
+ const side = SIDE_PREFIX[config.hand];
115
+ const names = options.boneNames;
116
+ const pick = (role, fallback) => (names ? resolveBone(names, role) ?? fallback : fallback);
117
+ const spineName = pick("spine", "Spine");
118
+ const chestName = names ? names.find((n) => /chest/i.test(n) && !/upper/i.test(n)) ?? spineName : "Chest";
119
+ const headName = pick("head", "Head");
120
+ const armUpper = pick(`${side}UpperArm`, config.hand === "left" ? "LeftUpperArm" : "RightUpperArm");
121
+ const armFore = pick(`${side}Forearm`, config.hand === "left" ? "LeftForearm" : "RightForearm");
122
+ let phase = 0;
123
+ let moving = false;
124
+ let releaseY = config.floorBallY + 0.4;
125
+ let active = false;
126
+ let contact = 1;
127
+ let effort = 0;
128
+ let palmY = config.floorY + config.standing.palmTop;
129
+ let ball = [0, config.floorBallY, 0];
130
+ let prevBall;
131
+ let lastDt = 1 / 60;
132
+ let floorContact = false;
133
+ const frame = () => ({ phase, moving, contact, effort, palmY, ball: [ball[0], ball[1], ball[2]], floorContact });
134
+ return {
135
+ config,
136
+ step(dt, input) {
137
+ if (!(dt > 0))
138
+ throw new Error("createHandBounce.step: dt must be a positive fixed step");
139
+ moving = input.moving ?? (input.speed ?? 0) > config.runSpeed;
140
+ const gait = moving ? config.running : config.standing;
141
+ if (!active) {
142
+ active = true;
143
+ phase = 0;
144
+ prevBall = undefined;
145
+ }
146
+ phase = input.hold ? 0 : (phase + dt / gait.period) % 1;
147
+ const cyc = handBounceCycle(config, phase, input.shoulderY, moving);
148
+ effort = input.hold ? 0 : cyc.effort;
149
+ contact = handBounceContactWeight(config, phase);
150
+ prevBall = [ball[0], ball[1], ball[2]];
151
+ lastDt = dt;
152
+ if (input.palm) {
153
+ const palm = input.palm;
154
+ if (input.hold) {
155
+ ball = [palm[0], palm[1], palm[2]];
156
+ }
157
+ else {
158
+ const at = handBounceBallXZ(config, palm, input.holder, phase);
159
+ if (phase < config.phases.rideEnd)
160
+ releaseY = palm[1] - config.ballGap;
161
+ ball = [at.x, handBounceBallY(config, phase, palm[1], releaseY, palm[1] - config.ballGap), at.z];
162
+ }
163
+ palmY = palm[1];
164
+ }
165
+ else {
166
+ palmY = cyc.palmY;
167
+ ball = [input.holder.x, cyc.ballY, input.holder.z];
168
+ }
169
+ floorContact = ball[1] <= config.floorBallY + 0.02;
170
+ return frame();
171
+ },
172
+ state() {
173
+ return { phase, moving, contact, effort, palmY, ball: [ball[0], ball[1], ball[2]], releaseY, floorContact, active };
174
+ },
175
+ overlay(leanScale = 1) {
176
+ const a = handBounceOverlayAngles(effort, moving, leanScale);
177
+ return {
178
+ mode: moving ? "overlay" : "pose",
179
+ effort,
180
+ bones: { [spineName]: { pitch: a.spine }, [chestName]: { pitch: a.chest }, [headName]: { pitch: a.head } },
181
+ arm: { upper: armUpper, forearm: armFore }
182
+ };
183
+ },
184
+ release() {
185
+ const dt = Math.max(lastDt, 1e-6);
186
+ const p = prevBall ?? ball;
187
+ active = false;
188
+ return {
189
+ position: [ball[0], ball[1], ball[2]],
190
+ velocity: [(ball[0] - p[0]) / dt, (ball[1] - p[1]) / dt, (ball[2] - p[2]) / dt]
191
+ };
192
+ },
193
+ pickup(at) {
194
+ active = true;
195
+ phase = config.phases.catchFrom;
196
+ releaseY = at[1];
197
+ ball = [at[0], at[1], at[2]];
198
+ prevBall = undefined;
199
+ },
200
+ reset() {
201
+ phase = 0;
202
+ active = false;
203
+ moving = false;
204
+ prevBall = undefined;
205
+ ball = [0, config.floorBallY, 0];
206
+ }
207
+ };
208
+ }
209
+ /** Limits the Aura Hoops dribble is held to. */
210
+ export const DEFAULT_HAND_BOUNCE_LIMITS = { meet: 0.12, floorContact: 0.55, floorError: 0.02, maxDistance: 0.9 };
211
+ /** Probe: feed per-frame palm and ball world positions of a dribble; returns the distances the game must keep small. Call it from QA hooks and tools/game-checks. */
212
+ export function measureHandBall(samples, options = {}) {
213
+ const config = resolveHandBounceConfig(options);
214
+ const limits = { ...DEFAULT_HAND_BOUNCE_LIMITS, ...options.limits };
215
+ let meetMax = 0;
216
+ let floorMax = Number.NaN;
217
+ let floorPalm = Number.NaN;
218
+ let maxDistance = 0;
219
+ let lowest = Infinity;
220
+ let floorSamples = 0;
221
+ let meetSamples = 0;
222
+ let used = 0;
223
+ for (const s of samples) {
224
+ if (s.dribbling === false)
225
+ continue;
226
+ used += 1;
227
+ const d = Math.hypot(s.palm[0] - s.ball[0], s.palm[1] - s.ball[1], s.palm[2] - s.ball[2]);
228
+ maxDistance = Math.max(maxDistance, d);
229
+ lowest = Math.min(lowest, s.ball[1]);
230
+ const t = ((s.phase % 1) + 1) % 1;
231
+ if (t < 0.04 || t > config.phases.catchFrom + 0.01) {
232
+ meetMax = Math.max(meetMax, d);
233
+ meetSamples += 1;
234
+ }
235
+ if (s.ball[1] <= config.floorBallY + 0.02) {
236
+ floorMax = Number.isNaN(floorMax) ? d : Math.max(floorMax, d);
237
+ const h = s.palm[1] - config.floorY;
238
+ floorPalm = Number.isNaN(floorPalm) ? h : Math.max(floorPalm, h);
239
+ floorSamples += 1;
240
+ }
241
+ }
242
+ const floorError = used === 0 ? Number.NaN : Math.abs(lowest - config.floorBallY);
243
+ const failures = [];
244
+ if (used === 0)
245
+ failures.push("no dribble samples");
246
+ if (meetSamples > 0 && meetMax > limits.meet)
247
+ failures.push(`palm to ball at the meet ${meetMax.toFixed(3)} m > ${limits.meet} m`);
248
+ if (floorSamples > 0 && floorMax > limits.floorContact)
249
+ failures.push(`palm to ball at the floor contact ${floorMax.toFixed(3)} m > ${limits.floorContact} m`);
250
+ if (used > 0 && floorError > limits.floorError)
251
+ failures.push(`ball centre misses the floor by ${floorError.toFixed(3)} m > ${limits.floorError} m`);
252
+ if (maxDistance > limits.maxDistance)
253
+ failures.push(`ball strays ${maxDistance.toFixed(3)} m from the hand > ${limits.maxDistance} m`);
254
+ return {
255
+ samples: used,
256
+ meetMax,
257
+ floorContactMax: floorMax,
258
+ floorContactPalmHeightMax: floorPalm,
259
+ floorError,
260
+ maxDistance,
261
+ floorSamples,
262
+ meetSamples,
263
+ ok: failures.length === 0,
264
+ failures
265
+ };
266
+ }
267
+ //# sourceMappingURL=handBounce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handBounce.js","sourceRoot":"","sources":["../../../../../packages/game/src/motion/handBounce.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,113 @@
1
+ export type V3 = [number, number, number];
2
+ export interface ImpactBoxCollider {
3
+ readonly kind: "box";
4
+ readonly id: string;
5
+ readonly center: readonly [number, number, number];
6
+ readonly half: readonly [number, number, number];
7
+ /** Rotation about Y in radians. */
8
+ readonly yaw?: number;
9
+ readonly tag?: string;
10
+ readonly restitution?: number;
11
+ readonly friction?: number;
12
+ }
13
+ export interface ImpactSphereCollider {
14
+ readonly kind: "sphere";
15
+ readonly id: string;
16
+ readonly center: readonly [number, number, number];
17
+ readonly radius: number;
18
+ readonly tag?: string;
19
+ readonly restitution?: number;
20
+ readonly friction?: number;
21
+ }
22
+ export type ImpactCollider = ImpactBoxCollider | ImpactSphereCollider;
23
+ export interface ImpactBody {
24
+ position: V3;
25
+ velocity: V3;
26
+ radius: number;
27
+ }
28
+ export interface Impact {
29
+ readonly colliderId: string;
30
+ readonly tag: string | undefined;
31
+ readonly point: V3;
32
+ /** Unit normal pointing out of the collider, towards the body. */
33
+ readonly normal: V3;
34
+ /** Approach speed along the normal before the response, m/s. */
35
+ readonly speed: number;
36
+ readonly impulse: number;
37
+ }
38
+ export interface ImpactWorldOptions {
39
+ readonly colliders: readonly ImpactCollider[];
40
+ readonly restitution?: number;
41
+ readonly friction?: number;
42
+ /** Contacts slower than this resolve but do not emit an event (resting contact). Default 0.5 m/s. */
43
+ readonly eventMinSpeed?: number;
44
+ readonly onImpact?: (impact: Impact) => void;
45
+ }
46
+ export interface ImpactWorld {
47
+ step(body: ImpactBody, dt: number): Impact[];
48
+ add(collider: ImpactCollider): void;
49
+ remove(id: string): void;
50
+ reset(): void;
51
+ }
52
+ /**
53
+ * Swept-sphere collision against static boxes (optionally yawed) and spheres. A body moving fast cannot
54
+ * tunnel through a wall or gate; each new contact emits one `Impact` (continuous sliding does not repeat).
55
+ * Box corners are treated as sharp expanded boxes (slightly conservative at corners).
56
+ */
57
+ export declare function createImpactWorld(options: ImpactWorldOptions): ImpactWorld;
58
+ export interface HitStop {
59
+ trigger(ms: number): void;
60
+ update(realDtSeconds: number): void;
61
+ /** Multiply the simulation time step by this; 1 normally, near 0 during a hit-stop. */
62
+ timeScale(): number;
63
+ readonly active: boolean;
64
+ }
65
+ export declare function createHitStop(frozenScale?: number): HitStop;
66
+ export interface CameraShake {
67
+ add(trauma: number): void;
68
+ update(dt: number): {
69
+ readonly x: number;
70
+ readonly y: number;
71
+ readonly roll: number;
72
+ };
73
+ readonly trauma: number;
74
+ }
75
+ /** Trauma-based shake: offset scales with trauma squared, decays linearly, deterministic (no Math.random). */
76
+ export declare function createCameraShake(options?: {
77
+ readonly decayPerSecond?: number;
78
+ readonly maxOffset?: number;
79
+ readonly maxRoll?: number;
80
+ }): CameraShake;
81
+ export interface ParticleBurst {
82
+ readonly point: V3;
83
+ readonly normal: V3;
84
+ readonly count: number;
85
+ readonly speed: number;
86
+ }
87
+ export interface ImpactFeedbackOptions {
88
+ readonly hitStop?: HitStop;
89
+ readonly shake?: CameraShake;
90
+ /** Play a cue by name at a gain 0..1 (wire to a cue bank). */
91
+ readonly cue?: (name: string, gain: number) => void;
92
+ readonly cueName?: string;
93
+ readonly particles?: (burst: ParticleBurst) => void;
94
+ readonly onDamage?: (amount: number, impact: Impact) => void;
95
+ /** Impact speed (m/s) that maps to full strength. Default 12. */
96
+ readonly fullSpeed?: number;
97
+ /** Hit-stop duration range in ms. Defaults 30 to 80. */
98
+ readonly hitStopMs?: readonly [number, number];
99
+ readonly damagePerSpeed?: number;
100
+ readonly minSpeed?: number;
101
+ }
102
+ export interface ImpactFeedbackResult {
103
+ readonly strength: number;
104
+ readonly hitStopMs: number;
105
+ readonly trauma: number;
106
+ readonly damage: number;
107
+ readonly particleCount: number;
108
+ }
109
+ /** The standard feedback bundle for a solid hit: hit-stop, camera shake, sound, particles and damage, scaled by speed. */
110
+ export declare function createImpactFeedback(options: ImpactFeedbackOptions): {
111
+ handle(impact: Impact): ImpactFeedbackResult;
112
+ };
113
+ //# sourceMappingURL=impact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"impact.d.ts","sourceRoot":"","sources":["../../../../../packages/game/src/motion/impact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,233 @@
1
+ const EPS = 1e-9;
2
+ function rotY(v, yaw) {
3
+ const c = Math.cos(yaw);
4
+ const s = Math.sin(yaw);
5
+ return [c * v[0] + s * v[2], v[1], -s * v[0] + c * v[2]];
6
+ }
7
+ function sweepBox(p, d, radius, box) {
8
+ const yaw = box.yaw ?? 0;
9
+ const rel = [p[0] - box.center[0], p[1] - box.center[1], p[2] - box.center[2]];
10
+ const lp = rotY(rel, -yaw);
11
+ const ld = rotY(d, -yaw);
12
+ const h = [box.half[0] + radius, box.half[1] + radius, box.half[2] + radius];
13
+ const inside = Math.abs(lp[0]) < h[0] && Math.abs(lp[1]) < h[1] && Math.abs(lp[2]) < h[2];
14
+ if (inside) {
15
+ let axis = 0;
16
+ let best = Number.POSITIVE_INFINITY;
17
+ for (let i = 0; i < 3; i += 1) {
18
+ const pen = h[i] - Math.abs(lp[i]);
19
+ if (pen < best) {
20
+ best = pen;
21
+ axis = i;
22
+ }
23
+ }
24
+ const n = [0, 0, 0];
25
+ n[axis] = lp[axis] >= 0 ? 1 : -1;
26
+ return { t: 0, normal: rotY(n, yaw), collider: box };
27
+ }
28
+ let tmin = 0;
29
+ let tmax = 1;
30
+ let axisHit = -1;
31
+ let sign = 1;
32
+ for (let i = 0; i < 3; i += 1) {
33
+ const o = lp[i];
34
+ const dir = ld[i];
35
+ if (Math.abs(dir) < EPS) {
36
+ if (Math.abs(o) >= h[i])
37
+ return undefined;
38
+ continue;
39
+ }
40
+ let t1 = (-h[i] - o) / dir;
41
+ let t2 = (h[i] - o) / dir;
42
+ let s = -1;
43
+ if (t1 > t2) {
44
+ [t1, t2] = [t2, t1];
45
+ s = 1;
46
+ }
47
+ if (t1 > tmin) {
48
+ tmin = t1;
49
+ axisHit = i;
50
+ sign = s;
51
+ }
52
+ tmax = Math.min(tmax, t2);
53
+ if (tmin > tmax)
54
+ return undefined;
55
+ }
56
+ if (axisHit < 0)
57
+ return undefined;
58
+ const n = [0, 0, 0];
59
+ n[axisHit] = sign;
60
+ return { t: tmin, normal: rotY(n, yaw), collider: box };
61
+ }
62
+ function sweepSphere(p, d, radius, s) {
63
+ const R = radius + s.radius;
64
+ const m = [p[0] - s.center[0], p[1] - s.center[1], p[2] - s.center[2]];
65
+ const a = d[0] * d[0] + d[1] * d[1] + d[2] * d[2];
66
+ const c = m[0] * m[0] + m[1] * m[1] + m[2] * m[2] - R * R;
67
+ if (c < 0) {
68
+ const len = Math.hypot(m[0], m[1], m[2]) || 1;
69
+ return { t: 0, normal: [m[0] / len, m[1] / len, m[2] / len], collider: s };
70
+ }
71
+ if (a < EPS)
72
+ return undefined;
73
+ const b = m[0] * d[0] + m[1] * d[1] + m[2] * d[2];
74
+ if (b >= 0)
75
+ return undefined;
76
+ const disc = b * b - a * c;
77
+ if (disc < 0)
78
+ return undefined;
79
+ const t = (-b - Math.sqrt(disc)) / a;
80
+ if (t < 0 || t > 1)
81
+ return undefined;
82
+ const hit = [m[0] + d[0] * t, m[1] + d[1] * t, m[2] + d[2] * t];
83
+ const len = Math.hypot(hit[0], hit[1], hit[2]) || 1;
84
+ return { t, normal: [hit[0] / len, hit[1] / len, hit[2] / len], collider: s };
85
+ }
86
+ /**
87
+ * Swept-sphere collision against static boxes (optionally yawed) and spheres. A body moving fast cannot
88
+ * tunnel through a wall or gate; each new contact emits one `Impact` (continuous sliding does not repeat).
89
+ * Box corners are treated as sharp expanded boxes (slightly conservative at corners).
90
+ */
91
+ export function createImpactWorld(options) {
92
+ const colliders = new Map();
93
+ for (const c of options.colliders)
94
+ colliders.set(c.id, c);
95
+ const baseRestitution = options.restitution ?? 0.2;
96
+ const baseFriction = options.friction ?? 0.1;
97
+ const eventMin = options.eventMinSpeed ?? 0.5;
98
+ let touching = new Set();
99
+ return {
100
+ add(c) {
101
+ colliders.set(c.id, c);
102
+ },
103
+ remove(id) {
104
+ colliders.delete(id);
105
+ touching.delete(id);
106
+ },
107
+ reset() {
108
+ touching = new Set();
109
+ },
110
+ step(body, dt) {
111
+ const impacts = [];
112
+ const now = new Set();
113
+ let remaining = dt;
114
+ for (let iter = 0; iter < 4 && remaining > 0; iter += 1) {
115
+ const d = [body.velocity[0] * remaining, body.velocity[1] * remaining, body.velocity[2] * remaining];
116
+ let best;
117
+ for (const c of colliders.values()) {
118
+ const hit = c.kind === "box" ? sweepBox(body.position, d, body.radius, c) : sweepSphere(body.position, d, body.radius, c);
119
+ if (hit !== undefined && (best === undefined || hit.t < best.t))
120
+ best = hit;
121
+ }
122
+ if (best === undefined) {
123
+ body.position[0] += d[0];
124
+ body.position[1] += d[1];
125
+ body.position[2] += d[2];
126
+ remaining = 0;
127
+ break;
128
+ }
129
+ const skin = 1e-4;
130
+ const tt = Math.max(0, best.t);
131
+ body.position[0] += d[0] * tt + best.normal[0] * skin;
132
+ body.position[1] += d[1] * tt + best.normal[1] * skin;
133
+ body.position[2] += d[2] * tt + best.normal[2] * skin;
134
+ const n = best.normal;
135
+ const vn = body.velocity[0] * n[0] + body.velocity[1] * n[1] + body.velocity[2] * n[2];
136
+ const approach = Math.max(0, -vn);
137
+ const e = best.collider.restitution ?? baseRestitution;
138
+ const mu = best.collider.friction ?? baseFriction;
139
+ if (vn < 0) {
140
+ const tx = body.velocity[0] - vn * n[0];
141
+ const ty = body.velocity[1] - vn * n[1];
142
+ const tz = body.velocity[2] - vn * n[2];
143
+ const keep = Math.max(0, 1 - mu);
144
+ body.velocity[0] = tx * keep - e * vn * n[0];
145
+ body.velocity[1] = ty * keep - e * vn * n[1];
146
+ body.velocity[2] = tz * keep - e * vn * n[2];
147
+ }
148
+ const id = best.collider.id;
149
+ now.add(id);
150
+ if (!touching.has(id) && approach >= eventMin) {
151
+ const point = [body.position[0] - n[0] * body.radius, body.position[1] - n[1] * body.radius, body.position[2] - n[2] * body.radius];
152
+ const impact = { colliderId: id, tag: best.collider.tag, point, normal: [n[0], n[1], n[2]], speed: approach, impulse: approach * (1 + e) };
153
+ impacts.push(impact);
154
+ options.onImpact?.(impact);
155
+ }
156
+ remaining *= 1 - tt;
157
+ if (tt >= 1)
158
+ break;
159
+ }
160
+ touching = now;
161
+ return impacts;
162
+ }
163
+ };
164
+ }
165
+ export function createHitStop(frozenScale = 0.02) {
166
+ let remaining = 0;
167
+ return {
168
+ trigger(ms) {
169
+ remaining = Math.max(remaining, Math.max(0, ms) / 1000);
170
+ },
171
+ update(dt) {
172
+ remaining = Math.max(0, remaining - Math.max(0, dt));
173
+ },
174
+ timeScale() {
175
+ return remaining > 0 ? frozenScale : 1;
176
+ },
177
+ get active() {
178
+ return remaining > 0;
179
+ }
180
+ };
181
+ }
182
+ /** Trauma-based shake: offset scales with trauma squared, decays linearly, deterministic (no Math.random). */
183
+ export function createCameraShake(options = {}) {
184
+ const decay = options.decayPerSecond ?? 1.6;
185
+ const maxOffset = options.maxOffset ?? 0.12;
186
+ const maxRoll = options.maxRoll ?? 0.04;
187
+ let trauma = 0;
188
+ let t = 0;
189
+ return {
190
+ add(amount) {
191
+ trauma = Math.min(1, trauma + Math.max(0, amount));
192
+ },
193
+ update(dt) {
194
+ t += Math.max(0, dt);
195
+ trauma = Math.max(0, trauma - decay * Math.max(0, dt));
196
+ const s = trauma * trauma;
197
+ return {
198
+ x: s * maxOffset * Math.sin(t * 61.3 + 1.7),
199
+ y: s * maxOffset * Math.sin(t * 47.9 + 4.1),
200
+ roll: s * maxRoll * Math.sin(t * 39.1 + 2.9)
201
+ };
202
+ },
203
+ get trauma() {
204
+ return trauma;
205
+ }
206
+ };
207
+ }
208
+ /** The standard feedback bundle for a solid hit: hit-stop, camera shake, sound, particles and damage, scaled by speed. */
209
+ export function createImpactFeedback(options) {
210
+ const full = options.fullSpeed ?? 12;
211
+ const [msLo, msHi] = options.hitStopMs ?? [30, 80];
212
+ const minSpeed = options.minSpeed ?? 0.5;
213
+ return {
214
+ handle(impact) {
215
+ const strength = Math.max(0, Math.min(1, impact.speed / full));
216
+ if (impact.speed < minSpeed)
217
+ return { strength, hitStopMs: 0, trauma: 0, damage: 0, particleCount: 0 };
218
+ const hitStopMs = msLo + (msHi - msLo) * strength;
219
+ const trauma = 0.2 + 0.8 * strength;
220
+ const damage = (options.damagePerSpeed ?? 0) * impact.speed;
221
+ const particleCount = Math.round(4 + 28 * strength);
222
+ options.hitStop?.trigger(hitStopMs);
223
+ options.shake?.add(trauma);
224
+ if (options.cue !== undefined)
225
+ options.cue(options.cueName ?? "impact", 0.25 + 0.75 * strength);
226
+ options.particles?.({ point: impact.point, normal: impact.normal, count: particleCount, speed: 1 + 5 * strength });
227
+ if (damage > 0)
228
+ options.onDamage?.(damage, impact);
229
+ return { strength, hitStopMs, trauma, damage, particleCount };
230
+ }
231
+ };
232
+ }
233
+ //# sourceMappingURL=impact.js.map