Lab 048 – No really, open a window
Playing with an idea to hide a portal behind some window content.
Watch the video first!
I’ve wanted to make this for a while now. Here is how it works
- We load a simple scene from Reality Composer Pro
- We show that scene in a portal
- The portal plane is sized for the window
- See this project from Apple: https://developer.apple.com/documentation/visionos/displaying-a-3d-environment-through-a-portal
- We throw some regular SwiftUI content in front of the portal
- Simple state var to indicate open state
- We use that state to offset the SwiftUI content and change the opacity of the RealityView
Lab Example Code
struct Lab048: View {
@State var windowIsOpen = false
// The root for our scene *outside* of the portal
@State var rootEntity = Entity()
// An entity that will render the portal
@State var portalPlane = ModelEntity(
mesh: .generatePlane(width: 1.0, height: 1.0),
materials: [PortalMaterial()]
)
var body: some View {
GeometryReader3D { geometry in
ZStack {
RealityView { content in
// The root for the content that will appear *inside* the portal
let portalContentRoot = Entity()
portalContentRoot.scale *= 0.3
portalContentRoot.position.y -= 0.5
portalContentRoot.components.set(WorldComponent())
// We'll load some content to add to the portalContentRoot
guard let scene = try? await Entity(named: "SkyOutWindow", in: realityKitContentBundle)
else { return }
portalContentRoot.addChild(scene)
portalPlane.components.set(PortalComponent(target: portalContentRoot))
rootEntity.addChild(portalContentRoot)
rootEntity.addChild(portalPlane)
content.add(rootEntity)
} update: { content in
// Resize the scene based on the size of the reality view content.
// Based on the example from Apple https://developer.apple.com/documentation/visionos/displaying-a-3d-environment-through-a-portal
let size = content.convert(geometry.size, from: .local, to: .scene)
portalPlane.model?.mesh = .generatePlane(
width: size.x, height: size.y, cornerRadius: 0.03)
}
.opacity(windowIsOpen ? 1.0 : 0.0)
.frame(depth: 0.4)
VStack {
HStack {
Text("Fruits")
.font(.title)
.frame(height: 60)
Spacer()
Button(
action: {
print("nothing is real")
},
label: {
Text("Add")
})
}
.padding(.horizontal, 24)
.padding(.top, 12)
List {
Text("Apple")
Text("Banana")
Text("Orange")
}
}
.glassBackgroundEffect()
.offset(y: windowIsOpen ? -360 : 0)
}
.frame(width: geometry.size.width, height: geometry.size.height)
}
.ornament(attachmentAnchor: .scene(.bottom)) {
Button(
action: {
print("button pressed")
withAnimation(.easeInOut(duration: 0.3)) {
windowIsOpen.toggle()
}
},
label: {
Text("\(windowIsOpen ? "Close" : "Open") Window")
})
.glassBackgroundEffect()
}
}
}Support our work so we can continue to bring you new examples and articles.

Follow Step Into Vision