Building native visionOS apps
Build native visionOS apps — Swift + SwiftUI + RealityKit + ARKit, authored
in Xcode with Reality Composer Pro. Native is the right default: it gets the full
system look-and-feel, the lowest latency, every OS feature, and the smoothest App
Store path. Unity's PolySpatial is the alternative for teams with an existing
Unity codebase or a fully-immersive game; treat it as out of scope here.
This skill ships a buildable starter project and focused reference files.
Read the references on demand — do not dump them all into context. The map is the
decision tree below.
Start here: the mental model
visionOS apps are SwiftUI apps whose App.body is composed of scenes. There
are three scene types, and choosing among them is the single most important
design decision:
| Scene |
What it is |
Lives in |
Use when |
Window (WindowGroup, .plain/default) |
A flat 2D panel (can host 3D via Model3D/RealityView) |
Shared Space (alongside other apps) |
Most UI, the launch surface, anything that's "an app window" |
Volume (WindowGroup + .windowStyle(.volumetric)) |
A bounded 3D box, sized in meters, viewable from any angle |
Shared Space |
A 3D object/model the user inspects (a globe, a game board, a car) |
Immersive Space (ImmersiveSpace) |
Content placed anywhere around the user |
Full Space (the app, optionally exclusive) |
Surround experiences, room-scale content, anything beyond a box |
Shared Space vs. Full Space is the other axis. By default apps run in the
Shared Space (windows + volumes coexist with other apps). Opening an
ImmersiveSpace moves the app into the Full Space, where content can be placed
freely and other apps optionally hidden. Immersion has three styles:
.mixed — app content blended with passthrough of the real room (AR).
.progressive — a partial portal; the user dials immersion with the Digital Crown.
.full — passthrough fully replaced by the app's environment (VR).
RealityKit's 3D content lives in entities (an Entity–Component–System world)
and is presented to SwiftUI through RealityView. 3D assets are authored in
Reality Composer Pro and loaded from a Swift package by name. ARKit
(ARKitSession + data providers) supplies hand tracking, world sensing, etc.,
and only delivers data while an immersive space is open.
That is the whole architecture. Everything else is detail in the references.
Decision tree → which reference to read
- Setting up the project / Xcode / permissions / Swift 6 concurrency?
→
references/project-setup.md, then scaffold with the template (below).
- Deciding/working with windows, volumes, immersive spaces, ornaments, opening/dismissing scenes?
→
references/app-structure.md
- Anything with 3D content — entities, components, systems, RealityView, materials, animation, audio, attachments, portals, particles?
→
references/realitykit.md
- Authoring/importing 3D assets, USD/USDZ, shader graphs, the content package?
→
references/reality-composer-pro.md
- Hand tracking, world/plane/scene/image/object/room tracking, world anchors, permissions?
→
references/arkit.md
- Gestures, taps/drags/rotate/zoom on 3D, eye+hand targeting, hover, accessibility?
→
references/interaction.md
- Deep immersion, passthrough control, fully-custom Metal rendering (Compositor Services), spatial & immersive video/photos?
→
references/immersive-and-rendering.md
- Shared experiences (SharePlay, Spatial Personas, GroupActivities) or visionOS Enterprise APIs (camera access, etc.)?
→
references/shareplay-and-enterprise.md
- Designing it well (spatial HIG, ergonomics, comfort, materials, typography)?
→
references/design-hig.md
- Performance, profiling (Instruments/RealityKit Trace), testing, App Store submission?
→
references/performance-testing-shipping.md
- What changed across visionOS 1→2→26→27, or need the primary-source citations?
→
references/versions-and-sources.md
When the latest API details matter, verify against current Apple documentation
(developer.apple.com — the ARKit, RealityKit, and SwiftUI references, plus the
"What's new" updates pages) using whatever web-search or docs tools are
available — visionOS moves fast and training data may lag a release.
The build workflow
Confirm prerequisites (see end of this file). If full Xcode + the
visionOS SDK are not installed, say so up front — building or running a
visionOS app is impossible without them; the simulator ships inside Xcode.
Scaffold from the template rather than hand-rolling project files:
python3 <skill>/scripts/new_visionos_app.py "AppName" \
--bundle-id com.yourco.appname --dest ~/Developer/AppName
This produces a verified source tree (a window, a volume, an immersive space,
and a Reality Composer Pro package), renames everything, and runs
xcodegen generate if XcodeGen is installed. See
assets/templates/VisionApp/README.md. Then open AppName.xcodeproj, pick
the Apple Vision Pro simulator, and Run.
Build features by reading the relevant reference(s) and following their
patterns. Keep AppModel (@Observable, @MainActor) as the shared state
passed through the SwiftUI environment.
Verify behavior before claiming success. Never assume the user can
validate the code by reading it — run it. In the simulator: launch the app,
open each scene, exercise the feature. Capture a screenshot or describe the observed
behavior. When only code edits are possible (e.g. no Xcode here), say so
plainly and provide exact steps for the user to verify on their Mac.
Profile and tidy before shipping — frame rate, entity/draw-call budgets,
memory — using the guidance in references/performance-testing-shipping.md.
High-leverage rules (the things that most often go wrong)
The "why" matters more than the rule — understand it and the rest generalizes.
ARKit data only flows inside an open immersive space. Hand/world tracking
returns nothing from a plain window. Gate provider setup on the space being
open, and request authorization (session.requestAuthorization /
implicit-on-run) before relying on data. Add the matching usage-description
key (NSHandsTrackingUsageDescription, NSWorldSensingUsageDescription) only
when actually adopting the provider.
Stay on the main actor for RealityKit + SwiftUI. Under Swift 6 strict
concurrency, entity mutation, RealityView closures, and UI updates belong on
@MainActor. Do heavy asset/IO work off-main, then hop back to mutate the scene.
Immersive-space state is async and can change on its own. The system can
dismiss the space (Digital Crown, focus loss). Drive UI from real lifecycle
(onAppear/onDisappear of the immersive view), not from the return of
openImmersiveSpace, and guard against double open/dismiss. The template's
ToggleImmersiveSpaceButton shows the pattern.
Load content by name from the content bundle, not by file path:
try await Entity(named: "Scene", in: realityKitContentBundle). Asset names
come from Reality Composer Pro, and loaders are async throws — handle both.
Position is in meters, the origin is the user, +Y is up, −Z is forward/away.
A SIMD3 of [0, 1.5, -1.5] is roughly eye height, 1.5 m in front. Tiny numbers
are correct; if something "disappears," it is usually centimeters from the
user's face or kilometers away.
An entity needs InputTargetComponent + a CollisionComponent to receive
gestures, and HoverEffectComponent to react to where the user looks. No
collision shape → taps/drags silently do nothing.
The simulator cannot do everything. No real eye/hand input, no passthrough
camera, limited tracking. Design for it, but validate genuinely spatial input
on device. Note this when only the simulator is available.
Prefer system materials and standard components (glass backgrounds, hover
effects, standard ornaments) — they get correct lighting, accessibility, and
ergonomics for free, and keep the app feeling native.
Platform status (verify before relying on it — visionOS moves fast)
As of mid-2026 (research-dated 2026-06-19):
- visionOS 26 is the current shipping line (year-based numbering jumped 2 → 26
at WWDC 2025 to align with iOS/macOS 26); point releases through 26.6.
- visionOS 27 was announced at WWDC 2026 (session 287), shipping fall 2026 —
treat its APIs as pre-GA and subject to change.
- App Store: since April 28, 2026, uploads must be built with Xcode 26+
using the visionOS 26 SDK or later.
- Hardware: the M5 Apple Vision Pro ($3,499, Oct 2025) is current; no
cheaper/newer headset has shipped. Hand tracking is 90Hz (was 30Hz on visionOS 1).
references/versions-and-sources.md has the full visionOS 1→2→26→27 delta table
and the primary-source citation index. Re-confirm "latest" claims against Apple's
docs (developer.apple.com, via available web-search tools) before stating them.
Prerequisites & environment
- macOS with Xcode 26+ and the visionOS SDK (Xcode ▸ Settings ▸
Components). The visionOS Simulator is bundled with Xcode.
- Swift 6 language mode (the template enables
SWIFT_STRICT_CONCURRENCY).
- Optional but recommended: XcodeGen (
brew install xcodegen) for the
scaffold script's project generation.
- A physical Apple Vision Pro is needed for true input/passthrough testing
but not for development; most work happens in the simulator.
If a required piece is missing, surface it immediately and offer to help install
it — do not generate code and imply it ran when it could not.
What's in this skill
visionos-dev/
├── SKILL.md (this file — orientation + workflow + map)
├── references/ (read on demand; see the decision tree)
├── scripts/new_visionos_app.py (scaffold a renamed copy of the template)
└── assets/templates/VisionApp/ (verified buildable starter: window + volume
+ immersive space + RealityKitContent package)
1---2name: visionos-dev3description: This skill should be used to build native Apple visionOS apps (Apple Vision Pro / spatial computing) in Swift with SwiftUI, RealityKit, ARKit, and Reality Composer Pro — whenever the user wants to create, scaffold, design, debug, or extend a visionOS / Vision Pro / spatial / immersive app: windows, volumetric (3D) windows, immersive spaces (mixed/progressive/full), RealityView and RealityKit entities/components/systems, hand & world tracking, spatial gestures, attachments, portals, spatial/immersive video, SharePlay Spatial Personas, TabletopKit, or the visionOS Enterprise APIs — even when the request never says "visionOS" (e.g. "an app for the Vision Pro", "a mixed reality app for Apple's headset", "place 3D content in the room"). Also covers visionOS Xcode setup, permissions, performance, and App Store submission. NOT for handheld iPhone/iPad ARKit games, the Vision computer-vision framework, VisionKit scanning, Unity/Unreal headset apps, or generic non-spatial SwiftUI.4---56# Building native visionOS apps78Build **native** visionOS apps — Swift + SwiftUI + RealityKit + ARKit, authored9in Xcode with Reality Composer Pro. Native is the right default: it gets the full10system look-and-feel, the lowest latency, every OS feature, and the smoothest App11Store path. Unity's PolySpatial is the alternative for teams with an existing12Unity codebase or a fully-immersive game; treat it as out of scope here.1314This skill ships a **buildable starter project** and **focused reference files**.15Read the references on demand — do not dump them all into context. The map is the16decision tree below.1718## Start here: the mental model1920visionOS apps are SwiftUI apps whose `App.body` is composed of **scenes**. There21are three scene types, and choosing among them is the single most important22design decision:2324| Scene | What it is | Lives in | Use when |25|---|---|---|---|26| **Window** (`WindowGroup`, `.plain`/default) | A flat 2D panel (can host 3D via `Model3D`/`RealityView`) | **Shared Space** (alongside other apps) | Most UI, the launch surface, anything that's "an app window" |27| **Volume** (`WindowGroup` + `.windowStyle(.volumetric)`) | A bounded 3D box, sized in meters, viewable from any angle | **Shared Space** | A 3D object/model the user inspects (a globe, a game board, a car) |28| **Immersive Space** (`ImmersiveSpace`) | Content placed anywhere around the user | **Full Space** (the app, optionally exclusive) | Surround experiences, room-scale content, anything beyond a box |2930**Shared Space vs. Full Space** is the other axis. By default apps run in the31Shared Space (windows + volumes coexist with other apps). Opening an32`ImmersiveSpace` moves the app into the Full Space, where content can be placed33freely and other apps optionally hidden. Immersion has three styles:3435- **`.mixed`** — app content blended with passthrough of the real room (AR).36- **`.progressive`** — a partial portal; the user dials immersion with the Digital Crown.37- **`.full`** — passthrough fully replaced by the app's environment (VR).3839RealityKit's **3D content lives in entities** (an Entity–Component–System world)40and is presented to SwiftUI through **`RealityView`**. 3D assets are authored in41**Reality Composer Pro** and loaded from a Swift package by name. ARKit42(`ARKitSession` + data providers) supplies hand tracking, world sensing, etc.,43and **only delivers data while an immersive space is open**.4445That is the whole architecture. Everything else is detail in the references.4647## Decision tree → which reference to read4849- **Setting up the project / Xcode / permissions / Swift 6 concurrency?**50 → `references/project-setup.md`, then scaffold with the template (below).51- **Deciding/working with windows, volumes, immersive spaces, ornaments, opening/dismissing scenes?**52 → `references/app-structure.md`53- **Anything with 3D content — entities, components, systems, RealityView, materials, animation, audio, attachments, portals, particles?**54 → `references/realitykit.md`55- **Authoring/importing 3D assets, USD/USDZ, shader graphs, the content package?**56 → `references/reality-composer-pro.md`57- **Hand tracking, world/plane/scene/image/object/room tracking, world anchors, permissions?**58 → `references/arkit.md`59- **Gestures, taps/drags/rotate/zoom on 3D, eye+hand targeting, hover, accessibility?**60 → `references/interaction.md`61- **Deep immersion, passthrough control, fully-custom Metal rendering (Compositor Services), spatial & immersive video/photos?**62 → `references/immersive-and-rendering.md`63- **Shared experiences (SharePlay, Spatial Personas, GroupActivities) or visionOS Enterprise APIs (camera access, etc.)?**64 → `references/shareplay-and-enterprise.md`65- **Designing it well (spatial HIG, ergonomics, comfort, materials, typography)?**66 → `references/design-hig.md`67- **Performance, profiling (Instruments/RealityKit Trace), testing, App Store submission?**68 → `references/performance-testing-shipping.md`69- **What changed across visionOS 1→2→26→27, or need the primary-source citations?**70 → `references/versions-and-sources.md`7172When the latest API details matter, verify against current Apple documentation73(developer.apple.com — the ARKit, RealityKit, and SwiftUI references, plus the74"What's new" updates pages) using whatever web-search or docs tools are75available — visionOS moves fast and training data may lag a release.7677## The build workflow78791. **Confirm prerequisites** (see end of this file). If full Xcode + the80 visionOS SDK are not installed, say so up front — building or running a81 visionOS app is impossible without them; the simulator ships inside Xcode.82832. **Scaffold from the template** rather than hand-rolling project files:8485 ```bash86 python3 <skill>/scripts/new_visionos_app.py "AppName" \87 --bundle-id com.yourco.appname --dest ~/Developer/AppName88 ```8990 This produces a verified source tree (a window, a volume, an immersive space,91 and a Reality Composer Pro package), renames everything, and runs92 `xcodegen generate` if XcodeGen is installed. See93 `assets/templates/VisionApp/README.md`. Then `open AppName.xcodeproj`, pick94 the **Apple Vision Pro** simulator, and Run.95963. **Build features** by reading the relevant reference(s) and following their97 patterns. Keep `AppModel` (`@Observable`, `@MainActor`) as the shared state98 passed through the SwiftUI environment.991004. **Verify behavior before claiming success.** Never assume the user can101 validate the code by reading it — run it. In the simulator: launch the app,102 open each scene, exercise the feature. Capture a screenshot or describe the observed103 behavior. When only code edits are possible (e.g. no Xcode here), say so104 plainly and provide exact steps for the user to verify on their Mac.1051065. **Profile and tidy** before shipping — frame rate, entity/draw-call budgets,107 memory — using the guidance in `references/performance-testing-shipping.md`.108109## High-leverage rules (the things that most often go wrong)110111The "why" matters more than the rule — understand it and the rest generalizes.112113- **ARKit data only flows inside an open immersive space.** Hand/world tracking114 returns nothing from a plain window. Gate provider setup on the space being115 open, and request authorization (`session.requestAuthorization` /116 implicit-on-`run`) before relying on data. Add the matching usage-description117 key (`NSHandsTrackingUsageDescription`, `NSWorldSensingUsageDescription`) only118 when actually adopting the provider.119120- **Stay on the main actor for RealityKit + SwiftUI.** Under Swift 6 strict121 concurrency, entity mutation, `RealityView` closures, and UI updates belong on122 `@MainActor`. Do heavy asset/IO work off-main, then hop back to mutate the scene.123124- **Immersive-space state is async and can change on its own.** The system can125 dismiss the space (Digital Crown, focus loss). Drive UI from real lifecycle126 (`onAppear`/`onDisappear` of the immersive view), not from the return of127 `openImmersiveSpace`, and guard against double open/dismiss. The template's128 `ToggleImmersiveSpaceButton` shows the pattern.129130- **Load content by name from the content bundle**, not by file path:131 `try await Entity(named: "Scene", in: realityKitContentBundle)`. Asset names132 come from Reality Composer Pro, and loaders are `async throws` — handle both.133134- **Position is in meters, the origin is the user, +Y is up, −Z is forward/away.**135 A SIMD3 of `[0, 1.5, -1.5]` is roughly eye height, 1.5 m in front. Tiny numbers136 are correct; if something "disappears," it is usually centimeters from the137 user's face or kilometers away.138139- **An entity needs `InputTargetComponent` + a `CollisionComponent` to receive140 gestures**, and `HoverEffectComponent` to react to where the user looks. No141 collision shape → taps/drags silently do nothing.142143- **The simulator cannot do everything.** No real eye/hand input, no passthrough144 camera, limited tracking. Design for it, but validate genuinely spatial input145 on device. Note this when only the simulator is available.146147- **Prefer system materials and standard components** (glass backgrounds, hover148 effects, standard ornaments) — they get correct lighting, accessibility, and149 ergonomics for free, and keep the app feeling native.150151## Platform status (verify before relying on it — visionOS moves fast)152153As of mid-2026 (research-dated 2026-06-19):154155- **visionOS 26** is the current shipping line (year-based numbering jumped 2 → 26156 at WWDC 2025 to align with iOS/macOS 26); point releases through 26.6.157- **visionOS 27** was announced at WWDC 2026 (session 287), shipping fall 2026 —158 treat its APIs as pre-GA and subject to change.159- **App Store**: since **April 28, 2026**, uploads must be built with **Xcode 26+**160 using the **visionOS 26 SDK** or later.161- **Hardware**: the **M5 Apple Vision Pro** ($3,499, Oct 2025) is current; no162 cheaper/newer headset has shipped. Hand tracking is 90Hz (was 30Hz on visionOS 1).163164`references/versions-and-sources.md` has the full visionOS 1→2→26→27 delta table165and the primary-source citation index. Re-confirm "latest" claims against Apple's166docs (developer.apple.com, via available web-search tools) before stating them.167168## Prerequisites & environment169170- **macOS** with **Xcode 26+** and the **visionOS SDK** (Xcode ▸ Settings ▸171 Components). The visionOS Simulator is bundled with Xcode.172- **Swift 6** language mode (the template enables `SWIFT_STRICT_CONCURRENCY`).173- Optional but recommended: **XcodeGen** (`brew install xcodegen`) for the174 scaffold script's project generation.175- A physical **Apple Vision Pro** is needed for true input/passthrough testing176 but not for development; most work happens in the simulator.177178If a required piece is missing, surface it immediately and offer to help install179it — do not generate code and imply it ran when it could not.180181## What's in this skill182183```184visionos-dev/185├── SKILL.md (this file — orientation + workflow + map)186├── references/ (read on demand; see the decision tree)187├── scripts/new_visionos_app.py (scaffold a renamed copy of the template)188└── assets/templates/VisionApp/ (verified buildable starter: window + volume189 + immersive space + RealityKitContent package)190```