@terraware/web-components 4.3.3 → 5.0.1-rc.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/components/VirtualWalkthrough/AnnotationEditPane.d.ts +1 -21
  2. package/components/VirtualWalkthrough/AnnotationEditPane.d.ts.map +1 -1
  3. package/components/VirtualWalkthrough/AnnotationEditPane.js +18 -17
  4. package/components/VirtualWalkthrough/BoundaryWall.d.ts +0 -1
  5. package/components/VirtualWalkthrough/BoundaryWall.d.ts.map +1 -1
  6. package/components/VirtualWalkthrough/CameraInfo.d.ts +1 -7
  7. package/components/VirtualWalkthrough/CameraInfo.d.ts.map +1 -1
  8. package/components/VirtualWalkthrough/CameraInfo.js +5 -4
  9. package/components/VirtualWalkthrough/ControlsInfoPane.d.ts +1 -25
  10. package/components/VirtualWalkthrough/ControlsInfoPane.d.ts.map +1 -1
  11. package/components/VirtualWalkthrough/ControlsInfoPane.js +23 -22
  12. package/components/VirtualWalkthrough/SplatControls.d.ts +1 -20
  13. package/components/VirtualWalkthrough/SplatControls.d.ts.map +1 -1
  14. package/components/VirtualWalkthrough/SplatControls.js +15 -16
  15. package/components/VirtualWalkthrough/SplatModel.d.ts +6 -1
  16. package/components/VirtualWalkthrough/SplatModel.d.ts.map +1 -1
  17. package/components/VirtualWalkthrough/SplatModel.js +2 -0
  18. package/components/VirtualWalkthrough/TfAnnotationManager.d.ts +2 -9
  19. package/components/VirtualWalkthrough/TfAnnotationManager.d.ts.map +1 -1
  20. package/components/VirtualWalkthrough/TfAnnotationManager.js +11 -32
  21. package/components/VirtualWalkthrough/VirtualWalkthroughViewer.d.ts +15 -3
  22. package/components/VirtualWalkthrough/VirtualWalkthroughViewer.d.ts.map +1 -1
  23. package/components/VirtualWalkthrough/VirtualWalkthroughViewer.js +51 -29
  24. package/components/VirtualWalkthrough/VrAnnotationPanel.d.ts +1 -2
  25. package/components/VirtualWalkthrough/VrAnnotationPanel.d.ts.map +1 -1
  26. package/components/VirtualWalkthrough/VrAnnotationPanel.js +2 -4
  27. package/components/VirtualWalkthrough/XrStartPose.d.ts +52 -0
  28. package/components/VirtualWalkthrough/XrStartPose.d.ts.map +1 -0
  29. package/components/VirtualWalkthrough/XrStartPose.js +128 -0
  30. package/components/VirtualWalkthrough/boundary-wall.d.ts +0 -2
  31. package/components/VirtualWalkthrough/boundary-wall.d.ts.map +1 -1
  32. package/components/VirtualWalkthrough/boundary-wall.js +0 -2
  33. package/components/VirtualWalkthrough/vr-annotation-panel.d.ts +0 -1
  34. package/components/VirtualWalkthrough/vr-annotation-panel.d.ts.map +1 -1
  35. package/components/VirtualWalkthrough/vr-annotation-panel.js +6 -9
  36. package/components/VirtualWalkthrough/walkthrough-camera.d.ts +0 -1
  37. package/components/VirtualWalkthrough/walkthrough-camera.d.ts.map +1 -1
  38. package/components/VirtualWalkthrough/walkthrough-camera.js +3 -5
  39. package/components/VirtualWalkthrough/xr-start-pose.d.ts +57 -0
  40. package/components/VirtualWalkthrough/xr-start-pose.d.ts.map +1 -0
  41. package/components/VirtualWalkthrough/xr-start-pose.js +80 -0
  42. package/index.d.ts +5 -1
  43. package/index.d.ts.map +1 -1
  44. package/index.js +2 -0
  45. package/license-report.html +1 -1
  46. package/package.json +2 -1
  47. package/strings/csv/en.csv +50 -0
  48. package/strings/csv/es.csv +50 -0
  49. package/strings/csv/fr.csv +50 -0
  50. package/strings/csv/instructions-es.txt +14 -0
  51. package/strings/csv/instructions-fr.txt +14 -0
  52. package/strings/csv/instructions.txt +13 -0
  53. package/strings/export.d.ts +36 -0
  54. package/strings/export.d.ts.map +1 -0
  55. package/strings/export.js +116 -0
  56. package/strings/index.d.ts +22 -0
  57. package/strings/index.d.ts.map +1 -0
  58. package/strings/index.js +62 -0
  59. package/strings/locales.d.ts +38 -0
  60. package/strings/locales.d.ts.map +1 -0
  61. package/strings/locales.js +42 -0
  62. package/strings/strings-en.d.ts +52 -0
  63. package/strings/strings-en.d.ts.map +1 -0
  64. package/strings/strings-en.js +54 -0
  65. package/strings/strings-es.d.ts +52 -0
  66. package/strings/strings-es.d.ts.map +1 -0
  67. package/strings/strings-es.js +54 -0
  68. package/strings/strings-fr.d.ts +52 -0
  69. package/strings/strings-fr.d.ts.map +1 -0
  70. package/strings/strings-fr.js +54 -0
  71. package/strings/strings-gx.d.ts +52 -0
  72. package/strings/strings-gx.d.ts.map +1 -0
  73. package/strings/strings-gx.js +54 -0
  74. package/virtualWalkthrough.d.ts +2 -4
  75. package/virtualWalkthrough.d.ts.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"TfAnnotationManager.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/TfAnnotationManager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoC,OAAO,EAAQ,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,iBAAiB,IAAI,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAIlG,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAelD;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,mBAAmB;IAC1D,MAAM,CAAC,UAAU,SAAyB;IAE1C,OAAO,CAAC,aAAa,CAAO;IAC5B,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,sBAAsB,CAAkB;IAChD,OAAO,CAAC,uBAAuB,CAAa;IAC5C,OAAO,CAAC,WAAW,CAAmD;IAEtE;;;;;;;;OAQG;IACH,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,EAE7B;IAED,IAAI,YAAY,IAJQ,MAAM,CAM7B;IAED;;;;;;;;;;OAUG;IACH,IAAI,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAEvC;IAED,IAAI,sBAAsB,IAJQ,MAAM,CAMvC;IAED;;OAEG;IACH,UAAU;IAgBV;;;;OAIG;IACH,eAAe;IAiBf;;;;OAIG;IACH,YAAY,CAAC,QAAQ,EAAE,kBAAkB;IAazC;;OAEG;IACH,MAAM;IAmCN;;;;OAIG;IACH,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAcnC;;;OAGG;IACH,oBAAoB,CAAC,UAAU,EAAE,GAAG;IAiBpC;;;;;OAKG;IACH,SAAS,CAAC,GAAG,EAAE,wBAAwB,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM;IAW/E;;;;OAIG;IACH,cAAc,CAAC,UAAU,EAAE,GAAG;IAI9B;;;;OAIG;IACH,sBAAsB,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG;IASlD,mBAAmB,CAAC,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO;IAKrD,0BAA0B;IAK1B,YAAY,CAAC,WAAW,EAAE,GAAG;IAK7B,aAAa,CAAC,WAAW,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM;IAI7C;;;OAGG;IACH,0BAA0B,CAAC,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG;IA6B1E;;;;;OAKG;IACH,uBAAuB,CAAC,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG;IAMvD;;;;OAIG;IACH,iCAAiC,CAAC,UAAU,EAAE,GAAG;IAiDjD;;;;OAIG;IACH,oBAAoB,CAAC,MAAM,EAAE,GAAG;IAUhC;;;OAGG;IACH,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,SAAuB,EAAE,WAAW,SAAI,EAAE,IAAI,CAAC,EAAE,kBAAkB;CAyD7G"}
1
+ {"version":3,"file":"TfAnnotationManager.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/TfAnnotationManager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoC,OAAO,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,iBAAiB,IAAI,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAIlG,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAelD;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,mBAAmB;IAC1D,MAAM,CAAC,UAAU,SAAyB;IAE1C,OAAO,CAAC,aAAa,CAAO;IAC5B,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,sBAAsB,CAAkB;IAChD,OAAO,CAAC,uBAAuB,CAAa;IAC5C,OAAO,CAAC,WAAW,CAAmD;IAEtE;;;;;;;;OAQG;IACH,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,EAE7B;IAED,IAAI,YAAY,IAJQ,MAAM,CAM7B;IAED;;;;;;;;;;OAUG;IACH,IAAI,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAEvC;IAED,IAAI,sBAAsB,IAJQ,MAAM,CAMvC;IAED;;OAEG;IACH,UAAU;IAgBV;;;;OAIG;IACH,eAAe;IAiBf;;;;OAIG;IACH,YAAY,CAAC,QAAQ,EAAE,kBAAkB;IAazC;;OAEG;IACH,MAAM;IAmCN;;;;OAIG;IACH,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAcnC;;;OAGG;IACH,oBAAoB,CAAC,UAAU,EAAE,GAAG;IAiBpC;;;;;OAKG;IACH,SAAS,CAAC,GAAG,EAAE,wBAAwB,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM;IAW/E;;;;OAIG;IACH,cAAc,CAAC,UAAU,EAAE,GAAG;IAI9B;;;;OAIG;IACH,sBAAsB,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG;IASlD,mBAAmB,CAAC,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO;IAKrD,0BAA0B;IAK1B,YAAY,CAAC,WAAW,EAAE,GAAG;IAK7B,aAAa,CAAC,WAAW,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM;IAI7C;;;OAGG;IACH,0BAA0B,CAAC,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG;IA6B1E;;;;;OAKG;IACH,uBAAuB,CAAC,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG;IAMvD;;;;OAIG;IACH,iCAAiC,CAAC,UAAU,EAAE,GAAG;IA2CjD;;;OAGG;IACH,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,SAAuB,EAAE,WAAW,SAAI,EAAE,IAAI,CAAC,EAAE,kBAAkB;CAyD7G"}
@@ -1,6 +1,6 @@
1
1
  import { createElement } from 'react';
2
2
  import { renderToStaticMarkup } from 'react-dom/server';
3
- import { Vec3, Texture, FILTER_LINEAR, PIXELFORMAT_RGBA8 } from 'playcanvas';
3
+ import { Texture, FILTER_LINEAR, PIXELFORMAT_RGBA8 } from 'playcanvas';
4
4
  import { AnnotationManager } from 'playcanvas/scripts/esm/annotations.mjs';
5
5
  import Icon from '../Icon/Icon.js';
6
6
 
@@ -24,7 +24,6 @@ const HOTSPOT_HOVER_SCALE = 1.3;
24
24
  class TfAnnotationManager extends AnnotationManager {
25
25
  static scriptName = 'tfAnnotationManager';
26
26
  _maxWorldSize = 1.0;
27
- _scratchScale = new Vec3();
28
27
  _customParentDom = null;
29
28
  _clickHandlersAttached = new Set();
30
29
  _hotspotBackgroundColor = '#2C8658';
@@ -163,9 +162,9 @@ class TfAnnotationManager extends AnnotationManager {
163
162
  super._registerAnnotation(annotation);
164
163
  this._applyAnnotationIcon(annotation);
165
164
 
166
- // Keep the hotspot mesh hidden until the first scale pass clamps it. The annotation entity
167
- // starts at unit local scale, so under a scaled content-root the plane would render many world
168
- // units across for the frames before _updateAnnotationRotationAndScale runs.
165
+ // Keep the hotspot mesh hidden until the first scale pass sizes it. The annotation entity
166
+ // starts at unit scale, so the plane would render a metre across for the frames before
167
+ // _updateAnnotationRotationAndScale runs.
169
168
  const resources = this._annotationResources.get(annotation);
170
169
  if (resources) {
171
170
  resources.baseEntity.enabled = false;
@@ -281,8 +280,8 @@ class TfAnnotationManager extends AnnotationManager {
281
280
 
282
281
  /**
283
282
  * Override to also disable the hotspot mesh (not just the DOM) when the annotation is behind the
284
- * camera. The base implementation leaves the mesh enabled, so a not-yet-scaled plane under a
285
- * scaled content-root would stay huge in view until the camera moves the anchor in front.
283
+ * camera. The base implementation leaves the mesh enabled, so a not-yet-scaled plane would stay
284
+ * in view at its full unit size until the camera moves the anchor in front.
286
285
  * @private
287
286
  */
288
287
  _hideAnnotationElements(annotation, resources) {
@@ -309,14 +308,9 @@ class TfAnnotationManager extends AnnotationManager {
309
308
  // The world size that projects to _hotspotSize screen pixels at this distance.
310
309
  const targetWorldSize = this._hotspotSize / screenHeight * (2 * distance / projMatrix.data[5]);
311
310
 
312
- // setLocalScale is applied on top of the parent's world scale (e.g. a scaled
313
- // content-root), so divide it out to keep the on-screen size independent of it.
314
- const parentScale = this._getParentWorldScale(annotation.entity);
315
- const unclampedScale = targetWorldSize / parentScale;
316
-
317
- // Clamp in the annotation's own (parent-local) space so maxWorldSize keeps the
318
- // same size relative to the model regardless of the content-root scale.
319
- const clampedScale = Math.min(unclampedScale, this._maxWorldSize);
311
+ // Annotations hang off an unscaled parent, so local scale is world scale and maxWorldSize
312
+ // clamps the hotspot at a size in metres.
313
+ const clampedScale = Math.min(targetWorldSize, this._maxWorldSize);
320
314
  const hovered = this._hoverAnnotation === annotation;
321
315
  const hoverScale = hovered ? HOTSPOT_HOVER_SCALE : 1;
322
316
  const entityScale = clampedScale * hoverScale;
@@ -324,8 +318,7 @@ class TfAnnotationManager extends AnnotationManager {
324
318
 
325
319
  // Scale the hotspot DOM element proportionally when clamped, including the
326
320
  // hover growth so it tracks the visible circle. This is a pure screen-space
327
- // size, so it uses the true _hotspotSize and the clamp ratio only (never the
328
- // parent scale, which the DOM overlay does not inherit).
321
+ // size, so it uses the true _hotspotSize and the clamp ratio only.
329
322
  const resources = this._annotationResources.get(annotation);
330
323
  if (resources) {
331
324
  // This branch only runs for annotations in front of the camera, and the scale above is now
@@ -334,7 +327,7 @@ class TfAnnotationManager extends AnnotationManager {
334
327
  resources.overlayEntity.enabled = true;
335
328
  }
336
329
  if (resources && resources.hotspotDom) {
337
- const clampRatio = clampedScale / unclampedScale;
330
+ const clampRatio = clampedScale / targetWorldSize;
338
331
  const baseSize = this._hotspotSize + 5; // Match the +5 from the stylesheet
339
332
  const scaledSize = baseSize * clampRatio * hoverScale;
340
333
  resources.hotspotDom.style.width = `${scaledSize}px`;
@@ -342,20 +335,6 @@ class TfAnnotationManager extends AnnotationManager {
342
335
  }
343
336
  }
344
337
 
345
- /**
346
- * World-space uniform scale of the annotation entity's parent (e.g. a scaled
347
- * content-root). Returns 1 when there is no parent or it has no scale.
348
- * @private
349
- */
350
- _getParentWorldScale(entity) {
351
- const parent = entity.parent;
352
- if (!parent) {
353
- return 1;
354
- }
355
- parent.getWorldTransform().getScale(this._scratchScale);
356
- return this._scratchScale.x || 1;
357
- }
358
-
359
338
  /**
360
339
  * Override to create hotspot texture with custom background color.
361
340
  * @private
@@ -1,31 +1,43 @@
1
1
  import { AnnotationProps } from './Annotation';
2
- import { SplatControlsStrings } from './SplatControls';
3
2
  import { SplatFormat } from './splatFormat';
3
+ /**
4
+ * Every coordinate, distance and size in this component is world-space, in the metres an XR
5
+ * headset imposes on the scene: `scaleFactor` converts the splat's own arbitrary units to them,
6
+ * and is applied to nothing but the splat itself.
7
+ */
4
8
  export interface VirtualWalkthroughViewerProps {
5
9
  splatSrc: string;
6
10
  splatFormat?: SplatFormat;
11
+ /** World-space point the camera looks at. */
7
12
  origin?: [number, number, number];
13
+ /** World-space point the camera starts at. */
8
14
  cameraPosition?: [number, number, number];
15
+ /** World-space centre (x, y, z) and radius (m) of the circle the camera is held inside. */
9
16
  sceneBounds?: {
10
17
  x: number;
11
18
  y: number;
12
19
  z: number;
13
20
  m: number;
14
21
  };
22
+ /** Three world-space points defining the plane the camera walks on. */
15
23
  groundPlane?: [number, number, number][];
16
24
  skyColor?: string;
17
25
  groundColor?: string;
26
+ /** Eye height (m) above the ground plane. */
18
27
  averageCameraHeight?: number;
28
+ /**
29
+ * Scale that converts the splat model's units to the world's metres. Applied to the splat
30
+ * entity alone — every other coordinate this component takes is already world-space.
31
+ */
19
32
  scaleFactor?: number;
20
33
  annotations: AnnotationProps[];
21
34
  onSaveAnnotations: (annotations: AnnotationProps[]) => void | Promise<void>;
22
- strings: SplatControlsStrings;
23
35
  editable?: boolean;
24
36
  showFreeFly?: boolean;
25
37
  isFullScreen?: boolean;
26
38
  onToggleFullScreen?: () => void;
27
39
  maxImagesPerAnnotation?: number;
28
40
  }
29
- declare const VirtualWalkthroughViewer: ({ splatSrc, splatFormat, origin, cameraPosition, sceneBounds, groundPlane: groundPlaneProp, skyColor, groundColor, averageCameraHeight, scaleFactor, annotations, onSaveAnnotations, strings, editable, showFreeFly, isFullScreen, onToggleFullScreen, maxImagesPerAnnotation, }: VirtualWalkthroughViewerProps) => import("react/jsx-runtime").JSX.Element;
41
+ declare const VirtualWalkthroughViewer: ({ splatSrc, splatFormat, origin, cameraPosition, sceneBounds, groundPlane: groundPlaneProp, skyColor, groundColor, averageCameraHeight, scaleFactor, annotations, onSaveAnnotations, editable, showFreeFly, isFullScreen, onToggleFullScreen, maxImagesPerAnnotation, }: VirtualWalkthroughViewerProps) => import("react/jsx-runtime").JSX.Element;
30
42
  export default VirtualWalkthroughViewer;
31
43
  //# sourceMappingURL=VirtualWalkthroughViewer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"VirtualWalkthroughViewer.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/VirtualWalkthroughViewer.tsx"],"names":[],"mappings":"AAYA,OAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAM3D,OAAsB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAStE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAa5C,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,WAAW,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,iBAAiB,EAAE,CAAC,WAAW,EAAE,eAAe,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,OAAO,EAAE,oBAAoB,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,QAAA,MAAM,wBAAwB,GAAI,kRAmB/B,6BAA6B,4CAuX/B,CAAC;AAEF,eAAe,wBAAwB,CAAC"}
1
+ {"version":3,"file":"VirtualWalkthroughViewer.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/VirtualWalkthroughViewer.tsx"],"names":[],"mappings":"AAYA,OAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAgB3D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAkB5C;;;;GAIG;AACH,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,6CAA6C;IAC7C,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,8CAA8C;IAC9C,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,2FAA2F;IAC3F,WAAW,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,uEAAuE;IACvE,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,iBAAiB,EAAE,CAAC,WAAW,EAAE,eAAe,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,QAAA,MAAM,wBAAwB,GAAI,yQAkB/B,6BAA6B,4CA6X/B,CAAC;AAEF,eAAe,wBAAwB,CAAC"}
@@ -23,6 +23,7 @@ import XrAnnotationInteraction from './XrAnnotationInteraction.js';
23
23
  import XrExitButton from './XrExitButton.js';
24
24
  import XrGazeDwell from './XrGazeDwell.js';
25
25
  import XrPointerRay from './XrPointerRay.js';
26
+ import { XrStartPose } from './XrStartPose.js';
26
27
  import { WalkthroughCamera } from './walkthrough-camera.js';
27
28
  import { rayHitsInteractiveUi } from './xr-interactive-ui.js';
28
29
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -32,9 +33,21 @@ const DEFAULT_POSITION = [1, 0.1, 0];
32
33
 
33
34
  // How far outside the clamp radius the boundary wall stands. Without it the wall would be coplanar
34
35
  // with the surface the head is clamped to, so a pinned user would have it in their face and through
35
- // their near clip plane. Deliberately an absolute world-space distance rather than one scaled by
36
- // scaleFactor: it is about the size of the user's body, not about the size of the scene.
36
+ // their near clip plane.
37
37
  const WALL_INSET = 0.25;
38
+
39
+ /**
40
+ * Largest world size (metres) a hotspot is allowed to reach as the camera approaches it, so it
41
+ * stops growing rather than filling the view from close up.
42
+ */
43
+ const MAX_HOTSPOT_WORLD_SIZE = 0.75;
44
+
45
+ /**
46
+ * Every coordinate, distance and size in this component is world-space, in the metres an XR
47
+ * headset imposes on the scene: `scaleFactor` converts the splat's own arbitrary units to them,
48
+ * and is applied to nothing but the splat itself.
49
+ */
50
+
38
51
  const VirtualWalkthroughViewer = ({
39
52
  splatSrc,
40
53
  splatFormat,
@@ -48,7 +61,6 @@ const VirtualWalkthroughViewer = ({
48
61
  scaleFactor = 1,
49
62
  annotations,
50
63
  onSaveAnnotations,
51
- strings,
52
64
  editable = false,
53
65
  showFreeFly = false,
54
66
  isFullScreen = false,
@@ -85,36 +97,45 @@ const VirtualWalkthroughViewer = ({
85
97
  const dx = cameraPosition[0] - origin[0];
86
98
  const dy = cameraPosition[1] - origin[1];
87
99
  const dz = cameraPosition[2] - origin[2];
88
- return Math.sqrt(dx * dx + dy * dy + dz * dz) * 0.5;
100
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
89
101
  }, [cameraPosition, sceneBounds, origin]);
90
102
  const sceneBoundsCenter = useMemo(() => sceneBounds ? new Vec3(sceneBounds.x, sceneBounds.y, sceneBounds.z) : new Vec3(origin[0], cameraPosition[1], origin[2]), [sceneBounds, origin, cameraPosition]);
91
- const cameraBoundsCenter = useMemo(() => sceneBoundsCenter.clone().mulScalar(scaleFactor), [sceneBoundsCenter, scaleFactor]);
92
103
  const groundPlane = useMemo(() => groundPlaneProp?.length === 3 ? groundPlaneProp.map(p => new Vec3(p[0], p[1], p[2])) : [], [groundPlaneProp]);
93
- const cameraGroundPlane = useMemo(() => groundPlane.map(p => p.clone().mulScalar(scaleFactor)), [groundPlane, scaleFactor]);
104
+
105
+ // Also runs when a session ends. WalkthroughCamera is unmounted for the duration of a session, so
106
+ // the camera entity is left holding the last head pose — an eye height above wherever in the rig
107
+ // the user was standing — which is neither where nor how high the walkthrough left off.
94
108
  useEffect(() => {
109
+ if (isCurrentlyInXr) {
110
+ return;
111
+ }
95
112
  setCamera(origin, cameraPosition);
96
- }, [origin, cameraPosition, setCamera]);
113
+ }, [origin, cameraPosition, setCamera, isCurrentlyInXr]);
114
+
115
+ // Re-applied when a session ends for the same reason: the script that comes back is a new
116
+ // instance, and without the ground plane it walks the camera at the bounds centre's height
117
+ // instead of an eye height above the ground.
97
118
  useEffect(() => {
98
- if (!cameraGroundPlane.length) {
119
+ if (!groundPlane.length || isCurrentlyInXr) {
99
120
  return;
100
121
  }
101
122
  // @ts-expect-error - scripts are added dynamically to the camera entity
102
123
  const walkthroughCam = app.root.findByName('camera')?.script?.walkthroughCamera;
103
124
  if (walkthroughCam) {
104
125
  // Should be changed to a react prop if shallowEquals in playcanvas/react is fixed (see https://github.com/playcanvas/react/pull/298)
105
- walkthroughCam.groundPlane = cameraGroundPlane;
126
+ walkthroughCam.groundPlane = groundPlane;
106
127
  }
107
- }, [cameraGroundPlane, app]);
128
+ }, [groundPlane, app, isCurrentlyInXr]);
108
129
  useEffect(() => {
109
130
  // Set imperatively for the same reason as BoundaryRing: boundsCenter is a Vec3, and the
110
131
  // @playcanvas/react memo() comparator stops at the first prop with an .equals() method.
111
132
  // @ts-expect-error - scripts are added dynamically to the entity
112
133
  const navigation = app.root.findByName('camera-root')?.script?.tfXrNavigation;
113
134
  if (navigation) {
114
- navigation.boundsCenter = cameraBoundsCenter;
115
- navigation.boundsRadius = sceneBoundsRadius * scaleFactor;
135
+ navigation.boundsCenter = sceneBoundsCenter;
136
+ navigation.boundsRadius = sceneBoundsRadius;
116
137
  }
117
- }, [app, cameraBoundsCenter, sceneBoundsRadius, scaleFactor]);
138
+ }, [app, sceneBoundsCenter, sceneBoundsRadius]);
118
139
  const handleToggleFreeFly = useCallback(() => {
119
140
  const newFreeFly = !isFreeFly;
120
141
  // @ts-expect-error - scripts are added dynamically to the camera entity
@@ -232,8 +253,9 @@ const VirtualWalkthroughViewer = ({
232
253
  splatSrc: splatSrc,
233
254
  splatFormat: splatFormat,
234
255
  rotation: [-180, 0, 0],
256
+ scaleFactor: scaleFactor,
235
257
  revealRain: isHighPerformance
236
- }, 'splat'), [isHighPerformance, splatSrc, splatFormat]);
258
+ }, 'splat'), [isHighPerformance, splatSrc, splatFormat, scaleFactor]);
237
259
  return /*#__PURE__*/jsxs(Fragment, {
238
260
  children: [/*#__PURE__*/jsx(GradientSky, {
239
261
  topColor: skyColor || '#FFFFFF',
@@ -248,13 +270,10 @@ const VirtualWalkthroughViewer = ({
248
270
  fov: 60
249
271
  }), !isCurrentlyInXr && /*#__PURE__*/jsx(Script, {
250
272
  script: WalkthroughCamera,
251
- boundsCenter: cameraBoundsCenter,
252
- boundsRadius: sceneBoundsRadius * scaleFactor,
273
+ boundsCenter: sceneBoundsCenter,
274
+ boundsRadius: sceneBoundsRadius,
253
275
  enableFly: !isTextFieldFocused,
254
- averageCameraHeight: scaleFactor * averageCameraHeight,
255
- moveSpeed: 0.3 * scaleFactor,
256
- moveFastSpeed: 0.5 * scaleFactor,
257
- moveSlowSpeed: 0.15 * scaleFactor
276
+ averageCameraHeight: averageCameraHeight
258
277
  })]
259
278
  }), /*#__PURE__*/jsx(XrExitButton, {}), /*#__PURE__*/jsx(Script, {
260
279
  script: XrControllers,
@@ -263,10 +282,15 @@ const VirtualWalkthroughViewer = ({
263
282
  onDismiss: handleCloseAnnotation
264
283
  }), /*#__PURE__*/jsx(XrPointerRay, {}), isCurrentlyInVr && viewingAnnotation && /*#__PURE__*/jsx(VrAnnotationPanel, {
265
284
  annotation: viewingAnnotation,
266
- annotationIndex: viewingAnnotationIndex,
267
- scaleFactor: scaleFactor
285
+ annotationIndex: viewingAnnotationIndex
268
286
  }, viewingAnnotationIndex), isCurrentlyInXr && /*#__PURE__*/jsx(XrGazeDwell, {
269
287
  activeIndex: viewingAnnotationIndex
288
+ }), /*#__PURE__*/jsx(Script, {
289
+ script: XrStartPose,
290
+ targetX: cameraPosition[0],
291
+ targetZ: cameraPosition[2],
292
+ focusX: origin[0],
293
+ focusZ: origin[2]
270
294
  }), /*#__PURE__*/jsx(Script, {
271
295
  script: TfXrNavigation,
272
296
  enabled: !isEdit,
@@ -281,7 +305,6 @@ const VirtualWalkthroughViewer = ({
281
305
  })]
282
306
  }), /*#__PURE__*/jsxs(Entity, {
283
307
  name: "content-root",
284
- scale: [scaleFactor, scaleFactor, scaleFactor],
285
308
  children: [splatModel, sceneBounds?.m !== undefined && groundPlane.length === 3 && /*#__PURE__*/jsx(BoundaryRing, {
286
309
  center: sceneBoundsCenter,
287
310
  radius: sceneBoundsRadius,
@@ -292,7 +315,7 @@ const VirtualWalkthroughViewer = ({
292
315
  script: TfAnnotationManager,
293
316
  enabled: true,
294
317
  hotspotSize: 30,
295
- maxWorldSize: 0.05,
318
+ maxWorldSize: MAX_HOTSPOT_WORLD_SIZE,
296
319
  opacity: 1,
297
320
  hotspotColor: new Color().fromString(theme.palette.TwClrIcnBrand),
298
321
  hoverColor: new Color().fromString('#ffffff'),
@@ -311,9 +334,9 @@ const VirtualWalkthroughViewer = ({
311
334
  }, `annotation-${index}`))]
312
335
  })]
313
336
  }), isCurrentlyInXr && sceneBoundsRadius > 0 && /*#__PURE__*/jsx(BoundaryWall, {
314
- center: cameraBoundsCenter,
315
- radius: sceneBoundsRadius * scaleFactor + WALL_INSET,
316
- groundPlane: cameraGroundPlane,
337
+ center: sceneBoundsCenter,
338
+ radius: sceneBoundsRadius + WALL_INSET,
339
+ groundPlane: groundPlane,
317
340
  baseY: 0
318
341
  }), /*#__PURE__*/jsx(SplatControls, {
319
342
  defaultCameraFocus: origin,
@@ -342,8 +365,7 @@ const VirtualWalkthroughViewer = ({
342
365
  onToggleFullScreen: onToggleFullScreen,
343
366
  isFreeFly: isFreeFly,
344
367
  onToggleFreeFly: handleToggleFreeFly,
345
- showFreeFly: showFreeFly,
346
- strings: strings
368
+ showFreeFly: showFreeFly
347
369
  }), /*#__PURE__*/jsx(AnnotationPanel, {
348
370
  annotation: viewingAnnotation,
349
371
  hotspotPosition: viewedScreenPos,
@@ -2,8 +2,7 @@ import type { AnnotationProps } from './Annotation';
2
2
  interface VrAnnotationPanelProps {
3
3
  annotation: AnnotationProps;
4
4
  annotationIndex: number;
5
- scaleFactor: number;
6
5
  }
7
- declare const VrAnnotationPanel: ({ annotation, annotationIndex, scaleFactor }: VrAnnotationPanelProps) => import("react/jsx-runtime").JSX.Element;
6
+ declare const VrAnnotationPanel: ({ annotation, annotationIndex }: VrAnnotationPanelProps) => import("react/jsx-runtime").JSX.Element;
8
7
  export default VrAnnotationPanel;
9
8
  //# sourceMappingURL=VrAnnotationPanel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"VrAnnotationPanel.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/VrAnnotationPanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGpD,UAAU,sBAAsB;IAC9B,UAAU,EAAE,eAAe,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,QAAA,MAAM,iBAAiB,GAAI,8CAA8C,sBAAsB,4CAY9F,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"VrAnnotationPanel.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/VrAnnotationPanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGpD,UAAU,sBAAsB;IAC9B,UAAU,EAAE,eAAe,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,QAAA,MAAM,iBAAiB,GAAI,iCAAiC,sBAAsB,4CAWjF,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -6,8 +6,7 @@ import { jsx } from 'react/jsx-runtime';
6
6
 
7
7
  const VrAnnotationPanel = ({
8
8
  annotation,
9
- annotationIndex,
10
- scaleFactor
9
+ annotationIndex
11
10
  }) => /*#__PURE__*/jsx(Entity, {
12
11
  name: "vr-annotation-panel",
13
12
  children: /*#__PURE__*/jsx(Script, {
@@ -16,8 +15,7 @@ const VrAnnotationPanel = ({
16
15
  label: annotation.label,
17
16
  bodyText: annotation.bodyText,
18
17
  imageUrls: annotation.imageUrls,
19
- annotationIndex: annotationIndex,
20
- scaleFactor: scaleFactor
18
+ annotationIndex: annotationIndex
21
19
  })
22
20
  });
23
21
 
@@ -0,0 +1,52 @@
1
+ import { Script } from 'playcanvas';
2
+ /**
3
+ * Starts an immersive session at the scene's camera position rather than at the world origin.
4
+ *
5
+ * PlayCanvas overwrites the camera entity's local transform with the head pose every frame, so the
6
+ * head lands wherever the headset's reference space puts it — near (0, 0) for a rig that has never
7
+ * been moved. This script moves the rig on the first frame of a session so the head instead starts
8
+ * at `targetX`/`targetZ` facing `focusX`/`focusZ`.
9
+ *
10
+ * Only XZ is touched: the user stands on the rig floor, which the boundary wall is also built
11
+ * against, so lifting the rig onto the splat's ground plane would put them through it.
12
+ *
13
+ * Attach to the rig entity — the camera's parent, alongside TfXrNavigation, whose bounds clamp
14
+ * pulls the start point back inside the scene bounds when the camera position sits outside them.
15
+ */
16
+ export declare class XrStartPose extends Script {
17
+ static scriptName: string;
18
+ /** World-space X the head should start at, i.e. the viewer's `cameraPosition`. */
19
+ targetX: number;
20
+ /** World-space Z the head should start at. */
21
+ targetZ: number;
22
+ /** World-space X the head should face from there, i.e. the viewer's `origin`. */
23
+ focusX: number;
24
+ /** World-space Z the head should face from there. */
25
+ focusZ: number;
26
+ /** Set when a session starts, cleared once the rig has been placed. */
27
+ private _pending;
28
+ /**
29
+ * Whether the engine has written a head pose for this session yet.
30
+ */
31
+ private _posed;
32
+ private _onXrStart;
33
+ /** Fired from XrManager.update only after the head pose has been written to the camera. */
34
+ private _onXrUpdate;
35
+ private _onXrEnd;
36
+ initialize(): void;
37
+ private _isXrActive;
38
+ /**
39
+ * The bounds circle to place the start point in, or undefined when nothing is clamping the head.
40
+ * Resolved per call rather than cached: the React wrapper assigns the bounds to the navigation
41
+ * script imperatively, so they can land after this script initializes.
42
+ */
43
+ private _bounds;
44
+ /**
45
+ * Runs in update rather than on the 'start' event: the engine writes the head pose during
46
+ * xr.update, which precedes the script update in the same tick, so a frame that has posed is the
47
+ * first point at which there is a real head to solve the rig pose from.
48
+ */
49
+ update(): void;
50
+ private _teardown;
51
+ }
52
+ //# sourceMappingURL=XrStartPose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XrStartPose.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/XrStartPose.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAwB,MAAM,YAAY,CAAC;AAM1D;;;;;;;;;;;;;GAaG;AACH,qBAAa,WAAY,SAAQ,MAAM;IACrC,MAAM,CAAC,UAAU,SAAiB;IAElC,kFAAkF;IAClF,OAAO,SAAK;IAEZ,8CAA8C;IAC9C,OAAO,SAAK;IAEZ,iFAAiF;IACjF,MAAM,SAAK;IAEX,qDAAqD;IACrD,MAAM,SAAK;IAEX,uEAAuE;IACvE,OAAO,CAAC,QAAQ,CAAS;IAEzB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,UAAU,CAEhB;IAEF,2FAA2F;IAC3F,OAAO,CAAC,WAAW,CAEjB;IAEF,OAAO,CAAC,QAAQ,CAEd;IAEF,UAAU;IAWV,OAAO,CAAC,WAAW,CACoF;IAEvG;;;;OAIG;IACH,OAAO,CAAC,OAAO,CAQb;IAEF;;;;OAIG;IACH,MAAM;IA2BN,OAAO,CAAC,SAAS;CAKlB"}
@@ -0,0 +1,128 @@
1
+ import { Script, XRTYPE_VR, XRTYPE_AR } from 'playcanvas';
2
+ import { xrStartRigPose, yawFromBasis } from './xr-start-pose.js';
3
+
4
+ /**
5
+ * Starts an immersive session at the scene's camera position rather than at the world origin.
6
+ *
7
+ * PlayCanvas overwrites the camera entity's local transform with the head pose every frame, so the
8
+ * head lands wherever the headset's reference space puts it — near (0, 0) for a rig that has never
9
+ * been moved. This script moves the rig on the first frame of a session so the head instead starts
10
+ * at `targetX`/`targetZ` facing `focusX`/`focusZ`.
11
+ *
12
+ * Only XZ is touched: the user stands on the rig floor, which the boundary wall is also built
13
+ * against, so lifting the rig onto the splat's ground plane would put them through it.
14
+ *
15
+ * Attach to the rig entity — the camera's parent, alongside TfXrNavigation, whose bounds clamp
16
+ * pulls the start point back inside the scene bounds when the camera position sits outside them.
17
+ */
18
+ class XrStartPose extends Script {
19
+ static scriptName = 'xrStartPose';
20
+
21
+ /** World-space X the head should start at, i.e. the viewer's `cameraPosition`. */
22
+ targetX = 0;
23
+
24
+ /** World-space Z the head should start at. */
25
+ targetZ = 0;
26
+
27
+ /** World-space X the head should face from there, i.e. the viewer's `origin`. */
28
+ focusX = 0;
29
+
30
+ /** World-space Z the head should face from there. */
31
+ focusZ = 0;
32
+
33
+ /** Set when a session starts, cleared once the rig has been placed. */
34
+ _pending = false;
35
+
36
+ /**
37
+ * Whether the engine has written a head pose for this session yet.
38
+ */
39
+ _posed = false;
40
+ _onXrStart = () => {
41
+ this._pending = true;
42
+ };
43
+
44
+ /** Fired from XrManager.update only after the head pose has been written to the camera. */
45
+ _onXrUpdate = () => {
46
+ this._posed = true;
47
+ };
48
+ _onXrEnd = () => {
49
+ this._posed = false;
50
+ };
51
+ initialize() {
52
+ // Covers mounting into a session that is already running as well as the usual mount before one.
53
+ this._pending = this._isXrActive();
54
+ this.app.xr?.on('start', this._onXrStart);
55
+ this.app.xr?.on('update', this._onXrUpdate);
56
+ this.app.xr?.on('end', this._onXrEnd);
57
+ // Script removal fires a 'destroy' event rather than calling a destroy() method, so the
58
+ // teardown has to be registered as a listener or these handlers outlive the script.
59
+ this.once('destroy', () => this._teardown());
60
+ }
61
+ _isXrActive = () => this.app.xr?.active === true && (this.app.xr?.type === XRTYPE_VR || this.app.xr?.type === XRTYPE_AR);
62
+
63
+ /**
64
+ * The bounds circle to place the start point in, or undefined when nothing is clamping the head.
65
+ * Resolved per call rather than cached: the React wrapper assigns the bounds to the navigation
66
+ * script imperatively, so they can land after this script initializes.
67
+ */
68
+ _bounds = () => {
69
+ // @ts-expect-error - scripts are added dynamically to the entity
70
+ const navigation = this.entity.script?.tfXrNavigation;
71
+ if (!navigation || navigation.boundsRadius <= 0) {
72
+ return undefined;
73
+ }
74
+ return {
75
+ x: navigation.boundsCenter.x,
76
+ z: navigation.boundsCenter.z,
77
+ radius: navigation.boundsRadius
78
+ };
79
+ };
80
+
81
+ /**
82
+ * Runs in update rather than on the 'start' event: the engine writes the head pose during
83
+ * xr.update, which precedes the script update in the same tick, so a frame that has posed is the
84
+ * first point at which there is a real head to solve the rig pose from.
85
+ */
86
+ update() {
87
+ if (!this._pending || !this._posed || !this._isXrActive()) {
88
+ return;
89
+ }
90
+ const camera = this.entity.findComponent('camera')?.entity;
91
+ if (!camera) {
92
+ return;
93
+ }
94
+ const head = camera.getPosition();
95
+ const rig = this.entity.getPosition();
96
+ const rigY = rig.y;
97
+ const pose = xrStartRigPose({
98
+ head: {
99
+ x: head.x,
100
+ z: head.z
101
+ },
102
+ headYaw: yawFromBasis(camera.forward, camera.right),
103
+ rig: {
104
+ x: rig.x,
105
+ z: rig.z
106
+ },
107
+ target: {
108
+ x: this.targetX,
109
+ z: this.targetZ
110
+ },
111
+ focus: {
112
+ x: this.focusX,
113
+ z: this.focusZ
114
+ },
115
+ bounds: this._bounds()
116
+ });
117
+ this.entity.rotate(0, pose.yawDelta, 0);
118
+ this.entity.setPosition(pose.x, rigY, pose.z);
119
+ this._pending = false;
120
+ }
121
+ _teardown() {
122
+ this.app.xr?.off('start', this._onXrStart);
123
+ this.app.xr?.off('update', this._onXrUpdate);
124
+ this.app.xr?.off('end', this._onXrEnd);
125
+ }
126
+ }
127
+
128
+ export { XrStartPose };
@@ -42,8 +42,6 @@ export declare const boundaryWallMesh: ({ center, radius, groundPlane, baseY, to
42
42
  *
43
43
  * center / radius / groundPlane / baseY are set imperatively by the BoundaryWall component (see
44
44
  * BoundaryWall.tsx for why they are not reactive Script props), which calls `rebuild()` afterwards.
45
- * All of them are world-space: this entity is deliberately mounted outside `content-root`, which
46
- * carries the scene's scaleFactor.
47
45
  */
48
46
  export declare class BoundaryWallScript extends Script {
49
47
  static scriptName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"boundary-wall.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/boundary-wall.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,EAOL,MAAM,EAEN,IAAI,EACL,MAAM,YAAY,CAAC;AAKpB,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,gHAAgH;IAChH,WAAW,EAAE,IAAI,EAAE,CAAC;IACpB,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,sGAAsG;IACtG,IAAI,EAAE,MAAM,CAAC;IACb,yGAAyG;IACzG,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,GAAI,sEAQ9B,0BAA0B,KAAG,oBAqD/B,CAAC;AA2EF;;;;;;;;;GASG;AACH,qBAAa,kBAAmB,SAAQ,MAAM;IAC5C,MAAM,CAAC,UAAU,SAAkB;IAEnC,MAAM,OAAc;IACpB,MAAM,SAAK;IACX,WAAW,EAAE,IAAI,EAAE,CAAM;IACzB,uEAAuE;IACvE,KAAK,SAAK;IACV;;;OAGG;IACH,IAAI,SAAO;IACX,QAAQ,SAAM;IACd,WAAW,SAAO;IAClB,2CAA2C;IAC3C,SAAS,SAAS;IAClB,0EAA0E;IAC1E,YAAY,SAAO;IACnB,0EAA0E;IAC1E,gBAAgB,SAAO;IACvB,SAAS,QAA2B;IACpC,SAAS,QAA2B;IAEpC,OAAO,CAAC,SAAS,CAAC,CAAiB;IACnC,OAAO,CAAC,KAAK,CAAC,CAAO;IACrB,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,UAAU,CAAuB;IAEzC,UAAU;IAwBV;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAW5B,OAAO;IA6CP,MAAM;IAgCN,OAAO,CAAC,UAAU;CASnB"}
1
+ {"version":3,"file":"boundary-wall.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/boundary-wall.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,EAOL,MAAM,EAEN,IAAI,EACL,MAAM,YAAY,CAAC;AAKpB,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,gHAAgH;IAChH,WAAW,EAAE,IAAI,EAAE,CAAC;IACpB,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,sGAAsG;IACtG,IAAI,EAAE,MAAM,CAAC;IACb,yGAAyG;IACzG,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,GAAI,sEAQ9B,0BAA0B,KAAG,oBAqD/B,CAAC;AA2EF;;;;;;;GAOG;AACH,qBAAa,kBAAmB,SAAQ,MAAM;IAC5C,MAAM,CAAC,UAAU,SAAkB;IAEnC,MAAM,OAAc;IACpB,MAAM,SAAK;IACX,WAAW,EAAE,IAAI,EAAE,CAAM;IACzB,uEAAuE;IACvE,KAAK,SAAK;IACV;;;OAGG;IACH,IAAI,SAAO;IACX,QAAQ,SAAM;IACd,WAAW,SAAO;IAClB,2CAA2C;IAC3C,SAAS,SAAS;IAClB,0EAA0E;IAC1E,YAAY,SAAO;IACnB,0EAA0E;IAC1E,gBAAgB,SAAO;IACvB,SAAS,QAA2B;IACpC,SAAS,QAA2B;IAEpC,OAAO,CAAC,SAAS,CAAC,CAAiB;IACnC,OAAO,CAAC,KAAK,CAAC,CAAO;IACrB,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,UAAU,CAAuB;IAEzC,UAAU;IAwBV;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAW5B,OAAO;IA6CP,MAAM;IAgCN,OAAO,CAAC,UAAU;CASnB"}
@@ -179,8 +179,6 @@ const wallFragmentGLSL = /* glsl */`
179
179
  *
180
180
  * center / radius / groundPlane / baseY are set imperatively by the BoundaryWall component (see
181
181
  * BoundaryWall.tsx for why they are not reactive Script props), which calls `rebuild()` afterwards.
182
- * All of them are world-space: this entity is deliberately mounted outside `content-root`, which
183
- * carries the scene's scaleFactor.
184
182
  */
185
183
  class BoundaryWallScript extends Script {
186
184
  static scriptName = 'boundaryWall';
@@ -6,7 +6,6 @@ export declare class VrAnnotationPanel extends Script {
6
6
  bodyText?: string;
7
7
  imageUrls?: string[];
8
8
  annotationIndex: number;
9
- scaleFactor: number;
10
9
  private _material?;
11
10
  private _texture?;
12
11
  private _mesh?;
@@ -1 +1 @@
1
- {"version":3,"file":"vr-annotation-panel.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/vr-annotation-panel.ts"],"names":[],"mappings":"AAAA,OAAO,EAUL,MAAM,EAGN,IAAI,EAEL,MAAM,YAAY,CAAC;AAiCpB,qBAAa,iBAAkB,SAAQ,MAAM;IAC3C,MAAM,CAAC,UAAU,SAAuB;IAGxC,KAAK,SAAM;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,eAAe,SAAM;IACrB,WAAW,SAAK;IAEhB,OAAO,CAAC,SAAS,CAAC,CAAmB;IACrC,OAAO,CAAC,QAAQ,CAAC,CAAU;IAC3B,OAAO,CAAC,KAAK,CAAC,CAAO;IACrB,OAAO,CAAC,OAAO,CAAC,CAAoB;IACpC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,UAAU,CAAK;IAEvB,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,aAAa,CAAc;IAEnC,OAAO,CAAC,SAAS,CAsBf;IAEF,UAAU;IAwCV,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,UAAU;IAkBlB,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,YAAY;IAqFpB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,WAAW;IAmBnB,8FAA8F;IAC9F,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,GAAG,OAAO;IAIpD,MAAM;IAsCN,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,SAAS;CAYlB"}
1
+ {"version":3,"file":"vr-annotation-panel.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/vr-annotation-panel.ts"],"names":[],"mappings":"AAAA,OAAO,EAUL,MAAM,EAGN,IAAI,EAEL,MAAM,YAAY,CAAC;AAmCpB,qBAAa,iBAAkB,SAAQ,MAAM;IAC3C,MAAM,CAAC,UAAU,SAAuB;IAGxC,KAAK,SAAM;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,eAAe,SAAM;IAErB,OAAO,CAAC,SAAS,CAAC,CAAmB;IACrC,OAAO,CAAC,QAAQ,CAAC,CAAU;IAC3B,OAAO,CAAC,KAAK,CAAC,CAAO;IACrB,OAAO,CAAC,OAAO,CAAC,CAAoB;IACpC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,UAAU,CAAK;IAEvB,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,aAAa,CAAc;IAEnC,OAAO,CAAC,SAAS,CAsBf;IAEF,UAAU;IAwCV,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,UAAU;IAkBlB,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,YAAY;IAqFpB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,WAAW;IAmBnB,8FAA8F;IAC9F,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,GAAG,OAAO;IAIpD,MAAM;IAmCN,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,SAAS;CAYlB"}