Skip to content

Instantly share code, notes, and snippets.

@banjun
Created July 16, 2025 08:12
Show Gist options
  • Save banjun/a9fb69548914ff16ffdfd11e26653def to your computer and use it in GitHub Desktop.
Save banjun/a9fb69548914ff16ffdfd11e26653def to your computer and use it in GitHub Desktop.
Remote visionOS CompositorLayer with required ARKit session enabled for RemoteImmersiveSpace
// copied from Apple Sample Codes: CS_HoverEffect https://developer.apple.com/documentation/compositorservices/rendering_hover_effects_in_metal_immersive_apps
// and modified by banjun
#if os(macOS)
import CompositorServices
import SwiftUI
/// Usage:
/// ```swift
/// RemoteVisionOSARKitLayer { renderer, worldTracker in
/// while renderer.state != .invalidated {
/// guard let frame = renderer.queryNextFrame() else { continue }
/// // draw here
/// }
/// }
/// ```
/// NOTE: RemoteImmersiveSpace requires drawables to be attached a DeviceAnchor, that can be get from WorldTrackingProvider, that can be run in ARKitSession, that can be initialized with \.remoteDeviceIdentifier, that can be obtained after Pairing UI, presented by RemoteImmersiveSpace.
/// NOTE: the `Debug Executable` setting can affect to whether content is head-anchored (debug) or not (not in debug)
struct RemoteVisionOSARKitLayer: CompositorContent {
@Environment(\.remoteDeviceIdentifier) private var remoteDeviceIdentifier: RemoteDeviceIdentifier?
var configuration: any CompositorLayerConfiguration = .default
var renderLoop: (LayerRenderer, WorldTrackingProvider?) async -> Void
var body: some CompositorContent {
CompositorLayer(configuration: configuration) { renderer in
Task(priority: .high) {
if let remoteDeviceIdentifier {
// NSLog("%@", "remoteDeviceIdentifier = \(remoteDeviceIdentifier)")
let arkitSession = ARKitSession(device: remoteDeviceIdentifier)
let worldTracker = WorldTrackingProvider()
// NSLog("%@", "starting arkitSession.run")
try await arkitSession.run([worldTracker])
NSLog("%@", "starting render loop")
await renderLoop(renderer, worldTracker)
NSLog("%@", "reached to end of render loop")
} else {
NSLog("%@", "remoteDeviceIdentifier = \(String(describing: remoteDeviceIdentifier))")
}
}
}
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment