2023 Spatial Computing
WWDC23 · 25 min · Spatial Computing
Build spatial SharePlay experiences
Discover how you can use the GroupActivities framework to build unique sharing and collaboration experiences for visionOS. We’ll introduce you to SharePlay on this platform, learn how to create experiences that make people feel present as if they were in the same space, and explore how immersive apps can respect shared context between participants.
Watch at developer.apple.com ↗Code shown on screen · 10 snippets
Observe the local participant state
for await session in ExploreActivity.sessions() {
guard let systemCoordinator = await session.systemCoordinator else { continue }
let isLocalParticipantSpatial = systemCoordinator.localParticipantState.isSpatial
Task.detached {
for await localParticipantState in systemCoordinator.localParticipantStates {
if localParticipantState.isSpatial {
// Start syncing scroll position
} else {
// Stop syncing scroll position
}
}
}
} Configure the spatial template preferences
for await session in ExploreActivity.sessions() {
guard let systemCoordinator = await session.systemCoordinator else { continue }
var configuration = SystemCoordinator.Configuration()
configuration.spatialTemplatePreference = .sideBySide
systemCoordinator.configuration = configuration
session.join()
} Configuring scene activation conditions
@main
struct ExploreTogetherApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.handlesExternalEvents(
preferring: ["com.example.explore-together.activity"],
allowing: ["com.example.explore-together.activity"]
)
}
}
} Configuring scene activation conditions
class SceneDelegate: NSObject, UISceneDelegate {
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// ...
scene.activationConditions.canActivateForTargetContentIdentifierPredicate =
NSPredicate(format: "self == %@", "com.example.explore-together.activity")
scene.activationConditions.prefersToActivateForTargetContentIdentifierPredicate =
NSPredicate(format: "self == %@", "com.example.explore-together.activity")
}
} Setting scene association behavior
struct ExploreActivity: GroupActivity {
var metadata: GroupActivityMetadata {
var metadata = GroupActivityMetadata()
// ...
metadata.sceneAssociationBehavior = .content("document-1")
return metadata
}
} Starting SharePlay
// Create the activity
let activity = ExploreActivity()
// Register the activity on the item provider
let itemProvider = NSItemProvider()
itemProvider.registerGroupActivity(activity)
// Create the activity items configuration
let configuration = UIActivityItemsConfiguration(itemProviders: [itemProvider])
// Provide the metadata for the group activity
configuration.metadataProvider = { key in
guard key == .linkPresentationMetadata else { return nil }
let metadata = LPLinkMetadata()
metadata.title = "Explore Together"
metadata.imageProvider = NSItemProvider(object: UIImage(named: "explore-activity")!)
return metadata
}
self.activityItemsConfiguration = configuration Configure group ImmersiveSpace
for await session in ExploreActivity.sessions() {
guard let systemCoordinator = await session.systemCoordinator else { continue }
var configuration = SystemCoordinator.Configuration()
configuration.supportsGroupImmersiveSpace = true
systemCoordinator.configuration = configuration
} System Experience Displacement
// Use immersiveSpaceDisplacement to offset contents in group immersive space
var body: some Scene {
ImmersiveSpace(id: "earth") {
GeometryReader3D { proxy in
let displacement = proxy.immersiveSpaceDisplacement(in: .global).inverse
Control()
.offset(displacement.position)
.rotation3DEffect(displacement.rotation)
}
}
} Spatial Template Preferences
// Configure the spatial template preferences with content extent
for await session in ExploreSolarActivity.sessions() {
guard let systemCoordinator = await session.systemCoordinator else { continue }
var configuration = SystemCoordinator.Configuration()
configuration.supportsGroupImmersiveSpace = true
configuration.spatialTemplatePreference = .sideBySide.contentExtent(200)
systemCoordinator.configuration = configuration
} Receive group immersion style to configure group immersive space
// Receive group immersion style to configure group immersive space
for await session in ExploreSolarActivity.sessions() {
guard let systemCoordinator = await session.systemCoordinator else { continue }
Task.detached {
for await immersionStyle in systemCoordinator.groupImmersionStyle {
if let immersionStyle {
// Open an immersive space with the same immersion style
} else {
// Dismiss the immersive space
}
}
}
} Resources
Related sessions
-
16 min -
24 min -
14 min -
25 min -
11 min