@aura3d/engine 1.5.0 → 1.5.2

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 (63) hide show
  1. package/README.md +111 -46
  2. package/dist/engine/agent-api/ApplicationKits.d.ts +307 -0
  3. package/dist/engine/agent-api/ApplicationKits.d.ts.map +1 -0
  4. package/dist/engine/agent-api/ApplicationKits.js +650 -0
  5. package/dist/engine/agent-api/ApplicationKits.js.map +1 -0
  6. package/dist/engine/agent-api/CombatFrameData.d.ts +210 -0
  7. package/dist/engine/agent-api/CombatFrameData.d.ts.map +1 -0
  8. package/dist/engine/agent-api/CombatFrameData.js +324 -0
  9. package/dist/engine/agent-api/CombatFrameData.js.map +1 -0
  10. package/dist/engine/agent-api/FocusSelection.d.ts +186 -0
  11. package/dist/engine/agent-api/FocusSelection.d.ts.map +1 -0
  12. package/dist/engine/agent-api/FocusSelection.js +436 -0
  13. package/dist/engine/agent-api/FocusSelection.js.map +1 -0
  14. package/dist/engine/agent-api/GameGenreKits.d.ts +32 -1
  15. package/dist/engine/agent-api/GameGenreKits.d.ts.map +1 -1
  16. package/dist/engine/agent-api/GameGenreKits.js +51 -7
  17. package/dist/engine/agent-api/GameGenreKits.js.map +1 -1
  18. package/dist/engine/agent-api/GameSceneGeometryBindings.d.ts +10 -0
  19. package/dist/engine/agent-api/GameSceneGeometryBindings.d.ts.map +1 -1
  20. package/dist/engine/agent-api/GameSceneGeometryBindings.js +7 -0
  21. package/dist/engine/agent-api/GameSceneGeometryBindings.js.map +1 -1
  22. package/dist/engine/agent-api/PlatformerMotion.d.ts +177 -0
  23. package/dist/engine/agent-api/PlatformerMotion.d.ts.map +1 -0
  24. package/dist/engine/agent-api/PlatformerMotion.js +207 -0
  25. package/dist/engine/agent-api/PlatformerMotion.js.map +1 -0
  26. package/dist/engine/agent-api/SceneQueries.d.ts +124 -0
  27. package/dist/engine/agent-api/SceneQueries.d.ts.map +1 -0
  28. package/dist/engine/agent-api/SceneQueries.js +221 -0
  29. package/dist/engine/agent-api/SceneQueries.js.map +1 -0
  30. package/dist/engine/agent-api/SpatialAnchoring.d.ts +279 -0
  31. package/dist/engine/agent-api/SpatialAnchoring.d.ts.map +1 -0
  32. package/dist/engine/agent-api/SpatialAnchoring.js +394 -0
  33. package/dist/engine/agent-api/SpatialAnchoring.js.map +1 -0
  34. package/dist/engine/agent-api/VehicleChassis.d.ts +192 -0
  35. package/dist/engine/agent-api/VehicleChassis.d.ts.map +1 -0
  36. package/dist/engine/agent-api/VehicleChassis.js +322 -0
  37. package/dist/engine/agent-api/VehicleChassis.js.map +1 -0
  38. package/dist/engine/agent-api/VehicleDriverAi.d.ts +123 -0
  39. package/dist/engine/agent-api/VehicleDriverAi.d.ts.map +1 -0
  40. package/dist/engine/agent-api/VehicleDriverAi.js +217 -0
  41. package/dist/engine/agent-api/VehicleDriverAi.js.map +1 -0
  42. package/dist/engine/agent-api/WorldLabelRenderer.d.ts +146 -0
  43. package/dist/engine/agent-api/WorldLabelRenderer.d.ts.map +1 -0
  44. package/dist/engine/agent-api/WorldLabelRenderer.js +331 -0
  45. package/dist/engine/agent-api/WorldLabelRenderer.js.map +1 -0
  46. package/dist/engine/agent-api/index.d.ts +64 -1
  47. package/dist/engine/agent-api/index.d.ts.map +1 -1
  48. package/dist/engine/agent-api/index.js +148 -2
  49. package/dist/engine/agent-api/index.js.map +1 -1
  50. package/dist/engine/agent-api/product-viewer-runtime.d.ts.map +1 -1
  51. package/dist/rendering/CameraFraming.d.ts +77 -0
  52. package/dist/rendering/CameraFraming.d.ts.map +1 -1
  53. package/dist/rendering/CameraFraming.js +176 -1
  54. package/dist/rendering/CameraFraming.js.map +1 -1
  55. package/dist/rendering/Renderer.d.ts +25 -2
  56. package/dist/rendering/Renderer.d.ts.map +1 -1
  57. package/dist/rendering/Renderer.js +11 -3
  58. package/dist/rendering/Renderer.js.map +1 -1
  59. package/dist/rendering/index.d.ts +3 -3
  60. package/dist/rendering/index.d.ts.map +1 -1
  61. package/dist/rendering/index.js +1 -1
  62. package/dist/rendering/index.js.map +1 -1
  63. package/package.json +120 -115
@@ -0,0 +1,394 @@
1
+ /**
2
+ * Asset-relative spatial layout and semantic anchoring.
3
+ *
4
+ * ## Why this exists
5
+ *
6
+ * Public routes placed helper geometry -- status markers, control stations,
7
+ * selection rings, callout panels, staging props -- at literal world
8
+ * coordinates chosen by eye against whatever asset was loaded that week. When
9
+ * the asset changed, or its bounds changed, the coordinates did not. The
10
+ * visible result is procedural boxes floating beside the scene rather than
11
+ * attached to the equipment they annotate.
12
+ *
13
+ * `CAR_SCENE_HEIGHT` was the same defect in a single constant: a value correct
14
+ * for one asset, frozen, then wrong. This module removes the reason to write
15
+ * such a constant. A route states intent -- "above this machine", "beside the
16
+ * workcell", "on the floor in front of the product" -- and reads back a world
17
+ * position derived from the asset's own placed bounds.
18
+ *
19
+ * Everything here is pure: no renderer, no asset loading, no DOM. Anchors are
20
+ * resolved from {@link PlacedBounds}, which a route obtains from typed asset
21
+ * bounds plus its intended scale via {@link placedBoundsFromAsset}.
22
+ */
23
+ import { boundsFromAsset, boundsSize } from "./SceneGroundingUtils.js";
24
+ /**
25
+ * Build placed bounds from a subject's world position, size and floor.
26
+ *
27
+ * `position` is the subject's floor contact point, matching how Aura3D's safe
28
+ * model renderer grounds a normalized model on its node origin.
29
+ */
30
+ export function placedBounds(options) {
31
+ const floorY = options.floorY ?? options.position[1];
32
+ const size = [
33
+ Math.max(0, options.size[0]),
34
+ Math.max(0, options.size[1]),
35
+ Math.max(0, options.size[2])
36
+ ];
37
+ const min = [options.position[0] - size[0] / 2, floorY, options.position[2] - size[2] / 2];
38
+ const max = [options.position[0] + size[0] / 2, floorY + size[1], options.position[2] + size[2] / 2];
39
+ return {
40
+ min,
41
+ max,
42
+ center: [(min[0] + max[0]) / 2, (min[1] + max[1]) / 2, (min[2] + max[2]) / 2],
43
+ size,
44
+ floorY
45
+ };
46
+ }
47
+ /**
48
+ * Placed bounds for a typed asset rendered with `model(asset)`.
49
+ *
50
+ * Mirrors the safe renderer: the asset is normalized to
51
+ * `normalizedMaxDimension`, multiplied by node scale, and grounded so its
52
+ * lowest point rests on `floorY`. A route therefore never needs the asset's raw
53
+ * dimensions to place something relative to it.
54
+ */
55
+ export function placedBoundsFromAsset(asset, options) {
56
+ const raw = boundsFromAsset(asset);
57
+ const rawSize = boundsSize(raw);
58
+ const rawMax = Math.max(rawSize[0], rawSize[1], rawSize[2]);
59
+ const factor = rawMax > 0 && options.targetMaxDimension > 0 ? options.targetMaxDimension / rawMax : 1;
60
+ const position = options.position ?? [0, options.floorY ?? 0, 0];
61
+ return placedBounds({
62
+ position,
63
+ size: [rawSize[0] * factor, rawSize[1] * factor, rawSize[2] * factor],
64
+ floorY: options.floorY ?? position[1]
65
+ });
66
+ }
67
+ /**
68
+ * Size an asset so it occupies a chosen fraction of a region it sits inside.
69
+ *
70
+ * Placement was already bounds-derived through {@link resolveSemanticRegion},
71
+ * but *sizing* was not: a route that knew where a vehicle belonged still had to
72
+ * invent a multiplier such as `.scale(1.58)` to decide how big it should be.
73
+ * That number carries no relationship to either the asset or its surroundings,
74
+ * so it silently becomes wrong the moment the asset is swapped or the scene
75
+ * resized — which is precisely the "hero fills the frame and occludes the scene"
76
+ * defect class.
77
+ *
78
+ * This returns a `targetMaxDimension` rather than a raw scale factor on purpose.
79
+ * A scale factor is only meaningful relative to an asset's unknown raw
80
+ * dimensions, whereas a target dimension is an absolute statement about world
81
+ * size that the renderer resolves against the asset's real bounds.
82
+ */
83
+ export function fitSizeToRegion(region, options) {
84
+ const regionSize = [
85
+ Math.max(0, region.size[0]),
86
+ Math.max(0, region.size[1]),
87
+ Math.max(0, region.size[2])
88
+ ];
89
+ const requested = Number.isFinite(options.occupancy) ? Math.min(1, Math.max(0, options.occupancy)) : 0;
90
+ const axes = options.axes ?? ["x", "z"];
91
+ const axisIndex = { x: 0, y: 1, z: 2 };
92
+ const candidates = axes
93
+ .map((axis) => regionSize[axisIndex[axis]])
94
+ .filter((value) => typeof value === "number" && value > 0);
95
+ if (candidates.length === 0) {
96
+ throw new RangeError("fitSizeToRegion requires a region with positive extent on at least one constraining axis.");
97
+ }
98
+ // The smallest constraining extent governs: fitting to the largest would let
99
+ // the subject overflow the tighter axis, which is the same visual failure as
100
+ // hardcoding the scale too high.
101
+ const governing = Math.min(...candidates);
102
+ const ideal = governing * requested;
103
+ const lowerBound = options.minSize !== undefined && Number.isFinite(options.minSize) ? Math.max(0, options.minSize) : 0;
104
+ const upperBound = options.maxSize !== undefined && Number.isFinite(options.maxSize) ? Math.max(0, options.maxSize) : Number.POSITIVE_INFINITY;
105
+ const targetMaxDimension = Math.min(upperBound, Math.max(lowerBound, ideal));
106
+ return {
107
+ targetMaxDimension,
108
+ occupancy: governing > 0 ? targetMaxDimension / governing : 0,
109
+ regionSize,
110
+ clamped: targetMaxDimension !== ideal
111
+ };
112
+ }
113
+ /** Placed bounds for a raw {@link SceneBounds} already expressed in world units. */
114
+ export function placedBoundsFromWorldBounds(bounds) {
115
+ const size = boundsSize(bounds);
116
+ return {
117
+ min: [bounds.min[0], bounds.min[1], bounds.min[2]],
118
+ max: [bounds.max[0], bounds.max[1], bounds.max[2]],
119
+ center: [
120
+ (bounds.min[0] + bounds.max[0]) / 2,
121
+ (bounds.min[1] + bounds.max[1]) / 2,
122
+ (bounds.min[2] + bounds.max[2]) / 2
123
+ ],
124
+ size,
125
+ floorY: bounds.min[1]
126
+ };
127
+ }
128
+ const ANCHOR_NORMALS = {
129
+ center: [0, 0, 0],
130
+ top: [0, 1, 0],
131
+ bottom: [0, -1, 0],
132
+ // "front" is +Z: Aura3D scenes look down -Z from a default camera, so the face
133
+ // nearest the viewer is +Z. Documented rather than inferred so a route reading
134
+ // "front" does not get the far side.
135
+ front: [0, 0, 1],
136
+ rear: [0, 0, -1],
137
+ left: [-1, 0, 0],
138
+ right: [1, 0, 0],
139
+ "top-front": [0, 0.7071, 0.7071],
140
+ "top-rear": [0, 0.7071, -0.7071],
141
+ "top-left": [-0.7071, 0.7071, 0],
142
+ "top-right": [0.7071, 0.7071, 0],
143
+ "floor-front": [0, 0, 1],
144
+ "floor-rear": [0, 0, -1],
145
+ "floor-left": [-1, 0, 0],
146
+ "floor-right": [1, 0, 0],
147
+ "corner-front-left": [-0.7071, 0, 0.7071],
148
+ "corner-front-right": [0.7071, 0, 0.7071],
149
+ "corner-rear-left": [-0.7071, 0, -0.7071],
150
+ "corner-rear-right": [0.7071, 0, -0.7071]
151
+ };
152
+ /**
153
+ * Resolve a world position on or beside a subject's placed bounds.
154
+ *
155
+ * The returned position is on the named face at `offset` distance outward. This
156
+ * is the replacement for literal helper coordinates: it tracks the asset.
157
+ */
158
+ export function resolveBoundsAnchor(bounds, anchor, options = {}) {
159
+ const normal = ANCHOR_NORMALS[anchor];
160
+ const offset = options.offset ?? 0;
161
+ const half = [bounds.size[0] / 2, bounds.size[1] / 2, bounds.size[2] / 2];
162
+ // Start at the bounds centre and walk out to the named face.
163
+ let position = [
164
+ bounds.center[0] + normal[0] * half[0],
165
+ bounds.center[1] + normal[1] * half[1],
166
+ bounds.center[2] + normal[2] * half[2]
167
+ ];
168
+ // Floor anchors sit on the ground plane beside the subject.
169
+ if (anchor.startsWith("floor-") || options.onFloor === true) {
170
+ position = [position[0], bounds.floorY, position[2]];
171
+ }
172
+ position = [
173
+ position[0] + normal[0] * offset,
174
+ position[1] + normal[1] * offset,
175
+ position[2] + normal[2] * offset
176
+ ];
177
+ const worldOffset = options.worldOffset ?? [0, 0, 0];
178
+ position = [position[0] + worldOffset[0], position[1] + worldOffset[1], position[2] + worldOffset[2]];
179
+ return {
180
+ position,
181
+ normal,
182
+ anchor,
183
+ outsideBounds: !containsPoint(bounds, position)
184
+ };
185
+ }
186
+ /** True when a world point lies inside the placed bounds (inclusive). */
187
+ export function containsPoint(bounds, point, epsilon = 1e-6) {
188
+ return point[0] >= bounds.min[0] - epsilon && point[0] <= bounds.max[0] + epsilon
189
+ && point[1] >= bounds.min[1] - epsilon && point[1] <= bounds.max[1] + epsilon
190
+ && point[2] >= bounds.min[2] - epsilon && point[2] <= bounds.max[2] + epsilon;
191
+ }
192
+ /** Resolve a normalized semantic region to world-space bounds on the subject. */
193
+ export function resolveSemanticRegion(bounds, region) {
194
+ const clamp01 = (value) => Math.min(1, Math.max(0, Number.isFinite(value) ? value : 0));
195
+ const u = clamp01(region.u);
196
+ const v = clamp01(region.v);
197
+ const w = clamp01(region.w);
198
+ const extent = region.extent ?? [0, 0, 0];
199
+ const center = [
200
+ bounds.min[0] + bounds.size[0] * u,
201
+ bounds.min[1] + bounds.size[1] * v,
202
+ bounds.min[2] + bounds.size[2] * w
203
+ ];
204
+ const size = [
205
+ bounds.size[0] * clamp01(extent[0]),
206
+ bounds.size[1] * clamp01(extent[1]),
207
+ bounds.size[2] * clamp01(extent[2])
208
+ ];
209
+ return {
210
+ id: region.id,
211
+ label: region.label,
212
+ center,
213
+ size,
214
+ min: [center[0] - size[0] / 2, center[1] - size[1] / 2, center[2] - size[2] / 2],
215
+ max: [center[0] + size[0] / 2, center[1] + size[1] / 2, center[2] + size[2] / 2]
216
+ };
217
+ }
218
+ /**
219
+ * Distribute items evenly across a region, honouring a minimum spacing.
220
+ *
221
+ * Deterministic for a given seed so gameplay and evidence are reproducible.
222
+ * Used instead of `-0.45 + index * 0.17` style literals, which encode both the
223
+ * region and its spacing into one unexplained pair of numbers.
224
+ */
225
+ export function distributeInRegion(region, options) {
226
+ const count = Math.max(0, Math.floor(options.count));
227
+ if (count === 0)
228
+ return [];
229
+ const spanX = region.max[0] - region.min[0];
230
+ const spanZ = region.max[2] - region.min[2];
231
+ const jitter = Math.min(1, Math.max(0, options.jitter ?? 0));
232
+ const seed = options.seed ?? 1;
233
+ // Lay items along the longer horizontal axis so a narrow conveyor stays a line.
234
+ const alongX = spanX >= spanZ;
235
+ const span = alongX ? spanX : spanZ;
236
+ const step = count > 1 ? span / (count - 1) : 0;
237
+ const y = options.onFloor === true ? region.min[1] : (region.min[1] + region.max[1]) / 2;
238
+ const positions = [];
239
+ let random = seed >>> 0 || 1;
240
+ const nextRandom = () => {
241
+ // xorshift32: deterministic, no dependencies, adequate for layout jitter.
242
+ random ^= random << 13;
243
+ random ^= random >>> 17;
244
+ random ^= random << 5;
245
+ return ((random >>> 0) / 0xffffffff) * 2 - 1;
246
+ };
247
+ for (let index = 0; index < count; index += 1) {
248
+ const t = count > 1 ? index * step : span / 2;
249
+ const jitterAmount = jitter * step * 0.5;
250
+ const primary = (alongX ? region.min[0] : region.min[2]) + t + (jitter > 0 ? nextRandom() * jitterAmount : 0);
251
+ const secondaryCenter = alongX ? (region.min[2] + region.max[2]) / 2 : (region.min[0] + region.max[0]) / 2;
252
+ const secondarySpan = alongX ? spanZ : spanX;
253
+ const secondary = secondaryCenter + (jitter > 0 ? nextRandom() * secondarySpan * 0.5 * jitter : 0);
254
+ positions.push(alongX ? [primary, y, secondary] : [secondary, y, primary]);
255
+ }
256
+ const minSpacing = options.minSpacing ?? 0;
257
+ return positions.map((position, index) => {
258
+ let nearest = Number.POSITIVE_INFINITY;
259
+ positions.forEach((other, otherIndex) => {
260
+ if (otherIndex === index)
261
+ return;
262
+ nearest = Math.min(nearest, distance(position, other));
263
+ });
264
+ if (!Number.isFinite(nearest))
265
+ nearest = Number.POSITIVE_INFINITY;
266
+ return {
267
+ index,
268
+ position,
269
+ nearestNeighborDistance: nearest === Number.POSITIVE_INFINITY ? Number.POSITIVE_INFINITY : round(nearest)
270
+ };
271
+ }).map((placement) => {
272
+ // Report rather than silently correct: a caller asking for spacing the region
273
+ // cannot provide should see it in the invariant report, not get moved items.
274
+ void minSpacing;
275
+ return placement;
276
+ });
277
+ }
278
+ /** Minimum-spacing check for a set of placements. */
279
+ export function validateSpacing(placements, minSpacing) {
280
+ const violations = placements
281
+ .filter((placement) => Number.isFinite(placement.nearestNeighborDistance) && placement.nearestNeighborDistance < minSpacing)
282
+ .map((placement) => ({ index: placement.index, distance: placement.nearestNeighborDistance }));
283
+ return { ok: violations.length === 0, violations };
284
+ }
285
+ /**
286
+ * Place items on a circle around a subject.
287
+ *
288
+ * The radius is added to the subject's own horizontal half-extent, so a ring of
289
+ * markers stays clear of the asset regardless of how large the asset is.
290
+ */
291
+ export function distributeAroundBounds(bounds, options) {
292
+ const count = Math.max(0, Math.floor(options.count));
293
+ if (count === 0)
294
+ return [];
295
+ const clearance = Math.max(bounds.size[0], bounds.size[2]) / 2;
296
+ const radius = clearance + Math.max(0, options.radius);
297
+ const sweep = options.sweep ?? Math.PI * 2;
298
+ const start = options.startAngle ?? 0;
299
+ const y = options.height ?? bounds.center[1];
300
+ const step = count > 1 ? sweep / (sweep >= Math.PI * 2 - 1e-6 ? count : count - 1) : 0;
301
+ const positions = [];
302
+ for (let index = 0; index < count; index += 1) {
303
+ const angle = start + step * index;
304
+ positions.push([
305
+ bounds.center[0] + Math.cos(angle) * radius,
306
+ y,
307
+ bounds.center[2] + Math.sin(angle) * radius
308
+ ]);
309
+ }
310
+ return positions.map((position, index) => {
311
+ let nearest = Number.POSITIVE_INFINITY;
312
+ positions.forEach((other, otherIndex) => {
313
+ if (otherIndex === index)
314
+ return;
315
+ nearest = Math.min(nearest, distance(position, other));
316
+ });
317
+ return { index, position, nearestNeighborDistance: Number.isFinite(nearest) ? round(nearest) : Number.POSITIVE_INFINITY };
318
+ });
319
+ }
320
+ /**
321
+ * Verify that helper geometry is anchored to its subject.
322
+ *
323
+ * `outside` elements must remain within `maxDistance` of the bounds: that is
324
+ * what separates "a control station beside the workcell" from "a box floating in
325
+ * the void". The default of 2x the subject's largest extent is generous enough
326
+ * for staging and tight enough to catch the digital-twin defect class.
327
+ */
328
+ export function checkSpatialInvariants(bounds, claims, options = {}) {
329
+ const tolerance = options.surfaceTolerance ?? Math.max(0.02, Math.max(...bounds.size) * 0.08);
330
+ const defaultMaxDistance = Math.max(...bounds.size) * 2;
331
+ const checks = claims.map((claim) => {
332
+ const inside = containsPoint(bounds, claim.position);
333
+ const surfaceDistance = distanceToBoundsSurface(bounds, claim.position);
334
+ const outsideDistance = distanceOutsideBounds(bounds, claim.position);
335
+ if (claim.relation === "inside") {
336
+ return {
337
+ id: claim.id,
338
+ description: `${claim.id} must lie inside the subject bounds`,
339
+ passes: inside,
340
+ detail: inside ? "inside bounds" : `outside bounds by ${round(outsideDistance)} units`
341
+ };
342
+ }
343
+ if (claim.relation === "surface") {
344
+ const passes = surfaceDistance <= tolerance;
345
+ return {
346
+ id: claim.id,
347
+ description: `${claim.id} must sit on the subject surface within ${round(tolerance)} units`,
348
+ passes,
349
+ detail: `distance to surface ${round(surfaceDistance)} (tolerance ${round(tolerance)})`
350
+ };
351
+ }
352
+ const limit = claim.maxDistance ?? defaultMaxDistance;
353
+ const passes = !inside && outsideDistance <= limit;
354
+ return {
355
+ id: claim.id,
356
+ description: `${claim.id} must sit beside the subject within ${round(limit)} units, not inside it`,
357
+ passes,
358
+ detail: inside
359
+ ? "unexpectedly inside the subject bounds"
360
+ : `distance outside bounds ${round(outsideDistance)} (limit ${round(limit)})`
361
+ };
362
+ });
363
+ return {
364
+ schema: "aura3d-spatial-invariants/1.0",
365
+ subjectBounds: bounds,
366
+ checks,
367
+ passes: checks.every((check) => check.passes)
368
+ };
369
+ }
370
+ /** Shortest distance from a point to the bounds surface (0 when on it). */
371
+ export function distanceToBoundsSurface(bounds, point) {
372
+ const outside = distanceOutsideBounds(bounds, point);
373
+ if (outside > 0)
374
+ return outside;
375
+ // Inside: distance to the nearest face.
376
+ return Math.min(point[0] - bounds.min[0], bounds.max[0] - point[0], point[1] - bounds.min[1], bounds.max[1] - point[1], point[2] - bounds.min[2], bounds.max[2] - point[2]);
377
+ }
378
+ /** Distance from a point to the bounds volume; 0 when inside. */
379
+ export function distanceOutsideBounds(bounds, point) {
380
+ const dx = Math.max(bounds.min[0] - point[0], 0, point[0] - bounds.max[0]);
381
+ const dy = Math.max(bounds.min[1] - point[1], 0, point[1] - bounds.max[1]);
382
+ const dz = Math.max(bounds.min[2] - point[2], 0, point[2] - bounds.max[2]);
383
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
384
+ }
385
+ function distance(a, b) {
386
+ const dx = a[0] - b[0];
387
+ const dy = a[1] - b[1];
388
+ const dz = a[2] - b[2];
389
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
390
+ }
391
+ function round(value) {
392
+ return Math.round(value * 1e6) / 1e6;
393
+ }
394
+ //# sourceMappingURL=SpatialAnchoring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpatialAnchoring.js","sourceRoot":"","sources":["../../../../../packages/engine/src/agent-api/SpatialAnchoring.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Reusable vehicle chassis: contact, suspension, attitude and wheel visuals.
3
+ *
4
+ * ## The defects this addresses
5
+ *
6
+ * Turbo Drift Circuit drove a 2D kinematic point (`game.racing`) and then pinned
7
+ * the car's rendered Y to a single literal, `TRACK_SURFACE_Y`. That has three
8
+ * visible consequences:
9
+ *
10
+ * 1. **The car sinks into the tarmac.** A model grounded on a frozen plane cannot
11
+ * respond to the surface it is actually over. There is no contact model, so
12
+ * there is nothing to hold the tyres on the road.
13
+ * 2. **No suspension.** The chassis never pitches under braking, never rolls in a
14
+ * corner, and the wheels never travel. A car that stays perfectly level at
15
+ * 111 km/h reads as a sprite sliding on a plane, which is what it is.
16
+ * 3. **Wheels do not turn or steer.** Nothing derived wheel spin from speed or
17
+ * wheel yaw from steering input.
18
+ *
19
+ * This module is the reusable answer. It takes a planar vehicle state -- position,
20
+ * heading, speed, steering, lateral slip -- plus a surface query, and produces the
21
+ * full 3D pose a renderer needs: chassis height from four independent contact
22
+ * points, pitch and roll from load transfer, per-wheel suspension travel, wheel
23
+ * spin and steer angles, and a contact report that states whether every tyre is
24
+ * on the ground.
25
+ *
26
+ * It is pure: no renderer, no DOM, no asset loading. That makes vehicle behaviour
27
+ * unit-testable, which is the only way "the car is grounded" becomes a fact rather
28
+ * than an opinion about a screenshot.
29
+ */
30
+ export type VehicleVec3 = readonly [number, number, number];
31
+ /** Surface sample under one contact point. */
32
+ export interface VehicleSurfaceSample {
33
+ /** World Y of the surface at the queried point. */
34
+ readonly height: number;
35
+ /** Surface normal. Defaults to world up when a track is flat. */
36
+ readonly normal?: VehicleVec3 | undefined;
37
+ /** Grip multiplier, 1 on tarmac and lower off-track. */
38
+ readonly grip?: number | undefined;
39
+ }
40
+ /**
41
+ * Surface the vehicle drives on.
42
+ *
43
+ * A route supplies this from its own track topology. Because the chassis asks the
44
+ * surface for a height at each wheel rather than being told one number, swapping
45
+ * the track asset cannot leave the car buried: there is no frozen plane to be
46
+ * wrong about.
47
+ */
48
+ export interface VehicleSurface {
49
+ sample(x: number, z: number): VehicleSurfaceSample;
50
+ }
51
+ /** Flat surface at a fixed height, for prototypes and tests. */
52
+ export declare function flatVehicleSurface(height?: number, grip?: number): VehicleSurface;
53
+ export interface VehicleChassisSpec {
54
+ /** Distance between front and rear axles, world units. */
55
+ readonly wheelbase: number;
56
+ /** Distance between left and right wheels, world units. */
57
+ readonly trackWidth: number;
58
+ /** Rolling radius of a wheel, world units. Drives visual spin rate. */
59
+ readonly wheelRadius: number;
60
+ /**
61
+ * Ride height: distance from the wheel contact patch to the chassis origin at
62
+ * rest. Derived from the asset's own bounds by the caller, never guessed.
63
+ */
64
+ readonly rideHeight: number;
65
+ /** Suspension travel available above and below rest, world units. */
66
+ readonly suspensionTravel?: number | undefined;
67
+ /**
68
+ * Spring stiffness as a normalized rate. Higher is firmer: the chassis resists
69
+ * pitch and roll more and settles faster.
70
+ */
71
+ readonly springRate?: number | undefined;
72
+ /** Damping ratio. 1 is critically damped; below 1 oscillates. */
73
+ readonly dampingRatio?: number | undefined;
74
+ /** Maximum steering angle at the front wheels, radians. */
75
+ readonly maxSteerAngle?: number | undefined;
76
+ /** Maximum chassis pitch under full braking or acceleration, radians. */
77
+ readonly maxPitch?: number | undefined;
78
+ /** Maximum chassis roll at full lateral load, radians. */
79
+ readonly maxRoll?: number | undefined;
80
+ }
81
+ export interface VehiclePlanarState {
82
+ /** World X of the chassis centre. */
83
+ readonly x: number;
84
+ /** World Z of the chassis centre. */
85
+ readonly z: number;
86
+ /** Heading in radians, measured so that heading 0 faces +X. */
87
+ readonly heading: number;
88
+ /** Forward speed in world units per second. */
89
+ readonly speed: number;
90
+ /** Steering input, -1..1. */
91
+ readonly steer: number;
92
+ /** Throttle input, 0..1. */
93
+ readonly throttle?: number | undefined;
94
+ /** Brake input, 0..1. */
95
+ readonly brake?: number | undefined;
96
+ /** Lateral slip, 0..1, used for roll and tyre scrub. */
97
+ readonly slip?: number | undefined;
98
+ }
99
+ export type VehicleWheelId = "front-left" | "front-right" | "rear-left" | "rear-right";
100
+ export interface VehicleWheelPose {
101
+ readonly id: VehicleWheelId;
102
+ /** World position of the wheel centre. */
103
+ readonly position: VehicleVec3;
104
+ /** Steering angle applied to this wheel, radians. Zero for rear wheels. */
105
+ readonly steerAngle: number;
106
+ /** Accumulated rolling rotation, radians. */
107
+ readonly spin: number;
108
+ /** Suspension compression, 0 at full extension and 1 at full compression. */
109
+ readonly compression: number;
110
+ /** True when this wheel's contact patch is on the surface. */
111
+ readonly grounded: boolean;
112
+ /** Distance from the contact patch to the surface. Zero when grounded. */
113
+ readonly contactGap: number;
114
+ }
115
+ export interface VehiclePose {
116
+ /**
117
+ * Chassis origin in world space: the body's centre height, as a rigid body would
118
+ * report it.
119
+ *
120
+ * Use this for a model whose pivot is at its own centre. For a model rendered with
121
+ * `scaleMode: "fit"`, use {@link groundedPosition} instead -- the safe renderer grounds
122
+ * a fitted model's *lowest point* on its node position, so placing the body centre
123
+ * there lifts the whole vehicle by its ride height. That mismatch is visible as a car
124
+ * hovering above the road, which is the same class of defect as the sinking it
125
+ * replaced, in the opposite direction.
126
+ */
127
+ readonly position: VehicleVec3;
128
+ /**
129
+ * Contact-plane position: the height the lowest tyre contact patch sits at.
130
+ *
131
+ * This is what a `scaleMode: "fit"` model's node position should be set to.
132
+ */
133
+ readonly groundedPosition: VehicleVec3;
134
+ /** Euler rotation: pitch on X, yaw on Y, roll on Z. */
135
+ readonly rotation: VehicleVec3;
136
+ readonly wheels: readonly VehicleWheelPose[];
137
+ /** Height of the lowest contact patch above the surface. */
138
+ readonly contactGap: number;
139
+ /** True when every wheel is on the ground. */
140
+ readonly grounded: boolean;
141
+ /** Mean suspension compression across all four wheels. */
142
+ readonly averageCompression: number;
143
+ }
144
+ export interface VehicleChassisTelemetry {
145
+ readonly speed: number;
146
+ readonly speedKph: number;
147
+ readonly pitch: number;
148
+ readonly roll: number;
149
+ readonly steerAngle: number;
150
+ readonly wheelSpinRate: number;
151
+ readonly groundedWheels: number;
152
+ readonly maxContactGap: number;
153
+ readonly averageCompression: number;
154
+ readonly surfaceGrip: number;
155
+ }
156
+ export interface VehicleChassis {
157
+ readonly kind: "aura-vehicle-chassis";
158
+ readonly spec: Required<Omit<VehicleChassisSpec, never>>;
159
+ /** Advance suspension and wheel state, returning the resolved 3D pose. */
160
+ step(dt: number, state: VehiclePlanarState): VehiclePose;
161
+ /** Most recent pose without advancing. */
162
+ pose(): VehiclePose;
163
+ telemetry(): VehicleChassisTelemetry;
164
+ /** Return to rest at a planar state, clearing suspension and spin history. */
165
+ reset(state: VehiclePlanarState): VehiclePose;
166
+ }
167
+ /**
168
+ * Create a vehicle chassis.
169
+ *
170
+ * `rideHeight` and `wheelRadius` should be derived from the vehicle asset's own
171
+ * bounds. That is the difference between this and the constant it replaces: the
172
+ * caller states a proportion of a measured asset, not a number that happened to
173
+ * look right once.
174
+ */
175
+ export declare function createVehicleChassis(spec: VehicleChassisSpec, surface: VehicleSurface): VehicleChassis;
176
+ /**
177
+ * Derive chassis geometry from a vehicle asset's rendered bounds.
178
+ *
179
+ * This is what removes the need for a `CAR_SCENE_HEIGHT`-style constant. Given the
180
+ * size the asset actually renders at, the wheelbase, track width, wheel radius and
181
+ * ride height follow from standard automotive proportions, so a different car
182
+ * produces a different chassis instead of inheriting the old one's numbers.
183
+ */
184
+ export declare function vehicleChassisSpecFromBounds(size: VehicleVec3, options?: {
185
+ /** Fraction of the body length between the axles. Real cars sit near 0.6. */
186
+ readonly wheelbaseFraction?: number | undefined;
187
+ /** Fraction of the body width between the wheel centres. */
188
+ readonly trackFraction?: number | undefined;
189
+ /** Fraction of body height taken by wheel diameter. */
190
+ readonly wheelDiameterFraction?: number | undefined;
191
+ }): VehicleChassisSpec;
192
+ //# sourceMappingURL=VehicleChassis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VehicleChassis.d.ts","sourceRoot":"","sources":["../../../../../packages/engine/src/agent-api/VehicleChassis.ts"],"names":[],"mappings":"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"}