@webspatial/builder 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +1 -0
  3. package/dist/lib/Cli.d.ts +3 -0
  4. package/dist/lib/Cli.js +1 -0
  5. package/dist/lib/cmds/build.d.ts +4 -0
  6. package/dist/lib/cmds/build.js +1 -0
  7. package/dist/lib/cmds/check.d.ts +3 -0
  8. package/dist/lib/cmds/check.js +1 -0
  9. package/dist/lib/cmds/help.d.ts +3 -0
  10. package/dist/lib/cmds/help.js +1 -0
  11. package/dist/lib/cmds/version.d.ts +2 -0
  12. package/dist/lib/cmds/version.js +1 -0
  13. package/dist/lib/pwa/config.d.ts +7 -0
  14. package/dist/lib/pwa/config.js +1 -0
  15. package/dist/lib/pwa/index.d.ts +16 -0
  16. package/dist/lib/pwa/index.js +1 -0
  17. package/dist/lib/pwa/validate.d.ts +4 -0
  18. package/dist/lib/pwa/validate.js +1 -0
  19. package/dist/lib/resource/file.d.ts +2 -0
  20. package/dist/lib/resource/file.js +1 -0
  21. package/dist/lib/resource/imageHelper.d.ts +7 -0
  22. package/dist/lib/resource/imageHelper.js +1 -0
  23. package/dist/lib/resource/index.d.ts +13 -0
  24. package/dist/lib/resource/index.js +1 -0
  25. package/dist/lib/resource/load.d.ts +6 -0
  26. package/dist/lib/resource/load.js +1 -0
  27. package/dist/lib/utils/CustomError.d.ts +13 -0
  28. package/dist/lib/utils/CustomError.js +1 -0
  29. package/dist/lib/utils/FetchUtils-1.d.ts +12 -0
  30. package/dist/lib/utils/FetchUtils-1.js +1 -0
  31. package/dist/lib/utils/Log.d.ts +88 -0
  32. package/dist/lib/utils/Log.js +1 -0
  33. package/dist/lib/utils/fetch.d.ts +5 -0
  34. package/dist/lib/utils/fetch.js +1 -0
  35. package/dist/lib/utils/messages.d.ts +50 -0
  36. package/dist/lib/utils/messages.js +1 -0
  37. package/dist/lib/utils/utils.d.ts +1 -0
  38. package/dist/lib/utils/utils.js +1 -0
  39. package/dist/lib/xcode/index.d.ts +5 -0
  40. package/dist/lib/xcode/index.js +1 -0
  41. package/dist/lib/xcode/manifestSwiftTemplate.d.ts +1 -0
  42. package/dist/lib/xcode/manifestSwiftTemplate.js +1 -0
  43. package/dist/lib/xcode/xcodebuild.d.ts +16 -0
  44. package/dist/lib/xcode/xcodebuild.js +1 -0
  45. package/dist/lib/xcode/xcodeproject.d.ts +11 -0
  46. package/dist/lib/xcode/xcodeproject.js +1 -0
  47. package/dist/lib/xcode/xcrun.d.ts +7 -0
  48. package/dist/lib/xcode/xcrun.js +1 -0
  49. package/package.json +2 -1
  50. package/template/visionOSApp/Packages/RealityKitContent/.build/workspace-state.json +7 -0
  51. package/template/visionOSApp/Packages/RealityKitContent/.swiftpm/xcode/xcuserdata/bytedance.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  52. package/template/visionOSApp/Packages/RealityKitContent/Package.realitycomposerpro/ProjectData/main.json +11 -0
  53. package/template/visionOSApp/Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/SceneMetadataList.json +112 -0
  54. package/template/visionOSApp/Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/Settings.rcprojectdata +17 -0
  55. package/template/visionOSApp/Packages/RealityKitContent/Package.swift +27 -0
  56. package/template/visionOSApp/Packages/RealityKitContent/README.md +3 -0
  57. package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Immersive.usda +50 -0
  58. package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Materials/GridMaterial.usda +216 -0
  59. package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Scene.usda +59 -0
  60. package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.swift +4 -0
  61. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/Contents.json +12 -0
  62. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Contents.json +6 -0
  63. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Contents.json +17 -0
  64. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/Contents.json +12 -0
  65. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Contents.json +6 -0
  66. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/Contents.json +12 -0
  67. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Contents.json +6 -0
  68. package/template/visionOSApp/web-spatial/Assets.xcassets/Contents.json +6 -0
  69. package/template/visionOSApp/web-spatial/Info.plist +33 -0
  70. package/template/visionOSApp/web-spatial/Preview Content/Preview Assets.xcassets/Contents.json +6 -0
  71. package/template/visionOSApp/web-spatial/libs/EventEmitter.swift +32 -0
  72. package/template/visionOSApp/web-spatial/libs/SpatialComponent.swift +31 -0
  73. package/template/visionOSApp/web-spatial/libs/SpatialEntity.swift +179 -0
  74. package/template/visionOSApp/web-spatial/libs/SpatialInputComponent.swift +26 -0
  75. package/template/visionOSApp/web-spatial/libs/SpatialMeshResource.swift +19 -0
  76. package/template/visionOSApp/web-spatial/libs/SpatialModel3DComponent.swift +51 -0
  77. package/template/visionOSApp/web-spatial/libs/SpatialModelComponent.swift +32 -0
  78. package/template/visionOSApp/web-spatial/libs/SpatialObject.swift +144 -0
  79. package/template/visionOSApp/web-spatial/libs/SpatialPhysicallyBasedMaterial.swift +19 -0
  80. package/template/visionOSApp/web-spatial/libs/SpatialViewComponent.swift +15 -0
  81. package/template/visionOSApp/web-spatial/libs/SpatialWindowComponent.swift +420 -0
  82. package/template/visionOSApp/web-spatial/libs/SpatialWindowContainer.swift +132 -0
  83. package/template/visionOSApp/web-spatial/libs/Utils/CommandManager.swift +799 -0
  84. package/template/visionOSApp/web-spatial/libs/Utils/Logger.swift +36 -0
  85. package/template/visionOSApp/web-spatial/libs/Utils/SceneManager.swift +108 -0
  86. package/template/visionOSApp/web-spatial/libs/Utils/WindowContainerMgr.swift +113 -0
  87. package/template/visionOSApp/web-spatial/libs/json/JsonParser.swift +52 -0
  88. package/template/visionOSApp/web-spatial/libs/uiKitDelegate/Window.swift +34 -0
  89. package/template/visionOSApp/web-spatial/libs/webView/UpdateSystem.swift +33 -0
  90. package/template/visionOSApp/web-spatial/libs/webView/backend/NativeWebView.swift +319 -0
  91. package/template/visionOSApp/web-spatial/libs/webView/manifest.swift +91 -0
  92. package/template/visionOSApp/web-spatial/static-web/index.html +9 -0
  93. package/template/visionOSApp/web-spatial/views/HideViewModifier.swift +17 -0
  94. package/template/visionOSApp/web-spatial/views/ImmersiveView.swift +24 -0
  95. package/template/visionOSApp/web-spatial/views/LoadingView.swift +25 -0
  96. package/template/visionOSApp/web-spatial/views/MaterialWithBorderCornerModifier.swift +82 -0
  97. package/template/visionOSApp/web-spatial/views/OpenDismissHandlerUI.swift +52 -0
  98. package/template/visionOSApp/web-spatial/views/PlainWindowContainerView.swift +84 -0
  99. package/template/visionOSApp/web-spatial/views/SpatialModel3DView.swift +193 -0
  100. package/template/visionOSApp/web-spatial/views/SpatialViewUI.swift +168 -0
  101. package/template/visionOSApp/web-spatial/views/SpatialWebViewUI.swift +187 -0
  102. package/template/visionOSApp/web-spatial/views/VolumetricWindowContainerView.swift +34 -0
  103. package/template/visionOSApp/web-spatial/views/ui/NavView.swift +88 -0
  104. package/template/visionOSApp/web-spatial/web_spatialApp.swift +134 -0
  105. package/template/visionOSApp/web-spatial.xcodeproj/project.pbxproj +686 -0
  106. package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  107. package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  108. package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +5 -0
  109. package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/xcuserdata/bytedance.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  110. package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/xcuserdata/bytedance.xcuserdatad/WorkspaceSettings.xcsettings +14 -0
  111. package/template/visionOSApp/web-spatial.xcodeproj/xcshareddata/xcschemes/web-spatial.xcscheme +115 -0
  112. package/template/visionOSApp/web-spatial.xcodeproj/xcuserdata/bytedance.xcuserdatad/xcschemes/xcschememanagement.plist +27 -0
  113. package/template/visionOSApp/web-spatialTests/web_spatialTests.swift +34 -0
@@ -0,0 +1,799 @@
1
+ //
2
+ // CommandManager.swift
3
+ // web-spatial
4
+ //
5
+ // Created by ByteDance on 2024/10/15.
6
+ //
7
+ import Foundation
8
+ import RealityKit
9
+ import SwiftUI
10
+
11
+ struct CommandInfo {
12
+ var windowContainerID = "notFound"
13
+ var entityID = "notFound"
14
+ var resourceID = "notFound"
15
+ var requestID = -1
16
+ var cmd: JSBCommand
17
+ }
18
+
19
+ class CommandManager {
20
+ static let Instance = CommandManager()
21
+
22
+ private let decoder = JSONDecoder()
23
+ private var commandList: [String: (_ target: SpatialWindowComponent, _ info: CommandInfo) -> Void] = [:]
24
+ private init() {
25
+ _ = registerCommand(name: "multiCommand", action: multiCommand)
26
+ _ = registerCommand(name: "ping", action: ping)
27
+ _ = registerCommand(name: "inspect", action: inspect)
28
+ _ = registerCommand(name: "getStats", action: getStats)
29
+ _ = registerCommand(name: "setComponent", action: setComponent)
30
+ _ = registerCommand(name: "removeComponent", action: removeComponent)
31
+ _ = registerCommand(name: "createResource", action: createResource)
32
+ _ = registerCommand(name: "destroyResource", action: destroyResource)
33
+ _ = registerCommand(name: "updateResource", action: updateResource)
34
+ _ = registerCommand(name: "createWindowContainer", action: createWindowContainer)
35
+ _ = registerCommand(name: "updateWindowContainer", action: updateWindowContainer)
36
+ _ = registerCommand(name: "openImmersiveSpace", action: openImmersiveSpace)
37
+ _ = registerCommand(name: "dismissImmersiveSpace", action: dismissImmersiveSpace)
38
+ _ = registerCommand(name: "log", action: log)
39
+ _ = registerCommand(name: "createScene", action: createScene)
40
+ _ = registerCommand(name: "setLoading", action: setLoading)
41
+ }
42
+
43
+ private func getInfo(_ target: SpatialWindowComponent, _ jsb: RawJSBCommand) -> CommandInfo? {
44
+ var ret = CommandInfo(cmd: JSBCommand(command: jsb.command, data: jsb.data, requestID: jsb.requestID))
45
+ ret.requestID = jsb.requestID
46
+ if let windowContainerID = jsb.data?.windowContainerID {
47
+ ret.windowContainerID = target.readWindowContainerID(id: windowContainerID)
48
+ }
49
+ if let entityID = jsb.data?.entityID {
50
+ ret.entityID = entityID
51
+ }
52
+ if let resourceID = jsb.data?.resourceID {
53
+ ret.resourceID = resourceID
54
+ }
55
+ if ret.resourceID == "current" {
56
+ ret.resourceID = target.id
57
+ }
58
+ return ret
59
+ }
60
+
61
+ private func registerCommand(name: String, action: @escaping (_ target: SpatialWindowComponent, _ info: CommandInfo) -> Void) -> Bool {
62
+ if commandList[name] == nil {
63
+ commandList[name] = action
64
+ return true
65
+ }
66
+ return false
67
+ }
68
+
69
+ public func decode(jsonData: String) -> RawJSBCommand {
70
+ var jsbCommand = RawJSBCommand(command: "", data: RawJSData(), requestID: 0)
71
+ do {
72
+ jsbCommand = try decoder.decode(RawJSBCommand.self, from: jsonData.data(using: .utf8)!)
73
+ } catch {
74
+ logger.error("\(error)")
75
+ }
76
+ return jsbCommand
77
+ }
78
+
79
+ public func doCommand(target: SpatialWindowComponent, jsb: RawJSBCommand) {
80
+ if let action = commandList[jsb.command] {
81
+ if let info = getInfo(target, jsb) {
82
+ action(target, info)
83
+ }
84
+ }
85
+ }
86
+
87
+ private func multiCommand(target: SpatialWindowComponent, info: CommandInfo) {
88
+ for subCommand in info.cmd.data!.commandList! {
89
+ doCommand(target: target, jsb: subCommand)
90
+ }
91
+ target.completeEvent(requestID: info.requestID)
92
+ }
93
+
94
+ private func ping(target: SpatialWindowComponent, info: CommandInfo) {
95
+ target.completeEvent(requestID: info.requestID, data: "{ping: 'Complete'}")
96
+ }
97
+
98
+ private func inspect(target: SpatialWindowComponent, info: CommandInfo) {
99
+ if let spatialObject = SpatialObject.getRefObject(info.resourceID) {
100
+ let inspectInfo = spatialObject.inspect()
101
+ let isValidJSON = JSONSerialization.isValidJSONObject(inspectInfo)
102
+ if isValidJSON {
103
+ do {
104
+ let jsonData = try JSONSerialization.data(withJSONObject: inspectInfo, options: [])
105
+ let jsonString = String(data: jsonData, encoding: .utf8)
106
+ target.completeEvent(requestID: info.requestID, data: jsonString ?? "Conver failed")
107
+ } catch {
108
+ logger.error("Error: \(error.localizedDescription)")
109
+ target.completeEvent(requestID: info.requestID, data: """
110
+ error: \(error.localizedDescription)
111
+ """)
112
+ }
113
+ } else {
114
+ logger.warning("\(inspectInfo)")
115
+ }
116
+ } else {
117
+ logger.warning("Missing spatialObject resource")
118
+ return
119
+ }
120
+ }
121
+
122
+ private func getStats(target: SpatialWindowComponent, info: CommandInfo) {
123
+ let statsInfo = SpatialObject.stats()
124
+ do {
125
+ let jsonData = try JSONEncoder().encode(statsInfo)
126
+ let jsonString = String(data: jsonData, encoding: .utf8)
127
+ target.completeEvent(requestID: info.requestID, data: jsonString ?? "Conver failed")
128
+ } catch {
129
+ logger.error("Error: \(error.localizedDescription)")
130
+ target.completeEvent(requestID: info.requestID, data: """
131
+ error: \(error.localizedDescription)
132
+ """)
133
+ }
134
+ }
135
+
136
+ private func setComponent(target: SpatialWindowComponent, info: CommandInfo) {
137
+ if let component = target.getChildSpatialObject(name: info.resourceID) as? SpatialComponent,
138
+ let entity = target.getChildSpatialObject(name: info.entityID) as? SpatialEntity
139
+ {
140
+ entity.addComponent(component)
141
+ } else {
142
+ logger.warning("missing resource, setComponent not processed")
143
+ }
144
+ }
145
+
146
+ private func removeComponent(target: SpatialWindowComponent, info: CommandInfo) {
147
+ if let component = target.getChildSpatialObject(name: info.resourceID) as? SpatialComponent,
148
+ let entity = target.getChildSpatialObject(name: info.entityID) as? SpatialEntity
149
+ {
150
+ entity.removeComponent(component)
151
+ } else {
152
+ logger.warning("missing resource, removeComponent not processed")
153
+ }
154
+ }
155
+
156
+ private func createResource(target: SpatialWindowComponent, info: CommandInfo) {
157
+ let data = info.cmd.data!
158
+ if let type = data.type {
159
+ var sr: SpatialObject?
160
+ switch type {
161
+ case "Entity":
162
+ sr = SpatialEntity()
163
+ case "InputComponent":
164
+ sr = SpatialInputComponent()
165
+ (sr as! SpatialInputComponent).wv = target
166
+ case "MeshResource":
167
+ if let shape = data.params?.shape {
168
+ let meshResource: MeshResource = shape == "sphere" ? .generateSphere(radius: 0.5) : .generateBox(size: 1.0)
169
+ sr = SpatialMeshResource(meshResource)
170
+ }
171
+ case "PhysicallyBasedMaterial":
172
+ sr = SpatialPhysicallyBasedMaterial(PhysicallyBasedMaterial())
173
+ case "SpatialWebView":
174
+ sr = SpatialWindowComponent(parentWindowContainerID: target.readWindowContainerID(id: info.windowContainerID))
175
+ let spatialWindowComponent = sr as! SpatialWindowComponent
176
+ spatialWindowComponent.parentWebviewID = target.id
177
+ case "SpatialView":
178
+ sr = SpatialViewComponent()
179
+ case "Model3DComponent":
180
+ let spatialModel3DComponent = SpatialModel3DComponent()
181
+ if let modelURL: String = data.params?.modelURL {
182
+ spatialModel3DComponent.setURL(modelURL)
183
+ }
184
+ sr = spatialModel3DComponent
185
+ spatialModel3DComponent.wv = target
186
+ case "ModelComponent":
187
+ if var modelURL: String = data.params?.modelURL {
188
+ modelURL = target.parseURL(url: modelURL)
189
+ // Create download task for the url
190
+ let url = URL(string: modelURL)!
191
+ let downloadSession = URLSession(configuration: URLSession.shared.configuration, delegate: nil, delegateQueue: nil)
192
+ let downloadTask = downloadSession.downloadTask(with: url, completionHandler: { a, _, _ in
193
+ var fileURL = url
194
+ if !pwaManager.isLocal {
195
+ // Copy temp file to documentes directory
196
+ let fileStr = modelURL.replacingOccurrences(of: ":", with: "__").replacingOccurrences(of: "/", with: "_x_")
197
+ do {
198
+ fileURL = getDocumentsDirectory().appendingPathComponent(fileStr)
199
+ try FileManager.default.copyItem(at: a!, to: fileURL)
200
+ logger.debug("Downloaded and copied model")
201
+ } catch {
202
+ logger.warning("Model already exists")
203
+ }
204
+ }
205
+
206
+ Task {
207
+ do {
208
+ let m = try await ModelEntity(contentsOf: fileURL)
209
+
210
+ let modelComponent = await m.model!
211
+ let spatialModelComponent = SpatialModelComponent(modelComponent)
212
+
213
+ Task.detached { @MainActor in
214
+ // Update state on main thread
215
+ target.completeEvent(requestID: info.requestID, data: "{createdID: '" + spatialModelComponent.id + "'}")
216
+ target.addChildSpatialObject(spatialModelComponent)
217
+ logger.debug("Model load success!")
218
+ }
219
+ } catch {
220
+ logger.warning("failed to load model: " + error.localizedDescription)
221
+ }
222
+ }
223
+ })
224
+ downloadTask.resume()
225
+ return
226
+ } else {
227
+ let modelComponent = ModelComponent(mesh: .generateBox(size: 0.0), materials: [])
228
+ sr = SpatialModelComponent(modelComponent)
229
+ }
230
+ default: logger.warning("failed to create sr of type \(type)")
231
+ }
232
+ if let srObject = sr {
233
+ target.completeEvent(requestID: info.requestID, data: "{createdID: '" + srObject.id + "'}")
234
+ target.addChildSpatialObject(srObject)
235
+ } else {
236
+ logger.warning("failed to create sr of type: \(type)")
237
+ }
238
+ }
239
+ }
240
+
241
+ private func destroyResource(target: SpatialWindowComponent, info: CommandInfo) {
242
+ let resourceID = info.resourceID
243
+ target.destroyChild(name: resourceID)
244
+ }
245
+
246
+ private func updateResource(target: SpatialWindowComponent, info: CommandInfo) {
247
+ let data = info.cmd.data!
248
+ var delayComplete = false
249
+ if SpatialObject.get(info.resourceID) == nil {
250
+ logger.warning("Missing resource:" + info.resourceID)
251
+ return
252
+ }
253
+ let sr = SpatialObject.get(info.resourceID)!
254
+ if let entity = sr as? SpatialEntity {
255
+ if let setParentID: String = data.update?.setParent {
256
+ if setParentID.isEmpty {
257
+ entity.setParent(parentEnt: nil)
258
+ } else {
259
+ if let parentEntity = SpatialObject.get(setParentID) as? SpatialEntity {
260
+ entity.setParent(parentEnt: parentEntity)
261
+ } else {
262
+ logger.warning("Invalid setParentID: \(setParentID)")
263
+ }
264
+ }
265
+ }
266
+
267
+ if let _ = data.update?.getBoundingBox {
268
+ let b = entity.modelEntity.visualBounds(relativeTo: nil)
269
+ let exts = "x:" + String(b.extents.x) + "," + "y:" + String(b.extents.y) + "," + "z:" + String(b.extents.z)
270
+ let center = "x:" + String(b.center.x) + "," + "y:" + String(b.center.y) + "," + "z:" + String(b.center.z)
271
+ target.completeEvent(requestID: info.requestID, data: "{center: {" + center + "}, extents: {" + exts + "}}")
272
+ return
273
+ }
274
+
275
+ if let name = data.update?.name {
276
+ entity.name = name
277
+ }
278
+
279
+ if let space: String = data.update?.setCoordinateSpace {
280
+ entity.coordinateSpace = .APP
281
+ if space == "Root" {
282
+ entity.coordinateSpace = .ROOT
283
+ }
284
+
285
+ if space == "Dom" {
286
+ entity.coordinateSpace = .DOM
287
+ }
288
+ }
289
+
290
+ if let zIndex: Double = data.update?.zIndex {
291
+ entity.zIndex = zIndex
292
+ }
293
+
294
+ if let visible: Bool = data.update?.visible {
295
+ entity.visible = visible
296
+ }
297
+
298
+ if var newParentID: String = data.update?.setParentWindowContainerID {
299
+ newParentID = target.readWindowContainerID(id: newParentID)
300
+ let wg = SpatialWindowContainer.getSpatialWindowContainer(newParentID)
301
+ entity.setParentWindowContainer(wg: wg)
302
+ }
303
+
304
+ if let position: JSVector3F = data.update?.position,
305
+ let scale: JSVector3F = data.update?.scale,
306
+ let orientation: JSVector4 = data.update?.orientation
307
+ {
308
+ entity.modelEntity.position = SIMD3<Float>(position.x, position.y, position.z)
309
+ entity.modelEntity.scale = SIMD3<Float>(scale.x, scale.y, scale.z)
310
+ entity.modelEntity.orientation.vector = SIMD4<Float>(orientation.x, orientation.y, orientation.z, orientation.w)
311
+ entity.forceUpdate = !entity.forceUpdate
312
+ }
313
+ } else if sr is SpatialMeshResource {
314
+ } else if let spatialPhysicallyBasedMaterial = sr as? SpatialPhysicallyBasedMaterial {
315
+ if let baseColor: JSColor = data.update?.baseColor {
316
+ spatialPhysicallyBasedMaterial.physicallyBasedMaterial.baseColor = PhysicallyBasedMaterial.BaseColor(tint: UIColor(red: baseColor.r, green: baseColor.g, blue: baseColor.b, alpha: baseColor.a))
317
+ }
318
+
319
+ if let roughness: Double = data.update?.roughness?.value {
320
+ spatialPhysicallyBasedMaterial.physicallyBasedMaterial.roughness = PhysicallyBasedMaterial.Roughness(floatLiteral: Float(roughness))
321
+ }
322
+
323
+ if let metallic: Double = data.update?.metallic?.value {
324
+ spatialPhysicallyBasedMaterial.physicallyBasedMaterial.metallic = PhysicallyBasedMaterial.Metallic(floatLiteral: Float(metallic))
325
+ }
326
+
327
+ } else if let spatialViewComponent = sr as? SpatialViewComponent {
328
+ if let resolution = data.update?.resolution {
329
+ spatialViewComponent.resolutionX = resolution.x
330
+ spatialViewComponent.resolutionY = resolution.y
331
+ }
332
+
333
+ if let isPortal = data.update?.isPortal {
334
+ spatialViewComponent.isPortal = isPortal
335
+ }
336
+
337
+ } else if let spatialModelComponent = sr as? SpatialModelComponent {
338
+ if let meshResourceId: String = data.update?.meshResource {
339
+ if let spatialMeshResource = target.getChildSpatialObject(name: meshResourceId) as? SpatialMeshResource {
340
+ spatialModelComponent.modelComponent.mesh = spatialMeshResource.meshResource
341
+ } else {
342
+ logger.warning("invalid meshResource")
343
+ }
344
+ }
345
+
346
+ if let materials: [String] = data.update?.materials {
347
+ spatialModelComponent.modelComponent.materials = []
348
+ for matID in materials {
349
+ if let spatialMaterialComponent = target.getChildSpatialObject(name: matID) as? SpatialPhysicallyBasedMaterial {
350
+ spatialModelComponent.modelComponent.materials.append(spatialMaterialComponent.physicallyBasedMaterial)
351
+ }
352
+ }
353
+ }
354
+ spatialModelComponent.onUpdate()
355
+ } else if let spatialModel3DComponent = sr as? SpatialModel3DComponent {
356
+ if let resolution: JSVector2 = data.update?.resolution {
357
+ spatialModel3DComponent.resolutionX = resolution.x
358
+ spatialModel3DComponent.resolutionY = resolution.y
359
+ }
360
+
361
+ if let rotationAnchor = data.update?.rotationAnchor {
362
+ spatialModel3DComponent.rotationAnchor = UnitPoint3D(
363
+ x: rotationAnchor.x,
364
+ y: rotationAnchor.y,
365
+ z: rotationAnchor.z
366
+ )
367
+ }
368
+
369
+ if let opacity = data.update?.opacity {
370
+ spatialModel3DComponent.opacity = opacity
371
+ }
372
+
373
+ if let contentMode: String = data.update?.contentMode {
374
+ if contentMode == "fill" {
375
+ spatialModel3DComponent.contentMode = .fill
376
+
377
+ } else if contentMode == "fit" {
378
+ spatialModel3DComponent.contentMode = .fit
379
+ }
380
+ }
381
+
382
+ if let resizable: Bool = data.update?.resizable {
383
+ spatialModel3DComponent.resizable = resizable
384
+ }
385
+
386
+ if let aspectRatio: Double = data.update?.aspectRatio {
387
+ if aspectRatio > 0 {
388
+ spatialModel3DComponent.aspectRatio = aspectRatio
389
+
390
+ } else if aspectRatio == 0 {
391
+ spatialModel3DComponent.aspectRatio = nil
392
+ }
393
+ }
394
+
395
+ if let enableTapEvent: Bool = data.update?.enableTapEvent {
396
+ spatialModel3DComponent.enableTapEvent = enableTapEvent
397
+ }
398
+
399
+ if let enableDoubleTapEvent: Bool = data.update?.enableDoubleTapEvent {
400
+ spatialModel3DComponent.enableDoubleTapEvent = enableDoubleTapEvent
401
+ }
402
+
403
+ if let enableDragEvent: Bool = data.update?.enableDragEvent {
404
+ spatialModel3DComponent.enableDragEvent = enableDragEvent
405
+ }
406
+
407
+ if let enableLongPressEvent: Bool = data.update?.enableLongPressEvent {
408
+ spatialModel3DComponent.enableLongPressEvent = enableLongPressEvent
409
+ }
410
+
411
+ } else if let spatialWindowComponent = sr as? SpatialWindowComponent {
412
+ if let _: String = data.update?.getEntityID {
413
+ if let entity: SpatialEntity = spatialWindowComponent.entity {
414
+ target.completeEvent(requestID: info.requestID, data: "{parentID:'" + entity.id + "'}")
415
+
416
+ } else {
417
+ target.completeEvent(requestID: info.requestID, data: "{parentID:''}")
418
+ }
419
+ return
420
+ }
421
+
422
+ if let _: String = data.update?.getParentID {
423
+ target.completeEvent(requestID: info.requestID, data: "{parentID:'" + spatialWindowComponent.parentWebviewID + "'}")
424
+ return
425
+ }
426
+
427
+ if let scrollEnabled: Bool = data.update?.scrollEnabled {
428
+ if !scrollEnabled {
429
+ spatialWindowComponent.getView()!.webViewHolder.appleWebView!.scrollView.contentOffset.y = 0
430
+ spatialWindowComponent.getView()!.webViewHolder.appleWebView!.scrollView.isScrollEnabled = false
431
+ } else {
432
+ spatialWindowComponent.getView()!.webViewHolder.appleWebView!.scrollView.isScrollEnabled = true
433
+ }
434
+ }
435
+
436
+ if let rect: JSRect = data.update?.setScrollEdgeInsets {
437
+ spatialWindowComponent.getView()!.webViewHolder.appleWebView!.scrollView.contentInset = UIEdgeInsets(top: rect.top, left: rect.left, bottom: rect.bottom, right: rect.right)
438
+ }
439
+
440
+ if let scrollWithParent: Bool = data.update?.scrollWithParent {
441
+ spatialWindowComponent.scrollWithParent = scrollWithParent
442
+ }
443
+
444
+ if let windowID: String = data.update?.windowID {
445
+ if let spawnedWebView = target.spawnedNativeWebviews.removeValue(forKey: windowID) {
446
+ spatialWindowComponent.getView()!.destroy()
447
+ spatialWindowComponent.setView(wv: spawnedWebView)
448
+ spatialWindowComponent.getView()!.webViewHolder.webViewCoordinator!.webViewRef = spatialWindowComponent
449
+ }
450
+ }
451
+
452
+ if let url: String = data.update?.url {
453
+ // Compute target url depending if the url is relative or not
454
+ let targetUrl = target.parseURL(url: url)
455
+
456
+ delayComplete = true
457
+ if spatialWindowComponent.loadRequestID == -1 {
458
+ spatialWindowComponent.loadRequestID = info.requestID
459
+ spatialWindowComponent.loadRequestWV = target
460
+ spatialWindowComponent.setURL(url: URL(string: targetUrl)!)
461
+ spatialWindowComponent.getView()!.initialLoad()
462
+ } else {
463
+ target.failEvent(requestID: info.requestID)
464
+ }
465
+ }
466
+
467
+ if let resolution: JSVector2 = data.update?.resolution {
468
+ spatialWindowComponent.resolutionX = resolution.x
469
+ spatialWindowComponent.resolutionY = resolution.y
470
+ }
471
+
472
+ if let rotationAnchor = data.update?.rotationAnchor {
473
+ spatialWindowComponent.rotationAnchor = UnitPoint3D(
474
+ x: rotationAnchor.x,
475
+ y: rotationAnchor.y,
476
+ z: rotationAnchor.z
477
+ )
478
+ }
479
+
480
+ if let opacity = data.update?.opacity {
481
+ spatialWindowComponent.opacity = opacity
482
+ }
483
+
484
+ if let backgroundMaterial: BackgroundMaterial = data.update?.style?.backgroundMaterial {
485
+ if target.isLoading {
486
+ target.loadingStyles.backgroundMaterial = backgroundMaterial
487
+ }
488
+ spatialWindowComponent.backgroundMaterial = backgroundMaterial
489
+ }
490
+ if let cornerRadius: CornerRadius = data.update?.style?.cornerRadius {
491
+ if target.isLoading {
492
+ target.loadingStyles.cornerRadius = cornerRadius
493
+ }
494
+ spatialWindowComponent.cornerRadius = cornerRadius
495
+ }
496
+ spatialWindowComponent.gotStyle = true
497
+ }
498
+ if !delayComplete {
499
+ target.completeEvent(requestID: info.requestID)
500
+ }
501
+ }
502
+
503
+ private func createWindowContainer(target: SpatialWindowComponent, info: CommandInfo) {
504
+ if let windowStyle: String = info.cmd.data!.windowStyle {
505
+ let uuid = UUID().uuidString
506
+ let wgd = WindowContainerData(windowStyle: windowStyle, windowContainerID: uuid)
507
+
508
+ // Force window container creation to happen now so it can be accessed after complete event returns
509
+ _ = SpatialWindowContainer.getOrCreateSpatialWindowContainer(uuid, wgd)
510
+
511
+ if let wg = SpatialWindowContainer.getOrCreateSpatialWindowContainer(target.parentWindowContainerID, wgd) {
512
+ wg.openWindowData.send(wgd)
513
+
514
+ // If the parent window component isn't set, the new container can continue to exist even after other window is closed
515
+ if info.resourceID != "notFound" {
516
+ var rid = info.resourceID
517
+ let so = SpatialObject.get(rid)
518
+ if let parentWindowComponent = so as? SpatialWindowComponent {
519
+ parentWindowComponent.setWindowContainer(uuid: uuid, wgd: wgd)
520
+ }
521
+ }
522
+
523
+ if info.windowContainerID != "notFound" {
524
+ if var parentContainer = SpatialWindowContainer.getSpatialWindowContainer(info.windowContainerID) {
525
+ parentContainer.childContainers[uuid] = wg
526
+ }
527
+ }
528
+
529
+ target.completeEvent(requestID: info.requestID, data: "{createdID: '" + uuid + "'}")
530
+ }
531
+ }
532
+ }
533
+
534
+ private func createScene(target: SpatialWindowComponent, info: CommandInfo) {
535
+ let data = info.cmd.data!
536
+ if let _: String = data.windowStyle {
537
+ // windowID exist in SWC
538
+
539
+ // TODO: check url scope
540
+ // in scope: the url is configured in manifest
541
+ // if not in scope, open in safari
542
+
543
+ if data.sceneData?.method == "createRoot" {
544
+ if let windowID = data.sceneData?.windowID {
545
+ // if windowID in spawned uuid, createRoot
546
+
547
+ if target.spawnedNativeWebviews[windowID] != nil {
548
+ // setup windowContainer defaultValues
549
+ if let config = data.sceneData?.sceneConfig {
550
+ SceneManager.Instance
551
+ .createRoot(target: target, windowID: windowID, config: config)
552
+ } else {
553
+ SceneManager.Instance
554
+ .createRoot(target: target, windowID: windowID)
555
+ }
556
+
557
+ } else {
558
+ if let windowContainerID = data.sceneData?.windowContainerID {
559
+ SceneManager.Instance.focusRoot(target: target, windowContainerID: windowContainerID)
560
+ } else {
561
+ logger.error("error: no windowContainerID")
562
+ }
563
+ }
564
+
565
+ target.completeEvent(requestID: info.requestID, data: "{}")
566
+ }
567
+ } else if data.sceneData?.method == "showRoot" {
568
+ if let config = data.sceneData?.sceneConfig {
569
+ let parentWindowContainerID = info.windowContainerID
570
+ SceneManager.Instance.showRoot(target: target, config: config, parentWindowContainerID: parentWindowContainerID)
571
+ }
572
+ target.completeEvent(requestID: info.requestID, data: "{}")
573
+
574
+ } else {
575
+ target.failEvent(requestID: info.requestID, data: "method not supported")
576
+ }
577
+ }
578
+ }
579
+
580
+ private func updateWindowContainer(target: SpatialWindowComponent, info: CommandInfo) {
581
+ let data = info.cmd.data!
582
+ if let _ = data.update?.getRootEntityID,
583
+ let wg = SpatialWindowContainer.getSpatialWindowContainer(target.readWindowContainerID(id: info.windowContainerID))
584
+ {
585
+ let rootEntity = wg.getEntities().filter {
586
+ $0.value.coordinateSpace == .ROOT
587
+ }.first?.value
588
+ if rootEntity != nil {
589
+ target.completeEvent(requestID: info.requestID, data: "{rootEntId:'" + rootEntity!
590
+ .id + "'}")
591
+ } else {
592
+ target.completeEvent(requestID: info.requestID, data: "{rootEntId:''}")
593
+ }
594
+ return
595
+ }
596
+
597
+ if let resolution = data.update?.nextOpenSettings?.resolution {
598
+ sceneStateChangedCB = { _ in
599
+ // Complete event after scene state change is completed
600
+ target.completeEvent(requestID: info.requestID)
601
+ sceneStateChangedCB = { _ in }
602
+ }
603
+
604
+ // Update scene state
605
+ var cfg = WindowContainerPlainDefaultValues()
606
+ cfg.defaultSize = CGSize(width: resolution.width, height: resolution.height)
607
+ WindowContainerMgr.Instance.updateWindowContainerPlainDefaultValues(cfg)
608
+ return
609
+ }
610
+ target.completeEvent(requestID: info.requestID)
611
+ }
612
+
613
+ private func openImmersiveSpace(target: SpatialWindowComponent, info: CommandInfo) {
614
+ let wg = SpatialWindowContainer.getSpatialWindowContainer(target.parentWindowContainerID)
615
+ wg?.toggleImmersiveSpace.send(true)
616
+ }
617
+
618
+ private func dismissImmersiveSpace(target: SpatialWindowComponent, info: CommandInfo) {
619
+ let wg = SpatialWindowContainer.getSpatialWindowContainer(target.parentWindowContainerID)
620
+ wg?.toggleImmersiveSpace.send(false)
621
+ }
622
+
623
+ private func log(target: SpatialWindowComponent, info: CommandInfo) {
624
+ if let logStringArr: [String] = info.cmd.data!.logString {
625
+ let logString = logStringArr.joined()
626
+ logger.debug(logString)
627
+ }
628
+ }
629
+
630
+ private func setLoading(target: SpatialWindowComponent, info: CommandInfo) {
631
+ let data = info.cmd.data!
632
+ switch data.loading?.method {
633
+ case "show":
634
+ SceneManager.Instance.setLoading(.show, windowContainerID: info.windowContainerID)
635
+ case "hide":
636
+ SceneManager.Instance.setLoading(.hide, windowContainerID: info.windowContainerID)
637
+ case _:
638
+ break
639
+ }
640
+ target.completeEvent(requestID: info.requestID)
641
+ }
642
+ }
643
+
644
+ struct RawJSBCommand: Codable {
645
+ var command: String
646
+ var data: RawJSData?
647
+ var requestID: Int
648
+ }
649
+
650
+ struct JSBCommand {
651
+ var command: String
652
+ var data: JSData?
653
+ var requestID: Int
654
+ }
655
+
656
+ protocol JSData {
657
+ var commandList: [RawJSBCommand]? { get } // multiCommand
658
+ var type: String? { get } // createResource
659
+ var params: JSParams? { get } // createResource
660
+ var update: JSResourceData? { get }
661
+ var windowStyle: String? { get }
662
+ var windowContainerOptions: WindowContainerOptions? { get }
663
+ var sceneData: SceneJSBData? { get }
664
+ var logString: [String]? { get }
665
+ var logLevel: String? { get }
666
+ var loading: LoadingJSBData? { get }
667
+ }
668
+
669
+ struct RawJSData: Codable, JSData {
670
+ var commandList: [RawJSBCommand]? // multiCommand
671
+ var resourceID: String?
672
+ var windowContainerID: String?
673
+ var entityID: String? // setComponent
674
+ var type: String? // createResource
675
+ var params: JSParams? // createResource
676
+ var update: JSResourceData?
677
+ var windowStyle: String?
678
+ var windowContainerOptions: WindowContainerOptions?
679
+ var sceneData: SceneJSBData?
680
+ var logString: [String]?
681
+ var logLevel: String?
682
+ var loading: LoadingJSBData?
683
+ }
684
+
685
+ struct JSParams: Codable {
686
+ var shape: String?
687
+ var modelURL: String?
688
+ }
689
+
690
+ struct JSResourceData: Codable {
691
+ var setParent: String?
692
+ var setCoordinateSpace: String?
693
+ var setParentWindowContainerID: String?
694
+ var position: JSVector3F?
695
+ var orientation: JSVector4?
696
+ var scale: JSVector3F?
697
+ var baseColor: JSColor?
698
+ var roughness: JSValue?
699
+ var metallic: JSValue?
700
+ var url: String?
701
+ var aspectRatio: Double?
702
+ var opacity: Double?
703
+ var contentMode: String?
704
+ var resizable: Bool?
705
+ var resolution: JSVector2?
706
+ var isPortal: Bool?
707
+ var rotationAnchor: JSVector3?
708
+ var meshResource: String?
709
+ var materials: [String]?
710
+ var getEntityID: String?
711
+ var getParentID: String?
712
+ var getRootEntityID: String?
713
+ var scrollEnabled: Bool?
714
+ var scrollWithParent: Bool?
715
+ var setScrollEdgeInsets: JSRect?
716
+ var windowID: String?
717
+ var style: JSEntityStyle?
718
+ var nextOpenSettings: JSNextOpen?
719
+ var getBoundingBox: Bool?
720
+ var zIndex: Double?
721
+ var visible: Bool?
722
+ var name: String?
723
+
724
+ var enableTapEvent: Bool?
725
+ var enableDoubleTapEvent: Bool?
726
+ var enableDragEvent: Bool?
727
+ var enableLongPressEvent: Bool?
728
+ }
729
+
730
+ struct JSColor: Codable {
731
+ var r: Double
732
+ var g: Double
733
+ var b: Double
734
+ var a: Double
735
+ }
736
+
737
+ struct JSVector2: Codable {
738
+ var x: Double
739
+ var y: Double
740
+ }
741
+
742
+ struct JSResolution: Codable {
743
+ var width: Double
744
+ var height: Double
745
+ }
746
+
747
+ struct JSVector3: Codable {
748
+ var x: Double
749
+ var y: Double
750
+ var z: Double
751
+ }
752
+
753
+ struct JSVector3F: Codable {
754
+ var x: Float
755
+ var y: Float
756
+ var z: Float
757
+ }
758
+
759
+ struct JSVector4: Codable {
760
+ var x: Float
761
+ var y: Float
762
+ var z: Float
763
+ var w: Float
764
+ }
765
+
766
+ struct JSValue: Codable {
767
+ var value: Double
768
+ }
769
+
770
+ struct JSRect: Codable {
771
+ var top: Double
772
+ var bottom: Double
773
+ var left: Double
774
+ var right: Double
775
+ }
776
+
777
+ struct JSEntityStyle: Codable {
778
+ var cornerRadius: CornerRadius?
779
+ var backgroundMaterial: BackgroundMaterial?
780
+ var dimensions: JSVector2?
781
+ }
782
+
783
+ struct JSNextOpen: Codable {
784
+ var resolution: JSResolution?
785
+ }
786
+
787
+ struct SceneJSBData: Codable {
788
+ var method: String?
789
+ var sceneName: String?
790
+ var sceneConfig: WindowContainerOptions?
791
+ var url: String?
792
+ var windowID: String?
793
+ var windowContainerID: String?
794
+ }
795
+
796
+ struct LoadingJSBData: Codable {
797
+ var method: String?
798
+ var style: String?
799
+ }