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