← Back to list

visionOS Development: Build Apps for Apple Vision Pro

Getting started with spatial computing

Chandra Welim · 2026-03-12 02:01 · 0 claps · 4.0 min read
#visionos #apple #swift #ar-vr #technology
Open on Medium ↗
Wiki topics: 3D · Motion & 3D Design 📱 · Mobile Development 🎮 · Gaming

Photo by Joshua Hoehne on Unsplash

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:

  1. File → New → Project
  2. visionOS → App
  3. 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:

  1. Window placement: Windows float in space. Don’t assume position.
  2. Comfortable viewing: Keep content at arm’s length (1–2 meters).
  3. Depth subtlety: Use depth sparingly. Too much causes discomfort.
  4. Eye fatigue: Don’t require constant focusing. Provide visual rest.
  5. 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:

  1. Add visionOS as deployment target
  2. Test in simulator
  3. Add glass effects, ornaments
  4. Consider volumetric elements
  5. 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