visionOS Development: Build Apps for Apple Vision Pro
Getting started with spatial computing
Photo by Joshua Hoehne on Unsplash
visionOS Development: Build Apps for Apple Vision Pro
Getting started with spatial computing
Vision Pro is Apple’s bet on the future. Spatial computing. Mixed reality. A new platform.
If you’re an iOS developer, you have a head start. visionOS shares foundation with iOS. SwiftUI works. UIKit works (in some cases). Your skills transfer.
But spatial computing is different. 3D interfaces. Depth. Immersion. New interaction paradigms.
Let me show you how to get started.
What visionOS Is
visionOS is a new operating system built for Apple Vision Pro. It’s based on iOS/iPadOS foundations but designed for spatial computing.
Key characteristics:
- Apps run in windows floating in space
- Windows can have depth (3D elements)
- Users interact via eye tracking and hand gestures
- Apps can create immersive experiences
- Compatible iPad/iPhone apps run automatically
App Types
1. Window-based apps (most common):
Traditional apps in floating windows. Good starting point.
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
2. Volumetric apps:
3D content that exists in the user’s space.
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.windowStyle(.volumetric)
.defaultSize(width: 0.5, height: 0.5, depth: 0.5, in: .meters)
}
}
3. Immersive experiences:
Full or mixed immersion that replaces or augments reality.
@main
struct MyApp: App {
var body: some Scene {
ImmersiveSpace(id: "immersive") {
ImmersiveView()
}
}
}
Setting Up Your Project
Requirements:
- Xcode 15+
- macOS Sonoma+
- visionOS SDK
Create a new project:
- File → New → Project
- visionOS → App
- Choose window style
Simulator:
Vision Pro simulator works without hardware. Test window layout, basic interactions, and UI.
For true spatial testing, you need actual hardware.
SwiftUI on visionOS
Most SwiftUI code works unchanged:
struct ContentView: View {
var body: some View {
VStack(spacing: 20) {
Text("Hello, visionOS!")
.font(.largeTitle)
Button("Tap Me") {
print("Tapped!")
}
.buttonStyle(.borderedProminent)
Image(systemName: "visionpro")
.font(.system(size: 80))
}
.padding()
}
}
New features for visionOS:
// Glass background effect
VStack {
// Content
}
.glassBackgroundEffect()
// Hover effects
Button("Hover Me") { }
.hoverEffect(.highlight)
// Depth
Image("photo")
.offset(z: 50) // Push toward user
3D Content with RealityKit
RealityKit brings 3D to your app:
import RealityKit
import RealityKitContent
struct ContentView: View {
var body: some View {
RealityView { content in
// Load a 3D model
if let model = try? await Entity.load(named: "Robot", in: realityKitContentBundle) {
content.add(model)
}
}
}
}
Adding interactions:
struct InteractiveModelView: View {
@State private var rotation: Angle = .zero
var body: some View {
RealityView { content in
if let model = try? await Entity.load(named: "Globe", in: realityKitContentBundle) {
model.components.set(InputTargetComponent())
model.components.set(CollisionComponent(shapes: [.generateSphere(radius: 0.1)]))
content.add(model)
}
}
.gesture(
DragGesture()
.targetedToAnyEntity()
.onChanged { value in
// Rotate based on drag
}
)
}
}
Ornaments
Ornaments are UI attached to windows:
struct ContentView: View {
var body: some View {
MainContent()
.ornament(attachmentAnchor: .scene(.bottom)) {
HStack {
Button("Play") { }
Button("Pause") { }
Button("Stop") { }
}
.padding()
.glassBackgroundEffect()
}
}
}
Immersive Spaces
For full immersion:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
ImmersiveSpace(id: "solar-system") {
SolarSystemView()
}
.immersionStyle(selection: .constant(.mixed), in: .mixed, .full)
}
}
struct ContentView: View {
@Environment(\.openImmersiveSpace) var openImmersiveSpace
@Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
var body: some View {
VStack {
Button("Enter Space") {
Task {
await openImmersiveSpace(id: "solar-system")
}
}
Button("Exit Space") {
Task {
await dismissImmersiveSpace()
}
}
}
}
}
Immersion styles:
.mixed— Virtual content blends with real world.full— Completely replaces surroundings.progressive— User controls immersion level
Hand Tracking
visionOS tracks hands without code. Standard gestures work:
- Tap: Look at element, pinch fingers
- Drag: Pinch and move
- Zoom: Two-hand pinch
- Rotate: Two-hand twist
For custom hand tracking:
import ARKit
class HandTrackingManager {
let session = ARKitSession()
let handTracking = HandTrackingProvider()
func startTracking() async {
do {
try await session.run([handTracking])
for await update in handTracking.anchorUpdates {
let anchor = update.anchor
// Access hand joints
if let thumbTip = anchor.handSkeleton?.joint(.thumbTip) {
let position = thumbTip.anchorFromJointTransform
// Use position
}
}
} catch {
print("Failed to start hand tracking: \(error)")
}
}
}
Eye Tracking
Eye position is used for targeting but privacy-protected:
// You don't get raw eye data
// Instead, use hover effects and look-to-select
Text("Look at me")
.hoverEffect(.highlight) // Highlights when user looks at it
Button("Select Me") { }
// Automatically selected when user looks + pinches
Designing for Vision Pro
Key principles:
- Window placement: Windows float in space. Don’t assume position.
- Comfortable viewing: Keep content at arm’s length (1–2 meters).
- Depth subtlety: Use depth sparingly. Too much causes discomfort.
- Eye fatigue: Don’t require constant focusing. Provide visual rest.
- Input clarity: Hover effects show what’s selectable.
Sizes and distances:
// Human Interface Guidelines recommendations
// Windows: 1-2 meters away
// Interactive elements: minimum 60pt tap target
// Text: minimum 17pt, preferably larger
Bringing Existing Apps
iPad apps run on Vision Pro in compatibility mode. To optimize:
- Add visionOS as deployment target
- Test in simulator
- Add glass effects, ornaments
- Consider volumetric elements
- Test interactions
#if os(visionOS)
// visionOS specific code
VStack { }
.glassBackgroundEffect()
#else
// iOS/iPadOS code
VStack { }
#endif
The Bottom Line
visionOS is new territory. It shares DNA with iOS but requires new thinking.
Start with window-based apps. Your SwiftUI skills transfer. Add spatial features gradually. Think about comfort and usability.
The platform is young. Early adopters will shape what spatial computing becomes.
Quick Reference
// Basic window app
WindowGroup {
ContentView()
}
// Volumetric
WindowGroup {
ContentView()
}
.windowStyle(.volumetric)
// Immersive space
ImmersiveSpace(id: "space") {
View()
}
// Glass effect
view.glassBackgroundEffect()
// 3D content
RealityView { content in
let model = try? await Entity.load(named: "Model")
content.add(model)
}
// Open immersive space
await openImmersiveSpace(id: "space")
Further reading:
*iOS 26 Programming for Beginners is a clear, project-based path from zero to building apps with Swift 6 and Xcode 26. [Mastering Swift 6](https://amzn.to/4rtvbEy)* is the reference I point people to on concurrency, performance, and modern Swift patterns.
References
메타데이터
- post_id
- 47c87a3b0a9b
- slug
- visionos-development-build-apps-for-apple-vision-pro-47c87a3b0a9b
- url
- https://medium.com/@chandra.welim/visionos-development-build-apps-for-apple-vision-pro-47c87a3b0a9b
- canonical_url
- https://medium.com/@chandra.welim/visionos-development-build-apps-for-apple-vision-pro-47c87a3b0a9b
- author_url
- https://medium.com/@chandra.welim
- status
- ok
- fetched_at
- 2026-06-09 14:34:10