Spatial Preview is a new macOS/visionOS framework that lets Mac apps share and synchronize 2D and 3D content (images, PDFs, USD scenes) directly to Apple Vision Pro via Mac Virtual Display or a device picker, launching it in QuickLook immersively with no visionOS code required.
⢠Enables content-creation tools (3D design, video, architecture) to offer real-time spatial review on Vision Pro with just a few lines of macOS code
⢠USD preview sessions support live two-way synchronization ā edits, annotations, and object moves on Vision Pro are reflected back on Mac instantly
⢠Built-in automatic scene optimization (mesh decimation, texture downsampling) ensures complex USD assets run well on Vision Pro without manual tuning
Demonstrates starting a SpatialPreview document session using the Mac Virtual Display endpoint, then swapping between Apple Immersive Video frame files in the same QuickLook scene on Vision Pro via updateContents.
import SwiftUI
import SpatialPreview
struct ImmersiveGalleryView: View {
// URLs of Apple Immersive Video frame files on disk
let frameURLs: [URL]
@State private var session: DocumentPreviewSession?
@State private var endpoint: SpatialPreviewEndpoint?
@State private var showDevicePicker = false
@State private var sessionInvalidated = false
var body: some View {
VStack(spacing: 16) {
Text("Immersive Rendering Gallery")
.font(.headline)
if session == nil {
Button("Start Spatial Preview") {
Task { await startSession() }
}
Button("Pick Vision Pro Device") {
showDevicePicker = true
}
} else {
ForEach(Array(frameURLs.enumerated()), id: \.offset) { index, url in
Button("Frame \(index + 1)") {
Task { await swapFrame(to: url) }
}
}
Button("Close Session", role: .destructive) {
session?.close()
session = nil
}
}
if sessionInvalidated {
Text("Session closed on Vision Pro.")
.foregroundStyle(.secondary)
}
}
.padding()
.sheet(isPresented: $showDevicePicker) {
SpatialPreviewDevicePickerView { picked in
endpoint = picked
showDevicePicker = false
Task { await startSession() }
}
}
.task {
// Observe the Mac Virtual Display connected endpoint
let observer = ConnectedSpatialEndpointObserver()
for await connectedEndpoint in observer.endpoints {
endpoint = connectedEndpoint
}
}
}
private func startSession() async {
guard let endpoint, let firstURL = frameURLs.first else { return }
let newSession = DocumentPreviewSession(
documentType: .immersiveVideoFrame,
name: "Rendering Gallery"
)
do {
try await newSession.start(on: endpoint, contentURL: firstURL)
session = newSession
observeSessionState(newSession)
} catch {
print("Failed to start session: \(error)")
}
}
private func swapFrame(to url: URL) async {
do {
try await session?.updateContents(contentURL: url)
} catch {
print("Failed to update contents: \(error)")
}
}
private func observeSessionState(_ s: DocumentPreviewSession) {
Task {
for await state in s.stateUpdates {
if state == .invalidated {
sessionInvalidated = true
session = nil
}
}
}
}
}
Highly complex USD scenes are auto-optimized by default (mesh decimation, texture downsampling, possible full reconstruction); reconstructed scenes cannot be edited on Vision Pro. Pass the .unmodified option to opt out, but an error is thrown at session start if the scene exceeds Vision Pro limits. Mac Virtual Display may not always be active, so always provide the device picker fallback UI.
Requires Apple Vision Pro as the target device; Mac Virtual Display or same-iCloud-account proximity needed for device discovery
More iOS 27 APIs land every week.
Get notified when new capabilities are published ā no noise, just signal.