Skip to Content
Course content

192: Building a Simple visionOS App

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I remember sitting with a developer friend of mine, Sarah, a few months after the Vision Pro launched. She had spent a week porting her high-performance task manager from iOS to visionOS. Technically, it was perfect. The buttons worked, the lists scrolled, and the data synced. But when she put the headset on, she looked at me and said, "It feels like I'm just wearing a giant iPad on my face. Where's the magic?"

That's the biggest trap in visionOS development. It's easy to treat the headset like a floating 2D screen, but the real power lies in breaking the "glass" and moving into the user's actual physical environment. To make a visionOS app feel native, you have to stop thinking about pixels and start thinking about volumes.

Designing for Spatial Windows

In a standard Swift app, you're used to the WindowGroup filling the screen. In visionOS, a WindowGroup creates a window that the user can move, resize, and place anywhere in their room. But you have a choice: do you want a flat 2D window, or a Volume? A Volume is essentially a 3D box that allows you to place objects that have depth, which users can walk around.

If you're building something like a 3D model viewer for a furniture store, a flat window is a mistake. You want a Volume. By specifying the .windowStyle(.volumetric) modifier, you tell the system that this window isn't just a piece of glass—it's a physical space. I've found that the most successful apps combine these: a 2D window for settings and controls, and a volumetric window for the actual "thing" the user is interacting with.

Injecting 3D Content via RealityView

Once you've defined your space, you need to actually put something in it. This is where RealityView comes in. Think of RealityView as the spatial equivalent of a Canvas or a SwiftUI.View, but instead of drawing shapes, you're loading Entity objects from RealityKit.

import SwiftUI
import RealityKit

struct SpatialModelView: View {
    var body: some View {
        RealityView { content in
            // Load a 3D model from your app bundle
            if let bonsaiTree = try? await Entity(named: "BonsaiTree") {
                bonsaiTree.position = [0, 0, 0] // Center of the volume
                content.add(bonsaiTree)
            }
        }
    }
}

One thing that tripped me up early on was the coordinate system. Remember that in visionOS, the Z-axis is depth. Positive Z moves the object toward the user, and negative Z pushes it away. If your model disappears the moment the app loads, check your coordinates; you've likely pushed your object behind the user's head.

Orchestrating the Immersive Transition

Sometimes, a window—even a volumetric one—isn't enough. You might want to completely hide the user's living room and transport them to a digital forest or a futuristic command center. This is called an ImmersiveSpace.

You define an ImmersiveSpace in your App struct, and then you use the openImmersiveSpace environment action to trigger the transition. It's a heavy lift for the system, so don't do it unless the experience actually demands it. I always tell my mentees: if the user can accomplish the task in a window, keep them in a window. The "wow factor" of full immersion wears off quickly if it gets in the way of the app's utility.




📋 Practical Task

Build a Spatial Solar System Viewer

Your task is to create a basic visionOS app that allows a user to view a 3D representation of a planet in their room. Follow these requirements:

  • Define a WindowGroup in your App file and set its style to .volumetric.
  • Create a RealityView that loads a 3D entity (you can use any .usdz file available in your assets or a primitive sphere if you don't have a model).
  • Implement a simple SwiftUI slider in a separate 2D window that updates a @State variable, which in turn adjusts the scale of the 3D entity in the RealityView.
  • Ensure the entity is positioned at the origin [0, 0, 0] so it remains centered within the volumetric window.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.