@woosh/meep-engine 2.146.0 → 2.147.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 (68) hide show
  1. package/package.json +1 -1
  2. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +0 -11
  3. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
  4. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +8 -6
  5. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
  6. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +552 -551
  7. package/src/engine/control/first-person/abilities/LedgeGrab.d.ts +8 -3
  8. package/src/engine/control/first-person/abilities/LedgeGrab.d.ts.map +1 -1
  9. package/src/engine/control/first-person/abilities/LedgeGrab.js +213 -199
  10. package/src/engine/control/first-person/abilities/Mantle.d.ts.map +1 -1
  11. package/src/engine/control/first-person/abilities/Mantle.js +195 -188
  12. package/src/engine/control/first-person/abilities/WallRun.d.ts.map +1 -1
  13. package/src/engine/control/first-person/abilities/WallRun.js +183 -175
  14. package/src/engine/control/first-person/sensors/FirstPersonSensors.d.ts +9 -0
  15. package/src/engine/control/first-person/sensors/FirstPersonSensors.d.ts.map +1 -1
  16. package/src/engine/control/first-person/sensors/FirstPersonSensors.js +87 -77
  17. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts +8 -0
  18. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts.map +1 -1
  19. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.js +229 -196
  20. package/src/engine/ecs/EntityManager.d.ts +34 -11
  21. package/src/engine/ecs/EntityManager.d.ts.map +1 -1
  22. package/src/engine/ecs/EntityManager.js +71 -42
  23. package/src/engine/interpolation/BinaryInterpolationAdapter.d.ts.map +1 -0
  24. package/src/engine/interpolation/Interpoland.d.ts +48 -0
  25. package/src/engine/interpolation/Interpoland.d.ts.map +1 -0
  26. package/src/engine/interpolation/Interpoland.js +49 -0
  27. package/src/engine/interpolation/Interpolated.d.ts +101 -0
  28. package/src/engine/interpolation/Interpolated.d.ts.map +1 -0
  29. package/src/engine/interpolation/Interpolated.js +149 -0
  30. package/src/engine/{network/sim → interpolation}/InterpolationLog.d.ts +1 -1
  31. package/src/engine/interpolation/InterpolationLog.d.ts.map +1 -0
  32. package/src/engine/{network/sim → interpolation}/InterpolationLog.js +2 -2
  33. package/src/engine/interpolation/InterpolationSystem.d.ts +116 -0
  34. package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -0
  35. package/src/engine/interpolation/InterpolationSystem.js +233 -0
  36. package/src/engine/interpolation/PoseInterpolationAdapter.d.ts +17 -0
  37. package/src/engine/interpolation/PoseInterpolationAdapter.d.ts.map +1 -0
  38. package/src/engine/interpolation/PoseInterpolationAdapter.js +61 -0
  39. package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts +35 -0
  40. package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts.map +1 -0
  41. package/src/engine/interpolation/TransformPoseSerializationAdapter.js +57 -0
  42. package/src/engine/interpolation/pose_interpoland.d.ts +18 -0
  43. package/src/engine/interpolation/pose_interpoland.d.ts.map +1 -0
  44. package/src/engine/interpolation/pose_interpoland.js +27 -0
  45. package/src/engine/network/NetworkSession.d.ts +2 -2
  46. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  47. package/src/engine/network/NetworkSession.js +2 -2
  48. package/src/engine/network/adapters/QuaternionInterpolationAdapter.d.ts +1 -1
  49. package/src/engine/network/adapters/QuaternionInterpolationAdapter.d.ts.map +1 -1
  50. package/src/engine/network/adapters/QuaternionInterpolationAdapter.js +1 -1
  51. package/src/engine/network/adapters/TransformInterpolationAdapter.d.ts +1 -1
  52. package/src/engine/network/adapters/TransformInterpolationAdapter.d.ts.map +1 -1
  53. package/src/engine/network/adapters/TransformInterpolationAdapter.js +1 -1
  54. package/src/engine/network/adapters/Vector3InterpolationAdapter.d.ts +1 -1
  55. package/src/engine/network/adapters/Vector3InterpolationAdapter.d.ts.map +1 -1
  56. package/src/engine/network/adapters/Vector3InterpolationAdapter.js +1 -1
  57. package/src/engine/physics/INTEPOLATION_SYSTEM_PLAN.md +287 -0
  58. package/src/engine/physics/PLAN.md +10 -9
  59. package/src/engine/physics/ecs/PhysicsSystem.d.ts +64 -0
  60. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  61. package/src/engine/physics/ecs/PhysicsSystem.js +168 -0
  62. package/src/engine/physics/narrowphase/box_triangle_contact.js +15 -12
  63. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  64. package/src/engine/physics/narrowphase/narrowphase_step.js +28 -1
  65. package/src/engine/network/sim/BinaryInterpolationAdapter.d.ts.map +0 -1
  66. package/src/engine/network/sim/InterpolationLog.d.ts.map +0 -1
  67. /package/src/engine/{network/sim → interpolation}/BinaryInterpolationAdapter.d.ts +0 -0
  68. /package/src/engine/{network/sim → interpolation}/BinaryInterpolationAdapter.js +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InterpolationSystem.d.ts","sourceRoot":"","sources":["../../../../src/engine/interpolation/InterpolationSystem.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH;IAEI;;OAEG;IACH,0DAFW;QAAE,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,EAmDvE;IA9CG,sCAAkC;IAElC,oEAEC;IAED;;;;OAIG;IACH,KAFU,gBAAgB,CAEkD;IAE5E;;;;;OAKG;IACH,mBAA2B;IAE3B;;;;OAIG;IACH,kBAAmC;IAGnC;;;;;;;OAOG;IACH,kBAA0B;IAE1B;;;;;OAKG;IACH,yBAAiC;IAGrC;;;;;;;;;;;OAWG;IACH,yBAJW,MAAM,OACN,gBAAgB,UAChB,MAAM;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,QAI7D;IAED;;OAEG;IACH,qDAEC;IAED;;;OAGG;IACH,mBAHW,YAAY,UACZ,MAAM,QAShB;IAED;;;OAGG;IACH,qBAHW,YAAY,UACZ,MAAM,QAIhB;IAED,sBA0FC;IAGL;;;OAGG;IACH,gCAFU,OAAO,CAEkC;CANlD;uBA/NsB,kBAAkB;6BAEyC,mBAAmB;4CAHzD,iDAAiD;iCAE5D,uBAAuB"}
@@ -0,0 +1,233 @@
1
+ import { BinaryBuffer } from "../../core/binary/BinaryBuffer.js";
2
+ import { ResourceAccessKind } from "../../core/model/ResourceAccessKind.js";
3
+ import { ResourceAccessSpecification } from "../../core/model/ResourceAccessSpecification.js";
4
+ import { System } from "../ecs/System.js";
5
+ import { InterpolationLog } from "./InterpolationLog.js";
6
+ import { Interpolated, INTERPOLATION_KEY_UNSET, INTERPOLATION_SOURCE_LOCAL } from "./Interpolated.js";
7
+
8
+ /**
9
+ * Render-time consumer of the interpolation log. Runs in {@link update} (the
10
+ * variable-rate, render-loop-driven cycle): for every {@link Interpolated}
11
+ * entity it blends each interpoland between the last two completed fixed ticks
12
+ * by the current fixed-step alpha and writes the result into the live target
13
+ * component (e.g. {@link Transform}). Because it writes the live component, all
14
+ * Transform-linked machinery (culling, particles, trails, attachments) renders
15
+ * the smoothed pose.
16
+ *
17
+ * Producers (physics, network) record authoritative per-tick snapshots into
18
+ * {@link log}; this system only consumes. Cost is O(entities × interpolands),
19
+ * and producers record only for things that moved, so the log stays sparse.
20
+ *
21
+ * For a LOCAL entity (the default), tick + alpha come from the simulation hub:
22
+ * `entityManager.fixedStepTick` is the latest completed fixed step and
23
+ * `entityManager.getFixedStepAlpha()` is the sub-step fraction, blending
24
+ * `(fixedStepTick - 1, fixedStepTick)` from this system's own log.
25
+ *
26
+ * An entity may instead carry a non-default {@link Interpolated#sourceId} naming
27
+ * a timeline registered via {@link registerSource} (the log + window provider
28
+ * live on the system, not the component) — e.g. a networked entity blended on
29
+ * the network's render-delayed playout. The same render pass then drives both
30
+ * local and remote entities, so a mixed scene is coherent; each source is
31
+ * sampled once per frame.
32
+ *
33
+ * @author Alex Goldring
34
+ * @copyright Company Named Limited (c) 2026
35
+ */
36
+ export class InterpolationSystem extends System {
37
+
38
+ /**
39
+ * @param {{ buffer_capacity_bytes?: number, records_capacity?: number }} [options]
40
+ */
41
+ constructor({ buffer_capacity_bytes = 65536, records_capacity = 4096 } = {}) {
42
+ super();
43
+
44
+ this.dependencies = [Interpolated];
45
+
46
+ this.components_used = [
47
+ ResourceAccessSpecification.from(Interpolated, ResourceAccessKind.Read | ResourceAccessKind.Write),
48
+ ];
49
+
50
+ /**
51
+ * Shared per-tick snapshot store. Producers record into it; this system
52
+ * blends from it.
53
+ * @type {InterpolationLog}
54
+ */
55
+ this.log = new InterpolationLog({ buffer_capacity_bytes, records_capacity });
56
+
57
+ /**
58
+ * Linked entities → their {@link Interpolated} component. Iterated each
59
+ * update.
60
+ * @private
61
+ * @type {Map<number, Interpolated>}
62
+ */
63
+ this.__entities = new Map();
64
+
65
+ /**
66
+ * Reusable decode buffer for blended snapshots.
67
+ * @private
68
+ * @type {BinaryBuffer}
69
+ */
70
+ this.__scratch = new BinaryBuffer();
71
+ this.__scratch.fromArrayBuffer(new ArrayBuffer(256));
72
+
73
+ /**
74
+ * Non-local timeline registry, keyed by `sourceId`. Each entry is the
75
+ * timeline's `{ log, sample() }` — its log to read and a per-frame window
76
+ * provider. Owners (e.g. the network layer) register here; the
77
+ * {@link Interpolated} component only carries the integer id.
78
+ * @private
79
+ * @type {Map<number, { log: InterpolationLog, sample: () => { tick_a: number, tick_b: number, t: number } }>}
80
+ */
81
+ this.__sources = new Map();
82
+
83
+ /**
84
+ * Per-update cache of `sourceId → window`, so a source's playout is
85
+ * sampled once per frame, not once per entity. Cleared each update.
86
+ * @private
87
+ * @type {Map<number, { tick_a: number, tick_b: number, t: number }>}
88
+ */
89
+ this.__source_windows = new Map();
90
+ }
91
+
92
+ /**
93
+ * Register a non-local interpolation timeline under `sourceId`. Entities
94
+ * carrying that id on their {@link Interpolated} component are blended from
95
+ * `log` on the window `sample()` returns (sampled once per render frame).
96
+ * Used by timeline owners — e.g. the network layer registers its
97
+ * render-delayed playout. `sourceId` must not be
98
+ * {@link INTERPOLATION_SOURCE_LOCAL} (reserved for the local clock).
99
+ *
100
+ * @param {number} sourceId
101
+ * @param {InterpolationLog} log
102
+ * @param {() => { tick_a: number, tick_b: number, t: number }} sample
103
+ */
104
+ registerSource(sourceId, log, sample) {
105
+ this.__sources.set(sourceId, { log, sample });
106
+ }
107
+
108
+ /**
109
+ * @param {EntityManager} entityManager
110
+ */
111
+ async startup(entityManager) {
112
+ this.entityManager = entityManager;
113
+ }
114
+
115
+ /**
116
+ * @param {Interpolated} interpolated
117
+ * @param {number} entity
118
+ */
119
+ link(interpolated, entity) {
120
+ if (interpolated.key === INTERPOLATION_KEY_UNSET) {
121
+ // Default identity: the entity id. A producer (e.g. the network
122
+ // layer) may have set a network_id already, in which case we keep it.
123
+ interpolated.key = entity;
124
+ }
125
+ this.__entities.set(entity, interpolated);
126
+ }
127
+
128
+ /**
129
+ * @param {Interpolated} interpolated
130
+ * @param {number} entity
131
+ */
132
+ unlink(interpolated, entity) {
133
+ this.__entities.delete(entity);
134
+ }
135
+
136
+ update(dt) {
137
+ const entities = this.__entities;
138
+ if (entities.size === 0) {
139
+ return;
140
+ }
141
+
142
+ const em = this.entityManager;
143
+ const dataset = (em !== null && em !== undefined) ? em.dataset : null;
144
+ if (dataset === null || dataset === undefined) {
145
+ return;
146
+ }
147
+
148
+ const scratch = this.__scratch;
149
+
150
+ // Default (local) timeline: blend the last two completed fixed steps at
151
+ // the sub-step alpha, reading this system's own log.
152
+ const local_log = this.log;
153
+ const local_tick_b = em.fixedStepTick;
154
+ const local_tick_a = local_tick_b - 1;
155
+ const local_t = em.getFixedStepAlpha();
156
+
157
+ // A non-local source's playout window is sampled once per frame.
158
+ const source_windows = this.__source_windows;
159
+ source_windows.clear();
160
+
161
+ for (const [entity, interpolated] of entities) {
162
+ const key = interpolated.key;
163
+ if (key === INTERPOLATION_KEY_UNSET) {
164
+ continue;
165
+ }
166
+
167
+ if (interpolated.snap) {
168
+ // Teleport / wake: the live components already hold the
169
+ // authoritative pose (set by setPose, or the body's own pose on
170
+ // wake), which isn't in the log as the latest two ticks yet.
171
+ // Leave them untouched this frame so we don't slide across the
172
+ // jump; resume interpolating next frame.
173
+ interpolated.snap = false;
174
+ continue;
175
+ }
176
+
177
+ // Pick the timeline by id: the default local fixed-step clock, or a
178
+ // registered non-local source (e.g. the network playout).
179
+ let log, tick_a, tick_b, t;
180
+ const source_id = interpolated.sourceId;
181
+ if (source_id === INTERPOLATION_SOURCE_LOCAL) {
182
+ log = local_log;
183
+ tick_a = local_tick_a;
184
+ tick_b = local_tick_b;
185
+ t = local_t;
186
+ } else {
187
+ const src = this.__sources.get(source_id);
188
+ if (src === undefined) {
189
+ continue; // unregistered source — nothing to read
190
+ }
191
+ log = src.log;
192
+ let win = source_windows.get(source_id);
193
+ if (win === undefined) {
194
+ win = src.sample();
195
+ source_windows.set(source_id, win);
196
+ }
197
+ tick_a = win.tick_a;
198
+ tick_b = win.tick_b;
199
+ t = win.t;
200
+ }
201
+
202
+ const interpolands = interpolated.interpolands;
203
+ const n = interpolands.length;
204
+ for (let i = 0; i < n; i++) {
205
+ const interpoland = interpolands[i];
206
+
207
+ scratch.position = 0;
208
+ const ok = log.interpolate(
209
+ scratch, key, interpoland.type_id, tick_a, tick_b, t, interpoland.interpolation_adapter
210
+ );
211
+ if (!ok) {
212
+ // Neither tick carries this interpoland — leave the live
213
+ // component untouched.
214
+ continue;
215
+ }
216
+
217
+ const target = dataset.getComponent(entity, interpoland.component_class);
218
+ if (target === undefined || target === null) {
219
+ continue;
220
+ }
221
+
222
+ scratch.position = 0;
223
+ interpoland.serialization_adapter.deserialize(scratch, target);
224
+ }
225
+ }
226
+ }
227
+ }
228
+
229
+ /**
230
+ * @readonly
231
+ * @type {boolean}
232
+ */
233
+ InterpolationSystem.prototype.isInterpolationSystem = true;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Linear-blend interpolator matching {@link TransformPoseSerializationAdapter}'s
3
+ * layout (7 × Float64: position xyz + rotation xyzw). Position lerps
4
+ * componentwise; rotation nlerps with shortest-arc correction and renormalize.
5
+ *
6
+ * `first_offset === second_offset` reduces to the input at any `t` (the
7
+ * snap-to-single-snapshot case the log relies on), with no special handling.
8
+ *
9
+ * @author Alex Goldring
10
+ * @copyright Company Named Limited (c) 2026
11
+ */
12
+ export class PoseInterpolationAdapter extends BinaryInterpolationAdapter {
13
+ /** @inheritdoc */
14
+ interpolate(out_buffer: any, source: any, first_offset: any, second_offset: any, t: any): void;
15
+ }
16
+ import { BinaryInterpolationAdapter } from "./BinaryInterpolationAdapter.js";
17
+ //# sourceMappingURL=PoseInterpolationAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PoseInterpolationAdapter.d.ts","sourceRoot":"","sources":["../../../../src/engine/interpolation/PoseInterpolationAdapter.js"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH;IAEI,kBAAkB;IAClB,+FA2CC;CACJ;2CA5D0C,iCAAiC"}
@@ -0,0 +1,61 @@
1
+ import { BinaryInterpolationAdapter } from "./BinaryInterpolationAdapter.js";
2
+
3
+ /**
4
+ * Linear-blend interpolator matching {@link TransformPoseSerializationAdapter}'s
5
+ * layout (7 × Float64: position xyz + rotation xyzw). Position lerps
6
+ * componentwise; rotation nlerps with shortest-arc correction and renormalize.
7
+ *
8
+ * `first_offset === second_offset` reduces to the input at any `t` (the
9
+ * snap-to-single-snapshot case the log relies on), with no special handling.
10
+ *
11
+ * @author Alex Goldring
12
+ * @copyright Company Named Limited (c) 2026
13
+ */
14
+ export class PoseInterpolationAdapter extends BinaryInterpolationAdapter {
15
+
16
+ /** @inheritdoc */
17
+ interpolate(out_buffer, source, first_offset, second_offset, t) {
18
+ source.position = first_offset;
19
+ const ax = source.readFloat64();
20
+ const ay = source.readFloat64();
21
+ const az = source.readFloat64();
22
+ const aqx = source.readFloat64();
23
+ const aqy = source.readFloat64();
24
+ const aqz = source.readFloat64();
25
+ const aqw = source.readFloat64();
26
+
27
+ source.position = second_offset;
28
+ const bx = source.readFloat64();
29
+ const by = source.readFloat64();
30
+ const bz = source.readFloat64();
31
+ let bqx = source.readFloat64();
32
+ let bqy = source.readFloat64();
33
+ let bqz = source.readFloat64();
34
+ let bqw = source.readFloat64();
35
+
36
+ // Position: componentwise lerp.
37
+ const ox = ax + (bx - ax) * t;
38
+ const oy = ay + (by - ay) * t;
39
+ const oz = az + (bz - az) * t;
40
+
41
+ // Rotation: shortest-arc nlerp.
42
+ if (aqx * bqx + aqy * bqy + aqz * bqz + aqw * bqw < 0) {
43
+ bqx = -bqx; bqy = -bqy; bqz = -bqz; bqw = -bqw;
44
+ }
45
+ let qx = aqx + (bqx - aqx) * t;
46
+ let qy = aqy + (bqy - aqy) * t;
47
+ let qz = aqz + (bqz - aqz) * t;
48
+ let qw = aqw + (bqw - aqw) * t;
49
+ const len2 = qx * qx + qy * qy + qz * qz + qw * qw;
50
+ const inv = len2 > 0 ? 1 / Math.sqrt(len2) : 1;
51
+ qx *= inv; qy *= inv; qz *= inv; qw *= inv;
52
+
53
+ out_buffer.writeFloat64(ox);
54
+ out_buffer.writeFloat64(oy);
55
+ out_buffer.writeFloat64(oz);
56
+ out_buffer.writeFloat64(qx);
57
+ out_buffer.writeFloat64(qy);
58
+ out_buffer.writeFloat64(qz);
59
+ out_buffer.writeFloat64(qw);
60
+ }
61
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Full-precision (Float64) pose serializer for {@link Transform}: position +
3
+ * rotation only (the physics integrator never changes scale, so it's left to
4
+ * the live component). 7 × Float64 = 56 bytes.
5
+ *
6
+ * This is the LOCAL interpolation format, deliberately distinct from the
7
+ * network's bandwidth-tuned Float32 + packed-quaternion wire adapter: render
8
+ * fidelity in a massive world needs the full mantissa far from the origin, and
9
+ * the interpolation log is local memory, not wire bytes.
10
+ *
11
+ * `deserialize` writes through `position.set` / `rotation.set` so the
12
+ * Transform's onChanged subscribers (render, culling, particles, trails,
13
+ * attachments) all observe the interpolated pose.
14
+ *
15
+ * @author Alex Goldring
16
+ * @copyright Company Named Limited (c) 2026
17
+ */
18
+ export class TransformPoseSerializationAdapter extends BinaryClassSerializationAdapter<any> {
19
+ constructor();
20
+ klass: typeof Transform;
21
+ version: number;
22
+ /**
23
+ * @param {BinaryBuffer} buffer
24
+ * @param {Transform} transform
25
+ */
26
+ serialize(buffer: BinaryBuffer, transform: Transform): void;
27
+ /**
28
+ * @param {BinaryBuffer} buffer
29
+ * @param {Transform} transform
30
+ */
31
+ deserialize(buffer: BinaryBuffer, transform: Transform): void;
32
+ }
33
+ import { BinaryClassSerializationAdapter } from "../ecs/storage/binary/BinaryClassSerializationAdapter.js";
34
+ import { Transform } from "../ecs/transform/Transform.js";
35
+ //# sourceMappingURL=TransformPoseSerializationAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TransformPoseSerializationAdapter.d.ts","sourceRoot":"","sources":["../../../../src/engine/interpolation/TransformPoseSerializationAdapter.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;GAgBG;AACH;;IAEI,wBAAkB;IAClB,gBAAY;IAEZ;;;OAGG;IACH,2CAFW,SAAS,QAYnB;IAED;;;OAGG;IACH,6CAFW,SAAS,QAYnB;CACJ;gDAxD+C,0DAA0D;0BAChF,+BAA+B"}
@@ -0,0 +1,57 @@
1
+ import { BinaryClassSerializationAdapter } from "../ecs/storage/binary/BinaryClassSerializationAdapter.js";
2
+ import { Transform } from "../ecs/transform/Transform.js";
3
+
4
+ /**
5
+ * Full-precision (Float64) pose serializer for {@link Transform}: position +
6
+ * rotation only (the physics integrator never changes scale, so it's left to
7
+ * the live component). 7 × Float64 = 56 bytes.
8
+ *
9
+ * This is the LOCAL interpolation format, deliberately distinct from the
10
+ * network's bandwidth-tuned Float32 + packed-quaternion wire adapter: render
11
+ * fidelity in a massive world needs the full mantissa far from the origin, and
12
+ * the interpolation log is local memory, not wire bytes.
13
+ *
14
+ * `deserialize` writes through `position.set` / `rotation.set` so the
15
+ * Transform's onChanged subscribers (render, culling, particles, trails,
16
+ * attachments) all observe the interpolated pose.
17
+ *
18
+ * @author Alex Goldring
19
+ * @copyright Company Named Limited (c) 2026
20
+ */
21
+ export class TransformPoseSerializationAdapter extends BinaryClassSerializationAdapter {
22
+
23
+ klass = Transform;
24
+ version = 0;
25
+
26
+ /**
27
+ * @param {BinaryBuffer} buffer
28
+ * @param {Transform} transform
29
+ */
30
+ serialize(buffer, transform) {
31
+ const p = transform.position;
32
+ const r = transform.rotation;
33
+ buffer.writeFloat64(p.x);
34
+ buffer.writeFloat64(p.y);
35
+ buffer.writeFloat64(p.z);
36
+ buffer.writeFloat64(r.x);
37
+ buffer.writeFloat64(r.y);
38
+ buffer.writeFloat64(r.z);
39
+ buffer.writeFloat64(r.w);
40
+ }
41
+
42
+ /**
43
+ * @param {BinaryBuffer} buffer
44
+ * @param {Transform} transform
45
+ */
46
+ deserialize(buffer, transform) {
47
+ const px = buffer.readFloat64();
48
+ const py = buffer.readFloat64();
49
+ const pz = buffer.readFloat64();
50
+ const rx = buffer.readFloat64();
51
+ const ry = buffer.readFloat64();
52
+ const rz = buffer.readFloat64();
53
+ const rw = buffer.readFloat64();
54
+ transform.position.set(px, py, pz);
55
+ transform.rotation.set(rx, ry, rz, rw);
56
+ }
57
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Interpolation-log type id for the {@link Transform} pose interpoland. Type ids
3
+ * distinguish interpoland kinds under one entity key; pose is the first (0).
4
+ * When more kinds land, an interpolation registry should assign these so they
5
+ * can't collide. (For replicated entities this must eventually align with the
6
+ * network's replicated-component type id — tracked in INTEPOLATION_SYSTEM_PLAN.)
7
+ * @type {number}
8
+ */
9
+ export const POSE_TYPE_ID: number;
10
+ /**
11
+ * Shared, stateless pose interpoland: blend a body's {@link Transform} position
12
+ * + rotation. Reused across every entity that interpolates its pose — a body
13
+ * opting in carries an `Interpolated` whose `interpolands` is `[POSE_INTERPOLAND]`.
14
+ * @type {Interpoland}
15
+ */
16
+ export const POSE_INTERPOLAND: Interpoland;
17
+ import { Interpoland } from "./Interpoland.js";
18
+ //# sourceMappingURL=pose_interpoland.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pose_interpoland.d.ts","sourceRoot":"","sources":["../../../../src/engine/interpolation/pose_interpoland.js"],"names":[],"mappings":"AAKA;;;;;;;GAOG;AACH,2BAFU,MAAM,CAEc;AAE9B;;;;;GAKG;AACH,+BAFU,WAAW,CAOnB;4BAzB0B,kBAAkB"}
@@ -0,0 +1,27 @@
1
+ import { Transform } from "../ecs/transform/Transform.js";
2
+ import { Interpoland } from "./Interpoland.js";
3
+ import { PoseInterpolationAdapter } from "./PoseInterpolationAdapter.js";
4
+ import { TransformPoseSerializationAdapter } from "./TransformPoseSerializationAdapter.js";
5
+
6
+ /**
7
+ * Interpolation-log type id for the {@link Transform} pose interpoland. Type ids
8
+ * distinguish interpoland kinds under one entity key; pose is the first (0).
9
+ * When more kinds land, an interpolation registry should assign these so they
10
+ * can't collide. (For replicated entities this must eventually align with the
11
+ * network's replicated-component type id — tracked in INTEPOLATION_SYSTEM_PLAN.)
12
+ * @type {number}
13
+ */
14
+ export const POSE_TYPE_ID = 0;
15
+
16
+ /**
17
+ * Shared, stateless pose interpoland: blend a body's {@link Transform} position
18
+ * + rotation. Reused across every entity that interpolates its pose — a body
19
+ * opting in carries an `Interpolated` whose `interpolands` is `[POSE_INTERPOLAND]`.
20
+ * @type {Interpoland}
21
+ */
22
+ export const POSE_INTERPOLAND = new Interpoland(
23
+ POSE_TYPE_ID,
24
+ Transform,
25
+ new TransformPoseSerializationAdapter(),
26
+ new PoseInterpolationAdapter(),
27
+ );
@@ -375,12 +375,12 @@ export class NetworkSession {
375
375
  import { UUID } from "../ecs/guid/UUID.js";
376
376
  import Signal from "../../core/events/signal/Signal.js";
377
377
  import { BinarySerializationRegistry } from "../ecs/storage/binary/BinarySerializationRegistry.js";
378
- import { BinaryInterpolationAdapter } from "./sim/BinaryInterpolationAdapter.js";
378
+ import { BinaryInterpolationAdapter } from "../interpolation/BinaryInterpolationAdapter.js";
379
379
  import { SimAction } from "./sim/SimAction.js";
380
380
  import { ServerAuthoritativeServer } from "./orchestrator/ServerAuthoritativeServer.js";
381
381
  import { ServerAuthoritativeClient } from "./orchestrator/ServerAuthoritativeClient.js";
382
382
  import { NetworkPeer } from "./orchestrator/NetworkPeer.js";
383
- import { InterpolationLog } from "./sim/InterpolationLog.js";
383
+ import { InterpolationLog } from "../interpolation/InterpolationLog.js";
384
384
  import { AdaptiveRenderDelay } from "./time/AdaptiveRenderDelay.js";
385
385
  import { TimeDilation } from "./time/TimeDilation.js";
386
386
  //# sourceMappingURL=NetworkSession.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkSession.d.ts","sourceRoot":"","sources":["../../../../src/engine/network/NetworkSession.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NetworkSession.d.ts","sourceRoot":"","sources":["../../../../src/engine/network/NetworkSession.js"],"names":[],"mappings":"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"}
@@ -12,8 +12,8 @@ import { NetworkPeer, ResumeRejectReason, } from "./orchestrator/NetworkPeer.js"
12
12
  import { ServerAuthoritativeClient } from "./orchestrator/ServerAuthoritativeClient.js";
13
13
  import { ServerAuthoritativeServer } from "./orchestrator/ServerAuthoritativeServer.js";
14
14
  import { OwnerAwareScope } from "./replication/ScopeFilter.js";
15
- import { BinaryInterpolationAdapter, InterpolationKind, } from "./sim/BinaryInterpolationAdapter.js";
16
- import { InterpolationLog } from "./sim/InterpolationLog.js";
15
+ import { BinaryInterpolationAdapter, InterpolationKind, } from "../interpolation/BinaryInterpolationAdapter.js";
16
+ import { InterpolationLog } from "../interpolation/InterpolationLog.js";
17
17
  import { SimAction } from "./sim/SimAction.js";
18
18
  import { snapshotter_emit } from "./sim/Snapshotter.js";
19
19
  import { AdaptiveRenderDelay } from "./time/AdaptiveRenderDelay.js";
@@ -10,5 +10,5 @@ export class QuaternionInterpolationAdapter extends BinaryInterpolationAdapter {
10
10
  /** @inheritdoc */
11
11
  interpolate(out_buffer: any, source: any, first_offset: any, second_offset: any, t: any): void;
12
12
  }
13
- import { BinaryInterpolationAdapter } from "../sim/BinaryInterpolationAdapter.js";
13
+ import { BinaryInterpolationAdapter } from "../../interpolation/BinaryInterpolationAdapter.js";
14
14
  //# sourceMappingURL=QuaternionInterpolationAdapter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"QuaternionInterpolationAdapter.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/adapters/QuaternionInterpolationAdapter.js"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH;IAEI,kBAAkB;IAClB,+FA6BC;CACJ;2CA3C0C,sCAAsC"}
1
+ {"version":3,"file":"QuaternionInterpolationAdapter.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/adapters/QuaternionInterpolationAdapter.js"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH;IAEI,kBAAkB;IAClB,+FA6BC;CACJ;2CA3C0C,mDAAmD"}
@@ -1,4 +1,4 @@
1
- import { BinaryInterpolationAdapter } from "../sim/BinaryInterpolationAdapter.js";
1
+ import { BinaryInterpolationAdapter } from "../../interpolation/BinaryInterpolationAdapter.js";
2
2
 
3
3
  /**
4
4
  * Shortest-path nlerp for a 4 × Float32 quaternion payload (16 bytes).
@@ -14,5 +14,5 @@ export class TransformInterpolationAdapter extends BinaryInterpolationAdapter {
14
14
  /** @inheritdoc */
15
15
  interpolate(out_buffer: any, source: any, first_offset: any, second_offset: any, t: any): void;
16
16
  }
17
- import { BinaryInterpolationAdapter } from "../sim/BinaryInterpolationAdapter.js";
17
+ import { BinaryInterpolationAdapter } from "../../interpolation/BinaryInterpolationAdapter.js";
18
18
  //# sourceMappingURL=TransformInterpolationAdapter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TransformInterpolationAdapter.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/adapters/TransformInterpolationAdapter.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;GAWG;AACH;IAEI,kBAAkB;IAClB,+FAiDC;CACJ;2CA1E0C,sCAAsC"}
1
+ {"version":3,"file":"TransformInterpolationAdapter.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/adapters/TransformInterpolationAdapter.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;GAWG;AACH;IAEI,kBAAkB;IAClB,+FAiDC;CACJ;2CA1E0C,mDAAmD"}
@@ -2,7 +2,7 @@ import { quat_decode_from_uint32 } from "../../../core/geom/3d/quaternion/quat_d
2
2
  import { quat_encode_to_uint32 } from "../../../core/geom/3d/quaternion/quat_encode_to_uint32.js";
3
3
  import { v3_binary_equality_decode } from "../../../core/geom/vec3/serialization/v3_binary_equality_decode.js";
4
4
  import { v3_binary_equality_encode } from "../../../core/geom/vec3/serialization/v3_binary_equality_encode.js";
5
- import { BinaryInterpolationAdapter } from "../sim/BinaryInterpolationAdapter.js";
5
+ import { BinaryInterpolationAdapter } from "../../interpolation/BinaryInterpolationAdapter.js";
6
6
 
7
7
  /**
8
8
  * Module-level scratch. Layout: `[aq.xyzw, bq.xyzw, as.xyz, bs.xyz]`.
@@ -14,5 +14,5 @@
14
14
  */
15
15
  export class Vector3InterpolationAdapter extends BinaryInterpolationAdapter {
16
16
  }
17
- import { BinaryInterpolationAdapter } from "../sim/BinaryInterpolationAdapter.js";
17
+ import { BinaryInterpolationAdapter } from "../../interpolation/BinaryInterpolationAdapter.js";
18
18
  //# sourceMappingURL=Vector3InterpolationAdapter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Vector3InterpolationAdapter.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/adapters/Vector3InterpolationAdapter.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AACH;CA4BC;2CA5C0C,sCAAsC"}
1
+ {"version":3,"file":"Vector3InterpolationAdapter.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/adapters/Vector3InterpolationAdapter.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AACH;CA4BC;2CA5C0C,mDAAmD"}
@@ -1,5 +1,5 @@
1
1
  import { lerp } from "../../../core/math/lerp.js";
2
- import { BinaryInterpolationAdapter } from "../sim/BinaryInterpolationAdapter.js";
2
+ import { BinaryInterpolationAdapter } from "../../interpolation/BinaryInterpolationAdapter.js";
3
3
 
4
4
  /**
5
5
  * Componentwise lerp of a 3-Float32 position payload.