@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
@@ -3,6 +3,16 @@ import { createExternalParityEnvironmentLighting, Geometry, IndexBuffer, PBRMate
3
3
  import { DirectionalLight, PointLight, SpotLight } from "../../scene/index.js";
4
4
  import { createTypedGLBActor } from "../production-runtime/TypedGLBActor.js";
5
5
  import { AURA_NORMALIZED_MODEL_MAX_DIMENSION, boundsFromAsset, boundsHeight, boundsMaxDimension, boundsSize } from "./SceneGroundingUtils.js";
6
+ import { createWorldLabelLayer } from "./WorldLabelRenderer.js";
7
+ export * from "./SpatialAnchoring.js";
8
+ export * from "./FocusSelection.js";
9
+ export * from "./WorldLabelRenderer.js";
10
+ export * from "./VehicleChassis.js";
11
+ export * from "./VehicleDriverAi.js";
12
+ export * from "./PlatformerMotion.js";
13
+ export * from "./CombatFrameData.js";
14
+ export * from "./SceneQueries.js";
15
+ export * from "./ApplicationKits.js";
6
16
  export * from "./FrameEncoder.js";
7
17
  export * from "./BrowserFrameCaptureAdapter.js";
8
18
  export * from "./MediaRecorderFrameEncoder.js";
@@ -1052,6 +1062,50 @@ export const camera = {
1052
1062
  easing: options.easing ?? "easeInOut",
1053
1063
  captureTime: options.captureTime
1054
1064
  }),
1065
+ /**
1066
+ * A parallel-projection camera: no foreshortening, so equal world lengths
1067
+ * occupy equal screen lengths wherever they sit in depth.
1068
+ *
1069
+ * Reach for this when the projection is part of the meaning rather than a
1070
+ * stylistic choice — CAD and engineering views, floor plans, technical
1071
+ * diagrams, sprite and texture bakes, chart axes, and product shots that must
1072
+ * read as measurable. A long-lens perspective camera approximates it but
1073
+ * still converges, which is visible on long straight edges.
1074
+ */
1075
+ orthographic: (options = {}) => ({
1076
+ mode: "orthographic",
1077
+ position: options.position ?? [0, 1.4, 4],
1078
+ target: options.target ?? [0, 0.8, 0],
1079
+ orthographicSize: options.orthographicSize ?? 1.4
1080
+ }),
1081
+ /**
1082
+ * The conventional isometric view: an orthographic camera on a 45-degree
1083
+ * azimuth and a ~35.264-degree elevation.
1084
+ *
1085
+ * That elevation is `atan(1 / sqrt(2))`, the angle at which the three world
1086
+ * axes project to equal screen lengths and 120 degrees apart. Authoring it as
1087
+ * a preset matters because the value is not memorable and an approximation
1088
+ * such as 30 or 45 degrees produces the subtly-wrong grid alignment that
1089
+ * isometric tile art immediately reveals.
1090
+ */
1091
+ isometric: (options = {}) => {
1092
+ const target = options.target ?? [0, 0, 0];
1093
+ const distance = options.distance ?? 12;
1094
+ const elevation = Math.atan(1 / Math.SQRT2);
1095
+ const azimuth = Math.PI / 4;
1096
+ const horizontal = Math.cos(elevation) * distance;
1097
+ return {
1098
+ mode: "isometric",
1099
+ target,
1100
+ distance,
1101
+ orthographicSize: options.orthographicSize ?? 6,
1102
+ position: options.position ?? [
1103
+ target[0] + Math.sin(azimuth) * horizontal,
1104
+ target[1] + Math.sin(elevation) * distance,
1105
+ target[2] + Math.cos(azimuth) * horizontal
1106
+ ]
1107
+ };
1108
+ },
1055
1109
  autoFrame: (options = {}) => {
1056
1110
  const bounds = options.bounds ?? { min: [-1, 0, -1], max: [1, 1.6, 1] };
1057
1111
  const center = options.target ?? [
@@ -7073,6 +7127,66 @@ function isRenderableModelNode(node) {
7073
7127
  function isWebGLRenderableNode(node) {
7074
7128
  return isRenderableModelNode(node) || node.kind === "primitive";
7075
7129
  }
7130
+ /**
7131
+ * Translate scene label nodes into world-anchored labels for the label layer.
7132
+ *
7133
+ * `labels.callout(...)` and friends previously reached the scene snapshot and were
7134
+ * counted by evidence but drawn only by the canvas2d fallback. Every route with a
7135
+ * typed GLB takes the production WebGL2 path, so every production callout was
7136
+ * silently dropped. This is the bridge that makes the public label API real in the
7137
+ * path public routes actually use.
7138
+ */
7139
+ function worldLabelsFromSnapshot(snapshot, runtimeNodes) {
7140
+ const labelNodes = groups.flatten(snapshot.nodes).filter((node) => node.kind === "label");
7141
+ return labelNodes.map((node, index) => {
7142
+ const runtimeId = node.runtime?.id;
7143
+ const runtimeSnapshot = runtimeId ? runtimeNodes?.get(runtimeId)?.snapshot() : undefined;
7144
+ if (runtimeSnapshot?.visible === false) {
7145
+ return {
7146
+ id: node.name ?? `${node.label}-${index + 1}`,
7147
+ text: node.text,
7148
+ anchor: [0, 0, 0],
7149
+ offscreenPolicy: "hide"
7150
+ };
7151
+ }
7152
+ const position = (runtimeSnapshot?.position ?? node.position ?? labelDefaultPosition(node));
7153
+ const anchor = node.anchorWorldPosition ?? position;
7154
+ // Screen offset is derived from the gap between the label box and its anchor,
7155
+ // projected as a vertical nudge. A label that requests no separate anchor sits
7156
+ // directly on its own position.
7157
+ const separated = node.anchorWorldPosition !== undefined;
7158
+ return {
7159
+ id: node.name ?? `${node.label}-${index + 1}`,
7160
+ text: node.text,
7161
+ anchor: [position[0], position[1], position[2]],
7162
+ leaderAnchor: [anchor[0], anchor[1], anchor[2]],
7163
+ screenOffset: separated ? [0, 0] : [0, -26],
7164
+ color: typeof node.color === "string" ? node.color : undefined,
7165
+ background: typeof node.background === "string" ? node.background : undefined,
7166
+ // `size` is authored in world units for scene labels; map it onto a legible
7167
+ // pixel range rather than using it directly as a font size.
7168
+ fontSize: Math.max(11, Math.min(26, Math.round((node.size ?? 0.34) * 46))),
7169
+ leader: node.leader === true,
7170
+ offscreenPolicy: node.offscreenPolicy ?? (node.label === "hud" ? "draw" : "clamp"),
7171
+ ...(node.label === "hud" && node.screenAnchor ? { screenAnchor: node.screenAnchor } : {}),
7172
+ ...(node.label === "hud" && !node.screenAnchor ? { screenAnchor: "top-left" } : {})
7173
+ };
7174
+ });
7175
+ }
7176
+ /**
7177
+ * Mount the world-label layer for a canvas, if the scene has any label nodes.
7178
+ *
7179
+ * Returns `undefined` in headless or label-free scenes so nothing is created that
7180
+ * would then need disposing.
7181
+ */
7182
+ function createSceneLabelLayer(canvas, snapshot) {
7183
+ if (!canvas || typeof document === "undefined")
7184
+ return undefined;
7185
+ const hasLabels = groups.flatten(snapshot.nodes).some((node) => node.kind === "label");
7186
+ if (!hasLabels)
7187
+ return undefined;
7188
+ return createWorldLabelLayer({ container: canvas.parentElement ?? document.body, canvas });
7189
+ }
7076
7190
  async function startProductionRender(canvas, snapshot, diagnosticsState, options, overlay, beforeRender, isPaused = () => false, runtimeNodes) {
7077
7191
  const renderableNode = snapshot.nodes.find(isWebGLRenderableNode);
7078
7192
  if (!renderableNode) {
@@ -7081,6 +7195,7 @@ async function startProductionRender(canvas, snapshot, diagnosticsState, options
7081
7195
  const renderer = await createProductionSceneRenderer(canvas, snapshot, options.renderer, runtimeNodes);
7082
7196
  diagnosticsState.renderer = renderer.diagnostics;
7083
7197
  const continuousRender = shouldContinuouslyRender(snapshot);
7198
+ const labelLayer = createSceneLabelLayer(canvas, snapshot);
7084
7199
  let disposed = false;
7085
7200
  let animationHandle = 0;
7086
7201
  let lastTime = 0;
@@ -7098,6 +7213,13 @@ async function startProductionRender(canvas, snapshot, diagnosticsState, options
7098
7213
  diagnosticsState.renderSize = [canvas.width, canvas.height];
7099
7214
  diagnosticsState.evidence = collectAuraSceneEvidence(snapshot);
7100
7215
  diagnosticsState.renderer = renderer.diagnostics;
7216
+ if (labelLayer) {
7217
+ // Reproject every frame against the renderer's own camera so labels track
7218
+ // their anchors while the camera moves.
7219
+ labelLayer.setLabels(worldLabelsFromSnapshot(snapshot, runtimeNodes));
7220
+ labelLayer.update(renderer.viewProjection(time));
7221
+ diagnosticsState.labels = labelLayer.snapshot();
7222
+ }
7101
7223
  overlay?.update();
7102
7224
  if (continuousRender && options.autoStart !== false && typeof requestAnimationFrame !== "undefined") {
7103
7225
  animationHandle = requestAnimationFrame(renderFrame);
@@ -7112,6 +7234,7 @@ async function startProductionRender(canvas, snapshot, diagnosticsState, options
7112
7234
  disposed = true;
7113
7235
  if (animationHandle && typeof cancelAnimationFrame !== "undefined")
7114
7236
  cancelAnimationFrame(animationHandle);
7237
+ labelLayer?.dispose();
7115
7238
  renderer.dispose();
7116
7239
  }
7117
7240
  };
@@ -7699,6 +7822,9 @@ async function createProductionRuntimeSceneRenderer(canvas, snapshot, rendererOp
7699
7822
  latestFeatures = result.features;
7700
7823
  return latestDeviceDiagnostics.drawCalls;
7701
7824
  },
7825
+ viewProjection(time) {
7826
+ return createViewProjection(snapshot, canvas.width / Math.max(1, canvas.height), time, runtimeNodes);
7827
+ },
7702
7828
  dispose() {
7703
7829
  productionRenderer.dispose();
7704
7830
  for (const { actor } of actorEntries)
@@ -8411,6 +8537,9 @@ async function createWebGLSceneRenderer(canvas, snapshot, rendererOptions, runti
8411
8537
  }
8412
8538
  return drawCalls;
8413
8539
  },
8540
+ viewProjection(time) {
8541
+ return createViewProjection(snapshot, canvas.width / Math.max(1, canvas.height), time, runtimeNodes);
8542
+ },
8414
8543
  dispose() {
8415
8544
  for (const modelEntry of models) {
8416
8545
  const textures = new Set();
@@ -9715,7 +9844,9 @@ function createViewProjection(snapshot, aspect, time, runtimeNodes) {
9715
9844
  const target = resolveCameraTarget(snapshot, cameraSpec, runtimeNodes);
9716
9845
  const eye = resolveCameraEye(snapshot, cameraSpec, time, runtimeNodes);
9717
9846
  const view = lookAt(eye, target, [0, 1, 0]);
9718
- const projection = perspective(((cameraSpec.fov ?? 45) * Math.PI) / 180, aspect, 0.05, 100);
9847
+ const projection = isOrthographicCameraMode(cameraSpec.mode)
9848
+ ? orthographic(cameraSpec.orthographicSize ?? 1.4, aspect, 0.05, 100)
9849
+ : perspective(((cameraSpec.fov ?? 45) * Math.PI) / 180, aspect, 0.05, 100);
9719
9850
  return multiply4(projection, view);
9720
9851
  }
9721
9852
  function createModelMatrix(node, bounds, normalizeToUnit, time = 0) {
@@ -9792,6 +9923,20 @@ function primitiveSize(node) {
9792
9923
  return [node.size, node.size, node.size];
9793
9924
  return node.size ?? [1, 1, 1];
9794
9925
  }
9926
+ export function isOrthographicCameraMode(mode) {
9927
+ return mode === "orthographic" || mode === "isometric";
9928
+ }
9929
+ function orthographic(halfHeight, aspect, near, far) {
9930
+ const safeHalfHeight = Math.max(1e-4, halfHeight);
9931
+ const halfWidth = Math.max(1e-4, safeHalfHeight * aspect);
9932
+ const nf = 1 / (near - far);
9933
+ return new Float32Array([
9934
+ 1 / halfWidth, 0, 0, 0,
9935
+ 0, 1 / safeHalfHeight, 0, 0,
9936
+ 0, 0, 2 * nf, 0,
9937
+ 0, 0, (far + near) * nf, 1
9938
+ ]);
9939
+ }
9795
9940
  function perspective(fovRadians, aspect, near, far) {
9796
9941
  const f = 1 / Math.tan(fovRadians / 2);
9797
9942
  const nf = 1 / (near - far);
@@ -10110,7 +10255,8 @@ function snapshotDiagnostics(value) {
10110
10255
  evidence: value.evidence,
10111
10256
  renderer: value.renderer,
10112
10257
  warnings: [...value.warnings],
10113
- errors: [...value.errors]
10258
+ errors: [...value.errors],
10259
+ ...(value.labels ? { labels: value.labels } : {})
10114
10260
  };
10115
10261
  }
10116
10262
  function collectGeneratedCodeWarnings(snapshot) {