@webspatial/builder 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/lib/Cli.js +1 -1
  3. package/dist/lib/cmds/build.js +1 -1
  4. package/dist/lib/cmds/check.js +1 -1
  5. package/dist/lib/cmds/help.js +1 -1
  6. package/dist/lib/cmds/version.js +1 -1
  7. package/dist/lib/pwa/config.js +1 -1
  8. package/dist/lib/pwa/index.js +1 -1
  9. package/dist/lib/pwa/validate.js +1 -1
  10. package/dist/lib/resource/file.js +1 -1
  11. package/dist/lib/resource/imageHelper.js +1 -1
  12. package/dist/lib/resource/index.js +1 -1
  13. package/dist/lib/resource/load.js +1 -1
  14. package/dist/lib/utils/CustomError.js +1 -1
  15. package/dist/lib/utils/FetchUtils-1.js +1 -1
  16. package/dist/lib/utils/Log.js +1 -1
  17. package/dist/lib/utils/fetch.js +1 -1
  18. package/dist/lib/utils/messages.js +1 -1
  19. package/dist/lib/utils/utils.js +1 -1
  20. package/dist/lib/xcode/index.js +1 -1
  21. package/dist/lib/xcode/manifestSwiftTemplate.d.ts +1 -1
  22. package/dist/lib/xcode/manifestSwiftTemplate.js +1 -1
  23. package/dist/lib/xcode/xcodebuild.js +1 -1
  24. package/dist/lib/xcode/xcodeproject.js +1 -1
  25. package/dist/lib/xcode/xcrun.js +1 -1
  26. package/package.json +1 -1
  27. package/template/visionOSApp/web-spatial/libs/SpatialWindowContainer.swift +20 -3
  28. package/template/visionOSApp/web-spatial/libs/webView/manifest.swift +1 -0
  29. package/template/visionOSApp/web-spatial/views/SpatialWebViewUI.swift +124 -125
  30. package/template/visionOSApp/web-spatial/views/VolumetricWindowContainerView.swift +5 -1
  31. package/template/visionOSApp/web-spatial/views/ui/NavView.swift +80 -40
  32. package/template/visionOSApp/web-spatial/web_spatialApp.swift +34 -10
@@ -34,108 +34,32 @@ struct SpatialWebViewUI: View {
34
34
  let childEntities = ent.getEntities()
35
35
 
36
36
  // Display child entities of the webview
37
- VStack(alignment: .trailing, spacing: 20) {
38
- if wv.isRootWebview() {
39
- NavView(swc: wv)
40
- }
41
-
42
- ZStack {
43
- OptionalClip(clipEnabled: ent.coordinateSpace != .ROOT && wv.isScrollEnabled()) {
44
- ZStack {
45
- ForEach(Array(childEntities.keys), id: \.self) { key in
46
- if let e = childEntities[key] {
47
- let _ = e.forceUpdate ? 0 : 0
48
- if let childWindowcomponent = e.getComponent(SpatialWindowComponent.self) {
49
- if e.coordinateSpace == .DOM {
50
- let view = childWindowcomponent
51
- let x = CGFloat(e.modelEntity.position.x)
52
- let y = CGFloat(e.modelEntity.position.y - (view.scrollWithParent ? parentYOffset : 0))
53
- let z = CGFloat(e.modelEntity.position.z)
54
- let width = CGFloat(view.resolutionX)
55
- let height = CGFloat(view.resolutionY)
56
- let anchor = view.rotationAnchor
57
-
58
- // Matrix = MTranslate X MRotate X MScale
59
- SpatialWebViewUI().environment(e)
60
- .frame(width: width, height: height)
61
- // use .offset(smallVal) to workaround for glassEffect not working and small width/height spatialDiv not working
62
- .offset(z: 0.0001)
63
- .scaleEffect(
64
- x: CGFloat(e.modelEntity.scale.x),
65
- y: CGFloat(e.modelEntity.scale.y),
66
- z: CGFloat(e.modelEntity.scale.z),
67
- anchor: anchor
68
- )
69
- .rotation3DEffect(
70
- Rotation3D(simd_quatf(
71
- ix: e.modelEntity.orientation.vector.x,
72
- iy: e.modelEntity.orientation.vector.y,
73
- iz: e.modelEntity.orientation.vector.z,
74
- r: e.modelEntity.orientation.vector.w
75
- )),
76
- anchor: anchor
77
- )
78
-
79
- .position(x: x, y: y)
80
- .offset(z: z)
81
- .zIndex(e.zIndex)
82
- .gesture(
83
- DragGesture()
84
- .onChanged { gesture in
85
- let scrollEnabled = view.isScrollEnabled()
86
- if !scrollEnabled, wv.isScrollEnabled() {
87
- if !view.dragStarted {
88
- view.dragStarted = true
89
- view.dragStart = (gesture.translation.height)
90
- }
91
-
92
- // TODO: this should have velocity
93
- let delta = view.dragStart - gesture.translation.height
94
- view.dragStart = gesture.translation.height
95
- wv.updateScrollOffset(delta: delta)
96
- }
97
- }
98
- .onEnded { _ in
99
- let scrollEnabled = view.isScrollEnabled()
100
- if !scrollEnabled, wv.isScrollEnabled() {
101
- view.dragStarted = false
102
- view.dragStart = 0
103
-
104
- wv.stopScrolling()
105
- }
106
- }
107
- )
108
- }
109
- }
110
- }
111
- }
112
-
113
- // Model3D content
114
- ForEach(Array(childEntities.keys), id: \.self) { key in
115
- if let e = childEntities[key] {
116
- let _ = e.forceUpdate ? 0 : 0
117
- SpatialModel3DView(parentYOffset: parentYOffset)
118
- .environment(e)
119
- }
120
- }
121
-
122
- // SpatialView content
123
- ForEach(Array(childEntities.keys), id: \.self) { key in
124
- if let e = childEntities[key] {
37
+ ZStack {
38
+ OptionalClip(clipEnabled: ent.coordinateSpace != .ROOT && wv.isScrollEnabled()) {
39
+ ZStack {
40
+ ForEach(Array(childEntities.keys), id: \.self) { key in
41
+ if let e = childEntities[key] {
42
+ let _ = e.forceUpdate ? 0 : 0
43
+ if let childWindowcomponent = e.getComponent(SpatialWindowComponent.self) {
125
44
  if e.coordinateSpace == .DOM {
126
- if let viewComponent = e.getComponent(SpatialViewComponent.self) {
127
- let _ = e.forceUpdate ? 0 : 0
128
- let x = CGFloat(e.modelEntity.position.x)
129
- let y = CGFloat(e.modelEntity.position.y - parentYOffset)
130
- let z = CGFloat(e.modelEntity.position.z)
131
-
132
- let width = CGFloat(viewComponent.resolutionX)
133
- let height = CGFloat(viewComponent.resolutionY)
134
-
135
- SpatialViewUI().environment(e).frame(width: width, height: height).scaleEffect(
45
+ let view = childWindowcomponent
46
+ let x = CGFloat(e.modelEntity.position.x)
47
+ let y = CGFloat(e.modelEntity.position.y - (view.scrollWithParent ? parentYOffset : 0))
48
+ let z = CGFloat(e.modelEntity.position.z)
49
+ let width = CGFloat(view.resolutionX)
50
+ let height = CGFloat(view.resolutionY)
51
+ let anchor = view.rotationAnchor
52
+
53
+ // Matrix = MTranslate X MRotate X MScale
54
+ SpatialWebViewUI().environment(e)
55
+ .frame(width: width, height: height)
56
+ // use .offset(smallVal) to workaround for glassEffect not working and small width/height spatialDiv not working
57
+ .offset(z: 0.0001)
58
+ .scaleEffect(
136
59
  x: CGFloat(e.modelEntity.scale.x),
137
60
  y: CGFloat(e.modelEntity.scale.y),
138
- z: CGFloat(e.modelEntity.scale.z)
61
+ z: CGFloat(e.modelEntity.scale.z),
62
+ anchor: anchor
139
63
  )
140
64
  .rotation3DEffect(
141
65
  Rotation3D(simd_quatf(
@@ -143,44 +67,119 @@ struct SpatialWebViewUI: View {
143
67
  iy: e.modelEntity.orientation.vector.y,
144
68
  iz: e.modelEntity.orientation.vector.z,
145
69
  r: e.modelEntity.orientation.vector.w
146
- ))
147
- ).position(x: x, y: y)
70
+ )),
71
+ anchor: anchor
72
+ )
73
+
74
+ .position(x: x, y: y)
148
75
  .offset(z: z)
149
- }
76
+ .zIndex(e.zIndex)
77
+ .gesture(
78
+ DragGesture()
79
+ .onChanged { gesture in
80
+ let scrollEnabled = view.isScrollEnabled()
81
+ if !scrollEnabled, wv.isScrollEnabled() {
82
+ if !view.dragStarted {
83
+ view.dragStarted = true
84
+ view.dragStart = (gesture.translation.height)
85
+ }
86
+
87
+ // TODO: this should have velocity
88
+ let delta = view.dragStart - gesture.translation.height
89
+ view.dragStart = gesture.translation.height
90
+ wv.updateScrollOffset(delta: delta)
91
+ }
92
+ }
93
+ .onEnded { _ in
94
+ let scrollEnabled = view.isScrollEnabled()
95
+ if !scrollEnabled, wv.isScrollEnabled() {
96
+ view.dragStarted = false
97
+ view.dragStart = 0
98
+
99
+ wv.stopScrolling()
100
+ }
101
+ }
102
+ )
150
103
  }
151
104
  }
152
105
  }
153
- }.frame(maxWidth: .infinity, maxHeight: .infinity).frame(maxDepth: 0, alignment: .back).offset(z: 0)
154
- }
106
+ }
155
107
 
156
- // Display the main webview
157
- if wv.didFailLoad {
158
- VStack {
159
- Text("Failed to load webpage. Is the server running?")
160
- .foregroundColor(.white)
161
- Button("Reload") {
162
- if let url = wv.getURL() {
163
- wv.navigateToURL(url: url)
164
- } else {
165
- logger.warning("Unable to reload URL")
108
+ // Model3D content
109
+ ForEach(Array(childEntities.keys), id: \.self) { key in
110
+ if let e = childEntities[key] {
111
+ let _ = e.forceUpdate ? 0 : 0
112
+ SpatialModel3DView(parentYOffset: parentYOffset)
113
+ .environment(e)
114
+ }
115
+ }
116
+
117
+ // SpatialView content
118
+ ForEach(Array(childEntities.keys), id: \.self) { key in
119
+ if let e = childEntities[key] {
120
+ if e.coordinateSpace == .DOM {
121
+ if let viewComponent = e.getComponent(SpatialViewComponent.self) {
122
+ let _ = e.forceUpdate ? 0 : 0
123
+ let x = CGFloat(e.modelEntity.position.x)
124
+ let y = CGFloat(e.modelEntity.position.y - parentYOffset)
125
+ let z = CGFloat(e.modelEntity.position.z)
126
+
127
+ let width = CGFloat(viewComponent.resolutionX)
128
+ let height = CGFloat(viewComponent.resolutionY)
129
+
130
+ SpatialViewUI().environment(e).frame(width: width, height: height).scaleEffect(
131
+ x: CGFloat(e.modelEntity.scale.x),
132
+ y: CGFloat(e.modelEntity.scale.y),
133
+ z: CGFloat(e.modelEntity.scale.z)
134
+ )
135
+ .rotation3DEffect(
136
+ Rotation3D(simd_quatf(
137
+ ix: e.modelEntity.orientation.vector.x,
138
+ iy: e.modelEntity.orientation.vector.y,
139
+ iz: e.modelEntity.orientation.vector.z,
140
+ r: e.modelEntity.orientation.vector.w
141
+ ))
142
+ ).position(x: x, y: y)
143
+ .offset(z: z)
144
+ }
166
145
  }
167
146
  }
147
+ }
148
+ }.frame(maxWidth: .infinity, maxHeight: .infinity).frame(maxDepth: 0, alignment: .back).offset(z: 0)
149
+ }
150
+
151
+ // Display the main webview
152
+ if wv.didFailLoad {
153
+ VStack {
154
+ Text("Failed to load webpage. Is the server running?")
168
155
  .foregroundColor(.white)
156
+ Button("Reload") {
157
+ if let url = wv.getURL() {
158
+ wv.navigateToURL(url: url)
159
+ } else {
160
+ logger.warning("Unable to reload URL")
161
+ }
169
162
  }
170
- .frame(maxWidth: .infinity, maxHeight: .infinity).glassBackgroundEffect()
163
+ .foregroundColor(.white)
164
+ }
165
+ .frame(maxWidth: .infinity, maxHeight: .infinity).glassBackgroundEffect()
171
166
 
172
- } else {
173
- wv.getView()
174
- .materialWithBorderCorner(
175
- wv.backgroundMaterial,
176
- wv.cornerRadius
177
- )
167
+ } else {
168
+ wv.getView()
169
+ .materialWithBorderCorner(
170
+ wv.backgroundMaterial,
171
+ wv.cornerRadius
172
+ )
178
173
 
179
- .frame(maxWidth: .infinity, maxHeight: .infinity)
180
- }
174
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
175
+ }
176
+ }
177
+ .opacity(wv.opacity)
178
+ .hidden(!ent.visible)
179
+ .ornament(attachmentAnchor: .scene(.bottomTrailing), contentAlignment: .bottomTrailing) {
180
+ if wv.isRootWebview() {
181
+ NavView(swc: wv)
181
182
  }
182
- .opacity(wv.opacity)
183
- .hidden(!ent.visible)
184
183
  }
185
184
  }
186
185
  }
@@ -1,3 +1,4 @@
1
+
1
2
  //
2
3
  // VolumetricWindowContainerView.swift
3
4
  // web-spatial
@@ -19,7 +20,10 @@ struct VolumetricWindowContainerView: View {
19
20
 
20
21
  var body: some View {
21
22
  OpenDismissHandlerUI().environment(windowContainerContent).onDisappear {
22
- windowContainerContent.destroy()
23
+ // Don't destroy immersive space content as it is reused next time its opened
24
+ if windowContainerContent.id != SpatialWindowContainer.ImmersiveID {
25
+ windowContainerContent.destroy()
26
+ }
23
27
  }
24
28
 
25
29
  let entities = windowContainerContent.getEntities().filter { _, entity in
@@ -12,53 +12,81 @@ struct NavView: View {
12
12
  @State var swc: SpatialWindowComponent?
13
13
  @State var showUrl: Bool = false
14
14
  @State private var showCopyTip = false
15
+ @State private var nowHover = false
16
+ @State private var navWidth: CGFloat = 0
15
17
 
16
18
  var body: some View {
17
19
  ZStack(alignment: .bottomTrailing) {
18
- VStack(alignment: .trailing, spacing: 0) {
19
- HStack(spacing: 10) {
20
- Text(pwaManager.name).padding(.trailing, 10)
21
- if pwaManager.display == .minimal {
22
- Button(action: {
23
- swc?.goBack()
24
- }, label: {
25
- Image(systemName: "arrow.left")
26
- })
27
- .disabled(!swc!.canGoBack)
28
- Button(action: {
29
- swc?.goForward()
30
- }, label: {
31
- Image(systemName: "arrow.right")
32
- })
33
- .disabled(!swc!.canGoForward)
34
- Button(action: {
35
- swc?.reload()
36
- }, label: {
37
- Image(systemName: "arrow.clockwise")
38
- })
39
- Button(
40
- action: {
41
- swc?
42
- .navigateToURL(
43
- url: URL(string: pwaManager.start_url)!
44
- )
45
- },
46
- label: {
47
- Image(systemName: "house.fill")
48
- }
49
- )
50
- }
20
+ HStack(spacing: 5) {
21
+ Text(pwaManager.name).padding(.trailing, 10)
22
+ if pwaManager.display == .minimal {
23
+ Button(action: {
24
+ swc?.goBack()
25
+ }, label: {
26
+ Image(systemName: "arrow.left")
27
+ })
28
+ .disabled(!(swc?.canGoBack ?? false))
51
29
  Button(action: {
52
- showUrl.toggle()
30
+ swc?.goForward()
53
31
  }, label: {
54
- Image(systemName: "info.circle")
32
+ Image(systemName: "arrow.right")
55
33
  })
34
+ .disabled(!(swc?.canGoBack ?? false))
35
+ Button(action: {
36
+ swc?.reload()
37
+ }, label: {
38
+ Image(systemName: "arrow.clockwise")
39
+ })
40
+ Button(
41
+ action: {
42
+ swc?
43
+ .navigateToURL(
44
+ url: URL(string: pwaManager.start_url)!
45
+ )
46
+ },
47
+ label: {
48
+ Image(systemName: "house.fill")
49
+ }
50
+ )
51
+ }
52
+ Button(action: {
53
+ showUrl.toggle()
54
+ }, label: {
55
+ Image(systemName: "info.circle")
56
+ })
57
+ }.overlay(GeometryReader { geo -> AnyView in
58
+ DispatchQueue.main.async {
59
+ navWidth = geo.size.width
60
+ print(navWidth)
61
+ }
62
+ return AnyView(EmptyView())
63
+ })
64
+ .hoverEffect { effect, isHover, body in
65
+ effect.clipShape(getMaskPath(rect: CGRect(x: isHover || showUrl ? 0 : body.size.width - 65, y: 0, width: body.size.width, height: body.size.height)))
66
+ // effect.clipShape(.rect.size(width: isHover || showUrl ? 0 : body.size.width - 65, height: body.size.height))
67
+ }
68
+ .gesture(SpatialTapGesture().onEnded { evt in
69
+ let rangeX = navWidth - evt.location.x
70
+ if rangeX < 60 {
71
+ showUrl.toggle()
72
+ } else if rangeX >= 74, rangeX <= 140 {
73
+ swc?
74
+ .navigateToURL(
75
+ url: URL(string: pwaManager.start_url)!
76
+ )
77
+ } else if rangeX >= 150, rangeX <= 210 {
78
+ swc?.reload()
79
+ } else if rangeX >= 221, rangeX <= 281 {
80
+ swc?.goForward()
81
+ } else if rangeX >= 294, rangeX <= 355 {
82
+ swc?.goBack()
56
83
  }
57
- }.padding().glassBackgroundEffect(in: .rect).cornerRadius(15)
58
- HStack(spacing: 0) {
84
+ })
85
+ HStack(spacing: 5) {
59
86
  Text(
60
87
  swc?.getURL()?.absoluteString ?? ""
61
88
  )
89
+ .frame(maxWidth: navWidth)
62
90
  .padding()
63
91
  Button(action: {
64
92
  UIPasteboard.general.string = swc?.getURL()?.absoluteString ?? ""
@@ -68,21 +96,33 @@ struct NavView: View {
68
96
  }
69
97
  }, label: {
70
98
  Text("copy")
71
- }).padding(.trailing, 5)
99
+ })
72
100
 
73
101
  Button(action: {
74
102
  showUrl = false
75
103
  }, label: {
76
104
  Text("X")
77
105
  })
78
- }.glassBackgroundEffect(in: .rect).cornerRadius(15).offset(y: 35).opacity(showUrl ? 1 : 0).animation(.easeOut, value: 0.2)
106
+ }.glassBackgroundEffect(in: .rect).cornerRadius(15).offset(y: 0).opacity(showUrl ? 1 : 0).animation(.easeOut, value: 0.2)
79
107
  }
80
108
  .zIndex(10) // closer to user
81
109
  .popover(isPresented: $showCopyTip) {
82
110
  Text("copied!")
83
111
  .padding()
84
- .background(.ultraThinMaterial)
85
112
  .cornerRadius(10)
113
+ // .background(.ultraThinMaterial)
86
114
  }
87
115
  }
116
+
117
+ func getMaskPath(rect: CGRect) -> Path {
118
+ var path = Path()
119
+ path.addRoundedRect(in: rect, cornerSize: CGSize(width: 15, height: 15))
120
+ return path
121
+ }
88
122
  }
123
+
124
+ // struct NavView_Previews: PreviewProvider {
125
+ // static var previews: some View {
126
+ // NavView()
127
+ // }
128
+ // }
@@ -92,24 +92,47 @@ struct web_spatialApp: App {
92
92
  windowData.windowContainerID, windowData
93
93
  )
94
94
  PlainWindowContainerView().environment(wg)
95
- // https://stackoverflow.com/questions/78567737/how-to-get-initial-windowgroup-to-reopen-on-launch-visionos
96
- .handlesExternalEvents(preferring: [], allowing: [])
95
+ // we no longer need the initial windowGroup to live all the time
96
+ // https://stackoverflow.com/questions/78567737/how-to-get-initial-windowgroup-to-reopen-on-launch-visionos
97
+ // .handlesExternalEvents(preferring: [], allowing: [])
97
98
  }
98
- } defaultValue: {
99
- WindowContainerData(windowStyle: "Plain", windowContainerID: SpatialWindowContainer.getRootID())
100
-
101
- }.windowStyle(.plain).onChange(of: scenePhase) { oldPhase, newPhase in
99
+ }
100
+ defaultValue: {
101
+ WindowContainerData(
102
+ windowStyle: "Plain",
103
+ windowContainerID: SpatialWindowContainer.getRootID()
104
+ )
105
+ }
106
+ .windowStyle(.plain).onChange(of: scenePhase) {
107
+ oldPhase,
108
+ newPhase in
102
109
  if oldPhase == .background && newPhase == .inactive {
103
110
  if initialLaunch {
104
111
  // App initial open
105
112
  initialLaunch = false
106
113
  } else {
107
114
  // App reopened
115
+
108
116
  let fileUrl = getFileUrl()
109
- root?.navigateToURL(url: fileUrl)
110
- rootWGD.setSize.send(DefaultPlainWindowContainerSize)
117
+ if let awid = SpatialWindowContainer.firstActivePlainWindowContainerId,
118
+ let wc = SpatialWindowContainer.getSpatialWindowContainer(
119
+ awid
120
+ )
121
+ {
122
+ let rootEntity = wc.getEntities().filter {
123
+ $0.value.getComponent(SpatialWindowComponent.self) != nil && $0.value.coordinateSpace == .ROOT
124
+ }.first?.value
125
+
126
+ if let wv = rootEntity?.getComponent(SpatialWindowComponent.self) {
127
+ wv.navigateToURL(url: fileUrl)
128
+ }
129
+ // reset to mainScene size
130
+ wgm.setToMainSceneCfg()
131
+ wc.setSize.send(getDefaultSize())
132
+ }
111
133
  }
112
134
  }
135
+
113
136
  }.defaultSize(
114
137
  getDefaultSize()
115
138
  ).windowResizability(
@@ -123,8 +146,9 @@ struct web_spatialApp: App {
123
146
  }.windowStyle(.volumetric).defaultSize(width: 1, height: 1, depth: 1, in: .meters)
124
147
 
125
148
  ImmersiveSpace(id: "ImmersiveSpace") {
126
- let wg = SpatialWindowContainer.getImmersiveWindowContainer()
127
- VolumetricWindowContainerView().environment(wg).handlesExternalEvents(preferring: [], allowing: [])
149
+ if let wg = SpatialWindowContainer.getImmersiveWindowContainer() {
150
+ VolumetricWindowContainerView().environment(wg).handlesExternalEvents(preferring: [], allowing: [])
151
+ }
128
152
  }
129
153
 
130
154
  WindowGroup(id: "loading") {