@flighthq/physics3d 0.4.0-next.1694.598ef6f

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 (109) hide show
  1. package/dist/contacts.d.ts +4 -0
  2. package/dist/contacts.d.ts.map +1 -0
  3. package/dist/contacts.js +55 -0
  4. package/dist/contacts.js.map +1 -0
  5. package/dist/contract.d.ts +17 -0
  6. package/dist/contract.d.ts.map +1 -0
  7. package/dist/contract.js +17 -0
  8. package/dist/contract.js.map +1 -0
  9. package/dist/enablePhysics3DGuards.d.ts +4 -0
  10. package/dist/enablePhysics3DGuards.d.ts.map +1 -0
  11. package/dist/enablePhysics3DGuards.js +68 -0
  12. package/dist/enablePhysics3DGuards.js.map +1 -0
  13. package/dist/explainPhysics3DJoints.d.ts +3 -0
  14. package/dist/explainPhysics3DJoints.d.ts.map +1 -0
  15. package/dist/explainPhysics3DJoints.js +32 -0
  16. package/dist/explainPhysics3DJoints.js.map +1 -0
  17. package/dist/explainPhysics3DStep.d.ts +3 -0
  18. package/dist/explainPhysics3DStep.d.ts.map +1 -0
  19. package/dist/explainPhysics3DStep.js +48 -0
  20. package/dist/explainPhysics3DStep.js.map +1 -0
  21. package/dist/index.d.ts +14 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +14 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/integrate.d.ts +6 -0
  26. package/dist/integrate.d.ts.map +1 -0
  27. package/dist/integrate.js +154 -0
  28. package/dist/integrate.js.map +1 -0
  29. package/dist/islands.d.ts +5 -0
  30. package/dist/islands.d.ts.map +1 -0
  31. package/dist/islands.js +316 -0
  32. package/dist/islands.js.map +1 -0
  33. package/dist/jointCollisionSuppression.d.ts +4 -0
  34. package/dist/jointCollisionSuppression.d.ts.map +1 -0
  35. package/dist/jointCollisionSuppression.js +40 -0
  36. package/dist/jointCollisionSuppression.js.map +1 -0
  37. package/dist/jointFactories.d.ts +8 -0
  38. package/dist/jointFactories.d.ts.map +1 -0
  39. package/dist/jointFactories.js +126 -0
  40. package/dist/jointFactories.js.map +1 -0
  41. package/dist/jointMath.d.ts +17 -0
  42. package/dist/jointMath.d.ts.map +1 -0
  43. package/dist/jointMath.js +361 -0
  44. package/dist/jointMath.js.map +1 -0
  45. package/dist/jointRegistry.d.ts +8 -0
  46. package/dist/jointRegistry.d.ts.map +1 -0
  47. package/dist/jointRegistry.js +144 -0
  48. package/dist/jointRegistry.js.map +1 -0
  49. package/dist/jointRows.d.ts +32 -0
  50. package/dist/jointRows.d.ts.map +1 -0
  51. package/dist/jointRows.js +308 -0
  52. package/dist/jointRows.js.map +1 -0
  53. package/dist/joints.d.ts +14 -0
  54. package/dist/joints.d.ts.map +1 -0
  55. package/dist/joints.js +758 -0
  56. package/dist/joints.js.map +1 -0
  57. package/dist/massProperties.d.ts +8 -0
  58. package/dist/massProperties.d.ts.map +1 -0
  59. package/dist/massProperties.js +169 -0
  60. package/dist/massProperties.js.map +1 -0
  61. package/dist/ownership.d.ts +5 -0
  62. package/dist/ownership.d.ts.map +1 -0
  63. package/dist/ownership.js +16 -0
  64. package/dist/ownership.js.map +1 -0
  65. package/dist/registerBuiltInPhysics3DJointSolvers.d.ts +3 -0
  66. package/dist/registerBuiltInPhysics3DJointSolvers.d.ts.map +1 -0
  67. package/dist/registerBuiltInPhysics3DJointSolvers.js +14 -0
  68. package/dist/registerBuiltInPhysics3DJointSolvers.js.map +1 -0
  69. package/dist/solver.d.ts +8 -0
  70. package/dist/solver.d.ts.map +1 -0
  71. package/dist/solver.js +383 -0
  72. package/dist/solver.js.map +1 -0
  73. package/dist/step.d.ts +5 -0
  74. package/dist/step.d.ts.map +1 -0
  75. package/dist/step.js +250 -0
  76. package/dist/step.js.map +1 -0
  77. package/dist/stepValidation.d.ts +12 -0
  78. package/dist/stepValidation.d.ts.map +1 -0
  79. package/dist/stepValidation.js +201 -0
  80. package/dist/stepValidation.js.map +1 -0
  81. package/dist/symmetricTensor.d.ts +11 -0
  82. package/dist/symmetricTensor.d.ts.map +1 -0
  83. package/dist/symmetricTensor.js +150 -0
  84. package/dist/symmetricTensor.js.map +1 -0
  85. package/dist/world.d.ts +19 -0
  86. package/dist/world.d.ts.map +1 -0
  87. package/dist/world.js +370 -0
  88. package/dist/world.js.map +1 -0
  89. package/package.json +49 -0
  90. package/src/contacts.test.ts +64 -0
  91. package/src/enablePhysics3DGuards.test.ts +105 -0
  92. package/src/explainPhysics3DJoints.test.ts +101 -0
  93. package/src/explainPhysics3DStep.test.ts +123 -0
  94. package/src/integrate.test.ts +249 -0
  95. package/src/islands.test.ts +357 -0
  96. package/src/jointCollisionSuppression.test.ts +94 -0
  97. package/src/jointFactories.test.ts +195 -0
  98. package/src/jointMath.test.ts +643 -0
  99. package/src/jointRegistry.test.ts +229 -0
  100. package/src/jointRows.test.ts +484 -0
  101. package/src/joints.test.ts +677 -0
  102. package/src/massProperties.test.ts +305 -0
  103. package/src/ownership.test.ts +36 -0
  104. package/src/registerBuiltInPhysics3DJointSolvers.test.ts +48 -0
  105. package/src/solver.test.ts +481 -0
  106. package/src/step.test.ts +390 -0
  107. package/src/stepValidation.test.ts +244 -0
  108. package/src/symmetricTensor.test.ts +166 -0
  109. package/src/world.test.ts +512 -0
@@ -0,0 +1,4 @@
1
+ import type { Physics3DContact, Physics3DContactPoint } from '@flighthq/types/contract';
2
+ export declare function createPhysics3DContact(bodyA: number, bodyB: number): Physics3DContact;
3
+ export declare function createPhysics3DContactPoint(): Physics3DContactPoint;
4
+ //# sourceMappingURL=contacts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contacts.d.ts","sourceRoot":"","sources":["../src/contacts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAuBxF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAerF;AAKD,wBAAgB,2BAA2B,IAAI,qBAAqB,CAcnE"}
@@ -0,0 +1,55 @@
1
+ // Constructors for the contact records the step consumes.
2
+ //
3
+ // This package does not PRODUCE contacts and cannot: the 3D narrow phase and broadphase do not exist yet,
4
+ // so a caller supplies them directly. That makes these constructors part of the ordinary API rather than a
5
+ // test convenience — they are how a caller builds the input the solver is defined against, and they are
6
+ // what stops every callsite from hand-writing a literal that happens to match the fields.
7
+ //
8
+ // A contact allocated here is inert until a caller fills in the geometry: no points, a zero normal, and
9
+ // `touching` false. The solver skips exactly that shape, so a half-built contact costs nothing and moves
10
+ // nothing.
11
+ // Allocates one contact between two bodies, in canonical order.
12
+ //
13
+ // The order is an invariant of creation rather than a convention a caller is asked to respect, so it is
14
+ // enforced here: a narrow phase resolves contact points on the reference shape's surface and ties toward
15
+ // its first argument, which means passing the same pair the other way round moves the points and renumbers
16
+ // their feature ids — and the warm-start cache is keyed to those ids.
17
+ //
18
+ // The normal is NOT reordered with the bodies, because there is nothing yet to reorder: a fresh contact
19
+ // carries a zero normal, and the caller writing the geometry is the one who knows which way it points. It
20
+ // must point so that resolving pushes A out of B.
21
+ export function createPhysics3DContact(bodyA, bodyB) {
22
+ return {
23
+ bodyA: Math.min(bodyA, bodyB),
24
+ bodyB: Math.max(bodyA, bodyB),
25
+ normalX: 0,
26
+ normalY: 0,
27
+ normalZ: 0,
28
+ pointCount: 0,
29
+ points: [],
30
+ friction: 0,
31
+ restitution: 0,
32
+ enabled: true,
33
+ sensor: false,
34
+ touching: false,
35
+ };
36
+ }
37
+ // Allocates one contact point, zeroed. `featureId` is the caller's to assign and is opaque to this
38
+ // package: its only contract is that the SAME physical feature carries the SAME id between steps, which is
39
+ // what lets the solver match this step's points against last step's accumulators.
40
+ export function createPhysics3DContactPoint() {
41
+ return {
42
+ x: 0,
43
+ y: 0,
44
+ z: 0,
45
+ depth: 0,
46
+ featureId: 0,
47
+ rAX: 0,
48
+ rAY: 0,
49
+ rAZ: 0,
50
+ rBX: 0,
51
+ rBY: 0,
52
+ rBZ: 0,
53
+ };
54
+ }
55
+ //# sourceMappingURL=contacts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contacts.js","sourceRoot":"","sources":["../src/contacts.ts"],"names":[],"mappings":"AAEA,0DAA0D;AAC1D,EAAE;AACF,0GAA0G;AAC1G,2GAA2G;AAC3G,wGAAwG;AACxG,0FAA0F;AAC1F,EAAE;AACF,wGAAwG;AACxG,yGAAyG;AACzG,WAAW;AAEX,gEAAgE;AAChE,EAAE;AACF,wGAAwG;AACxG,yGAAyG;AACzG,2GAA2G;AAC3G,sEAAsE;AACtE,EAAE;AACF,wGAAwG;AACxG,0GAA0G;AAC1G,kDAAkD;AAClD,MAAM,UAAU,sBAAsB,CAAC,KAAa,EAAE,KAAa;IACjE,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC;QAC7B,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC;QAC7B,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,CAAC;QACV,UAAU,EAAE,CAAC;QACb,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE,CAAC;QACX,WAAW,EAAE,CAAC;QACd,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,KAAK;KAChB,CAAC;AACJ,CAAC;AAED,mGAAmG;AACnG,2GAA2G;AAC3G,kFAAkF;AAClF,MAAM,UAAU,2BAA2B;IACzC,OAAO;QACL,CAAC,EAAE,CAAC;QACJ,CAAC,EAAE,CAAC;QACJ,CAAC,EAAE,CAAC;QACJ,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,CAAC;QACZ,GAAG,EAAE,CAAC;QACN,GAAG,EAAE,CAAC;QACN,GAAG,EAAE,CAAC;QACN,GAAG,EAAE,CAAC;QACN,GAAG,EAAE,CAAC;QACN,GAAG,EAAE,CAAC;KACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ export * from './contacts';
2
+ export * from './explainPhysics3DJoints';
3
+ export * from './enablePhysics3DGuards';
4
+ export * from './explainPhysics3DStep';
5
+ export * from './integrate';
6
+ export * from './islands';
7
+ export * from './jointCollisionSuppression';
8
+ export * from './jointFactories';
9
+ export * from './jointRegistry';
10
+ export * from './joints';
11
+ export * from './massProperties';
12
+ export * from './registerBuiltInPhysics3DJointSolvers';
13
+ export * from './solver';
14
+ export * from './step';
15
+ export * from './stepValidation';
16
+ export * from './world';
17
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,wCAAwC,CAAC;AACvD,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC"}
@@ -0,0 +1,17 @@
1
+ export * from './contacts';
2
+ export * from './explainPhysics3DJoints';
3
+ export * from './enablePhysics3DGuards';
4
+ export * from './explainPhysics3DStep';
5
+ export * from './integrate';
6
+ export * from './islands';
7
+ export * from './jointCollisionSuppression';
8
+ export * from './jointFactories';
9
+ export * from './jointRegistry';
10
+ export * from './joints';
11
+ export * from './massProperties';
12
+ export * from './registerBuiltInPhysics3DJointSolvers';
13
+ export * from './solver';
14
+ export * from './step';
15
+ export * from './stepValidation';
16
+ export * from './world';
17
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,wCAAwC,CAAC;AACvD,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function arePhysics3DGuardsEnabled(): boolean;
2
+ export declare function disablePhysics3DGuards(): void;
3
+ export declare function enablePhysics3DGuards(): void;
4
+ //# sourceMappingURL=enablePhysics3DGuards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enablePhysics3DGuards.d.ts","sourceRoot":"","sources":["../src/enablePhysics3DGuards.ts"],"names":[],"mappings":"AAOA,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAG7C;AAUD,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C"}
@@ -0,0 +1,68 @@
1
+ import { logOnce } from '@flighthq/log/contract';
2
+ import { LogLevel } from '@flighthq/types/contract';
3
+ import { explainPhysics3DStep } from './explainPhysics3DStep';
4
+ import { setPhysics3DStepGuard } from './step';
5
+ export function arePhysics3DGuardsEnabled() {
6
+ return physics3DGuardsEnabled;
7
+ }
8
+ export function disablePhysics3DGuards() {
9
+ setPhysics3DStepGuard(null);
10
+ physics3DGuardsEnabled = false;
11
+ }
12
+ // Installs opt-in diagnostics for a step that refuses to advance.
13
+ //
14
+ // `stepPhysics3D` declines silently on any failed precondition, which is the right behaviour — a NaN
15
+ // velocity is a state a caller reaches by writing a field, and throwing would take down a frame loop over
16
+ // something inspectable. But silence and success are indistinguishable from the callsite: a world that
17
+ // stopped simulating looks exactly like a world where nothing happens to be moving. This is the seam that
18
+ // tells them apart, and applications that omit this module shed both the message text and
19
+ // `@flighthq/log`.
20
+ export function enablePhysics3DGuards() {
21
+ setPhysics3DStepGuard(warnOnUnsteppablePhysics3DWorld);
22
+ physics3DGuardsEnabled = true;
23
+ }
24
+ // Warns once per distinct set of failing preconditions.
25
+ //
26
+ // EVERY failing flag is reported in one message rather than the first. The step's own condition
27
+ // short-circuits, so a world with a bad timestep and a NaN velocity would otherwise surface the timestep,
28
+ // get repaired, and reveal the next fault a frame later — one round trip per fault, which is the failure
29
+ // the explain seam was built to avoid and would be pointless to reintroduce here.
30
+ //
31
+ // Keyed on the failing set, so a loop calling this at 60Hz logs once and not once per frame, while a world
32
+ // that develops a SECOND fault after the first is repaired still says so.
33
+ function warnOnUnsteppablePhysics3DWorld(world, dt) {
34
+ const explanation = explainPhysics3DStep(world, dt);
35
+ const failing = getFailingPhysics3DPreconditions(explanation);
36
+ if (failing.length === 0)
37
+ return;
38
+ logOnce(`physics3d:${explanation.status}:${failing.join(',')}`, LogLevel.Warn, {
39
+ failing,
40
+ message: `stepPhysics3D: the world advanced nothing because ${failing.length === 1 ? 'a precondition' : 'several preconditions'} failed (${failing.join(', ')}) — call explainPhysics3DStep(world, dt) for the same flags as data, and repair the reported fields.`,
41
+ status: explanation.status,
42
+ }, 'physics3d');
43
+ }
44
+ // The names of the flags that are false, in the explanation's own field order so the key is stable for a
45
+ // given set of faults however they arose.
46
+ function getFailingPhysics3DPreconditions(explanation) {
47
+ const failing = [];
48
+ for (const flag of physics3DPreconditionFlags) {
49
+ if (!explanation[flag])
50
+ failing.push(flag);
51
+ }
52
+ return failing;
53
+ }
54
+ // Listed rather than derived by walking the object, so `status` — which is a summary and not a
55
+ // precondition — cannot be swept in, and so a flag added to the explanation is a deliberate addition here.
56
+ const physics3DPreconditionFlags = [
57
+ 'bodyStateValid',
58
+ 'contactStateValid',
59
+ 'gravityValid',
60
+ 'jointStateValid',
61
+ 'solverConfigValid',
62
+ 'substepsValid',
63
+ 'timestepValid',
64
+ 'velocityIterationsValid',
65
+ 'positionIterationsValid',
66
+ ];
67
+ let physics3DGuardsEnabled = false;
68
+ //# sourceMappingURL=enablePhysics3DGuards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enablePhysics3DGuards.js","sourceRoot":"","sources":["../src/enablePhysics3DGuards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAE/C,MAAM,UAAU,yBAAyB;IACvC,OAAO,sBAAsB,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC5B,sBAAsB,GAAG,KAAK,CAAC;AACjC,CAAC;AAED,kEAAkE;AAClE,EAAE;AACF,qGAAqG;AACrG,0GAA0G;AAC1G,uGAAuG;AACvG,0GAA0G;AAC1G,0FAA0F;AAC1F,mBAAmB;AACnB,MAAM,UAAU,qBAAqB;IACnC,qBAAqB,CAAC,+BAA+B,CAAC,CAAC;IACvD,sBAAsB,GAAG,IAAI,CAAC;AAChC,CAAC;AAED,wDAAwD;AACxD,EAAE;AACF,gGAAgG;AAChG,0GAA0G;AAC1G,yGAAyG;AACzG,kFAAkF;AAClF,EAAE;AACF,2GAA2G;AAC3G,0EAA0E;AAC1E,SAAS,+BAA+B,CAAC,KAA+B,EAAE,EAAU;IAClF,MAAM,WAAW,GAAG,oBAAoB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,gCAAgC,CAAC,WAAW,CAAC,CAAC;IAC9D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAEjC,OAAO,CACL,aAAa,WAAW,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EACtD,QAAQ,CAAC,IAAI,EACb;QACE,OAAO;QACP,OAAO,EAAE,qDAAqD,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,uBAAuB,YAAY,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,sGAAsG;QACnQ,MAAM,EAAE,WAAW,CAAC,MAAM;KAC3B,EACD,WAAW,CACZ,CAAC;AACJ,CAAC;AAED,yGAAyG;AACzG,0CAA0C;AAC1C,SAAS,gCAAgC,CAAC,WAA+C;IACvF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,0BAA0B,EAAE,CAAC;QAC9C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,+FAA+F;AAC/F,2GAA2G;AAC3G,MAAM,0BAA0B,GAAG;IACjC,gBAAgB;IAChB,mBAAmB;IACnB,cAAc;IACd,iBAAiB;IACjB,mBAAmB;IACnB,eAAe;IACf,eAAe;IACf,yBAAyB;IACzB,yBAAyB;CACjB,CAAC;AAEX,IAAI,sBAAsB,GAAG,KAAK,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Physics3DJointExplanation, Physics3DWorld } from '@flighthq/types/contract';
2
+ export declare function explainPhysics3DJoints(world: Readonly<Physics3DWorld>): Physics3DJointExplanation[];
3
+ //# sourceMappingURL=explainPhysics3DJoints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explainPhysics3DJoints.d.ts","sourceRoot":"","sources":["../src/explainPhysics3DJoints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAc1F,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,yBAAyB,EAAE,CAmBnG"}
@@ -0,0 +1,32 @@
1
+ import { findPhysics3DBody } from './world';
2
+ // Which joints the step will actually solve, and why the others are skipped.
3
+ //
4
+ // The step skips a joint in TOTAL SILENCE in two cases, and they need telling apart. An unregistered kind
5
+ // is not a fault — a scene deserialized ahead of the code that solves it is explicitly supported, and the
6
+ // joint is meant to sit inert until someone registers its solver. A joint whose body index no longer
7
+ // resolves is a fault, usually a joint outliving a `removePhysics3DBody` that missed it. Both look
8
+ // identical from outside: a constraint that holds nothing.
9
+ //
10
+ // One entry per joint, in world-list order, so `index` is a handle back into `world.joints`. Pure — it
11
+ // re-walks the world as it stands and retains nothing.
12
+ export function explainPhysics3DJoints(world) {
13
+ const explanations = [];
14
+ for (let index = 0; index < world.joints.length; index += 1) {
15
+ const joint = world.joints[index];
16
+ const solver = world.jointSolvers.get(joint.kind);
17
+ const hasSolver = solver !== undefined;
18
+ // A one-body kind never reads bodyA, so a placeholder index there is not a fault. Asking the solver
19
+ // rather than assuming two endpoints is what keeps this honest for a kind the package does not own.
20
+ const bodyAResolvable = solver?.usesBodyA === false || findPhysics3DBody(world, joint.bodyA) !== null;
21
+ const bodiesResolvable = bodyAResolvable && findPhysics3DBody(world, joint.bodyB) !== null;
22
+ explanations.push({
23
+ kind: joint.kind,
24
+ index,
25
+ hasSolver,
26
+ bodiesResolvable,
27
+ status: !hasSolver ? 'unregistered-kind' : bodiesResolvable ? 'solvable' : 'invalid-bodies',
28
+ });
29
+ }
30
+ return explanations;
31
+ }
32
+ //# sourceMappingURL=explainPhysics3DJoints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explainPhysics3DJoints.js","sourceRoot":"","sources":["../src/explainPhysics3DJoints.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE5C,6EAA6E;AAC7E,EAAE;AACF,0GAA0G;AAC1G,0GAA0G;AAC1G,qGAAqG;AACrG,mGAAmG;AACnG,2DAA2D;AAC3D,EAAE;AACF,uGAAuG;AACvG,uDAAuD;AACvD,MAAM,UAAU,sBAAsB,CAAC,KAA+B;IACpE,MAAM,YAAY,GAAgC,EAAE,CAAC;IACrD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC5D,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,MAAM,KAAK,SAAS,CAAC;QACvC,oGAAoG;QACpG,oGAAoG;QACpG,MAAM,eAAe,GAAG,MAAM,EAAE,SAAS,KAAK,KAAK,IAAI,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;QACtG,MAAM,gBAAgB,GAAG,eAAe,IAAI,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;QAC3F,YAAY,CAAC,IAAI,CAAC;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK;YACL,SAAS;YACT,gBAAgB;YAChB,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,gBAAgB;SAC5F,CAAC,CAAC;IACL,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Physics3DStepExplanation, Physics3DWorld } from '@flighthq/types/contract';
2
+ export declare function explainPhysics3DStep(world: Readonly<Physics3DWorld>, dt: number): Physics3DStepExplanation;
3
+ //# sourceMappingURL=explainPhysics3DStep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explainPhysics3DStep.d.ts","sourceRoot":"","sources":["../src/explainPhysics3DStep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AA2BzF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,wBAAwB,CAmC1G"}
@@ -0,0 +1,48 @@
1
+ import { isPhysics3DBodyStateValid, isPhysics3DContactStateValid, isPhysics3DGravityValid, isPhysics3DJointStateValid, isPhysics3DPositionIterationsValid, isPhysics3DSolverConfigValid, isPhysics3DSubstepsValid, isPhysics3DTimestepValid, isPhysics3DVelocityIterationsValid, } from './stepValidation';
2
+ // Why `stepPhysics3D(world, dt)` would advance nothing, as plain data.
3
+ //
4
+ // The step declines silently on any failed precondition, because a NaN velocity or a zero timestep is a
5
+ // state a caller reaches by writing a field and not a reason to take down a frame loop. This is the seam
6
+ // that makes that silence readable, and it is separately importable so a shipping build that never asks
7
+ // never links it.
8
+ //
9
+ // It asks the SAME predicates the step asks, in the same order, so the two cannot disagree about what
10
+ // "steppable" means. Every flag is reported rather than short-circuiting at the first false: a world with
11
+ // two faults would otherwise be repaired one frame at a time, each fix revealing the next.
12
+ //
13
+ // Pure — it reads the world as it stands and retains nothing. Calling it never changes whether the next
14
+ // step runs.
15
+ export function explainPhysics3DStep(world, dt) {
16
+ const config = world.config;
17
+ const bodyStateValid = isPhysics3DBodyStateValid(world);
18
+ const contactStateValid = isPhysics3DContactStateValid(world);
19
+ const gravityValid = isPhysics3DGravityValid(world);
20
+ const jointStateValid = isPhysics3DJointStateValid(world);
21
+ const solverConfigValid = isPhysics3DSolverConfigValid(config);
22
+ const substepsValid = isPhysics3DSubstepsValid(config);
23
+ const timestepValid = isPhysics3DTimestepValid(dt);
24
+ const velocityIterationsValid = isPhysics3DVelocityIterationsValid(config);
25
+ const positionIterationsValid = isPhysics3DPositionIterationsValid(config);
26
+ const ready = bodyStateValid &&
27
+ contactStateValid &&
28
+ gravityValid &&
29
+ jointStateValid &&
30
+ solverConfigValid &&
31
+ substepsValid &&
32
+ timestepValid &&
33
+ velocityIterationsValid &&
34
+ positionIterationsValid;
35
+ return {
36
+ bodyStateValid,
37
+ contactStateValid,
38
+ gravityValid,
39
+ jointStateValid,
40
+ solverConfigValid,
41
+ substepsValid,
42
+ timestepValid,
43
+ velocityIterationsValid,
44
+ positionIterationsValid,
45
+ status: ready ? 'ready' : 'invalid-step',
46
+ };
47
+ }
48
+ //# sourceMappingURL=explainPhysics3DStep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explainPhysics3DStep.js","sourceRoot":"","sources":["../src/explainPhysics3DStep.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,EAC1B,kCAAkC,EAClC,4BAA4B,EAC5B,wBAAwB,EACxB,wBAAwB,EACxB,kCAAkC,GACnC,MAAM,kBAAkB,CAAC;AAE1B,uEAAuE;AACvE,EAAE;AACF,wGAAwG;AACxG,yGAAyG;AACzG,wGAAwG;AACxG,kBAAkB;AAClB,EAAE;AACF,sGAAsG;AACtG,0GAA0G;AAC1G,2FAA2F;AAC3F,EAAE;AACF,wGAAwG;AACxG,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,KAA+B,EAAE,EAAU;IAC9E,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC5B,MAAM,cAAc,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;IACxD,MAAM,iBAAiB,GAAG,4BAA4B,CAAC,KAAK,CAAC,CAAC;IAC9D,MAAM,YAAY,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,eAAe,GAAG,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAC1D,MAAM,iBAAiB,GAAG,4BAA4B,CAAC,MAAM,CAAC,CAAC;IAC/D,MAAM,aAAa,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACvD,MAAM,aAAa,GAAG,wBAAwB,CAAC,EAAE,CAAC,CAAC;IACnD,MAAM,uBAAuB,GAAG,kCAAkC,CAAC,MAAM,CAAC,CAAC;IAC3E,MAAM,uBAAuB,GAAG,kCAAkC,CAAC,MAAM,CAAC,CAAC;IAE3E,MAAM,KAAK,GACT,cAAc;QACd,iBAAiB;QACjB,YAAY;QACZ,eAAe;QACf,iBAAiB;QACjB,aAAa;QACb,aAAa;QACb,uBAAuB;QACvB,uBAAuB,CAAC;IAE1B,OAAO;QACL,cAAc;QACd,iBAAiB;QACjB,YAAY;QACZ,eAAe;QACf,iBAAiB;QACjB,aAAa;QACb,aAAa;QACb,uBAAuB;QACvB,uBAAuB;QACvB,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc;KACzC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ export { clearRigidBody3DForces, integrateRigidBody3DPose, integrateRigidBody3DVelocity, refreshRigidBody3DWorldInertia, } from './integrate';
2
+ export { createPhysics3DContact, createPhysics3DContactPoint } from './contacts';
3
+ export { explainPhysics3DJoints } from './explainPhysics3DJoints';
4
+ export { arePhysics3DGuardsEnabled, disablePhysics3DGuards, enablePhysics3DGuards } from './enablePhysics3DGuards';
5
+ export { explainPhysics3DStep } from './explainPhysics3DStep';
6
+ export { isPhysics3DPairJointSuppressed } from './jointCollisionSuppression';
7
+ export { createPhysics3DBallAndSocketJoint, createPhysics3DConeTwistJoint, createPhysics3DFixedJoint, createPhysics3DGeneric6DofJoint, createPhysics3DHingeJoint, createPhysics3DSliderJoint, } from './jointFactories';
8
+ export { addPhysics3DJoint, getPhysics3DJointSolver, invalidatePhysics3DJoint, registerPhysics3DJointSolver, removePhysics3DJoint, } from './jointRegistry';
9
+ export { physics3DBallAndSocketJointSolver, physics3DConeTwistJointSolver, physics3DFixedJointSolver, physics3DGeneric6DofJointSolver, physics3DHingeJointSolver, physics3DSliderJointSolver, Physics3DBallAndSocketJointKind, Physics3DConeTwistJointKind, Physics3DFixedJointKind, Physics3DGeneric6DofJointKind, Physics3DHingeJointKind, Physics3DSliderJointKind, } from './joints';
10
+ export { combinePhysics3DMassData, computePhysics3DBoxMassData, computePhysics3DCapsuleMassData, computePhysics3DSphereMassData, createPhysics3DMassData, setRigidBody3DMassData, } from './massProperties';
11
+ export { registerBuiltInPhysics3DJointSolvers } from './registerBuiltInPhysics3DJointSolvers';
12
+ export { stepPhysics3D, stepPhysics3DInterval } from './step';
13
+ export { addPhysics3DBody, applyPhysics3DForce, applyPhysics3DForceAtPoint, applyPhysics3DLinearImpulse, applyPhysics3DTorque, createPhysics3DSequentialImpulseConfig, createPhysics3DSolverConfig, createPhysics3DWorld, createRigidBody3D, findPhysics3DBody, Physics3DWorldVersion, removePhysics3DBody, setPhysics3DBodyFixedRotation, setPhysics3DBodyTransform, setPhysics3DBodyType, wakePhysics3DBody, writeRigidBody3DWorldCenter, } from './world';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACnH,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EACL,iCAAiC,EACjC,6BAA6B,EAC7B,yBAAyB,EACzB,+BAA+B,EAC/B,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,wBAAwB,EACxB,4BAA4B,EAC5B,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,iCAAiC,EACjC,6BAA6B,EAC7B,yBAAyB,EACzB,+BAA+B,EAC/B,yBAAyB,EACzB,0BAA0B,EAC1B,+BAA+B,EAC/B,2BAA2B,EAC3B,uBAAuB,EACvB,6BAA6B,EAC7B,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,+BAA+B,EAC/B,8BAA8B,EAC9B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oCAAoC,EAAE,MAAM,wCAAwC,CAAC;AAC9F,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,0BAA0B,EAC1B,2BAA2B,EAC3B,oBAAoB,EACpB,sCAAsC,EACtC,2BAA2B,EAC3B,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,6BAA6B,EAC7B,yBAAyB,EACzB,oBAAoB,EACpB,iBAAiB,EACjB,2BAA2B,GAC5B,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ export { clearRigidBody3DForces, integrateRigidBody3DPose, integrateRigidBody3DVelocity, refreshRigidBody3DWorldInertia, } from './integrate';
2
+ export { createPhysics3DContact, createPhysics3DContactPoint } from './contacts';
3
+ export { explainPhysics3DJoints } from './explainPhysics3DJoints';
4
+ export { arePhysics3DGuardsEnabled, disablePhysics3DGuards, enablePhysics3DGuards } from './enablePhysics3DGuards';
5
+ export { explainPhysics3DStep } from './explainPhysics3DStep';
6
+ export { isPhysics3DPairJointSuppressed } from './jointCollisionSuppression';
7
+ export { createPhysics3DBallAndSocketJoint, createPhysics3DConeTwistJoint, createPhysics3DFixedJoint, createPhysics3DGeneric6DofJoint, createPhysics3DHingeJoint, createPhysics3DSliderJoint, } from './jointFactories';
8
+ export { addPhysics3DJoint, getPhysics3DJointSolver, invalidatePhysics3DJoint, registerPhysics3DJointSolver, removePhysics3DJoint, } from './jointRegistry';
9
+ export { physics3DBallAndSocketJointSolver, physics3DConeTwistJointSolver, physics3DFixedJointSolver, physics3DGeneric6DofJointSolver, physics3DHingeJointSolver, physics3DSliderJointSolver, Physics3DBallAndSocketJointKind, Physics3DConeTwistJointKind, Physics3DFixedJointKind, Physics3DGeneric6DofJointKind, Physics3DHingeJointKind, Physics3DSliderJointKind, } from './joints';
10
+ export { combinePhysics3DMassData, computePhysics3DBoxMassData, computePhysics3DCapsuleMassData, computePhysics3DSphereMassData, createPhysics3DMassData, setRigidBody3DMassData, } from './massProperties';
11
+ export { registerBuiltInPhysics3DJointSolvers } from './registerBuiltInPhysics3DJointSolvers';
12
+ export { stepPhysics3D, stepPhysics3DInterval } from './step';
13
+ export { addPhysics3DBody, applyPhysics3DForce, applyPhysics3DForceAtPoint, applyPhysics3DLinearImpulse, applyPhysics3DTorque, createPhysics3DSequentialImpulseConfig, createPhysics3DSolverConfig, createPhysics3DWorld, createRigidBody3D, findPhysics3DBody, Physics3DWorldVersion, removePhysics3DBody, setPhysics3DBodyFixedRotation, setPhysics3DBodyTransform, setPhysics3DBodyType, wakePhysics3DBody, writeRigidBody3DWorldCenter, } from './world';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACnH,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EACL,iCAAiC,EACjC,6BAA6B,EAC7B,yBAAyB,EACzB,+BAA+B,EAC/B,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,wBAAwB,EACxB,4BAA4B,EAC5B,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,iCAAiC,EACjC,6BAA6B,EAC7B,yBAAyB,EACzB,+BAA+B,EAC/B,yBAAyB,EACzB,0BAA0B,EAC1B,+BAA+B,EAC/B,2BAA2B,EAC3B,uBAAuB,EACvB,6BAA6B,EAC7B,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,+BAA+B,EAC/B,8BAA8B,EAC9B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oCAAoC,EAAE,MAAM,wCAAwC,CAAC;AAC9F,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,0BAA0B,EAC1B,2BAA2B,EAC3B,oBAAoB,EACpB,sCAAsC,EACtC,2BAA2B,EAC3B,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,6BAA6B,EAC7B,yBAAyB,EACzB,oBAAoB,EACpB,iBAAiB,EACjB,2BAA2B,GAC5B,MAAM,SAAS,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { RigidBody3D } from '@flighthq/types/contract';
2
+ export declare function clearRigidBody3DForces(body: RigidBody3D): void;
3
+ export declare function integrateRigidBody3DPose(body: RigidBody3D, dt: number): void;
4
+ export declare function integrateRigidBody3DVelocity(body: RigidBody3D, gravityX: number, gravityY: number, gravityZ: number, dt: number): void;
5
+ export declare function refreshRigidBody3DWorldInertia(body: RigidBody3D): void;
6
+ //# sourceMappingURL=integrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrate.d.ts","sourceRoot":"","sources":["../src/integrate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAyB5D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAO9D;AAUD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAmC5E;AAYD,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,GACT,IAAI,CA+DN;AAQD,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAuBtE"}
@@ -0,0 +1,154 @@
1
+ import { applySymmetricTensor, rotateSymmetricTensor, TENSOR_XX, TENSOR_XY, TENSOR_XZ, TENSOR_YY, TENSOR_YZ, TENSOR_ZZ, } from './symmetricTensor';
2
+ // Integration: turning forces into velocities and velocities into poses.
3
+ //
4
+ // The scheme is semi-implicit (symplectic) Euler — velocity is advanced first and the NEW velocity
5
+ // moves the pose. The ordering is the whole reason it is stable enough for games: explicit Euler, which
6
+ // moves the pose by the old velocity, injects energy on every step and makes an orbit spiral outward.
7
+ //
8
+ // These are exported separately rather than folded into the step because a caller assembling its own
9
+ // step wants exactly these pieces, and because each is independently testable — which matters most for
10
+ // the angular half, whose failure mode is a slow drift no single-step assertion would catch.
11
+ // Clears the force and torque accumulators. Called by the step once the forces have been integrated, so
12
+ // a caller applying a force each frame does not have it applied twice.
13
+ export function clearRigidBody3DForces(body) {
14
+ body.forceX = 0;
15
+ body.forceY = 0;
16
+ body.forceZ = 0;
17
+ body.torqueX = 0;
18
+ body.torqueY = 0;
19
+ body.torqueZ = 0;
20
+ }
21
+ // Advances a body's pose by its current velocity over `dt`.
22
+ //
23
+ // Position is a straight Euler step. Orientation is not: a quaternion is advanced by the quaternion
24
+ // derivative `0.5 * omega * q`, where omega is the angular velocity as a pure quaternion. That step
25
+ // leaves the unit sphere — it is a tangent move on a curved manifold — so the result is renormalized.
26
+ // Skipping the renormalization does not look wrong for a step or a hundred; it accumulates into a
27
+ // quaternion whose rotation matrix is no longer orthonormal, which reads downstream as a body that is
28
+ // subtly sheared and getting worse.
29
+ export function integrateRigidBody3DPose(body, dt) {
30
+ if (body.type === 'static' || body.sleeping)
31
+ return;
32
+ body.x += body.velocityX * dt;
33
+ body.y += body.velocityY * dt;
34
+ body.z += body.velocityZ * dt;
35
+ const wX = body.angularVelocityX;
36
+ const wY = body.angularVelocityY;
37
+ const wZ = body.angularVelocityZ;
38
+ if (wX === 0 && wY === 0 && wZ === 0)
39
+ return;
40
+ const qX = body.orientationX;
41
+ const qY = body.orientationY;
42
+ const qZ = body.orientationZ;
43
+ const qW = body.orientationW;
44
+ const half = dt * 0.5;
45
+ const nX = qX + half * (wX * qW + wY * qZ - wZ * qY);
46
+ const nY = qY + half * (wY * qW + wZ * qX - wX * qZ);
47
+ const nZ = qZ + half * (wZ * qW + wX * qY - wY * qX);
48
+ const nW = qW + half * (-wX * qX - wY * qY - wZ * qZ);
49
+ const lengthSquared = nX * nX + nY * nY + nZ * nZ + nW * nW;
50
+ if (lengthSquared <= 0 || !Number.isFinite(lengthSquared)) {
51
+ // The only way here is a non-finite angular velocity, which a diverging simulation produces. Hold
52
+ // the previous orientation rather than writing NaN into it: a NaN pose spreads to every constraint
53
+ // the body touches within one step, and a held orientation is at least a state a caller can see.
54
+ return;
55
+ }
56
+ const scale = 1 / Math.sqrt(lengthSquared);
57
+ body.orientationX = nX * scale;
58
+ body.orientationY = nY * scale;
59
+ body.orientationZ = nZ * scale;
60
+ body.orientationW = nW * scale;
61
+ }
62
+ // Advances a body's velocities by the accumulated forces, gravity, and damping over `dt`.
63
+ //
64
+ // The angular half carries the term that does not exist in 2D: Euler's equation for a rotating rigid
65
+ // body is `torque = I * alpha + omega x (I * omega)`, and that second term — the gyroscopic torque — is
66
+ // what makes a thrown object tumble rather than spin about a fixed axis. In 2D it vanishes identically,
67
+ // because omega and `I * omega` are parallel when I is a scalar. Dropping it in 3D costs nothing on a
68
+ // sphere and is visibly wrong on anything long.
69
+ //
70
+ // Damping is applied as an exponential decay rather than a subtraction, so the result does not depend
71
+ // on the step size and a large `dt` can never drive a velocity through zero into reverse.
72
+ export function integrateRigidBody3DVelocity(body, gravityX, gravityY, gravityZ, dt) {
73
+ if (body.type !== 'dynamic' || body.sleeping)
74
+ return;
75
+ body.velocityX += (body.forceX * body.inverseMass + gravityX * body.gravityScale) * dt;
76
+ body.velocityY += (body.forceY * body.inverseMass + gravityY * body.gravityScale) * dt;
77
+ body.velocityZ += (body.forceZ * body.inverseMass + gravityZ * body.gravityScale) * dt;
78
+ const wX = body.angularVelocityX;
79
+ const wY = body.angularVelocityY;
80
+ const wZ = body.angularVelocityZ;
81
+ // The gyroscopic torque, `-omega x (I * omega)`. It needs the FORWARD world inertia, which is why the
82
+ // body stores its forward local tensor: rotating that into world space is one similarity transform,
83
+ // where recovering it from the inverse would be a 3x3 inversion per body per substep.
84
+ //
85
+ // Explicit here, which is the standard game-engine treatment and is stable at ordinary timesteps. A
86
+ // body spinning fast enough that its momentum turns appreciably within one step needs an implicit
87
+ // form; the substep count is the lever for that, and is why it exists.
88
+ let torqueX = body.torqueX;
89
+ let torqueY = body.torqueY;
90
+ let torqueZ = body.torqueZ;
91
+ if (wX !== 0 || wY !== 0 || wZ !== 0) {
92
+ scratchTensor[TENSOR_XX] = body.inertiaXX;
93
+ scratchTensor[TENSOR_YY] = body.inertiaYY;
94
+ scratchTensor[TENSOR_ZZ] = body.inertiaZZ;
95
+ scratchTensor[TENSOR_XY] = body.inertiaXY;
96
+ scratchTensor[TENSOR_XZ] = body.inertiaXZ;
97
+ scratchTensor[TENSOR_YZ] = body.inertiaYZ;
98
+ rotateSymmetricTensor(scratchTensor, body.orientationX, body.orientationY, body.orientationZ, body.orientationW, scratchTensor);
99
+ // scratchVector becomes the angular momentum `L = I * omega`.
100
+ applySymmetricTensor(scratchTensor, wX, wY, wZ, scratchVector);
101
+ torqueX -= wY * scratchVector[2] - wZ * scratchVector[1];
102
+ torqueY -= wZ * scratchVector[0] - wX * scratchVector[2];
103
+ torqueZ -= wX * scratchVector[1] - wY * scratchVector[0];
104
+ }
105
+ readWorldInertia(body, scratchTensor);
106
+ applySymmetricTensor(scratchTensor, torqueX, torqueY, torqueZ, scratchVector);
107
+ body.angularVelocityX = wX + scratchVector[0] * dt;
108
+ body.angularVelocityY = wY + scratchVector[1] * dt;
109
+ body.angularVelocityZ = wZ + scratchVector[2] * dt;
110
+ if (body.linearDamping > 0) {
111
+ const damping = 1 / (1 + dt * body.linearDamping);
112
+ body.velocityX *= damping;
113
+ body.velocityY *= damping;
114
+ body.velocityZ *= damping;
115
+ }
116
+ if (body.angularDamping > 0) {
117
+ const damping = 1 / (1 + dt * body.angularDamping);
118
+ body.angularVelocityX *= damping;
119
+ body.angularVelocityY *= damping;
120
+ body.angularVelocityZ *= damping;
121
+ }
122
+ }
123
+ // Refreshes the world-space inverse inertia tensor from the body's orientation and its local tensor.
124
+ //
125
+ // Must run whenever the orientation changes — which is every substep for anything rotating, and at
126
+ // insertion and teleport for everything else. It is a pull rather than an invalidation flag because
127
+ // every rotating body needs it every substep anyway, so a flag would be checked far more often than it
128
+ // would ever be false.
129
+ export function refreshRigidBody3DWorldInertia(body) {
130
+ scratchTensor[TENSOR_XX] = body.inverseInertiaXX;
131
+ scratchTensor[TENSOR_YY] = body.inverseInertiaYY;
132
+ scratchTensor[TENSOR_ZZ] = body.inverseInertiaZZ;
133
+ scratchTensor[TENSOR_XY] = body.inverseInertiaXY;
134
+ scratchTensor[TENSOR_XZ] = body.inverseInertiaXZ;
135
+ scratchTensor[TENSOR_YZ] = body.inverseInertiaYZ;
136
+ rotateSymmetricTensor(scratchTensor, body.orientationX, body.orientationY, body.orientationZ, body.orientationW, scratchTensor);
137
+ body.inverseInertiaWorldXX = scratchTensor[TENSOR_XX];
138
+ body.inverseInertiaWorldYY = scratchTensor[TENSOR_YY];
139
+ body.inverseInertiaWorldZZ = scratchTensor[TENSOR_ZZ];
140
+ body.inverseInertiaWorldXY = scratchTensor[TENSOR_XY];
141
+ body.inverseInertiaWorldXZ = scratchTensor[TENSOR_XZ];
142
+ body.inverseInertiaWorldYZ = scratchTensor[TENSOR_YZ];
143
+ }
144
+ function readWorldInertia(body, out) {
145
+ out[TENSOR_XX] = body.inverseInertiaWorldXX;
146
+ out[TENSOR_YY] = body.inverseInertiaWorldYY;
147
+ out[TENSOR_ZZ] = body.inverseInertiaWorldZZ;
148
+ out[TENSOR_XY] = body.inverseInertiaWorldXY;
149
+ out[TENSOR_XZ] = body.inverseInertiaWorldXZ;
150
+ out[TENSOR_YZ] = body.inverseInertiaWorldYZ;
151
+ }
152
+ const scratchTensor = [0, 0, 0, 0, 0, 0];
153
+ const scratchVector = [0, 0, 0];
154
+ //# sourceMappingURL=integrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrate.js","sourceRoot":"","sources":["../src/integrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Physics3DWorld, RigidBody3D } from '@flighthq/types/contract';
2
+ export declare function buildPhysics3DSolveIslands(world: Physics3DWorld): void;
3
+ export declare function isRigidBody3DPairAwake(a: Readonly<RigidBody3D>, b: Readonly<RigidBody3D>): boolean;
4
+ export declare function updatePhysics3DSleep(world: Physics3DWorld, dt: number): void;
5
+ //# sourceMappingURL=islands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"islands.d.ts","sourceRoot":"","sources":["../src/islands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAc5E,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAsFtE;AAYD,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,OAAO,CAElG;AAkBD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAuF5E"}