@series-inc/rundot-syncplay 5.23.0-beta.7 → 5.23.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 (75) hide show
  1. package/README.md +116 -15
  2. package/dist/browser.d.ts +87 -55
  3. package/dist/browser.js +47 -52
  4. package/dist/certification.d.ts +32 -3
  5. package/dist/certification.js +88 -3
  6. package/dist/cjs/browser.js +259 -87
  7. package/dist/cjs/certification.js +87 -2
  8. package/dist/cjs/collision.js +58 -0
  9. package/dist/cjs/creator.js +2 -1
  10. package/dist/cjs/engine-complete.js +213 -3
  11. package/dist/cjs/engine-parity-matrix.js +19 -4
  12. package/dist/cjs/index.js +199 -132
  13. package/dist/cjs/math.js +342 -15
  14. package/dist/cjs/movement3d.js +230 -1
  15. package/dist/cjs/node.js +5 -1
  16. package/dist/cjs/noise.js +58 -0
  17. package/dist/cjs/physics-cert.js +147 -6
  18. package/dist/cjs/physics2d.js +10 -4
  19. package/dist/cjs/physics3d-joints.js +637 -0
  20. package/dist/cjs/physics3d-shared.js +288 -0
  21. package/dist/cjs/physics3d-solver.js +1351 -0
  22. package/dist/cjs/physics3d-vehicle.js +467 -0
  23. package/dist/cjs/physics3d.js +1057 -223
  24. package/dist/cjs/random.js +49 -0
  25. package/dist/cjs/replay-bundle.js +127 -20
  26. package/dist/cjs/sample-scenes.js +3 -0
  27. package/dist/cjs/sdk-offline.js +6 -32
  28. package/dist/cjs/sdk-session.js +156 -0
  29. package/dist/cjs/session-build.js +42 -0
  30. package/dist/cjs/testing.js +107 -0
  31. package/dist/cli.js +40 -12
  32. package/dist/collision.d.ts +12 -0
  33. package/dist/collision.js +52 -0
  34. package/dist/creator.d.ts +1 -1
  35. package/dist/creator.js +1 -1
  36. package/dist/engine-complete.js +214 -4
  37. package/dist/engine-parity-matrix.js +19 -4
  38. package/dist/index.d.ts +94 -89
  39. package/dist/index.js +45 -56
  40. package/dist/math.d.ts +59 -6
  41. package/dist/math.js +342 -15
  42. package/dist/movement3d.d.ts +73 -0
  43. package/dist/movement3d.js +229 -1
  44. package/dist/node.d.ts +4 -0
  45. package/dist/node.js +2 -0
  46. package/dist/noise.d.ts +7 -0
  47. package/dist/noise.js +51 -0
  48. package/dist/physics-cert.d.ts +1 -1
  49. package/dist/physics-cert.js +147 -6
  50. package/dist/physics2d.js +10 -4
  51. package/dist/physics3d-joints.d.ts +94 -0
  52. package/dist/physics3d-joints.js +634 -0
  53. package/dist/physics3d-shared.d.ts +72 -0
  54. package/dist/physics3d-shared.js +257 -0
  55. package/dist/physics3d-solver.d.ts +197 -0
  56. package/dist/physics3d-solver.js +1346 -0
  57. package/dist/physics3d-vehicle.d.ts +84 -0
  58. package/dist/physics3d-vehicle.js +463 -0
  59. package/dist/physics3d.d.ts +108 -8
  60. package/dist/physics3d.js +1006 -177
  61. package/dist/random.d.ts +7 -0
  62. package/dist/random.js +49 -0
  63. package/dist/replay-bundle.d.ts +40 -1
  64. package/dist/replay-bundle.js +126 -20
  65. package/dist/sample-scenes.js +3 -0
  66. package/dist/sdk-offline.js +6 -32
  67. package/dist/sdk-session.d.ts +47 -0
  68. package/dist/sdk-session.js +153 -0
  69. package/dist/session-build.d.ts +21 -0
  70. package/dist/session-build.js +39 -0
  71. package/dist/testing.d.ts +52 -0
  72. package/dist/testing.js +45 -0
  73. package/dist/tools/vite-plugin.d.ts +8 -0
  74. package/dist/tools/vite-plugin.js +63 -9
  75. package/package.json +11 -3
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Leaf numeric kernel + vector/quaternion/matrix helpers for the deterministic
3
+ * rigid-body solver. This module imports nothing package-local so `physics3d`,
4
+ * `physics3d-solver`, and `physics3d-joints` can all depend on it in one
5
+ * direction with no ESM cycle.
6
+ *
7
+ * Determinism regime: plain IEEE doubles restricted to `+ - * /` plus integer
8
+ * rounding/abs/min/max/trunc (no transcendental library calls — the static
9
+ * checker bans the square-root/power/trig family). Square roots go through
10
+ * `deterministicSqrt` (quantized, for persisted distances) or `solverSqrt`
11
+ * (unquantized Newton, for solver-internal math — state is quantized only at the
12
+ * frame edge, never mid-solve).
13
+ */
14
+ export interface Point3D {
15
+ readonly x: number;
16
+ readonly y: number;
17
+ readonly z: number;
18
+ }
19
+ export interface Quat3D {
20
+ readonly x: number;
21
+ readonly y: number;
22
+ readonly z: number;
23
+ readonly w: number;
24
+ }
25
+ /** Row-major 3x3 matrix, length 9. */
26
+ export type Mat3 = readonly number[];
27
+ export declare function quantizeDistance(distance: number): number;
28
+ export declare function quantizeAngle(value: number): number;
29
+ export declare function deterministicSqrt(value: number): number;
30
+ /**
31
+ * Unquantized Newton square root for solver-internal math. Bit-for-bit identical
32
+ * to the seed/iteration schedule the validated spike used; every operation is
33
+ * exactly specified IEEE-754 arithmetic, so all certified V8 peers agree. State
34
+ * that reaches the canonical world is quantized separately at the frame edge.
35
+ */
36
+ export declare function solverSqrt(value: number): number;
37
+ export declare function vec3(x: number, y: number, z: number): Point3D;
38
+ export declare function addVec3(a: Point3D, b: Point3D): Point3D;
39
+ export declare function subVec3(a: Point3D, b: Point3D): Point3D;
40
+ export declare function scaleVec3(a: Point3D, s: number): Point3D;
41
+ export declare function dotVec3(a: Point3D, b: Point3D): number;
42
+ export declare function crossVec3(a: Point3D, b: Point3D): Point3D;
43
+ export declare function lengthVec3(a: Point3D): number;
44
+ export declare function normalizeVec3(a: Point3D): Point3D;
45
+ export declare function quatToMat3(q: Quat3D): Mat3;
46
+ export declare function mulMat3Vec(m: Mat3, a: Point3D): Point3D;
47
+ export declare function mulMat3TransposeVec(m: Mat3, a: Point3D): Point3D;
48
+ /** World-space inverse inertia = R · diag(invI) · Rᵀ. */
49
+ export declare function worldInvInertia(rot: Mat3, invI: Point3D): Mat3;
50
+ /**
51
+ * Trig-free quaternion integration: q += ½·(ω⊗q)·dt, renormalized with
52
+ * `solverSqrt`. Returns a unit quaternion; degenerate inputs collapse to
53
+ * identity so no NaN reaches state.
54
+ */
55
+ export declare function integrateQuat(q: Quat3D, w: Point3D, dt: number): Quat3D;
56
+ export declare function normalizeQuat(q: Quat3D): Quat3D;
57
+ export declare function quatConjugate(q: Quat3D): Quat3D;
58
+ export declare function quatMultiply(a: Quat3D, b: Quat3D): Quat3D;
59
+ /** Compose integer quarter-turn rotations about x, then y, then z into a quaternion. */
60
+ export declare function quaternionFromQuarterTurns(turns: Point3D): Quat3D;
61
+ /** Rotate a vector by a quaternion using only mul/add/cross (no transcendentals). */
62
+ export declare function rotatePointByQuat(q: Quat3D, p: Point3D): Point3D;
63
+ /** Rotate a vector by the inverse (conjugate) of a quaternion. */
64
+ export declare function rotatePointByQuatInverse(q: Quat3D, p: Point3D): Point3D;
65
+ export declare function clampNumber(value: number, lo: number, hi: number): number;
66
+ /** Skew-symmetric (cross-product) matrix of a vector. */
67
+ export declare function skewMat3(v: Point3D): Mat3;
68
+ export declare function mat3Multiply(a: Mat3, b: Mat3): Mat3;
69
+ export declare function mat3Sub(a: Mat3, b: Mat3): Mat3;
70
+ export declare function mat3FromDiag(d: Point3D): Mat3;
71
+ /** Invert a 3x3 matrix; returns a zero matrix if singular (deterministic fallback). */
72
+ export declare function invertMat3(m: Mat3): Mat3;
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Leaf numeric kernel + vector/quaternion/matrix helpers for the deterministic
3
+ * rigid-body solver. This module imports nothing package-local so `physics3d`,
4
+ * `physics3d-solver`, and `physics3d-joints` can all depend on it in one
5
+ * direction with no ESM cycle.
6
+ *
7
+ * Determinism regime: plain IEEE doubles restricted to `+ - * /` plus integer
8
+ * rounding/abs/min/max/trunc (no transcendental library calls — the static
9
+ * checker bans the square-root/power/trig family). Square roots go through
10
+ * `deterministicSqrt` (quantized, for persisted distances) or `solverSqrt`
11
+ * (unquantized Newton, for solver-internal math — state is quantized only at the
12
+ * frame edge, never mid-solve).
13
+ */
14
+ export function quantizeDistance(distance) {
15
+ // Pure integer rounding, not fixed-point string rounding — see physics2d
16
+ // quantizeDistance (cross-engine half-way divergence on checksummed state).
17
+ const quantized = Math.round(distance * 1e6) / 1e6;
18
+ return quantized === 0 ? 0 : quantized;
19
+ }
20
+ export function quantizeAngle(value) {
21
+ const wrapped = value - Math.floor(value);
22
+ const quantizedAngle = Math.round(wrapped * 1e6) / 1e6;
23
+ return quantizedAngle === 0 ? 0 : quantizedAngle;
24
+ }
25
+ export function deterministicSqrt(value) {
26
+ if (value <= 0) {
27
+ return 0;
28
+ }
29
+ let estimate = 1;
30
+ let magnitude = value;
31
+ while (magnitude >= 4) {
32
+ magnitude /= 4;
33
+ estimate *= 2;
34
+ }
35
+ if (magnitude > 1) {
36
+ estimate *= 2;
37
+ }
38
+ for (let iteration = 0; iteration < 8; iteration += 1) {
39
+ estimate = (estimate + value / estimate) / 2;
40
+ }
41
+ return quantizeDistance(estimate);
42
+ }
43
+ /**
44
+ * Unquantized Newton square root for solver-internal math. Bit-for-bit identical
45
+ * to the seed/iteration schedule the validated spike used; every operation is
46
+ * exactly specified IEEE-754 arithmetic, so all certified V8 peers agree. State
47
+ * that reaches the canonical world is quantized separately at the frame edge.
48
+ */
49
+ export function solverSqrt(value) {
50
+ if (value <= 0) {
51
+ return 0;
52
+ }
53
+ let estimate = 1;
54
+ let magnitude = value;
55
+ while (magnitude >= 4) {
56
+ magnitude /= 4;
57
+ estimate *= 2;
58
+ }
59
+ if (magnitude > 1) {
60
+ estimate *= 2;
61
+ }
62
+ for (let iteration = 0; iteration < 8; iteration += 1) {
63
+ estimate = (estimate + value / estimate) / 2;
64
+ }
65
+ return estimate;
66
+ }
67
+ export function vec3(x, y, z) {
68
+ return { x, y, z };
69
+ }
70
+ export function addVec3(a, b) {
71
+ return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
72
+ }
73
+ export function subVec3(a, b) {
74
+ return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
75
+ }
76
+ export function scaleVec3(a, s) {
77
+ return { x: a.x * s, y: a.y * s, z: a.z * s };
78
+ }
79
+ export function dotVec3(a, b) {
80
+ return a.x * b.x + a.y * b.y + a.z * b.z;
81
+ }
82
+ export function crossVec3(a, b) {
83
+ return {
84
+ x: a.y * b.z - a.z * b.y,
85
+ y: a.z * b.x - a.x * b.z,
86
+ z: a.x * b.y - a.y * b.x,
87
+ };
88
+ }
89
+ export function lengthVec3(a) {
90
+ return solverSqrt(dotVec3(a, a));
91
+ }
92
+ export function normalizeVec3(a) {
93
+ const length = lengthVec3(a);
94
+ return length === 0 ? { x: 0, y: 0, z: 0 } : scaleVec3(a, 1 / length);
95
+ }
96
+ export function quatToMat3(q) {
97
+ const { x, y, z, w } = q;
98
+ return [
99
+ 1 - 2 * (y * y + z * z), 2 * (x * y - w * z), 2 * (x * z + w * y),
100
+ 2 * (x * y + w * z), 1 - 2 * (x * x + z * z), 2 * (y * z - w * x),
101
+ 2 * (x * z - w * y), 2 * (y * z + w * x), 1 - 2 * (x * x + y * y),
102
+ ];
103
+ }
104
+ export function mulMat3Vec(m, a) {
105
+ return {
106
+ x: m[0] * a.x + m[1] * a.y + m[2] * a.z,
107
+ y: m[3] * a.x + m[4] * a.y + m[5] * a.z,
108
+ z: m[6] * a.x + m[7] * a.y + m[8] * a.z,
109
+ };
110
+ }
111
+ export function mulMat3TransposeVec(m, a) {
112
+ return {
113
+ x: m[0] * a.x + m[3] * a.y + m[6] * a.z,
114
+ y: m[1] * a.x + m[4] * a.y + m[7] * a.z,
115
+ z: m[2] * a.x + m[5] * a.y + m[8] * a.z,
116
+ };
117
+ }
118
+ /** World-space inverse inertia = R · diag(invI) · Rᵀ. */
119
+ export function worldInvInertia(rot, invI) {
120
+ const invIArr = [invI.x, invI.y, invI.z];
121
+ const out = new Array(9).fill(0);
122
+ for (let row = 0; row < 3; row += 1) {
123
+ for (let col = 0; col < 3; col += 1) {
124
+ out[row * 3 + col] =
125
+ rot[row * 3 + 0] * invIArr[0] * rot[col * 3 + 0] +
126
+ rot[row * 3 + 1] * invIArr[1] * rot[col * 3 + 1] +
127
+ rot[row * 3 + 2] * invIArr[2] * rot[col * 3 + 2];
128
+ }
129
+ }
130
+ return out;
131
+ }
132
+ /**
133
+ * Trig-free quaternion integration: q += ½·(ω⊗q)·dt, renormalized with
134
+ * `solverSqrt`. Returns a unit quaternion; degenerate inputs collapse to
135
+ * identity so no NaN reaches state.
136
+ */
137
+ export function integrateQuat(q, w, dt) {
138
+ const hx = w.x * 0.5 * dt;
139
+ const hy = w.y * 0.5 * dt;
140
+ const hz = w.z * 0.5 * dt;
141
+ const nx = q.x + (hx * q.w + hy * q.z - hz * q.y);
142
+ const ny = q.y + (hy * q.w + hz * q.x - hx * q.z);
143
+ const nz = q.z + (hz * q.w + hx * q.y - hy * q.x);
144
+ const nw = q.w + (-hx * q.x - hy * q.y - hz * q.z);
145
+ const length = solverSqrt(nx * nx + ny * ny + nz * nz + nw * nw);
146
+ if (length === 0) {
147
+ return { x: 0, y: 0, z: 0, w: 1 };
148
+ }
149
+ return { x: nx / length, y: ny / length, z: nz / length, w: nw / length };
150
+ }
151
+ export function normalizeQuat(q) {
152
+ const length = solverSqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
153
+ if (length === 0) {
154
+ return { x: 0, y: 0, z: 0, w: 1 };
155
+ }
156
+ return { x: q.x / length, y: q.y / length, z: q.z / length, w: q.w / length };
157
+ }
158
+ export function quatConjugate(q) {
159
+ return { x: -q.x, y: -q.y, z: -q.z, w: q.w };
160
+ }
161
+ export function quatMultiply(a, b) {
162
+ return {
163
+ w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
164
+ x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
165
+ y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
166
+ z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
167
+ };
168
+ }
169
+ const QUARTER_ROOT_HALF = solverSqrt(0.5);
170
+ function axisQuarterTurnQuat(axis, turns) {
171
+ const c = ((Math.trunc(turns) % 4) + 4) % 4;
172
+ // half-angle is turns·45°; sin/cos of {0,45,90,135}° are exactly {0/1, ±√½}.
173
+ const table = [
174
+ { s: 0, w: 1 },
175
+ { s: QUARTER_ROOT_HALF, w: QUARTER_ROOT_HALF },
176
+ { s: 1, w: 0 },
177
+ { s: QUARTER_ROOT_HALF, w: -QUARTER_ROOT_HALF },
178
+ ];
179
+ const entry = table[c];
180
+ return {
181
+ x: axis === 0 ? entry.s : 0,
182
+ y: axis === 1 ? entry.s : 0,
183
+ z: axis === 2 ? entry.s : 0,
184
+ w: entry.w,
185
+ };
186
+ }
187
+ /** Compose integer quarter-turn rotations about x, then y, then z into a quaternion. */
188
+ export function quaternionFromQuarterTurns(turns) {
189
+ const qx = axisQuarterTurnQuat(0, turns.x);
190
+ const qy = axisQuarterTurnQuat(1, turns.y);
191
+ const qz = axisQuarterTurnQuat(2, turns.z);
192
+ return quatMultiply(quatMultiply(qx, qy), qz);
193
+ }
194
+ /** Rotate a vector by a quaternion using only mul/add/cross (no transcendentals). */
195
+ export function rotatePointByQuat(q, p) {
196
+ const u = { x: q.x, y: q.y, z: q.z };
197
+ const t = scaleVec3(crossVec3(u, p), 2);
198
+ return addVec3(addVec3(p, scaleVec3(t, q.w)), crossVec3(u, t));
199
+ }
200
+ /** Rotate a vector by the inverse (conjugate) of a quaternion. */
201
+ export function rotatePointByQuatInverse(q, p) {
202
+ return rotatePointByQuat(quatConjugate(q), p);
203
+ }
204
+ export function clampNumber(value, lo, hi) {
205
+ return value < lo ? lo : value > hi ? hi : value;
206
+ }
207
+ /** Skew-symmetric (cross-product) matrix of a vector. */
208
+ export function skewMat3(v) {
209
+ return [
210
+ 0, -v.z, v.y,
211
+ v.z, 0, -v.x,
212
+ -v.y, v.x, 0,
213
+ ];
214
+ }
215
+ export function mat3Multiply(a, b) {
216
+ const out = new Array(9).fill(0);
217
+ for (let row = 0; row < 3; row += 1) {
218
+ for (let col = 0; col < 3; col += 1) {
219
+ out[row * 3 + col] =
220
+ a[row * 3 + 0] * b[0 * 3 + col] +
221
+ a[row * 3 + 1] * b[1 * 3 + col] +
222
+ a[row * 3 + 2] * b[2 * 3 + col];
223
+ }
224
+ }
225
+ return out;
226
+ }
227
+ export function mat3Sub(a, b) {
228
+ return a.map((value, index) => value - b[index]);
229
+ }
230
+ export function mat3FromDiag(d) {
231
+ return [d.x, 0, 0, 0, d.y, 0, 0, 0, d.z];
232
+ }
233
+ /** Invert a 3x3 matrix; returns a zero matrix if singular (deterministic fallback). */
234
+ export function invertMat3(m) {
235
+ const a = m[0];
236
+ const b = m[1];
237
+ const c = m[2];
238
+ const d = m[3];
239
+ const e = m[4];
240
+ const f = m[5];
241
+ const g = m[6];
242
+ const h = m[7];
243
+ const i = m[8];
244
+ const co0 = e * i - f * h;
245
+ const co1 = f * g - d * i;
246
+ const co2 = d * h - e * g;
247
+ const det = a * co0 + b * co1 + c * co2;
248
+ if (det === 0) {
249
+ return [0, 0, 0, 0, 0, 0, 0, 0, 0];
250
+ }
251
+ const inv = 1 / det;
252
+ return [
253
+ co0 * inv, (c * h - b * i) * inv, (b * f - c * e) * inv,
254
+ co1 * inv, (a * i - c * g) * inv, (c * d - a * f) * inv,
255
+ co2 * inv, (b * g - a * h) * inv, (a * e - b * d) * inv,
256
+ ];
257
+ }
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Deterministic rigid-body solver core (geometry half): SAT + face-clipping
3
+ * manifolds for boxes, closed-form manifolds for sphere/capsule pairs,
4
+ * one-sided triangle contacts for dynamic-shape-vs-static-mesh, and compound
5
+ * decomposition. The velocity/position solver, contact cache matching, islands
6
+ * and sleeping live alongside in this module (see solveRigidStep).
7
+ *
8
+ * Numeric regime: unquantized solver math via the shared kernel; every constant
9
+ * here is load-bearing (each was earned by a failure mode in the validated
10
+ * spike) — do not "simplify" them without re-running the stack/tumble/
11
+ * determinism scenarios.
12
+ */
13
+ import { Mat3, Point3D, Quat3D } from './physics3d-shared.js';
14
+ export type SolverPrimitiveShape = {
15
+ readonly kind: 'box';
16
+ readonly half: Point3D;
17
+ } | {
18
+ readonly kind: 'sphere';
19
+ readonly radius: number;
20
+ } | {
21
+ readonly kind: 'capsule';
22
+ readonly radius: number;
23
+ readonly halfHeight: number;
24
+ };
25
+ export interface SolverCompoundChild {
26
+ readonly shape: SolverPrimitiveShape;
27
+ readonly offset: Point3D;
28
+ readonly q: Quat3D;
29
+ }
30
+ export type SolverShape = SolverPrimitiveShape | {
31
+ readonly kind: 'compound';
32
+ readonly children: readonly SolverCompoundChild[];
33
+ } | {
34
+ readonly kind: 'mesh';
35
+ readonly triangles: readonly (readonly [Point3D, Point3D, Point3D])[];
36
+ };
37
+ export interface SolverGeomBody {
38
+ readonly index: number;
39
+ readonly p: Point3D;
40
+ readonly q: Quat3D;
41
+ readonly shape: SolverShape;
42
+ }
43
+ export interface SolverContactPoint {
44
+ /** Anchor relative to body A center, world axes. */
45
+ readonly rA: Point3D;
46
+ readonly rB: Point3D;
47
+ /** >= 0 real contact; < 0 speculative (CCD). */
48
+ readonly penetration: number;
49
+ /** Stable feature id used for deterministic point ordering. */
50
+ readonly feature: number;
51
+ }
52
+ export interface SolverManifold {
53
+ readonly a: number;
54
+ readonly b: number;
55
+ /** Unit, points A -> B. */
56
+ readonly normal: Point3D;
57
+ readonly points: readonly SolverContactPoint[];
58
+ }
59
+ export declare function generateManifold(a: SolverGeomBody, b: SolverGeomBody, speculativeMargin?: number): SolverManifold | undefined;
60
+ declare function closestPointOnSegment(point: Point3D, start: Point3D, end: Point3D): Point3D;
61
+ declare function closestSegmentSegment(p1: Point3D, q1: Point3D, p2: Point3D, q2: Point3D): {
62
+ c1: Point3D;
63
+ c2: Point3D;
64
+ };
65
+ declare function triangleNormal(a: Point3D, b: Point3D, c: Point3D): Point3D;
66
+ declare function closestPointOnTriangle(p: Point3D, a: Point3D, b: Point3D, c: Point3D): Point3D;
67
+ export declare const SOLVER_CONSTANTS: {
68
+ readonly BAUMGARTE: 0.2;
69
+ readonly SLOP: 0.005;
70
+ readonly WAKE_VEL2: 0.005;
71
+ readonly SLEEP_VEL2: 0.005;
72
+ readonly SLEEP_FRAMES: 20;
73
+ readonly RESTITUTION_THRESHOLD: 1;
74
+ readonly WARM_MATCH_TOL2: 0.01;
75
+ readonly LINEAR_DAMPING: 0.995;
76
+ readonly ANGULAR_DAMPING: 0.98;
77
+ };
78
+ /** Solver-owned velocity vector — mutated in place on the hot impulse path. */
79
+ export interface SolverVec3 {
80
+ x: number;
81
+ y: number;
82
+ z: number;
83
+ }
84
+ export interface SolverBody {
85
+ readonly index: number;
86
+ readonly id: string;
87
+ readonly isDynamic: boolean;
88
+ sleeping: boolean;
89
+ p: Point3D;
90
+ q: Quat3D;
91
+ v: SolverVec3;
92
+ w: SolverVec3;
93
+ vb: SolverVec3;
94
+ wb: SolverVec3;
95
+ /** Per-axis inverse mass (axis locks zero individual components). */
96
+ readonly invMassVec: Point3D;
97
+ /** Body-space diagonal inverse inertia. */
98
+ readonly invInertiaLocal: Point3D;
99
+ /** Per-world-axis angular lock multiplier (0 locked, 1 free). */
100
+ readonly angularLock: Point3D;
101
+ /** 0..1 material coefficients (already divided from 0-10 ints). */
102
+ readonly matFriction: number;
103
+ readonly matRestitution: number;
104
+ readonly linearDamping: number;
105
+ readonly angularDamping: number;
106
+ /** Multiplies world gravity for this body in solver step 1; default 1. */
107
+ readonly gravityScale: number;
108
+ readonly hasOrientation: boolean;
109
+ readonly shape: SolverShape;
110
+ lowVelFrames: number;
111
+ wakeForced: boolean;
112
+ readonly ccd: boolean;
113
+ readonly layer: number;
114
+ readonly mask: number;
115
+ /** Trigger/sensor bodies integrate but never generate solved contacts. */
116
+ readonly noCollide: boolean;
117
+ }
118
+ export interface SolverJointCacheEntry {
119
+ readonly jointId: string;
120
+ readonly impulseX: number;
121
+ readonly impulseY: number;
122
+ readonly impulseZ: number;
123
+ readonly axialImpulse: number;
124
+ readonly hingeAngle: number;
125
+ /** Set once a breakable joint exceeded its breakImpulse; sticky via the cache. */
126
+ readonly broken?: boolean;
127
+ }
128
+ export interface SolverJointContext {
129
+ readonly bodies: readonly SolverBody[];
130
+ readonly invMass: readonly Point3D[];
131
+ readonly invInertia: readonly Mat3[];
132
+ readonly dt: number;
133
+ apply(a: number, b: number, rA: Point3D, rB: Point3D, impulse: Point3D): void;
134
+ /** Angular-only impulse (no linear component), e.g. hinge motor/limit rows. */
135
+ applyAngular(a: number, b: number, angularImpulse: Point3D): void;
136
+ /** Apply an impulse to a single body at anchor `r` (grab / world-target joints). */
137
+ applyToBody(index: number, r: Point3D, impulse: Point3D): void;
138
+ /** Split-impulse position correction on pseudo-velocities (no real momentum). */
139
+ applyBias(a: number, b: number, rA: Point3D, rB: Point3D, impulse: Point3D): void;
140
+ /** Relative pseudo-velocity at the anchor pair, for split-impulse joint solves. */
141
+ biasRelativeVelocity(a: number, b: number, rA: Point3D, rB: Point3D): Point3D;
142
+ }
143
+ export interface SolverJointSolve {
144
+ /** Compute effective masses + apply warm-start impulses (called once per step). */
145
+ prepare(ctx: SolverJointContext): void;
146
+ /** One velocity iteration. */
147
+ iterate(ctx: SolverJointContext): void;
148
+ /** Bodies coupled by this joint (for islands + wake propagation). */
149
+ readonly bodyIndices: readonly number[];
150
+ /** Emit the joint cache entry after solving. */
151
+ emitCache(): SolverJointCacheEntry;
152
+ }
153
+ export interface SolverWarmPoint {
154
+ readonly anchor: Point3D;
155
+ readonly normalImpulse: number;
156
+ readonly tangentImpulse1: number;
157
+ readonly tangentImpulse2: number;
158
+ }
159
+ export interface SolverStepOptions {
160
+ readonly dt: number;
161
+ readonly gravityY: number;
162
+ readonly velocityIterations: number;
163
+ /** Packed index-pair key `a * 2**20 + b` (a<b) → warm points from last frame. */
164
+ readonly warm: Map<number, SolverWarmPoint[]>;
165
+ /** Candidate index pairs (i<j, canonical order) to narrow-phase, or undefined = O(n²). */
166
+ readonly pairs?: readonly (readonly [number, number])[];
167
+ readonly joints?: readonly SolverJointSolve[];
168
+ /** Packed index pairs (min * WARM_KEY_BASE + max) whose contacts are suppressed (jointed pairs). */
169
+ readonly noCollidePairs?: ReadonlySet<number>;
170
+ }
171
+ export interface SolverContactImpulse {
172
+ readonly a: number;
173
+ readonly b: number;
174
+ readonly normalImpulse: number;
175
+ readonly pair: string;
176
+ }
177
+ export interface SolverStepResult {
178
+ readonly manifolds: readonly SolverManifold[];
179
+ readonly contactImpulses: readonly SolverContactImpulse[];
180
+ /** New warm cache, packed index-pair keyed (`a * 2**20 + b`). */
181
+ readonly warm: Map<number, SolverWarmPoint[]>;
182
+ readonly jointCache: readonly SolverJointCacheEntry[];
183
+ }
184
+ /**
185
+ * Warm-cache maps pack the canonical index pair (a<b) into one exact integer
186
+ * `a * WARM_KEY_BASE + b` — string pair keys were measurable churn on large piles.
187
+ */
188
+ export declare const WARM_KEY_BASE: number;
189
+ /** Runs one deterministic rigid-body step in place over `bodies`. */
190
+ export declare function solveRigidStep(bodies: SolverBody[], options: SolverStepOptions): SolverStepResult;
191
+ export declare const __solverInternals: {
192
+ closestPointOnSegment: typeof closestPointOnSegment;
193
+ closestSegmentSegment: typeof closestSegmentSegment;
194
+ closestPointOnTriangle: typeof closestPointOnTriangle;
195
+ triangleNormal: typeof triangleNormal;
196
+ };
197
+ export {};