@webspatial/builder 0.0.10 → 0.0.11
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 +1 -1
- package/dist/lib/Cli.js +1 -1
- package/dist/lib/cmds/build.d.ts +1 -1
- package/dist/lib/cmds/build.js +1 -1
- package/dist/lib/cmds/check.js +1 -1
- package/dist/lib/cmds/help.js +1 -1
- package/dist/lib/cmds/version.js +1 -1
- package/dist/lib/pwa/config.js +1 -1
- package/dist/lib/pwa/index.js +1 -1
- package/dist/lib/pwa/validate.js +1 -1
- package/dist/lib/resource/file.js +1 -1
- package/dist/lib/resource/imageHelper.js +1 -1
- package/dist/lib/resource/index.d.ts +10 -3
- package/dist/lib/resource/index.js +1 -1
- package/dist/lib/resource/load.js +1 -1
- package/dist/lib/utils/CustomError.js +1 -1
- package/dist/lib/utils/FetchUtils-1.js +1 -1
- package/dist/lib/utils/Log.js +1 -1
- package/dist/lib/utils/fetch.js +1 -1
- package/dist/lib/utils/messages.js +1 -1
- package/dist/lib/utils/utils.d.ts +9 -0
- package/dist/lib/utils/utils.js +1 -1
- package/dist/lib/xcode/index.js +1 -1
- package/dist/lib/xcode/manifestSwiftTemplate.js +1 -1
- package/dist/lib/xcode/xcodebuild.js +1 -1
- package/dist/lib/xcode/xcodeproject.js +1 -1
- package/dist/lib/xcode/xcrun.js +1 -1
- package/package.json +3 -2
- package/template/visionOSApp/Packages/RealityKitContent/.build/workspace-state.json +0 -7
- package/template/visionOSApp/Packages/RealityKitContent/.swiftpm/xcode/xcuserdata/bytedance.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
- package/template/visionOSApp/Packages/RealityKitContent/Package.realitycomposerpro/ProjectData/main.json +0 -11
- package/template/visionOSApp/Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/SceneMetadataList.json +0 -112
- package/template/visionOSApp/Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/Settings.rcprojectdata +0 -17
- package/template/visionOSApp/Packages/RealityKitContent/Package.swift +0 -27
- package/template/visionOSApp/Packages/RealityKitContent/README.md +0 -3
- package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Immersive.usda +0 -50
- package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Materials/GridMaterial.usda +0 -216
- package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Scene.usda +0 -59
- package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.swift +0 -4
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/Contents.json +0 -12
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Contents.json +0 -6
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Contents.json +0 -17
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/Contents.json +0 -12
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Contents.json +0 -6
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/Contents.json +0 -12
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Contents.json +0 -6
- package/template/visionOSApp/web-spatial/Assets.xcassets/Contents.json +0 -6
- package/template/visionOSApp/web-spatial/Info.plist +0 -33
- package/template/visionOSApp/web-spatial/Preview Content/Preview Assets.xcassets/Contents.json +0 -6
- package/template/visionOSApp/web-spatial/libs/EventEmitter.swift +0 -32
- package/template/visionOSApp/web-spatial/libs/SpatialComponent.swift +0 -31
- package/template/visionOSApp/web-spatial/libs/SpatialEntity.swift +0 -179
- package/template/visionOSApp/web-spatial/libs/SpatialInputComponent.swift +0 -26
- package/template/visionOSApp/web-spatial/libs/SpatialMeshResource.swift +0 -19
- package/template/visionOSApp/web-spatial/libs/SpatialModel3DComponent.swift +0 -51
- package/template/visionOSApp/web-spatial/libs/SpatialModelComponent.swift +0 -32
- package/template/visionOSApp/web-spatial/libs/SpatialObject.swift +0 -144
- package/template/visionOSApp/web-spatial/libs/SpatialPhysicallyBasedMaterial.swift +0 -19
- package/template/visionOSApp/web-spatial/libs/SpatialViewComponent.swift +0 -15
- package/template/visionOSApp/web-spatial/libs/SpatialWindowComponent.swift +0 -420
- package/template/visionOSApp/web-spatial/libs/SpatialWindowContainer.swift +0 -149
- package/template/visionOSApp/web-spatial/libs/Utils/CommandManager.swift +0 -800
- package/template/visionOSApp/web-spatial/libs/Utils/Logger.swift +0 -36
- package/template/visionOSApp/web-spatial/libs/Utils/SceneManager.swift +0 -108
- package/template/visionOSApp/web-spatial/libs/Utils/WindowContainerMgr.swift +0 -117
- package/template/visionOSApp/web-spatial/libs/json/JsonParser.swift +0 -52
- package/template/visionOSApp/web-spatial/libs/uiKitDelegate/Window.swift +0 -34
- package/template/visionOSApp/web-spatial/libs/webView/UpdateSystem.swift +0 -33
- package/template/visionOSApp/web-spatial/libs/webView/backend/NativeWebView.swift +0 -319
- package/template/visionOSApp/web-spatial/libs/webView/manifest.swift +0 -92
- package/template/visionOSApp/web-spatial/static-web/index.html +0 -9
- package/template/visionOSApp/web-spatial/views/HideViewModifier.swift +0 -17
- package/template/visionOSApp/web-spatial/views/ImmersiveView.swift +0 -24
- package/template/visionOSApp/web-spatial/views/LoadingView.swift +0 -29
- package/template/visionOSApp/web-spatial/views/MaterialWithBorderCornerModifier.swift +0 -82
- package/template/visionOSApp/web-spatial/views/OpenDismissHandlerUI.swift +0 -52
- package/template/visionOSApp/web-spatial/views/PlainWindowContainerView.swift +0 -84
- package/template/visionOSApp/web-spatial/views/SpatialModel3DView.swift +0 -193
- package/template/visionOSApp/web-spatial/views/SpatialViewUI.swift +0 -168
- package/template/visionOSApp/web-spatial/views/SpatialWebViewUI.swift +0 -186
- package/template/visionOSApp/web-spatial/views/VolumetricWindowContainerView.swift +0 -38
- package/template/visionOSApp/web-spatial/views/ui/NavView.swift +0 -125
- package/template/visionOSApp/web-spatial/web_spatialApp.swift +0 -158
- package/template/visionOSApp/web-spatial.xcodeproj/project.pbxproj +0 -686
- package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +0 -5
- package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/xcuserdata/bytedance.xcuserdatad/WorkspaceSettings.xcsettings +0 -14
- package/template/visionOSApp/web-spatial.xcodeproj/xcshareddata/xcschemes/web-spatial.xcscheme +0 -115
- package/template/visionOSApp/web-spatial.xcodeproj/xcuserdata/bytedance.xcuserdatad/xcschemes/xcschememanagement.plist +0 -27
- package/template/visionOSApp/web-spatialTests/web_spatialTests.swift +0 -34
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// PlainWindowContainerView.swift
|
|
3
|
-
// web-spatial
|
|
4
|
-
//
|
|
5
|
-
// Created by ByteDance on 5/9/24.
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
import RealityKit
|
|
9
|
-
import SwiftUI
|
|
10
|
-
|
|
11
|
-
struct PlainWindowContainerView: View {
|
|
12
|
-
@EnvironmentObject private var sceneDelegate: SceneDelegate
|
|
13
|
-
@Environment(SpatialWindowContainer.self) private var windowContainerContent: SpatialWindowContainer
|
|
14
|
-
|
|
15
|
-
@State private var windowResizeInProgress = false
|
|
16
|
-
@State private var timer: Timer?
|
|
17
|
-
|
|
18
|
-
private func setSize(size: CGSize) {
|
|
19
|
-
sceneDelegate.window?.windowScene?.requestGeometryUpdate(.Vision(size: size))
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
var body: some View {
|
|
23
|
-
OpenDismissHandlerUI().environment(windowContainerContent).onDisappear {
|
|
24
|
-
windowContainerContent.destroy()
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
let rootEntity = windowContainerContent.getEntities().filter {
|
|
28
|
-
$0.value.getComponent(SpatialWindowComponent.self) != nil && $0.value.coordinateSpace == .ROOT
|
|
29
|
-
}.first?.value
|
|
30
|
-
|
|
31
|
-
GeometryReader { proxy3D in
|
|
32
|
-
ZStack {
|
|
33
|
-
if let e = rootEntity {
|
|
34
|
-
let _ = e.forceUpdate ? 0 : 0
|
|
35
|
-
let x = proxy3D.size.width / 2
|
|
36
|
-
let y = proxy3D.size.height / 2
|
|
37
|
-
let z = CGFloat(e.modelEntity.position.z)
|
|
38
|
-
let width = proxy3D.size.width
|
|
39
|
-
let height = proxy3D.size.height
|
|
40
|
-
|
|
41
|
-
if windowResizeInProgress {
|
|
42
|
-
VStack {}.frame(width: width, height: height).glassBackgroundEffect().padding3D(.front, -100_000)
|
|
43
|
-
.position(x: x, y: y)
|
|
44
|
-
.offset(z: z)
|
|
45
|
-
} else {
|
|
46
|
-
// Avoid showing webview until its loading completes
|
|
47
|
-
let wc = e.getComponent(SpatialWindowComponent.self)
|
|
48
|
-
let didFinishFirstLoad = wc != nil ? wc!.didFinishFirstLoad : false
|
|
49
|
-
|
|
50
|
-
SpatialWebViewUI().environment(e)
|
|
51
|
-
.frame(width: width, height: height).padding3D(.front, -100_000)
|
|
52
|
-
.rotation3DEffect(Rotation3D(simd_quatf(ix: e.modelEntity.orientation.vector.x, iy: e.modelEntity.orientation.vector.y, iz: e.modelEntity.orientation.vector.z, r: e.modelEntity.orientation.vector.w)))
|
|
53
|
-
.position(x: x, y: y)
|
|
54
|
-
.offset(z: z)
|
|
55
|
-
.opacity(didFinishFirstLoad ? 1.0 : 0.0)
|
|
56
|
-
.animation(.linear(duration: 0.2), value: didFinishFirstLoad)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
.onReceive(windowContainerContent.setSize) { newSize in
|
|
61
|
-
setSize(size: newSize)
|
|
62
|
-
}
|
|
63
|
-
.onChange(of: proxy3D.size) {
|
|
64
|
-
// WkWebview has an issue where it doesn't resize while the swift window is resized
|
|
65
|
-
// Treid to call didMoveToWindow to force redraw to occur but that seemed to cause rendering artifacts so that solution was rejected
|
|
66
|
-
// Now we use a windowResizeInProgress state to hide the webview (by removoving from the view) and other content (using opacity).
|
|
67
|
-
// After resize is completed the webview is added back to the page which causes a redraw at the correct dimensions/position
|
|
68
|
-
if let wv = rootEntity?.getComponent(SpatialWindowComponent.self) {
|
|
69
|
-
windowResizeInProgress = true
|
|
70
|
-
if timer != nil {
|
|
71
|
-
timer!.invalidate()
|
|
72
|
-
}
|
|
73
|
-
// If we don't detect resolution change after x seconds we treat the resize as complete
|
|
74
|
-
timer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false) { _ in
|
|
75
|
-
windowResizeInProgress = false
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Trigger resize in the webview's body width and fire a window resize event to get the JS on the page to update state while dragging occurs
|
|
79
|
-
wv.evaluateJS(js: "var tempWidth_ = document.body.style.width;document.body.style.width='" + String(Float(proxy3D.size.width)) + "px'; window.dispatchEvent(new Event('resize'));")
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// SpatialModel3DView.swift
|
|
3
|
-
// web-spatial
|
|
4
|
-
//
|
|
5
|
-
// Created by ByteDance on 1/21/25.
|
|
6
|
-
//
|
|
7
|
-
import RealityKit
|
|
8
|
-
import SwiftUI
|
|
9
|
-
|
|
10
|
-
class SpatialModel3DViewGestureData {
|
|
11
|
-
// for dragging state
|
|
12
|
-
var isDragging = false
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
struct SpatialModel3DView: View {
|
|
16
|
-
@Environment(SpatialEntity.self) var e: SpatialEntity
|
|
17
|
-
var parentYOffset = Float(0.0)
|
|
18
|
-
|
|
19
|
-
@State private var gestureData = SpatialModel3DViewGestureData()
|
|
20
|
-
|
|
21
|
-
var drag: some Gesture {
|
|
22
|
-
DragGesture()
|
|
23
|
-
.onChanged(onDragging)
|
|
24
|
-
.onEnded(onDraggingEnded)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
var tapGesture: some Gesture {
|
|
28
|
-
TapGesture(count: 1)
|
|
29
|
-
.onEnded(onTapEnded)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
var doubleTapGesture: some Gesture {
|
|
33
|
-
TapGesture(count: 2)
|
|
34
|
-
.onEnded(onDoubleTapEnded)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
var longPressGesture: some Gesture {
|
|
38
|
-
LongPressGesture(minimumDuration: 1.0)
|
|
39
|
-
.onEnded(onLonePressEnded)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
@ViewBuilder
|
|
43
|
-
var body: some View {
|
|
44
|
-
if e.coordinateSpace == .DOM {
|
|
45
|
-
if let childModel3DComponent = e.getComponent(SpatialModel3DComponent.self),
|
|
46
|
-
let url = URL(string: childModel3DComponent.modelURL)
|
|
47
|
-
{
|
|
48
|
-
let x = CGFloat(e.modelEntity.position.x)
|
|
49
|
-
let y = CGFloat(e.modelEntity.position.y - (childModel3DComponent.scrollWithParent ? parentYOffset : 0))
|
|
50
|
-
let z = CGFloat(e.modelEntity.position.z)
|
|
51
|
-
let width = CGFloat(childModel3DComponent.resolutionX)
|
|
52
|
-
let height = CGFloat(childModel3DComponent.resolutionY)
|
|
53
|
-
let anchor = childModel3DComponent.rotationAnchor
|
|
54
|
-
let opacity = childModel3DComponent.opacity
|
|
55
|
-
let resizable = childModel3DComponent.resizable
|
|
56
|
-
let aspectRatio: CGFloat? = childModel3DComponent.aspectRatio == nil ? nil : CGFloat(childModel3DComponent.aspectRatio!)
|
|
57
|
-
let contentMode = childModel3DComponent.contentMode
|
|
58
|
-
|
|
59
|
-
let enableTapEvent = childModel3DComponent.enableTapEvent
|
|
60
|
-
let enableDoubleTapEvent = childModel3DComponent.enableDoubleTapEvent
|
|
61
|
-
let enableDragEvent = childModel3DComponent.enableDragEvent
|
|
62
|
-
let enableLongPressEvent = childModel3DComponent.enableLongPressEvent
|
|
63
|
-
|
|
64
|
-
// Matrix = MTranslate X MRotate X MScale
|
|
65
|
-
Model3D(url: url) { newPhase in
|
|
66
|
-
switch newPhase {
|
|
67
|
-
case .empty:
|
|
68
|
-
ProgressView()
|
|
69
|
-
|
|
70
|
-
case let .success(resolvedModel3D):
|
|
71
|
-
resolvedModel3D
|
|
72
|
-
.resizable(resizable)
|
|
73
|
-
.aspectRatio(
|
|
74
|
-
aspectRatio,
|
|
75
|
-
contentMode: contentMode
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
.onAppear {
|
|
79
|
-
self.onLoadSuccess()
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
case let .failure(error):
|
|
83
|
-
// use UIView.onAppear to notify error phase.
|
|
84
|
-
Text("").onAppear {
|
|
85
|
-
self.onLoadFailure(error.localizedDescription)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
@unknown default:
|
|
89
|
-
EmptyView()
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
.frame(width: width, height: height)
|
|
93
|
-
// .background(Color.blue)
|
|
94
|
-
.scaleEffect(
|
|
95
|
-
x: CGFloat(e.modelEntity.scale.x),
|
|
96
|
-
y: CGFloat(e.modelEntity.scale.y),
|
|
97
|
-
z: CGFloat(e.modelEntity.scale.z),
|
|
98
|
-
anchor: anchor
|
|
99
|
-
)
|
|
100
|
-
.rotation3DEffect(
|
|
101
|
-
Rotation3D(simd_quatf(
|
|
102
|
-
ix: e.modelEntity.orientation.vector.x,
|
|
103
|
-
iy: e.modelEntity.orientation.vector.y,
|
|
104
|
-
iz: e.modelEntity.orientation.vector.z,
|
|
105
|
-
r: e.modelEntity.orientation.vector.w
|
|
106
|
-
)),
|
|
107
|
-
anchor: anchor
|
|
108
|
-
)
|
|
109
|
-
.position(x: x, y: y)
|
|
110
|
-
.offset(z: z)
|
|
111
|
-
.frame(maxDepth: 0, alignment: .back)
|
|
112
|
-
.opacity(opacity)
|
|
113
|
-
.gesture(enableDragEvent ? drag : nil)
|
|
114
|
-
.gesture(enableDoubleTapEvent ?doubleTapGesture : nil)
|
|
115
|
-
.gesture(enableTapEvent ? tapGesture : nil)
|
|
116
|
-
.gesture(enableLongPressEvent ? longPressGesture : nil)
|
|
117
|
-
.hidden(!e.visible)
|
|
118
|
-
} else {
|
|
119
|
-
Text("").onAppear {
|
|
120
|
-
self.onLoadFailure("invalid URL")
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
} else {
|
|
124
|
-
EmptyView()
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
private func onLoadSuccess() {
|
|
129
|
-
if let model3DComponent = e.getComponent(SpatialModel3DComponent.self) {
|
|
130
|
-
let data = "{eventType: 'phase', value: 'success'}"
|
|
131
|
-
model3DComponent.wv?.fireComponentEvent(componentId: model3DComponent.id, data: data)
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
private func onLoadFailure(_ error: String) {
|
|
136
|
-
if let model3DComponent = e.getComponent(SpatialModel3DComponent.self) {
|
|
137
|
-
let data = "{eventType: 'phase', value: 'failure', error: '\(error)'} "
|
|
138
|
-
model3DComponent.wv?.fireComponentEvent(componentId: model3DComponent.id, data: data)
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
private func onDragging(dragValue: DragGesture.Value) {
|
|
143
|
-
var eventType = "drag"
|
|
144
|
-
if !gestureData.isDragging {
|
|
145
|
-
gestureData.isDragging = true
|
|
146
|
-
eventType = "dragstart"
|
|
147
|
-
}
|
|
148
|
-
fireDragEvent(eventType, dragValue)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private func onDraggingEnded(dragValue: DragGesture.Value) {
|
|
152
|
-
gestureData.isDragging = false
|
|
153
|
-
let eventType = "dragend"
|
|
154
|
-
fireDragEvent(eventType, dragValue)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
private func onTapEnded(_: TapGesture.Value) {
|
|
158
|
-
print("onTapEnded")
|
|
159
|
-
if let model3DComponent = e.getComponent(SpatialModel3DComponent.self) {
|
|
160
|
-
let eventType = "tap"
|
|
161
|
-
let data = "{eventType: '\(eventType)' } "
|
|
162
|
-
model3DComponent.wv?.fireComponentEvent(componentId: model3DComponent.id, data: data)
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
private func onDoubleTapEnded(_: TapGesture.Value) {
|
|
167
|
-
print("onDoubleTapEnded")
|
|
168
|
-
if let model3DComponent = e.getComponent(SpatialModel3DComponent.self) {
|
|
169
|
-
let eventType = "doubletap"
|
|
170
|
-
let data = "{eventType: '\(eventType)' } "
|
|
171
|
-
model3DComponent.wv?.fireComponentEvent(componentId: model3DComponent.id, data: data)
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
private func onLonePressEnded(_: LongPressGesture.Value) {
|
|
176
|
-
print("onLonePressEnded")
|
|
177
|
-
if let model3DComponent = e.getComponent(SpatialModel3DComponent.self) {
|
|
178
|
-
let eventType = "longpress"
|
|
179
|
-
let data = "{eventType: '\(eventType)' } "
|
|
180
|
-
model3DComponent.wv?.fireComponentEvent(componentId: model3DComponent.id, data: data)
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
private func fireDragEvent(_ eventType: String, _ value: DragGesture.Value) {
|
|
185
|
-
if let model3DComponent = e.getComponent(SpatialModel3DComponent.self) {
|
|
186
|
-
let startLocation3D = value.startLocation3D
|
|
187
|
-
let translation3D = value.translation3D
|
|
188
|
-
|
|
189
|
-
let data = "{eventType: '\(eventType)', value: { translation3D : { x: \(translation3D.x), y: \(translation3D.y), z: \(translation3D.z) }, startLocation3D: { x: \(startLocation3D.x), y: \(startLocation3D.y), z: \(startLocation3D.z)} } } "
|
|
190
|
-
model3DComponent.wv?.fireComponentEvent(componentId: model3DComponent.id, data: data)
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// SpatialViewUI.swift
|
|
3
|
-
// web-spatial
|
|
4
|
-
//
|
|
5
|
-
// Created by ByteDance on 11/6/24.
|
|
6
|
-
//
|
|
7
|
-
import RealityKit
|
|
8
|
-
import SwiftUI
|
|
9
|
-
|
|
10
|
-
extension View {
|
|
11
|
-
@ViewBuilder
|
|
12
|
-
func `if`<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View {
|
|
13
|
-
if condition {
|
|
14
|
-
transform(self)
|
|
15
|
-
} else {
|
|
16
|
-
self
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
struct SpatialViewUI: View {
|
|
22
|
-
@Environment(SpatialEntity.self) var ent: SpatialEntity
|
|
23
|
-
@State var isRoot = false
|
|
24
|
-
|
|
25
|
-
// Entity which will contain all the content of this realityView and scale to fit frame
|
|
26
|
-
@State var world = Entity()
|
|
27
|
-
@State var portal = Entity()
|
|
28
|
-
@State var light = PointLight()
|
|
29
|
-
@State var portalModel = ModelComponent(
|
|
30
|
-
mesh: .generatePlane(width: 1.0, height: 1.0, cornerRadius: 0.0),
|
|
31
|
-
materials: [PortalMaterial()]
|
|
32
|
-
)
|
|
33
|
-
@State var worldComponent = WorldComponent()
|
|
34
|
-
|
|
35
|
-
private func toJson(val: SIMD3<Float>) -> String {
|
|
36
|
-
return "{x: " + String(val.x) + ",y: " + String(val.y) + ",z: " + String(val.z) + "}"
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
var dragGesture: some Gesture {
|
|
40
|
-
DragGesture(minimumDistance: 0).handActivationBehavior(.automatic)
|
|
41
|
-
.targetedToAnyEntity()
|
|
42
|
-
.onChanged { value in
|
|
43
|
-
let startPos = value.convert(value.startLocation3D, from: .local, to: .scene)
|
|
44
|
-
let translate = value.convert(value.location3D, from: .local, to: .scene)
|
|
45
|
-
let spatialEntity = value.entity.components[SpatialBridgeComponent.self]!.spatialEntity
|
|
46
|
-
let ic = spatialEntity.getComponent(SpatialInputComponent.self)!
|
|
47
|
-
|
|
48
|
-
if !ic.isDragging {
|
|
49
|
-
ic.isDragging = true
|
|
50
|
-
ic.trackedPosition = startPos
|
|
51
|
-
let delta = translate - ic.trackedPosition
|
|
52
|
-
ic.trackedPosition = translate
|
|
53
|
-
|
|
54
|
-
ic.wv!.fireComponentEvent(componentId: ic.id, data: "{eventType: 'dragstart', translate: " + toJson(val: delta) + "}")
|
|
55
|
-
} else {
|
|
56
|
-
let delta = translate - ic.trackedPosition
|
|
57
|
-
ic.trackedPosition = translate
|
|
58
|
-
ic.wv!.fireComponentEvent(componentId: ic.id, data: "{eventType: 'drag', translate: " + toJson(val: delta) + "}")
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
.onEnded { value in
|
|
62
|
-
let spatialEntity = value.entity.components[SpatialBridgeComponent.self]!.spatialEntity
|
|
63
|
-
let ic = spatialEntity.getComponent(SpatialInputComponent.self)!
|
|
64
|
-
ic.wv!.fireComponentEvent(componentId: ic.id, data: "{eventType: 'dragend'}")
|
|
65
|
-
ic.isDragging = false
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
var body: some View {
|
|
70
|
-
if let viewComponent = ent.getComponent(SpatialViewComponent.self) {
|
|
71
|
-
GeometryReader3D { proxy in
|
|
72
|
-
// Get dimensions of the frame
|
|
73
|
-
let proxySize3d = proxy.frame(in: .local)
|
|
74
|
-
|
|
75
|
-
RealityView { _, _ in
|
|
76
|
-
} update: { content, attachments in
|
|
77
|
-
// Scale content so it will be a 1x1x1 space and not exceed the frame
|
|
78
|
-
let viewSpaceDimensions = content.convert(proxySize3d, from: .local, to: content)
|
|
79
|
-
let newScale = min(viewSpaceDimensions.extents.x, viewSpaceDimensions.extents.y)
|
|
80
|
-
|
|
81
|
-
world.transform.scale.x = newScale
|
|
82
|
-
world.transform.scale.y = newScale
|
|
83
|
-
world.transform.scale.z = newScale
|
|
84
|
-
portal.transform.scale.x = newScale
|
|
85
|
-
portal.transform.scale.y = newScale
|
|
86
|
-
portal.transform.scale.z = newScale
|
|
87
|
-
|
|
88
|
-
if !isRoot {
|
|
89
|
-
// Pull out content so volume sits in front of the page
|
|
90
|
-
world.transform.translation.z = world.transform.scale.z / 2
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
for (_, entity) in ent.getEntities() {
|
|
94
|
-
world.addChild(entity.modelEntity)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Add attachments for window entities
|
|
98
|
-
let entities = ent.getEntities().filter { _, entity in
|
|
99
|
-
entity.coordinateSpace == .APP && entity.hasComponent(SpatialWindowComponent.self)
|
|
100
|
-
}
|
|
101
|
-
for key in Array(entities.keys) {
|
|
102
|
-
let e = entities[key]!
|
|
103
|
-
let windowComponent = e.getComponent(SpatialWindowComponent.self)
|
|
104
|
-
if windowComponent != nil && e.coordinateSpace == .APP {
|
|
105
|
-
if let windowAttachment = attachments.entity(for: key) {
|
|
106
|
-
if e.modelEntity.children.count == 0 {
|
|
107
|
-
e.modelEntity.addChild(windowAttachment, preservingWorldTransform: false)
|
|
108
|
-
|
|
109
|
-
// Scale the window to fit the resolution to unit ratio as defined by setResolution API
|
|
110
|
-
let b = windowAttachment.attachment.bounds
|
|
111
|
-
let wv = e.getComponent(SpatialWindowComponent.self)!
|
|
112
|
-
let scaleFact = (Float(wv.resolutionX) / 1360.0) / (b.max.x - b.min.x)
|
|
113
|
-
windowAttachment.scale.x = scaleFact
|
|
114
|
-
windowAttachment.scale.y = scaleFact
|
|
115
|
-
windowAttachment.scale.z = scaleFact
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
if viewComponent.isPortal {
|
|
121
|
-
// Setup portal
|
|
122
|
-
portal.components.set(portalModel)
|
|
123
|
-
portal.transform.translation.z = 0.0001 // avoid z fighting
|
|
124
|
-
if !portal.components.has(PortalComponent.self) {
|
|
125
|
-
portal.components.set(PortalComponent(target: world))
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Setup default light
|
|
129
|
-
light.light.intensity = 5000
|
|
130
|
-
light.position.z = 2
|
|
131
|
-
light.position.y = 1
|
|
132
|
-
light.position.x = 0.5
|
|
133
|
-
world.addChild(light)
|
|
134
|
-
|
|
135
|
-
// Position volume behind portal instead of in front
|
|
136
|
-
world.transform.translation.z *= -1
|
|
137
|
-
|
|
138
|
-
// Add portal to scene
|
|
139
|
-
world.components.set(worldComponent)
|
|
140
|
-
content.add(portal)
|
|
141
|
-
} else {
|
|
142
|
-
// Remove portal elements/components
|
|
143
|
-
content.remove(portal)
|
|
144
|
-
world.components.remove(WorldComponent.self)
|
|
145
|
-
world.removeChild(light)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
content.add(world)
|
|
149
|
-
}
|
|
150
|
-
attachments: {
|
|
151
|
-
// Create an attachment for each window component
|
|
152
|
-
let entities = ent.getEntities().filter { _, entity in
|
|
153
|
-
entity.coordinateSpace == .APP && entity.hasComponent(SpatialWindowComponent.self)
|
|
154
|
-
}
|
|
155
|
-
ForEach(Array(entities.keys), id: \.self) { key in
|
|
156
|
-
let entity = entities[key]!
|
|
157
|
-
let wv = entity.getComponent(SpatialWindowComponent.self)!
|
|
158
|
-
Attachment(id: key) {
|
|
159
|
-
SpatialWebViewUI().environment(entity).frame(width: wv.resolutionX, height: wv.resolutionY)
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}.gesture(dragGesture).if(!isRoot) { view in
|
|
163
|
-
view.clipped()
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// SpatialWebViewUI.swift
|
|
3
|
-
// web-spatial
|
|
4
|
-
//
|
|
5
|
-
// Created by ByteDance on 5/9/24.
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
import RealityKit
|
|
9
|
-
import SwiftUI
|
|
10
|
-
|
|
11
|
-
// Using scrollview has some side effects so only use it on elements we want to clip the edges of
|
|
12
|
-
// Seems only scrollview has this clipping property so far on visionOS otherwise we would use ZStack
|
|
13
|
-
struct OptionalClip<Content: View>: View {
|
|
14
|
-
var clipEnabled = true
|
|
15
|
-
let viewBuilder: () -> Content
|
|
16
|
-
|
|
17
|
-
var body: some View {
|
|
18
|
-
if clipEnabled {
|
|
19
|
-
ScrollView {
|
|
20
|
-
viewBuilder()
|
|
21
|
-
}.offset(z: CGFloat(0)).frame(maxWidth: .infinity, maxHeight: .infinity).scrollDisabled(true)
|
|
22
|
-
} else {
|
|
23
|
-
viewBuilder()
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
struct SpatialWebViewUI: View {
|
|
29
|
-
@Environment(SpatialEntity.self) var ent: SpatialEntity
|
|
30
|
-
var body: some View {
|
|
31
|
-
if let wv = ent.getComponent(SpatialWindowComponent.self) {
|
|
32
|
-
let parentYOffset = Float(wv.scrollOffset.y)
|
|
33
|
-
|
|
34
|
-
let childEntities = ent.getEntities()
|
|
35
|
-
|
|
36
|
-
// Display child entities of the webview
|
|
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) {
|
|
44
|
-
if e.coordinateSpace == .DOM {
|
|
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(
|
|
59
|
-
x: CGFloat(e.modelEntity.scale.x),
|
|
60
|
-
y: CGFloat(e.modelEntity.scale.y),
|
|
61
|
-
z: CGFloat(e.modelEntity.scale.z),
|
|
62
|
-
anchor: anchor
|
|
63
|
-
)
|
|
64
|
-
.rotation3DEffect(
|
|
65
|
-
Rotation3D(simd_quatf(
|
|
66
|
-
ix: e.modelEntity.orientation.vector.x,
|
|
67
|
-
iy: e.modelEntity.orientation.vector.y,
|
|
68
|
-
iz: e.modelEntity.orientation.vector.z,
|
|
69
|
-
r: e.modelEntity.orientation.vector.w
|
|
70
|
-
)),
|
|
71
|
-
anchor: anchor
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
.position(x: x, y: y)
|
|
75
|
-
.offset(z: z)
|
|
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
|
-
)
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
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
|
-
}
|
|
145
|
-
}
|
|
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?")
|
|
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
|
-
}
|
|
162
|
-
}
|
|
163
|
-
.foregroundColor(.white)
|
|
164
|
-
}
|
|
165
|
-
.frame(maxWidth: .infinity, maxHeight: .infinity).glassBackgroundEffect()
|
|
166
|
-
|
|
167
|
-
} else {
|
|
168
|
-
wv.getView()
|
|
169
|
-
.materialWithBorderCorner(
|
|
170
|
-
wv.backgroundMaterial,
|
|
171
|
-
wv.cornerRadius
|
|
172
|
-
)
|
|
173
|
-
|
|
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)
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
// VolumetricWindowContainerView.swift
|
|
4
|
-
// web-spatial
|
|
5
|
-
//
|
|
6
|
-
// Created by ByteDance on 5/9/24.
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
import typealias RealityKit.Attachment
|
|
10
|
-
import typealias RealityKit.Entity
|
|
11
|
-
import typealias RealityKit.MeshResource
|
|
12
|
-
import typealias RealityKit.Model3D
|
|
13
|
-
import typealias RealityKit.ModelEntity
|
|
14
|
-
import typealias RealityKit.RealityView
|
|
15
|
-
import typealias RealityKit.SimpleMaterial
|
|
16
|
-
import SwiftUI
|
|
17
|
-
|
|
18
|
-
struct VolumetricWindowContainerView: View {
|
|
19
|
-
@Environment(SpatialWindowContainer.self) var windowContainerContent: SpatialWindowContainer
|
|
20
|
-
|
|
21
|
-
var body: some View {
|
|
22
|
-
OpenDismissHandlerUI().environment(windowContainerContent).onDisappear {
|
|
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
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
let entities = windowContainerContent.getEntities().filter { _, entity in
|
|
30
|
-
entity.coordinateSpace == .ROOT && entity.hasComponent(SpatialViewComponent.self)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
ForEach(Array(entities.keys), id: \.self) { key in
|
|
34
|
-
let entity = entities[key]!
|
|
35
|
-
SpatialViewUI(isRoot: true).environment(entity)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|