@webspatial/core-sdk 0.1.10 → 0.1.13

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.
package/dist/index.js CHANGED
@@ -1,3 +1,11 @@
1
+
2
+ (function(){
3
+ if(typeof window === 'undefined') return;
4
+ if(!window.__webspatialsdk__) window.__webspatialsdk__ = {}
5
+ window.__webspatialsdk__['core-sdk-version'] = "0.1.13"
6
+ })()
7
+
8
+
1
9
  // src/core/private/remote-command/RemoteCommand.ts
2
10
  var RemoteCommand = class _RemoteCommand {
3
11
  static requestCounter = 0;
@@ -35,7 +43,6 @@ var WebSpatial = class _WebSpatial {
35
43
  delete this.eventReceivers[resourceId];
36
44
  }
37
45
  static init() {
38
- ;
39
46
  window.__SpatialWebEvent = (e) => {
40
47
  if (e.resourceId) {
41
48
  var callback = _WebSpatial.eventReceivers[e.resourceId];
@@ -84,12 +91,10 @@ var WebSpatial = class _WebSpatial {
84
91
  }
85
92
  var msg = JSON.stringify(cmd);
86
93
  if (_WebSpatial.getBackend() == "AVP") {
87
- ;
88
94
  window.webkit.messageHandlers.bridge.postMessage(msg);
89
95
  return;
90
96
  } else {
91
- ;
92
- window.bridge.nativeMessage(msg);
97
+ window.__WebSpatialData.androidNativeMessage(msg);
93
98
  return;
94
99
  }
95
100
  }
@@ -475,1011 +480,1026 @@ var SpatialComponent = class extends SpatialObject {
475
480
  }
476
481
  };
477
482
 
478
- // src/core/component/SpatialWindowComponent.ts
479
- var SpatialWindowComponent = class extends SpatialComponent {
480
- /**
481
- * Loads a url page in the window
482
- * @param url url to load
483
- */
484
- async loadURL(url) {
485
- await WebSpatial.updateResource(this._resource, { url });
486
- }
487
- async setFromWindow(window2) {
488
- if (window2._webSpatialID) {
489
- await WebSpatial.updateResource(this._resource, {
490
- windowID: window2._webSpatialID
491
- });
492
- } else {
493
- await console.warn(
494
- "failed to call setFromWindow, window provided is not valid"
495
- );
496
- }
483
+ // src/core/SpatialWindowContainer.ts
484
+ var SpatialWindowContainer = class {
485
+ /** @hidden */
486
+ constructor(_wg) {
487
+ this._wg = _wg;
497
488
  }
498
489
  /**
499
- * Sets the resolution of the window, the resulting dimensions when rendered will be equal to 1/1360 units
500
- * eg. if the resolution is set to 1360x1360 it will be a 1x1 plane
501
- * See 1360 in spatialViewUI.swift for how this ratio works
502
- * @param width width in pixels
503
- * @param height height in pixels
490
+ * @hidden
491
+ * Sets sets the open configuration for opening new window containers
492
+ * @param options style options
504
493
  */
505
- async setResolution(width, height) {
506
- await WebSpatial.updateResource(this._resource, {
507
- resolution: { x: width, y: height }
494
+ async _setOpenSettings(options) {
495
+ await WebSpatial.updateWindowContainer(this._wg, {
496
+ nextOpenSettings: options
508
497
  });
509
498
  }
510
499
  /**
511
- * [Experimental] Sets the anchor which the entity this is attached to will rotate around
512
- * @param rotationAnchor
500
+ * Retrieves the root entity of the windowContainer
501
+ * @returns the root entity of the windowContainer if one exists
513
502
  */
514
- async setRotationAnchor(rotationAnchor) {
515
- await WebSpatial.updateResource(this._resource, {
516
- rotationAnchor
503
+ async getRootEntity() {
504
+ let reqResp = await WebSpatial.updateWindowContainer(this._wg, {
505
+ getRootEntityID: ""
517
506
  });
507
+ if (reqResp.data.rootEntId === "") {
508
+ return null;
509
+ } else {
510
+ var res = new WebSpatialResource();
511
+ res.id = reqResp.data.rootEntId;
512
+ return new SpatialEntity(res);
513
+ }
518
514
  }
519
- /**
520
- * [Experimental] Sets the opacity of the window after apply material
521
- * @param opacity
515
+ /*
516
+ * Sets the root entity that this windowContainer will display (this does not effect resource ownership)
517
+ * @param entity to display
522
518
  */
523
- async setOpacity(opacity) {
524
- await WebSpatial.updateResource(this._resource, {
525
- opacity
519
+ async setRootEntity(entity) {
520
+ await entity._setParentWindowContainer(this);
521
+ }
522
+ async close() {
523
+ await WebSpatial.updateWindowContainer(this._wg, {
524
+ close: true
526
525
  });
527
526
  }
527
+ };
528
+
529
+ // src/core/resource/SpatialMeshResource.ts
530
+ var SpatialMeshResource = class extends SpatialObject {
531
+ };
532
+
533
+ // src/core/resource/SpatialPhysicallyBasedMaterialResource.ts
534
+ var SpatialPhysicallyBasedMaterialResource = class extends SpatialObject {
528
535
  /**
529
- * Sets the style that should be applied to the window
530
- * @param options style options
536
+ * Base color of the material containing rgba between 0 and 1
531
537
  */
532
- async setStyle(styleParam) {
533
- const { material, cornerRadius } = styleParam;
534
- const options = {};
535
- if (material?.type) {
536
- options.backgroundMaterial = material.type;
537
- }
538
- if (cornerRadius !== void 0) {
539
- if (typeof cornerRadius === "number") {
540
- options.cornerRadius = {
541
- topLeading: cornerRadius,
542
- bottomLeading: cornerRadius,
543
- topTrailing: cornerRadius,
544
- bottomTrailing: cornerRadius
545
- };
546
- } else {
547
- options.cornerRadius = { ...cornerRadius };
548
- }
549
- }
550
- if (document && document.readyState == "loading") {
551
- var encoded = encodeURIComponent(JSON.stringify(options));
552
- var x = document.createElement("link");
553
- x.rel = "stylesheet";
554
- x.href = "forceStyle://mystyle.css?style=" + encoded;
555
- document.head.appendChild(x);
556
- }
557
- await WebSpatial.updateResource(this._resource, { style: options });
558
- }
538
+ baseColor = { r: 0, g: 0.7, b: 0.7, a: 1 };
559
539
  /**
560
- * Modifies the amount the spatial window can be scrolled
561
- * Should only be used internally
562
- * See https://developer.apple.com/documentation/uikit/1624475-uiedgeinsetsmake?language=objc
563
- * @param insets margin to modify scroll distances by
540
+ * PBR metalic value between 0 and 1
564
541
  */
565
- async setScrollEdgeInsets(insets) {
566
- await WebSpatial.updateResource(this._resource, {
567
- setScrollEdgeInsets: insets
568
- });
569
- }
542
+ metallic = { value: 0.5 };
570
543
  /**
571
- * Enable/Disable scrolling in the window (defaults to enabled), if disabled, scrolling will be applied to the root page
572
- * @param enabled value to set
544
+ * PBR roughness value between 0 and 1
573
545
  */
574
- async setScrollEnabled(enabled) {
575
- await WebSpatial.updateResource(this._resource, { scrollEnabled: enabled });
546
+ roughness = { value: 0.5 };
547
+ _modelComponentAttachedTo = {};
548
+ _addToComponent(c) {
549
+ this._modelComponentAttachedTo[c._resource.id] = c;
576
550
  }
577
551
  /**
578
- * Defaults to false. If set to true, scrolling the parent page will also scroll this window with it like other dom elements
579
- * @param scrollWithParent value to set
552
+ * Syncs state of color, metallic, roupghness to the renderer
580
553
  */
581
- async setScrollWithParent(scrollWithParent) {
554
+ async update() {
582
555
  await WebSpatial.updateResource(this._resource, {
583
- scrollWithParent
556
+ baseColor: this.baseColor,
557
+ metallic: this.metallic,
558
+ roughness: this.roughness
584
559
  });
560
+ for (var key in this._modelComponentAttachedTo) {
561
+ await this._modelComponentAttachedTo[key]._syncMaterials();
562
+ }
585
563
  }
586
564
  };
587
565
 
588
- // src/core/component/EventSpatialComponent.ts
589
- var EventSpatialComponent = class extends SpatialComponent {
590
- // Class implementation goes here
591
- constructor(_resource) {
592
- super(_resource);
593
- WebSpatial.registerEventReceiver(_resource.id, (data) => {
594
- this.onRecvEvent(data);
595
- });
596
- }
597
- async onDestroy() {
598
- WebSpatial.unregisterEventReceiver(this._resource.id);
566
+ // src/core/SpatialSession.ts
567
+ function _parseParentResources(options) {
568
+ var parentWindowContainer = null;
569
+ if (options?.windowContainer !== null) {
570
+ parentWindowContainer = options?.windowContainer ? options?.windowContainer._wg : WebSpatial.getCurrentWindowContainer();
599
571
  }
600
- };
601
-
602
- // src/core/component/SpatialInputComponent.ts
603
- var SpatialInputComponent = class extends EventSpatialComponent {
604
- onRecvEvent(data) {
605
- this.onTranslate(data);
572
+ var parentWindow = null;
573
+ if (options?.windowComponent !== null) {
574
+ parentWindow = options?.windowComponent ? options?.windowComponent._resource : WebSpatial.getCurrentWebPanel();
606
575
  }
576
+ return [parentWindowContainer, parentWindow];
577
+ }
578
+ var SpatialSession = class _SpatialSession {
579
+ /** @hidden */
580
+ _engineUpdateListeners = Array();
581
+ /** @hidden */
582
+ _frameLoopStarted = false;
607
583
  /**
608
- * Callback fired when a translate event occurs
609
- * @param data translate event data
584
+ * Add event listener callback to be called each frame
585
+ * @param callback callback to be called each update
610
586
  */
611
- onTranslate(data) {
587
+ addOnEngineUpdateEventListener(callback) {
588
+ this._engineUpdateListeners.push(callback);
589
+ if (!this._frameLoopStarted) {
590
+ this._frameLoopStarted = true;
591
+ WebSpatial.onFrame(async (time) => {
592
+ await Promise.all(
593
+ this._engineUpdateListeners.map((cb) => {
594
+ return cb(time);
595
+ })
596
+ );
597
+ });
598
+ }
612
599
  }
613
- };
614
-
615
- // src/core/component/SpatialModelComponent.ts
616
- var SpatialModelComponent = class extends SpatialComponent {
617
- cachedMaterials = new Array();
618
600
  /**
619
- * Sets the mesh to be displayed by the component
620
- * @param mesh mesh to set
601
+ * Creates a Entity
602
+ * @returns Entity
621
603
  */
622
- async setMesh(mesh) {
623
- await WebSpatial.updateResource(this._resource, {
624
- meshResource: mesh._resource.id
625
- });
604
+ async createEntity(options) {
605
+ var [parentWindowContainer, parentWindow] = _parseParentResources(options);
606
+ let entity = await WebSpatial.createResource(
607
+ "Entity",
608
+ parentWindowContainer,
609
+ parentWindow
610
+ );
611
+ return new SpatialEntity(entity);
626
612
  }
627
613
  /**
628
- * Sets the materials that should be applied to the mesh
629
- * @param materials array of materials to set
614
+ * Creates a WindowComponent
615
+ * [TODO] should creation of components be moved to entity? and these made private?
616
+ * @returns WindowComponent
630
617
  */
631
- async setMaterials(materials) {
632
- this.cachedMaterials = materials;
633
- await WebSpatial.updateResource(this._resource, {
634
- materials: materials.map((m) => {
635
- m._addToComponent(this);
636
- return m._resource.id;
637
- })
638
- });
639
- }
640
- /** @hidden */
641
- async _syncMaterials() {
642
- await this.setMaterials(this.cachedMaterials);
618
+ async createWindowComponent(options) {
619
+ var [parentWindowContainer, parentWindow] = _parseParentResources(options);
620
+ let entity = await WebSpatial.createResource(
621
+ "SpatialWebView",
622
+ parentWindowContainer,
623
+ parentWindow
624
+ );
625
+ return new SpatialWindowComponent(entity);
643
626
  }
644
- };
645
-
646
- // src/core/component/SpatialViewComponent.ts
647
- var SpatialViewComponent = class extends SpatialComponent {
648
627
  /**
649
- * Sets the resolution of the spatial view in dom pixels
628
+ * Creates a ViewComponent used to display 3D content within the entity
629
+ * @returns SpatialViewComponent
650
630
  */
651
- async setResolution(width, height) {
652
- await WebSpatial.updateResource(this._resource, {
653
- resolution: { x: width, y: height }
654
- });
631
+ async createViewComponent(options) {
632
+ var [parentWindowContainer, parentWindow] = _parseParentResources(options);
633
+ let entity = await WebSpatial.createResource(
634
+ "SpatialView",
635
+ parentWindowContainer,
636
+ parentWindow
637
+ );
638
+ return new SpatialViewComponent(entity);
655
639
  }
656
640
  /**
657
- * Sets if content of the spatialView should be within a portal
658
- * If true, volume will be behind the page, if false, it will be in front of the page
641
+ * Creates a ModelComponent used to display geometry + material of a 3D model
642
+ * @returns ModelComponent
659
643
  */
660
- async setIsPortal(isPortal) {
661
- await WebSpatial.updateResource(this._resource, {
662
- isPortal
663
- });
664
- }
665
- };
666
-
667
- // src/core/component/SpatialModel3DComponent.ts
668
- var SpatialModel3DComponent = class extends EventSpatialComponent {
669
- onRecvEvent(data) {
670
- const { eventType, value, error } = data;
671
- switch (eventType) {
672
- case "phase":
673
- if (value === "success") {
674
- this.onSuccess?.();
675
- } else {
676
- this.onFailure?.(error);
677
- }
678
- break;
679
- case "dragstart":
680
- this._onDragStart?.(value);
681
- break;
682
- case "dragend":
683
- this._onDragEnd?.(value);
684
- break;
685
- case "drag":
686
- this._onDrag?.(value);
687
- break;
688
- case "tap":
689
- this._onTap?.();
690
- break;
691
- case "doubletap":
692
- this._onDoubleTap?.();
693
- break;
694
- case "longpress":
695
- this._onLongPress?.();
696
- break;
697
- default:
698
- break;
644
+ async createModelComponent(options) {
645
+ var [parentWindowContainer, parentWindow] = _parseParentResources(options);
646
+ var opts = void 0;
647
+ if (options) {
648
+ opts = { modelURL: options.url };
699
649
  }
650
+ let entity = await WebSpatial.createResource(
651
+ "ModelComponent",
652
+ parentWindowContainer,
653
+ parentWindow,
654
+ opts
655
+ );
656
+ return new SpatialModelComponent(entity);
700
657
  }
701
658
  /**
702
- * Sets the resolution of the spatial view in dom pixels
659
+ * Creates a Model3DComponent
660
+ * @returns Model3DComponent
703
661
  */
704
- async setResolution(width, height) {
705
- await WebSpatial.updateResource(this._resource, {
706
- resolution: { x: width, y: height }
707
- });
708
- }
709
- async setRotationAnchor(rotationAnchor) {
710
- await WebSpatial.updateResource(this._resource, {
711
- rotationAnchor
712
- });
662
+ async createModel3DComponent(options) {
663
+ var [parentWindowContainer, parentWindow] = _parseParentResources(options);
664
+ var opts = void 0;
665
+ if (options) {
666
+ opts = { modelURL: options.url };
667
+ }
668
+ let entity = await WebSpatial.createResource(
669
+ "Model3DComponent",
670
+ parentWindowContainer,
671
+ parentWindow,
672
+ opts
673
+ );
674
+ return new SpatialModel3DComponent(entity);
713
675
  }
714
676
  /**
715
- * Sets the opacity of the model
716
- * @param opacity
677
+ * Creates a InputComponent
678
+ * [Experimental] Creates a InputComponent used to handle click and drag events of the entity containing a model
679
+ * @returns InputComponent
717
680
  */
718
- async setOpacity(opacity) {
719
- await WebSpatial.updateResource(this._resource, {
720
- opacity
721
- });
681
+ async createInputComponent(options) {
682
+ var [parentWindowContainer, parentWindow] = _parseParentResources(options);
683
+ let entity = await WebSpatial.createResource(
684
+ "InputComponent",
685
+ parentWindowContainer,
686
+ parentWindow
687
+ );
688
+ return new SpatialInputComponent(entity);
722
689
  }
723
690
  /**
724
- * Sets how the model fill the rect
725
- * @param contentMode
691
+ * Creates a MeshResource containing geometry data
692
+ * @returns MeshResource
726
693
  */
727
- async setContentMode(contentMode) {
728
- await WebSpatial.updateResource(this._resource, {
729
- contentMode
730
- });
694
+ async createMeshResource(options) {
695
+ var [parentWindowContainer, parentWindow] = _parseParentResources(options);
696
+ let entity = await WebSpatial.createResource(
697
+ "MeshResource",
698
+ parentWindowContainer,
699
+ parentWindow,
700
+ options
701
+ );
702
+ return new SpatialMeshResource(entity);
731
703
  }
732
704
  /**
733
- * Constrains this model dimensions to the specified aspect ratio.
734
- * with a value of 0, the model will use the original aspect ratio.
735
- *
736
- * @param aspectRatio number
705
+ * Creates a PhysicallyBasedMaterial containing PBR material data
706
+ * @returns PhysicallyBasedMaterial
737
707
  */
738
- async setAspectRatio(aspectRatio) {
739
- await WebSpatial.updateResource(this._resource, {
740
- aspectRatio
741
- });
708
+ async createPhysicallyBasedMaterialResource(options) {
709
+ var [parentWindowContainer, parentWindow] = _parseParentResources(options);
710
+ let entity = await WebSpatial.createResource(
711
+ "PhysicallyBasedMaterial",
712
+ parentWindowContainer,
713
+ parentWindow,
714
+ options
715
+ );
716
+ return new SpatialPhysicallyBasedMaterialResource(entity);
742
717
  }
743
718
  /**
744
- * Defaults to false. If set to true, scrolling the parent page will also scroll this window with it like other dom elements
745
- * @param scrollWithParent value to set
746
- */
747
- async setScrollWithParent(scrollWithParent) {
748
- await WebSpatial.updateResource(this._resource, {
749
- scrollWithParent
750
- });
719
+ * Creates a WindowContainer
720
+ * @returns SpatialWindowContainer
721
+ * */
722
+ async createWindowContainer(options) {
723
+ var style = options?.style ? options?.style : "Plain";
724
+ var [parentWindowContainer, parentWindow] = _parseParentResources(options);
725
+ return new SpatialWindowContainer(
726
+ await WebSpatial.createWindowContainer(
727
+ style,
728
+ parentWindowContainer,
729
+ parentWindow
730
+ )
731
+ );
751
732
  }
752
733
  /**
753
- * Sets whether the model appear in original size or fit the rect
754
- * @param resizable
734
+ * Creates a Scene to display content within an anchored area managed by the OS
735
+ * @hidden
736
+ * @param {WindowStyle} [style='Plain'] - The style of the Scene container to be created with. Defaults to 'Plain'.
737
+ * @param {Object} [cfg={}] - Configuration object for the Scene.
738
+ * @returns Boolean
755
739
  */
756
- async setResizable(resizable) {
757
- await WebSpatial.updateResource(this._resource, {
758
- resizable
759
- });
740
+ async _createScene(style = "Plain", cfg) {
741
+ return await WebSpatial.createScene(style, cfg);
760
742
  }
761
743
  /**
762
- * Callback fired when model load success
763
- */
764
- onSuccess;
765
- /**
766
- * Callback fired when model load failure
767
- * @param errorReason
744
+ * Retrieves the window for this page
745
+ * @returns the window component corresponding to the js running on this page
746
+ * [TODO] discuss implications of this not being async
768
747
  */
769
- onFailure;
748
+ getCurrentWindowComponent() {
749
+ return new SpatialWindowComponent(WebSpatial.getCurrentWebPanel());
750
+ }
770
751
  /**
771
- * Callback fired when model was dragged at the beginning
772
- * @param dragEvent
752
+ * Retrieves the parent window for this page or null if this is the root page
753
+ * @returns the window component or null
773
754
  */
774
- _onDragStart;
775
- set onDragStart(callback) {
776
- if (this._onDragStart !== callback) {
777
- this._onDragStart = callback;
778
- WebSpatial.updateResource(this._resource, {
779
- enableDragEvent: this.enableDragEvent
755
+ async getParentWindowComponent() {
756
+ let parentResp = await WebSpatial.updateResource(
757
+ WebSpatial.getCurrentWebPanel(),
758
+ { getParentID: "" }
759
+ );
760
+ if (parentResp.data.parentID === "") {
761
+ return new Promise((res2, rej) => {
762
+ res2(null);
780
763
  });
764
+ } else {
765
+ var res = new WebSpatialResource();
766
+ res.id = parentResp.data.parentID;
767
+ return new SpatialWindowComponent(res);
781
768
  }
782
769
  }
783
770
  /**
784
- * Callback fired when model was dragged
785
- * @param dragEvent
771
+ * Logs a message to the native apps console
772
+ * @param msg mesage to log
786
773
  */
787
- _onDrag;
788
- set onDrag(callback) {
789
- if (this._onDrag !== callback) {
790
- this._onDrag = callback;
791
- WebSpatial.updateResource(this._resource, {
792
- enableDragEvent: this.enableDragEvent
793
- });
794
- }
774
+ async log(...msg) {
775
+ await WebSpatial.sendCommand(
776
+ new RemoteCommand("log", {
777
+ logString: msg.map((x) => {
778
+ return JSON.stringify(x);
779
+ })
780
+ })
781
+ );
795
782
  }
796
783
  /**
797
- * Callback fired when model was dragged at the ending
798
- * @param dragEvent
784
+ * @hidden
785
+ * Debugging only, used to ping the native renderer
799
786
  */
800
- _onDragEnd;
801
- set onDragEnd(callback) {
802
- if (this._onDragEnd !== callback) {
803
- this._onDragEnd = callback;
804
- WebSpatial.updateResource(this._resource, {
805
- enableDragEvent: this.enableDragEvent
806
- });
807
- }
787
+ async _ping(msg) {
788
+ return await WebSpatial.ping(msg);
808
789
  }
809
- get enableDragEvent() {
810
- return void 0 !== this._onDrag || void 0 !== this._onDragStart || void 0 !== this._onDragEnd;
790
+ /**
791
+ * @hidden
792
+ * Debugging to get internal state from native code
793
+ * @returns data as a js object
794
+ */
795
+ async _getStats() {
796
+ return await WebSpatial.getStats();
811
797
  }
812
798
  /**
813
- * Callback fired when model was tapped
799
+ * @hidden
814
800
  */
815
- _onTap;
816
- set onTap(callback) {
817
- if (this._onTap !== callback) {
818
- this._onTap = callback;
819
- WebSpatial.updateResource(this._resource, {
820
- enableTapEvent: void 0 !== callback
821
- });
822
- }
801
+ async _inspect(spatialObjectId = WebSpatial.getCurrentWebPanel().id) {
802
+ return WebSpatial.inspect(spatialObjectId);
823
803
  }
824
- /** Callback fired when model was double tapped */
825
- _onDoubleTap;
826
- set onDoubleTap(callback) {
827
- if (this._onDoubleTap !== callback) {
828
- this._onDoubleTap = callback;
829
- WebSpatial.updateResource(this._resource, {
830
- enableDoubleTapEvent: void 0 !== callback
831
- });
832
- }
833
- }
834
- /** Callback fired when model was long pressed */
835
- _onLongPress;
836
- set onLongPress(callback) {
837
- if (this._onLongPress !== callback) {
838
- this._onLongPress = callback;
839
- WebSpatial.updateResource(this._resource, {
840
- enableLongPressEvent: void 0 !== callback
841
- });
842
- }
843
- }
844
- };
845
-
846
- // src/core/resource/SpatialMeshResource.ts
847
- var SpatialMeshResource = class extends SpatialObject {
848
- };
849
-
850
- // src/core/resource/SpatialPhysicallyBasedMaterialResource.ts
851
- var SpatialPhysicallyBasedMaterialResource = class extends SpatialObject {
852
- /**
853
- * Base color of the material containing rgba between 0 and 1
854
- */
855
- baseColor = { r: 0, g: 0.7, b: 0.7, a: 1 };
856
804
  /**
857
- * PBR metalic value between 0 and 1
805
+ * @hidden
858
806
  */
859
- metallic = { value: 0.5 };
807
+ async _inspectRootWindowContainer() {
808
+ return WebSpatial.inspectRootWindowContainer();
809
+ }
810
+ /** Opens the immersive space */
811
+ async openImmersiveSpace() {
812
+ return await WebSpatial.openImmersiveSpace();
813
+ }
814
+ /** Closes the immersive space */
815
+ async dismissImmersiveSpace() {
816
+ return await WebSpatial.dismissImmersiveSpace();
817
+ }
818
+ static _immersiveWindowContainer = null;
860
819
  /**
861
- * PBR roughness value between 0 and 1
820
+ * Retreives the window container corresponding to the Immersive space
821
+ * @returns the immersive window container
862
822
  */
863
- roughness = { value: 0.5 };
864
- _modelComponentAttachedTo = {};
865
- _addToComponent(c) {
866
- this._modelComponentAttachedTo[c._resource.id] = c;
823
+ async getImmersiveWindowContainer() {
824
+ if (_SpatialSession._immersiveWindowContainer) {
825
+ return _SpatialSession._immersiveWindowContainer;
826
+ } else {
827
+ _SpatialSession._immersiveWindowContainer = new SpatialWindowContainer(
828
+ WebSpatial.getImmersiveWindowContainer()
829
+ );
830
+ return _SpatialSession._immersiveWindowContainer;
831
+ }
867
832
  }
833
+ // Retreives the window container that is the parent to this spatial web page
834
+ static _currentWindowContainer = null;
868
835
  /**
869
- * Syncs state of color, metallic, roupghness to the renderer
836
+ * Gets the current window container for the window
837
+ * [TODO] discuss what happens if it doesnt yet have a window container
838
+ * @returns the current window container for the window
870
839
  */
871
- async update() {
872
- await WebSpatial.updateResource(this._resource, {
873
- baseColor: this.baseColor,
874
- metallic: this.metallic,
875
- roughness: this.roughness
876
- });
877
- for (var key in this._modelComponentAttachedTo) {
878
- await this._modelComponentAttachedTo[key]._syncMaterials();
840
+ getCurrentWindowContainer() {
841
+ if (_SpatialSession._currentWindowContainer) {
842
+ return _SpatialSession._currentWindowContainer;
843
+ } else {
844
+ _SpatialSession._currentWindowContainer = new SpatialWindowContainer(
845
+ WebSpatial.getCurrentWindowContainer()
846
+ );
847
+ return _SpatialSession._currentWindowContainer;
879
848
  }
880
849
  }
881
- };
882
-
883
- // src/core/SpatialWindowContainer.ts
884
- var SpatialWindowContainer = class {
885
- /** @hidden */
886
- constructor(_wg) {
887
- this._wg = _wg;
888
- }
889
850
  /**
890
- * @hidden
891
- * Sets sets the open configuration for opening new window containers
892
- * @param options style options
851
+ * Start a transaction that queues up commands to submit them all at once to reduce ipc overhead
852
+ * @param fn function to be run, within this function, promises will not resolve
853
+ * @returns promise for the entire transaction completion
893
854
  */
894
- async _setOpenSettings(options) {
895
- await WebSpatial.updateWindowContainer(this._wg, {
896
- nextOpenSettings: options
897
- });
855
+ transaction(fn) {
856
+ WebSpatial.startTransaction();
857
+ fn();
858
+ return WebSpatial.sendTransaction();
898
859
  }
899
860
  /**
900
- * Retrieves the root entity of the windowContainer
901
- * @returns the root entity of the windowContainer if one exists
861
+ * Creates a window context object that is compatable with SpatialWindowComponent's setFromWindow API
862
+ * @returns window context
902
863
  */
903
- async getRootEntity() {
904
- let reqResp = await WebSpatial.updateWindowContainer(this._wg, {
905
- getRootEntityID: ""
906
- });
907
- if (reqResp.data.rootEntId === "") {
908
- return null;
864
+ async createWindowContext() {
865
+ let openedWindow = window.open("webspatial://createWindowContext");
866
+ if (WebSpatial.getBackend() != "AVP") {
867
+ var counter = 0;
868
+ while (openedWindow.window.testAPI == null) {
869
+ if (counter > 15) {
870
+ openedWindow?.close();
871
+ openedWindow = window.open("about:blank");
872
+ counter = 0;
873
+ this.log("unexpected error when trying to open new window, retrying.");
874
+ }
875
+ var locName = "about:blank?x" + counter;
876
+ openedWindow.location.href = locName;
877
+ counter++;
878
+ await new Promise((resolve) => setTimeout(resolve, 10));
879
+ }
880
+ ;
881
+ openedWindow._webSpatialID = openedWindow.window.testAPI.getWindowID();
909
882
  } else {
910
- var res = new WebSpatialResource();
911
- res.id = reqResp.data.rootEntId;
912
- return new SpatialEntity(res);
883
+ while (openedWindow.window._webSpatialID == void 0) {
884
+ await new Promise((resolve) => setTimeout(resolve, 10));
885
+ }
913
886
  }
887
+ openedWindow.document.head.innerHTML = `<meta name="viewport" content="width=device-width, initial-scale=1">
888
+ <base href="${document.baseURI}">
889
+ `;
890
+ return openedWindow;
914
891
  }
915
- /*
916
- * Sets the root entity that this windowContainer will display (this does not effect resource ownership)
917
- * @param entity to display
918
- */
919
- async setRootEntity(entity) {
920
- await entity._setParentWindowContainer(this);
892
+ // Get Entity by id. Currently for debugging only.
893
+ /** @hidden */
894
+ async _getEntity(id) {
895
+ const entityInfo = await WebSpatial.inspect(id);
896
+ const [_, x, y, z] = entityInfo.position.match(/(\d+\.?\d*)/g);
897
+ const [__, sx, sy, sz] = entityInfo.scale.match(/(\d+\.?\d*)/g);
898
+ var res = new WebSpatialResource();
899
+ res.id = id;
900
+ res.windowContainerId = WebSpatial.getCurrentWindowContainer().id;
901
+ const entity = new SpatialEntity(res);
902
+ entity.transform.position.x = parseFloat(x);
903
+ entity.transform.position.y = parseFloat(y);
904
+ entity.transform.position.z = parseFloat(z);
905
+ entity.transform.scale.x = parseFloat(sx);
906
+ entity.transform.scale.y = parseFloat(sy);
907
+ entity.transform.scale.z = parseFloat(sz);
908
+ return entity;
909
+ }
910
+ // set loading view.
911
+ /** @hidden */
912
+ async setLoading(method, style) {
913
+ return WebSpatial.setLoading(method, style);
921
914
  }
922
915
  };
923
916
 
924
- // src/core/SpatialSession.ts
925
- function _parseParentResources(options) {
926
- var parentWindowContainer = null;
927
- if (options?.windowContainer !== null) {
928
- parentWindowContainer = options?.windowContainer ? options?.windowContainer._wg : WebSpatial.getCurrentWindowContainer();
929
- }
930
- var parentWindow = null;
931
- if (options?.windowComponent !== null) {
932
- parentWindow = options?.windowComponent ? options?.windowComponent._resource : WebSpatial.getCurrentWebPanel();
933
- }
934
- return [parentWindowContainer, parentWindow];
935
- }
936
- var SpatialSession = class _SpatialSession {
937
- /** @hidden */
938
- _engineUpdateListeners = Array();
939
- /** @hidden */
940
- _frameLoopStarted = false;
917
+ // src/core/Spatial.ts
918
+ var Spatial = class {
941
919
  /**
942
- * Add event listener callback to be called each frame
943
- * @param callback callback to be called each update
920
+ * Requests a session object from the browser
921
+ * @returns The session or null if not availible in the current browser
922
+ * [TODO] discuss implications of this not being async
944
923
  */
945
- addOnEngineUpdateEventListener(callback) {
946
- this._engineUpdateListeners.push(callback);
947
- if (!this._frameLoopStarted) {
948
- this._frameLoopStarted = true;
949
- WebSpatial.onFrame(async (time) => {
950
- await Promise.all(
951
- this._engineUpdateListeners.map((cb) => {
952
- return cb(time);
953
- })
954
- );
955
- });
924
+ requestSession() {
925
+ if (this.isSupported() && this.getNativeVersion() === this.getClientVersion()) {
926
+ return new SpatialSession();
927
+ } else {
928
+ return null;
956
929
  }
957
930
  }
958
931
  /**
959
- * Creates a Entity
960
- * @returns Entity
932
+ * @returns true if web spatial is supported by this webpage
961
933
  */
962
- async createEntity(options) {
963
- var [parentWindowContainer, parentWindow] = _parseParentResources(options);
964
- let entity = await WebSpatial.createResource(
965
- "Entity",
966
- parentWindowContainer,
967
- parentWindow
968
- );
969
- return new SpatialEntity(entity);
934
+ isSupported() {
935
+ return this.getNativeVersion() === this.getClientVersion();
970
936
  }
971
937
  /**
972
- * Creates a WindowComponent
973
- * [TODO] should creation of components be moved to entity? and these made private?
974
- * @returns WindowComponent
938
+ * Gets the native version, format is "x.x.x"
939
+ * @returns native version string
975
940
  */
976
- async createWindowComponent(options) {
977
- var [parentWindowContainer, parentWindow] = _parseParentResources(options);
978
- let entity = await WebSpatial.createResource(
979
- "SpatialWebView",
980
- parentWindowContainer,
981
- parentWindow
982
- );
983
- return new SpatialWindowComponent(entity);
941
+ getNativeVersion() {
942
+ if (window.__WebSpatialData && window.__WebSpatialData.getNativeVersion) {
943
+ return window.__WebSpatialData.getNativeVersion();
944
+ }
945
+ return window.WebSpatailNativeVersion;
984
946
  }
985
947
  /**
986
- * Creates a ViewComponent used to display 3D content within the entity
987
- * @returns SpatialViewComponent
948
+ * Gets the client version, format is "x.x.x"
949
+ * @returns client version string
988
950
  */
989
- async createViewComponent(options) {
990
- var [parentWindowContainer, parentWindow] = _parseParentResources(options);
991
- let entity = await WebSpatial.createResource(
992
- "SpatialView",
993
- parentWindowContainer,
994
- parentWindow
995
- );
996
- return new SpatialViewComponent(entity);
951
+ getClientVersion() {
952
+ return "0.0.1";
997
953
  }
998
- /**
999
- * Creates a ModelComponent used to display geometry + material of a 3D model
1000
- * @returns ModelComponent
1001
- */
1002
- async createModelComponent(options) {
1003
- var [parentWindowContainer, parentWindow] = _parseParentResources(options);
1004
- var opts = void 0;
1005
- if (options) {
1006
- opts = { modelURL: options.url };
954
+ };
955
+
956
+ // src/core/SpatialHelper.ts
957
+ var SpatialHelper = class _SpatialHelper {
958
+ constructor(session) {
959
+ this.session = session;
960
+ }
961
+ static _instance = null;
962
+ static get instance() {
963
+ if (this._instance) {
964
+ return this._instance;
965
+ } else {
966
+ let spatial = new Spatial();
967
+ if (spatial.isSupported()) {
968
+ let session = spatial.requestSession();
969
+ if (session) {
970
+ this._instance = new _SpatialHelper(session);
971
+ return this._instance;
972
+ }
973
+ }
1007
974
  }
1008
- let entity = await WebSpatial.createResource(
1009
- "ModelComponent",
1010
- parentWindowContainer,
1011
- parentWindow,
1012
- opts
1013
- );
1014
- return new SpatialModelComponent(entity);
975
+ return null;
1015
976
  }
977
+ shape = {
978
+ createShapeEntity: async (shape = "box") => {
979
+ var box = await this.session.createMeshResource({ shape });
980
+ var mat = await this.session.createPhysicallyBasedMaterialResource();
981
+ await mat.update();
982
+ var customModel = await this.session.createModelComponent();
983
+ customModel.setMaterials([mat]);
984
+ customModel.setMesh(box);
985
+ var boxEntity = await this.session.createEntity();
986
+ await boxEntity.setComponent(customModel);
987
+ boxEntity.transform.position.z = 0;
988
+ boxEntity.transform.scale = new Vec3(0.5, 0.5, 0.5);
989
+ await boxEntity.updateTransform();
990
+ return boxEntity;
991
+ },
992
+ createModelEntity: async (url) => {
993
+ var customModel = await this.session.createModelComponent({ url });
994
+ var boxEntity = await this.session.createEntity();
995
+ await boxEntity.setComponent(customModel);
996
+ await boxEntity.updateTransform();
997
+ return boxEntity;
998
+ },
999
+ wrapInBoundingBoxEntity: async (entityToWrap) => {
1000
+ var bb = await entityToWrap.getBoundingBox();
1001
+ var targetSize = 1;
1002
+ var scale = targetSize / Math.max(bb.extents.x, bb.extents.y, bb.extents.z);
1003
+ entityToWrap.transform.scale.x = scale;
1004
+ entityToWrap.transform.scale.y = scale;
1005
+ entityToWrap.transform.scale.z = scale;
1006
+ entityToWrap.transform.position.x = -bb.center.x * scale;
1007
+ entityToWrap.transform.position.y = -bb.center.y * scale;
1008
+ entityToWrap.transform.position.z = -bb.center.z * scale;
1009
+ await entityToWrap.updateTransform();
1010
+ var boudningEntity = await _SpatialHelper.instance?.session.createEntity();
1011
+ await entityToWrap.setParent(boudningEntity);
1012
+ return boudningEntity;
1013
+ }
1014
+ };
1015
+ navigation = {
1016
+ openPanel: async (url, options) => {
1017
+ if (options?.resolution) {
1018
+ await this.session.getCurrentWindowContainer()._setOpenSettings({ resolution: options.resolution });
1019
+ }
1020
+ var wg = await this.session.createWindowContainer({
1021
+ style: "Plain",
1022
+ windowComponent: null,
1023
+ windowContainer: null
1024
+ });
1025
+ var ent = await this.session.createEntity({
1026
+ windowComponent: null,
1027
+ windowContainer: wg
1028
+ });
1029
+ var i = await this.session.createWindowComponent({
1030
+ windowComponent: null,
1031
+ windowContainer: wg
1032
+ });
1033
+ await i.loadURL(url);
1034
+ await ent.setCoordinateSpace("Root");
1035
+ await ent.setComponent(i);
1036
+ await wg.setRootEntity(ent);
1037
+ await this.session.getCurrentWindowContainer()._setOpenSettings({ resolution: { width: 900, height: 700 } });
1038
+ return {
1039
+ windowContainer: wg
1040
+ };
1041
+ },
1042
+ openVolume: async (url, options) => {
1043
+ var wg = await this.session.createWindowContainer({
1044
+ style: "Volumetric",
1045
+ windowComponent: null,
1046
+ windowContainer: null
1047
+ });
1048
+ var rootEnt = await this.session.createEntity({
1049
+ windowComponent: null,
1050
+ windowContainer: wg
1051
+ });
1052
+ await rootEnt.setComponent(
1053
+ await this.session.createViewComponent({
1054
+ windowComponent: null,
1055
+ windowContainer: wg
1056
+ })
1057
+ );
1058
+ await rootEnt.setCoordinateSpace("Root");
1059
+ await wg.setRootEntity(rootEnt);
1060
+ var ent = await this.session.createEntity({
1061
+ windowComponent: null,
1062
+ windowContainer: wg
1063
+ });
1064
+ var i = await this.session.createWindowComponent({
1065
+ windowComponent: null,
1066
+ windowContainer: wg
1067
+ });
1068
+ await i.loadURL(url);
1069
+ if (options?.resolution) {
1070
+ await i.setResolution(
1071
+ options.resolution.width,
1072
+ options.resolution.height
1073
+ );
1074
+ } else {
1075
+ await i.setResolution(1e3, 1e3);
1076
+ }
1077
+ ent.transform.position.z = -0.49;
1078
+ await ent.updateTransform();
1079
+ await ent.setCoordinateSpace("App");
1080
+ await ent.setComponent(i);
1081
+ await ent.setParent(rootEnt);
1082
+ }
1083
+ };
1084
+ dom = {
1085
+ attachSpatialView: async (divOnPage) => {
1086
+ var viewEnt = await this.session.createEntity();
1087
+ await viewEnt.setCoordinateSpace("Dom");
1088
+ await viewEnt.setComponent(await this.session.createViewComponent());
1089
+ var wc = await this.session.getCurrentWindowComponent();
1090
+ var ent = await wc.getEntity();
1091
+ await viewEnt.setParent(ent);
1092
+ var update = () => {
1093
+ var rect = divOnPage.getBoundingClientRect();
1094
+ viewEnt.transform.position.x = rect.x + rect.width / 2;
1095
+ viewEnt.transform.position.y = rect.y + rect.height / 2 + window.scrollY;
1096
+ viewEnt.updateTransform();
1097
+ viewEnt.getComponent(SpatialViewComponent).setResolution(rect.width, rect.height);
1098
+ };
1099
+ var mo = new MutationObserver(update);
1100
+ mo.observe(divOnPage, { attributes: true });
1101
+ var ro = new ResizeObserver(update);
1102
+ ro.observe(divOnPage);
1103
+ const addRemoveObserver = new MutationObserver((mutations) => {
1104
+ mutations.forEach((mutation) => {
1105
+ mutation.removedNodes.forEach((node) => {
1106
+ if (node instanceof HTMLElement) {
1107
+ update();
1108
+ }
1109
+ });
1110
+ mutation.addedNodes.forEach((node) => {
1111
+ if (node instanceof HTMLElement) {
1112
+ update();
1113
+ }
1114
+ });
1115
+ });
1116
+ });
1117
+ addRemoveObserver.observe(document.body, {
1118
+ childList: true,
1119
+ subtree: true
1120
+ });
1121
+ update();
1122
+ return {
1123
+ entity: viewEnt
1124
+ };
1125
+ }
1126
+ };
1127
+ setBackgroundStyle = async (style, backgroundColor = "#00000000") => {
1128
+ document.documentElement.style.backgroundColor = backgroundColor;
1129
+ await this.session.getCurrentWindowComponent().setStyle(style);
1130
+ };
1131
+ };
1132
+
1133
+ // src/core/component/SpatialWindowComponent.ts
1134
+ var SpatialWindowComponent = class extends SpatialComponent {
1016
1135
  /**
1017
- * Creates a Model3DComponent
1018
- * @returns Model3DComponent
1136
+ * Loads a url page in the window
1137
+ * @param url url to load
1019
1138
  */
1020
- async createModel3DComponent(options) {
1021
- var [parentWindowContainer, parentWindow] = _parseParentResources(options);
1022
- var opts = void 0;
1023
- if (options) {
1024
- opts = { modelURL: options.url };
1139
+ async loadURL(url) {
1140
+ await WebSpatial.updateResource(this._resource, { url });
1141
+ }
1142
+ async setFromWindow(window2) {
1143
+ if (window2._webSpatialID) {
1144
+ await WebSpatial.updateResource(this._resource, {
1145
+ windowID: window2._webSpatialID
1146
+ });
1147
+ } else {
1148
+ await console.warn(
1149
+ "failed to call setFromWindow, window provided is not valid"
1150
+ );
1025
1151
  }
1026
- let entity = await WebSpatial.createResource(
1027
- "Model3DComponent",
1028
- parentWindowContainer,
1029
- parentWindow,
1030
- opts
1031
- );
1032
- return new SpatialModel3DComponent(entity);
1033
1152
  }
1034
1153
  /**
1035
- * Creates a InputComponent
1036
- * [Experimental] Creates a InputComponent used to handle click and drag events of the entity containing a model
1037
- * @returns InputComponent
1154
+ * Sets the resolution of the window, the resulting dimensions when rendered will be equal to 1/1360 units
1155
+ * eg. if the resolution is set to 1360x1360 it will be a 1x1 plane
1156
+ * See 1360 in spatialViewUI.swift for how this ratio works
1157
+ * @param width width in pixels
1158
+ * @param height height in pixels
1038
1159
  */
1039
- async createInputComponent(options) {
1040
- var [parentWindowContainer, parentWindow] = _parseParentResources(options);
1041
- let entity = await WebSpatial.createResource(
1042
- "InputComponent",
1043
- parentWindowContainer,
1044
- parentWindow
1045
- );
1046
- return new SpatialInputComponent(entity);
1160
+ async setResolution(width, height) {
1161
+ await WebSpatial.updateResource(this._resource, {
1162
+ resolution: { x: width, y: height }
1163
+ });
1047
1164
  }
1048
1165
  /**
1049
- * Creates a MeshResource containing geometry data
1050
- * @returns MeshResource
1166
+ * [Experimental] Sets the anchor which the entity this is attached to will rotate around
1167
+ * @param rotationAnchor
1051
1168
  */
1052
- async createMeshResource(options) {
1053
- var [parentWindowContainer, parentWindow] = _parseParentResources(options);
1054
- let entity = await WebSpatial.createResource(
1055
- "MeshResource",
1056
- parentWindowContainer,
1057
- parentWindow,
1058
- options
1059
- );
1060
- return new SpatialMeshResource(entity);
1169
+ async setRotationAnchor(rotationAnchor) {
1170
+ await WebSpatial.updateResource(this._resource, {
1171
+ rotationAnchor
1172
+ });
1061
1173
  }
1062
1174
  /**
1063
- * Creates a PhysicallyBasedMaterial containing PBR material data
1064
- * @returns PhysicallyBasedMaterial
1175
+ * [Experimental] Sets the opacity of the window after apply material
1176
+ * @param opacity
1065
1177
  */
1066
- async createPhysicallyBasedMaterialResource(options) {
1067
- var [parentWindowContainer, parentWindow] = _parseParentResources(options);
1068
- let entity = await WebSpatial.createResource(
1069
- "PhysicallyBasedMaterial",
1070
- parentWindowContainer,
1071
- parentWindow,
1072
- options
1073
- );
1074
- return new SpatialPhysicallyBasedMaterialResource(entity);
1178
+ async setOpacity(opacity) {
1179
+ await WebSpatial.updateResource(this._resource, {
1180
+ opacity
1181
+ });
1075
1182
  }
1076
1183
  /**
1077
- * Creates a WindowContainer
1078
- * @returns SpatialWindowContainer
1079
- * */
1080
- async createWindowContainer(options) {
1081
- var style = options?.style ? options?.style : "Plain";
1082
- var [parentWindowContainer, parentWindow] = _parseParentResources(options);
1083
- return new SpatialWindowContainer(
1084
- await WebSpatial.createWindowContainer(
1085
- style,
1086
- parentWindowContainer,
1087
- parentWindow
1088
- )
1089
- );
1184
+ * Sets the style that should be applied to the window
1185
+ * @param options style options
1186
+ */
1187
+ async setStyle(styleParam) {
1188
+ const currentWindowComponent = SpatialHelper.instance?.session.getCurrentWindowComponent();
1189
+ const isSettingSelfStyle = currentWindowComponent?._resource.id == this._resource.id;
1190
+ const { material, cornerRadius } = styleParam;
1191
+ const options = {};
1192
+ if (material?.type) {
1193
+ options.backgroundMaterial = material.type;
1194
+ }
1195
+ if (cornerRadius !== void 0) {
1196
+ if (typeof cornerRadius === "number") {
1197
+ options.cornerRadius = {
1198
+ topLeading: cornerRadius,
1199
+ bottomLeading: cornerRadius,
1200
+ topTrailing: cornerRadius,
1201
+ bottomTrailing: cornerRadius
1202
+ };
1203
+ } else {
1204
+ options.cornerRadius = { ...cornerRadius };
1205
+ }
1206
+ }
1207
+ if (isSettingSelfStyle && document && document.readyState == "loading") {
1208
+ var encoded = encodeURIComponent(JSON.stringify(options));
1209
+ var x = document.createElement("link");
1210
+ x.rel = "stylesheet";
1211
+ x.href = "forceStyle://mystyle.css?style=" + encoded;
1212
+ document.head.appendChild(x);
1213
+ x.remove();
1214
+ } else {
1215
+ await WebSpatial.updateResource(this._resource, { style: options });
1216
+ }
1090
1217
  }
1091
1218
  /**
1092
- * Creates a Scene to display content within an anchored area managed by the OS
1093
- * @hidden
1094
- * @param {WindowStyle} [style='Plain'] - The style of the Scene container to be created with. Defaults to 'Plain'.
1095
- * @param {Object} [cfg={}] - Configuration object for the Scene.
1096
- * @returns Boolean
1219
+ * Modifies the amount the spatial window can be scrolled
1220
+ * Should only be used internally
1221
+ * See https://developer.apple.com/documentation/uikit/1624475-uiedgeinsetsmake?language=objc
1222
+ * @param insets margin to modify scroll distances by
1097
1223
  */
1098
- async _createScene(style = "Plain", cfg) {
1099
- return await WebSpatial.createScene(style, cfg);
1224
+ async setScrollEdgeInsets(insets) {
1225
+ await WebSpatial.updateResource(this._resource, {
1226
+ setScrollEdgeInsets: insets
1227
+ });
1100
1228
  }
1101
1229
  /**
1102
- * Retrieves the window for this page
1103
- * @returns the window component corresponding to the js running on this page
1104
- * [TODO] discuss implications of this not being async
1230
+ * Enable/Disable scrolling in the window (defaults to enabled), if disabled, scrolling will be applied to the root page
1231
+ * @param enabled value to set
1105
1232
  */
1106
- getCurrentWindowComponent() {
1107
- return new SpatialWindowComponent(WebSpatial.getCurrentWebPanel());
1233
+ async setScrollEnabled(enabled) {
1234
+ await WebSpatial.updateResource(this._resource, { scrollEnabled: enabled });
1235
+ }
1236
+ /**
1237
+ * Defaults to false. If set to true, scrolling the parent page will also scroll this window with it like other dom elements
1238
+ * @param scrollWithParent value to set
1239
+ */
1240
+ async setScrollWithParent(scrollWithParent) {
1241
+ await WebSpatial.updateResource(this._resource, {
1242
+ scrollWithParent
1243
+ });
1244
+ }
1245
+ };
1246
+
1247
+ // src/core/component/EventSpatialComponent.ts
1248
+ var EventSpatialComponent = class extends SpatialComponent {
1249
+ // Class implementation goes here
1250
+ constructor(_resource) {
1251
+ super(_resource);
1252
+ WebSpatial.registerEventReceiver(_resource.id, (data) => {
1253
+ this.onRecvEvent(data);
1254
+ });
1255
+ }
1256
+ async onDestroy() {
1257
+ WebSpatial.unregisterEventReceiver(this._resource.id);
1258
+ }
1259
+ };
1260
+
1261
+ // src/core/component/SpatialInputComponent.ts
1262
+ var SpatialInputComponent = class extends EventSpatialComponent {
1263
+ onRecvEvent(data) {
1264
+ this.onTranslate(data);
1108
1265
  }
1109
1266
  /**
1110
- * Retrieves the parent window for this page or null if this is the root page
1111
- * @returns the window component or null
1267
+ * Callback fired when a translate event occurs
1268
+ * @param data translate event data
1112
1269
  */
1113
- async getParentWindowComponent() {
1114
- let parentResp = await WebSpatial.updateResource(
1115
- WebSpatial.getCurrentWebPanel(),
1116
- { getParentID: "" }
1117
- );
1118
- if (parentResp.data.parentID === "") {
1119
- return new Promise((res2, rej) => {
1120
- res2(null);
1121
- });
1122
- } else {
1123
- var res = new WebSpatialResource();
1124
- res.id = parentResp.data.parentID;
1125
- return new SpatialWindowComponent(res);
1126
- }
1270
+ onTranslate(data) {
1127
1271
  }
1272
+ };
1273
+
1274
+ // src/core/component/SpatialModelComponent.ts
1275
+ var SpatialModelComponent = class extends SpatialComponent {
1276
+ cachedMaterials = new Array();
1128
1277
  /**
1129
- * Logs a message to the native apps console
1130
- * @param msg mesage to log
1278
+ * Sets the mesh to be displayed by the component
1279
+ * @param mesh mesh to set
1131
1280
  */
1132
- async log(...msg) {
1133
- await WebSpatial.sendCommand(
1134
- new RemoteCommand("log", {
1135
- logString: msg.map((x) => {
1136
- return JSON.stringify(x);
1137
- })
1138
- })
1139
- );
1281
+ async setMesh(mesh) {
1282
+ await WebSpatial.updateResource(this._resource, {
1283
+ meshResource: mesh._resource.id
1284
+ });
1140
1285
  }
1141
1286
  /**
1142
- * @hidden
1143
- * Debugging only, used to ping the native renderer
1287
+ * Sets the materials that should be applied to the mesh
1288
+ * @param materials array of materials to set
1144
1289
  */
1145
- async _ping(msg) {
1146
- return await WebSpatial.ping(msg);
1290
+ async setMaterials(materials) {
1291
+ this.cachedMaterials = materials;
1292
+ await WebSpatial.updateResource(this._resource, {
1293
+ materials: materials.map((m) => {
1294
+ m._addToComponent(this);
1295
+ return m._resource.id;
1296
+ })
1297
+ });
1147
1298
  }
1299
+ /** @hidden */
1300
+ async _syncMaterials() {
1301
+ await this.setMaterials(this.cachedMaterials);
1302
+ }
1303
+ };
1304
+
1305
+ // src/core/component/SpatialViewComponent.ts
1306
+ var SpatialViewComponent = class extends SpatialComponent {
1148
1307
  /**
1149
- * @hidden
1150
- * Debugging to get internal state from native code
1151
- * @returns data as a js object
1308
+ * Sets the resolution of the spatial view in dom pixels
1152
1309
  */
1153
- async _getStats() {
1154
- return await WebSpatial.getStats();
1310
+ async setResolution(width, height) {
1311
+ await WebSpatial.updateResource(this._resource, {
1312
+ resolution: { x: width, y: height }
1313
+ });
1155
1314
  }
1156
1315
  /**
1157
- * @hidden
1316
+ * Sets if content of the spatialView should be within a portal
1317
+ * If true, volume will be behind the page, if false, it will be in front of the page
1158
1318
  */
1159
- async _inspect(spatialObjectId = WebSpatial.getCurrentWebPanel().id) {
1160
- return WebSpatial.inspect(spatialObjectId);
1319
+ async setIsPortal(isPortal) {
1320
+ await WebSpatial.updateResource(this._resource, {
1321
+ isPortal
1322
+ });
1323
+ }
1324
+ };
1325
+
1326
+ // src/core/component/SpatialModel3DComponent.ts
1327
+ var SpatialModel3DComponent = class extends EventSpatialComponent {
1328
+ onRecvEvent(data) {
1329
+ const { eventType, value, error } = data;
1330
+ switch (eventType) {
1331
+ case "phase":
1332
+ if (value === "success") {
1333
+ this.onSuccess?.();
1334
+ } else {
1335
+ this.onFailure?.(error);
1336
+ }
1337
+ break;
1338
+ case "dragstart":
1339
+ this._onDragStart?.(value);
1340
+ break;
1341
+ case "dragend":
1342
+ this._onDragEnd?.(value);
1343
+ break;
1344
+ case "drag":
1345
+ this._onDrag?.(value);
1346
+ break;
1347
+ case "tap":
1348
+ this._onTap?.();
1349
+ break;
1350
+ case "doubletap":
1351
+ this._onDoubleTap?.();
1352
+ break;
1353
+ case "longpress":
1354
+ this._onLongPress?.();
1355
+ break;
1356
+ default:
1357
+ break;
1358
+ }
1161
1359
  }
1162
1360
  /**
1163
- * @hidden
1361
+ * Sets the resolution of the spatial view in dom pixels
1164
1362
  */
1165
- async _inspectRootWindowContainer() {
1166
- return WebSpatial.inspectRootWindowContainer();
1167
- }
1168
- /** Opens the immersive space */
1169
- async openImmersiveSpace() {
1170
- return await WebSpatial.openImmersiveSpace();
1363
+ async setResolution(width, height) {
1364
+ await WebSpatial.updateResource(this._resource, {
1365
+ resolution: { x: width, y: height }
1366
+ });
1171
1367
  }
1172
- /** Closes the immersive space */
1173
- async dismissImmersiveSpace() {
1174
- return await WebSpatial.dismissImmersiveSpace();
1368
+ async setRotationAnchor(rotationAnchor) {
1369
+ await WebSpatial.updateResource(this._resource, {
1370
+ rotationAnchor
1371
+ });
1175
1372
  }
1176
- static _immersiveWindowContainer = null;
1177
1373
  /**
1178
- * Retreives the window container corresponding to the Immersive space
1179
- * @returns the immersive window container
1374
+ * Sets the opacity of the model
1375
+ * @param opacity
1180
1376
  */
1181
- async getImmersiveWindowContainer() {
1182
- if (_SpatialSession._immersiveWindowContainer) {
1183
- return _SpatialSession._immersiveWindowContainer;
1184
- } else {
1185
- _SpatialSession._immersiveWindowContainer = new SpatialWindowContainer(
1186
- WebSpatial.getImmersiveWindowContainer()
1187
- );
1188
- return _SpatialSession._immersiveWindowContainer;
1189
- }
1377
+ async setOpacity(opacity) {
1378
+ await WebSpatial.updateResource(this._resource, {
1379
+ opacity
1380
+ });
1190
1381
  }
1191
- // Retreives the window container that is the parent to this spatial web page
1192
- static _currentWindowContainer = null;
1193
1382
  /**
1194
- * Gets the current window container for the window
1195
- * [TODO] discuss what happens if it doesnt yet have a window container
1196
- * @returns the current window container for the window
1383
+ * Sets how the model fill the rect
1384
+ * @param contentMode
1197
1385
  */
1198
- getCurrentWindowContainer() {
1199
- if (_SpatialSession._currentWindowContainer) {
1200
- return _SpatialSession._currentWindowContainer;
1201
- } else {
1202
- _SpatialSession._currentWindowContainer = new SpatialWindowContainer(
1203
- WebSpatial.getCurrentWindowContainer()
1204
- );
1205
- return _SpatialSession._currentWindowContainer;
1206
- }
1386
+ async setContentMode(contentMode) {
1387
+ await WebSpatial.updateResource(this._resource, {
1388
+ contentMode
1389
+ });
1207
1390
  }
1208
1391
  /**
1209
- * Start a transaction that queues up commands to submit them all at once to reduce ipc overhead
1210
- * @param fn function to be run, within this function, promises will not resolve
1211
- * @returns promise for the entire transaction completion
1392
+ * Constrains this model dimensions to the specified aspect ratio.
1393
+ * with a value of 0, the model will use the original aspect ratio.
1394
+ *
1395
+ * @param aspectRatio number
1212
1396
  */
1213
- transaction(fn) {
1214
- WebSpatial.startTransaction();
1215
- fn();
1216
- return WebSpatial.sendTransaction();
1397
+ async setAspectRatio(aspectRatio) {
1398
+ await WebSpatial.updateResource(this._resource, {
1399
+ aspectRatio
1400
+ });
1217
1401
  }
1218
1402
  /**
1219
- * Creates a window context object that is compatable with SpatialWindowComponent's setFromWindow API
1220
- * @returns window context
1403
+ * Defaults to false. If set to true, scrolling the parent page will also scroll this window with it like other dom elements
1404
+ * @param scrollWithParent value to set
1221
1405
  */
1222
- async createWindowContext() {
1223
- let openedWindow = window.open("webspatial://createWindowContext");
1224
- if (WebSpatial.getBackend() != "AVP") {
1225
- var counter = 0;
1226
- while (openedWindow.window.testAPI == null) {
1227
- if (counter > 15) {
1228
- openedWindow?.close();
1229
- openedWindow = window.open("about:blank");
1230
- counter = 0;
1231
- this.log("unexpected error when trying to open new window, retrying.");
1232
- }
1233
- var locName = "about:blank?x" + counter;
1234
- openedWindow.location.href = locName;
1235
- counter++;
1236
- await new Promise((resolve) => setTimeout(resolve, 10));
1237
- }
1238
- ;
1239
- openedWindow._webSpatialID = openedWindow.window.testAPI.getWindowID();
1240
- } else {
1241
- while (openedWindow.window._webSpatialID == void 0) {
1242
- await new Promise((resolve) => setTimeout(resolve, 10));
1243
- }
1244
- }
1245
- openedWindow.document.head.innerHTML = `<meta name="viewport" content="width=device-width, initial-scale=1">
1246
- <base href="${document.baseURI}">
1247
- `;
1248
- return openedWindow;
1249
- }
1250
- // Get Entity by id. Currently for debugging only.
1251
- /** @hidden */
1252
- async _getEntity(id) {
1253
- const entityInfo = await WebSpatial.inspect(id);
1254
- const [_, x, y, z] = entityInfo.position.match(/(\d+\.?\d*)/g);
1255
- const [__, sx, sy, sz] = entityInfo.scale.match(/(\d+\.?\d*)/g);
1256
- var res = new WebSpatialResource();
1257
- res.id = id;
1258
- res.windowContainerId = WebSpatial.getCurrentWindowContainer().id;
1259
- const entity = new SpatialEntity(res);
1260
- entity.transform.position.x = parseFloat(x);
1261
- entity.transform.position.y = parseFloat(y);
1262
- entity.transform.position.z = parseFloat(z);
1263
- entity.transform.scale.x = parseFloat(sx);
1264
- entity.transform.scale.y = parseFloat(sy);
1265
- entity.transform.scale.z = parseFloat(sz);
1266
- return entity;
1406
+ async setScrollWithParent(scrollWithParent) {
1407
+ await WebSpatial.updateResource(this._resource, {
1408
+ scrollWithParent
1409
+ });
1267
1410
  }
1268
- // set loading view.
1269
- /** @hidden */
1270
- async setLoading(method, style) {
1271
- return WebSpatial.setLoading(method, style);
1411
+ /**
1412
+ * Sets whether the model appear in original size or fit the rect
1413
+ * @param resizable
1414
+ */
1415
+ async setResizable(resizable) {
1416
+ await WebSpatial.updateResource(this._resource, {
1417
+ resizable
1418
+ });
1272
1419
  }
1273
- };
1274
-
1275
- // src/core/Spatial.ts
1276
- var Spatial = class {
1277
1420
  /**
1278
- * Requests a session object from the browser
1279
- * @returns The session or null if not availible in the current browser
1280
- * [TODO] discuss implications of this not being async
1421
+ * Callback fired when model load success
1281
1422
  */
1282
- requestSession() {
1283
- if (this.isSupported() && this.getNativeVersion() === this.getClientVersion()) {
1284
- return new SpatialSession();
1285
- } else {
1286
- return null;
1287
- }
1288
- }
1423
+ onSuccess;
1289
1424
  /**
1290
- * @returns true if web spatial is supported by this webpage
1425
+ * Callback fired when model load failure
1426
+ * @param errorReason
1291
1427
  */
1292
- isSupported() {
1293
- return window.WebSpatailEnabled && this.getNativeVersion() === this.getClientVersion();
1428
+ onFailure;
1429
+ /**
1430
+ * Callback fired when model was dragged at the beginning
1431
+ * @param dragEvent
1432
+ */
1433
+ _onDragStart;
1434
+ set onDragStart(callback) {
1435
+ if (this._onDragStart !== callback) {
1436
+ this._onDragStart = callback;
1437
+ WebSpatial.updateResource(this._resource, {
1438
+ enableDragEvent: this.enableDragEvent
1439
+ });
1440
+ }
1294
1441
  }
1295
1442
  /**
1296
- * Gets the native version, format is "x.x.x"
1297
- * @returns native version string
1443
+ * Callback fired when model was dragged
1444
+ * @param dragEvent
1298
1445
  */
1299
- getNativeVersion() {
1300
- return window.WebSpatailNativeVersion;
1446
+ _onDrag;
1447
+ set onDrag(callback) {
1448
+ if (this._onDrag !== callback) {
1449
+ this._onDrag = callback;
1450
+ WebSpatial.updateResource(this._resource, {
1451
+ enableDragEvent: this.enableDragEvent
1452
+ });
1453
+ }
1301
1454
  }
1302
1455
  /**
1303
- * Gets the client version, format is "x.x.x"
1304
- * @returns client version string
1456
+ * Callback fired when model was dragged at the ending
1457
+ * @param dragEvent
1305
1458
  */
1306
- getClientVersion() {
1307
- return "0.0.1";
1459
+ _onDragEnd;
1460
+ set onDragEnd(callback) {
1461
+ if (this._onDragEnd !== callback) {
1462
+ this._onDragEnd = callback;
1463
+ WebSpatial.updateResource(this._resource, {
1464
+ enableDragEvent: this.enableDragEvent
1465
+ });
1466
+ }
1308
1467
  }
1309
- };
1310
-
1311
- // src/core/SpatialHelper.ts
1312
- var SpatialHelper = class _SpatialHelper {
1313
- constructor(session) {
1314
- this.session = session;
1468
+ get enableDragEvent() {
1469
+ return void 0 !== this._onDrag || void 0 !== this._onDragStart || void 0 !== this._onDragEnd;
1315
1470
  }
1316
- static _instance = null;
1317
- static get instance() {
1318
- if (this._instance) {
1319
- return this._instance;
1320
- } else {
1321
- let spatial = new Spatial();
1322
- if (spatial.isSupported()) {
1323
- let session = spatial.requestSession();
1324
- if (session) {
1325
- this._instance = new _SpatialHelper(session);
1326
- return this._instance;
1327
- }
1328
- }
1471
+ /**
1472
+ * Callback fired when model was tapped
1473
+ */
1474
+ _onTap;
1475
+ set onTap(callback) {
1476
+ if (this._onTap !== callback) {
1477
+ this._onTap = callback;
1478
+ WebSpatial.updateResource(this._resource, {
1479
+ enableTapEvent: void 0 !== callback
1480
+ });
1329
1481
  }
1330
- return null;
1331
1482
  }
1332
- shape = {
1333
- createShapeEntity: async (shape = "box") => {
1334
- var box = await this.session.createMeshResource({ shape });
1335
- var mat = await this.session.createPhysicallyBasedMaterialResource();
1336
- await mat.update();
1337
- var customModel = await this.session.createModelComponent();
1338
- customModel.setMaterials([mat]);
1339
- customModel.setMesh(box);
1340
- var boxEntity = await this.session.createEntity();
1341
- await boxEntity.setComponent(customModel);
1342
- boxEntity.transform.position.z = 0;
1343
- boxEntity.transform.scale = new Vec3(0.5, 0.5, 0.5);
1344
- await boxEntity.updateTransform();
1345
- return boxEntity;
1346
- },
1347
- createModelEntity: async (url) => {
1348
- var customModel = await this.session.createModelComponent({ url });
1349
- var boxEntity = await this.session.createEntity();
1350
- await boxEntity.setComponent(customModel);
1351
- await boxEntity.updateTransform();
1352
- return boxEntity;
1353
- },
1354
- wrapInBoundingBoxEntity: async (entityToWrap) => {
1355
- var bb = await entityToWrap.getBoundingBox();
1356
- var targetSize = 1;
1357
- var scale = targetSize / Math.max(bb.extents.x, bb.extents.y, bb.extents.z);
1358
- entityToWrap.transform.scale.x = scale;
1359
- entityToWrap.transform.scale.y = scale;
1360
- entityToWrap.transform.scale.z = scale;
1361
- entityToWrap.transform.position.x = -bb.center.x * scale;
1362
- entityToWrap.transform.position.y = -bb.center.y * scale;
1363
- entityToWrap.transform.position.z = -bb.center.z * scale;
1364
- await entityToWrap.updateTransform();
1365
- var boudningEntity = await _SpatialHelper.instance?.session.createEntity();
1366
- await entityToWrap.setParent(boudningEntity);
1367
- return boudningEntity;
1368
- }
1369
- };
1370
- navigation = {
1371
- openPanel: async (url, options) => {
1372
- if (options?.resolution) {
1373
- await this.session.getCurrentWindowContainer()._setOpenSettings({ resolution: options.resolution });
1374
- }
1375
- var wg = await this.session.createWindowContainer({
1376
- style: "Plain",
1377
- windowComponent: null,
1378
- windowContainer: null
1379
- });
1380
- var ent = await this.session.createEntity({
1381
- windowComponent: null,
1382
- windowContainer: wg
1383
- });
1384
- var i = await this.session.createWindowComponent({
1385
- windowComponent: null,
1386
- windowContainer: wg
1387
- });
1388
- await i.loadURL(url);
1389
- await ent.setCoordinateSpace("Root");
1390
- await ent.setComponent(i);
1391
- await wg.setRootEntity(ent);
1392
- await this.session.getCurrentWindowContainer()._setOpenSettings({ resolution: { width: 900, height: 700 } });
1393
- },
1394
- openVolume: async (url, options) => {
1395
- var wg = await this.session.createWindowContainer({
1396
- style: "Volumetric",
1397
- windowComponent: null,
1398
- windowContainer: null
1399
- });
1400
- var rootEnt = await this.session.createEntity({
1401
- windowComponent: null,
1402
- windowContainer: wg
1403
- });
1404
- await rootEnt.setComponent(
1405
- await this.session.createViewComponent({
1406
- windowComponent: null,
1407
- windowContainer: wg
1408
- })
1409
- );
1410
- await rootEnt.setCoordinateSpace("Root");
1411
- await wg.setRootEntity(rootEnt);
1412
- var ent = await this.session.createEntity({
1413
- windowComponent: null,
1414
- windowContainer: wg
1415
- });
1416
- var i = await this.session.createWindowComponent({
1417
- windowComponent: null,
1418
- windowContainer: wg
1483
+ /** Callback fired when model was double tapped */
1484
+ _onDoubleTap;
1485
+ set onDoubleTap(callback) {
1486
+ if (this._onDoubleTap !== callback) {
1487
+ this._onDoubleTap = callback;
1488
+ WebSpatial.updateResource(this._resource, {
1489
+ enableDoubleTapEvent: void 0 !== callback
1419
1490
  });
1420
- await i.loadURL(url);
1421
- if (options?.resolution) {
1422
- await i.setResolution(
1423
- options.resolution.width,
1424
- options.resolution.height
1425
- );
1426
- } else {
1427
- await i.setResolution(1e3, 1e3);
1428
- }
1429
- ent.transform.position.z = -0.49;
1430
- await ent.updateTransform();
1431
- await ent.setCoordinateSpace("App");
1432
- await ent.setComponent(i);
1433
- await ent.setParent(rootEnt);
1434
1491
  }
1435
- };
1436
- dom = {
1437
- attachSpatialView: async (divOnPage) => {
1438
- var viewEnt = await this.session.createEntity();
1439
- await viewEnt.setCoordinateSpace("Dom");
1440
- await viewEnt.setComponent(await this.session.createViewComponent());
1441
- var wc = await this.session.getCurrentWindowComponent();
1442
- var ent = await wc.getEntity();
1443
- await viewEnt.setParent(ent);
1444
- var update = () => {
1445
- var rect = divOnPage.getBoundingClientRect();
1446
- viewEnt.transform.position.x = rect.x + rect.width / 2;
1447
- viewEnt.transform.position.y = rect.y + rect.height / 2 + window.scrollY;
1448
- viewEnt.updateTransform();
1449
- viewEnt.getComponent(SpatialViewComponent).setResolution(rect.width, rect.height);
1450
- };
1451
- var mo = new MutationObserver(update);
1452
- mo.observe(divOnPage, { attributes: true });
1453
- var ro = new ResizeObserver(update);
1454
- ro.observe(divOnPage);
1455
- const addRemoveObserver = new MutationObserver((mutations) => {
1456
- mutations.forEach((mutation) => {
1457
- mutation.removedNodes.forEach((node) => {
1458
- if (node instanceof HTMLElement) {
1459
- update();
1460
- }
1461
- });
1462
- mutation.addedNodes.forEach((node) => {
1463
- if (node instanceof HTMLElement) {
1464
- update();
1465
- }
1466
- });
1467
- });
1468
- });
1469
- addRemoveObserver.observe(document.body, {
1470
- childList: true,
1471
- subtree: true
1492
+ }
1493
+ /** Callback fired when model was long pressed */
1494
+ _onLongPress;
1495
+ set onLongPress(callback) {
1496
+ if (this._onLongPress !== callback) {
1497
+ this._onLongPress = callback;
1498
+ WebSpatial.updateResource(this._resource, {
1499
+ enableLongPressEvent: void 0 !== callback
1472
1500
  });
1473
- update();
1474
- return {
1475
- entity: viewEnt
1476
- };
1477
1501
  }
1478
- };
1479
- setBackgroundStyle = async (style, backgroundColor = "#00000000") => {
1480
- document.documentElement.style.backgroundColor = backgroundColor;
1481
- await this.session.getCurrentWindowComponent().setStyle(style);
1482
- };
1502
+ }
1483
1503
  };
1484
1504
  export {
1485
1505
  Spatial,