●TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13●OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude Code●SIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App Store●MAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessage●NATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core ML●SEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round●TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13●OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude Code●SIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App Store●MAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessage●NATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core ML●SEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Rork Max × visionOS Spatial Computing App Development Guide— Build Vision Pro Apps with AI
A comprehensive guide to building visionOS spatial computing apps with Rork Max. Learn RealityKit, Immersive Spaces, 3D content placement, and hand tracking implementation patterns with full code examples.
Apple Vision Pro has opened a new frontier in spatial computing. As of 2026, the visionOS ecosystem is growing rapidly, with spatial-first apps appearing on the App Store at an accelerating pace.
However, building for visionOS is fundamentally different from traditional iOS or macOS development. You need to design UI in 3D space, render content with RealityKit, and handle entirely new input models like hand gestures and eye tracking.
Rork Max generates native Swift code through AI-driven prompts. For visionOS apps built on SwiftUI + RealityKit, this means you can go from spatial experience design to working implementation efficiently — letting the AI handle the boilerplate while you focus on the experience.
Who this is for: Developers with SwiftUI experience who have built at least one iOS app with Rork Max
Prerequisites:
Rork Max Plan ($200/month)
Xcode 16+ with the visionOS SDK
Apple Vision Pro device or Simulator
Understanding visionOS App Architecture
Three Scene Types: Windows, Volumes, and Immersive Spaces
visionOS apps are composed of three scene types. Understanding these distinctions is the first step in spatial app design.
Scene Type
Characteristics
Best For
Window
Flat 2D window, similar to traditional iOS apps
Settings, lists, text-heavy UI
Volume
A bounded box containing 3D content
3D model viewers, interactive objects
Immersive Space
Uses the full space around the user
AR experiences, spatial games, virtual exhibitions
When creating a project in Rork Max, explicitly state which scene types you need in your prompt. This helps the AI generate the right architectural foundation.
// visionOS app entry point// Window + Immersive Space combination patternimport SwiftUI@mainstruct SpatialGalleryApp: App { @State private var immersionStyle: ImmersionStyle = .mixed var body: some Scene { // Main window (2D UI) WindowGroup { ContentView() } // Immersive space (3D experience) ImmersiveSpace(id: "gallerySpace") { ImmersiveGalleryView() } .immersionStyle(selection: $immersionStyle, in: .mixed, .full) }}// Expected behavior:// - App launches with a 2D window// - User action transitions to the immersive space
Project Setup in Rork Max
To generate a visionOS project with Rork Max, use structured prompts like this:
Create a visionOS app with:
- A main window showing a gallery grid of 3D art pieces
- A volumetric view for previewing selected art in 3D
- An immersive space for the full exhibition experience
- Hand gesture support for rotating and scaling 3D objects
- Spatial audio tied to each art piece location
Target: visionOS 2.0+, Swift 6, SwiftUI + RealityKit
The key is specifying the purpose of each scene type and the interaction model. Vague prompts tend to produce flat, window-only apps that don't take advantage of spatial capabilities.
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦Understand the full workflow from visionOS project setup in Rork Max to App Store submission
✦Master RealityKit and Immersive Space implementation patterns for 3D content placement and spatial UI
✦Learn hands-on techniques for hand tracking, eye input, and spatial audio — interactions unique to Vision Pro
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
RealityKit uses the Entity-Component-System (ECS) pattern. Every 3D object is an Entity, and you attach Components to define its behavior and appearance.
import RealityKitimport RealityKitContentstruct ImmersiveGalleryView: View { @State private var artPieces: [ArtPiece] = [] var body: some View { RealityView { content in // Set up environment lighting let environment = try? await EnvironmentResource( named: "gallery_lighting" ) if let env = environment { content.add(env) } // Arrange 3D models in a circle for (index, piece) in artPieces.enumerated() { let angle = Float(index) / Float(artPieces.count) * 2 * .pi let radius: Float = 3.0 let entity = try? await Entity( named: piece.modelName, in: realityKitContentBundle ) if let model = entity { model.position = SIMD3<Float>( cos(angle) * radius, 1.5, // Position at eye level sin(angle) * radius ) // Rotate to face center model.look( at: SIMD3<Float>(0, 1.5, 0), from: model.position, relativeTo: nil ) // Enable tap interaction model.components.set( InputTargetComponent() ) model.components.set( CollisionComponent( shapes: [.generateBox( size: [0.5, 0.5, 0.5] )] ) ) content.add(model) } } } .gesture(tapGesture) } // Tap gesture for 3D entities private var tapGesture: some Gesture { SpatialTapGesture() .targetedToAnyEntity() .onEnded { value in let entity = value.entity // Play selection animation playSelectionAnimation(on: entity) } } private func playSelectionAnimation(on entity: Entity) { // Scale animation var transform = entity.transform transform.scale = SIMD3<Float>(repeating: 1.3) entity.move( to: transform, relativeTo: entity.parent, duration: 0.3, timingFunction: .easeInOut ) // Reset after 0.3 seconds Task { try? await Task.sleep(for: .seconds(0.3)) transform.scale = SIMD3<Float>(repeating: 1.0) entity.move( to: transform, relativeTo: entity.parent, duration: 0.3, timingFunction: .easeInOut ) } }}// Expected behavior:// - 3D models are arranged in a circle within the immersive space// - Each model faces the center and plays a selection animation on tap
Working with Reality Composer Pro
For managing 3D assets, Reality Composer Pro is essential. In Rork Max projects, assets are managed as a RealityKitContent package bundle.
// Load a scene created in Reality Composer Prolet sceneEntity = try await Entity( named: "GalleryScene", in: realityKitContentBundle)// Find a specific entity within the sceneif let pedestal = sceneEntity.findEntity(named: "Pedestal") { pedestal.components.set( HoverEffectComponent() // Visual feedback on gaze hover )}// Expected behavior:// - The scene designed in Reality Composer Pro loads as-is// - The Pedestal entity shows a hover effect when the user looks at it
Hand Tracking and Spatial Gestures
ARKit Hand Tracking API
Hand tracking is the signature input method on Vision Pro. To access raw hand data, use ARKit's Hand Tracking Provider.
import ARKitclass HandTrackingManager: ObservableObject { private let session = ARKitSession() private let handTracking = HandTrackingProvider() @Published var leftHandPosition: SIMD3<Float>? @Published var rightHandPosition: SIMD3<Float>? @Published var isPinching: Bool = false func startTracking() async { // Check hand tracking authorization guard HandTrackingProvider.isSupported else { print("Hand tracking is not supported") return } do { try await session.run([handTracking]) } catch { print("Failed to start hand tracking: \(error)") return } // Monitor hand anchor updates in real time for await update in handTracking.anchorUpdates { let hand = update.anchor guard hand.isTracked else { continue } // Get wrist position if let wrist = hand.skeleton.joint(.wrist) { let position = hand.originFromAnchorTransform * wrist.anchorFromJointTransform let worldPos = SIMD3<Float>( position.columns.3.x, position.columns.3.y, position.columns.3.z ) await MainActor.run { switch hand.chirality { case .left: self.leftHandPosition = worldPos case .right: self.rightHandPosition = worldPos } } } // Detect pinch gesture // Based on distance between thumb tip and index finger tip if let thumbTip = hand.skeleton.joint(.thumbTip), let indexTip = hand.skeleton.joint( .indexFingerTip ) { let thumbPos = hand.originFromAnchorTransform * thumbTip.anchorFromJointTransform let indexPos = hand.originFromAnchorTransform * indexTip.anchorFromJointTransform let distance = simd_distance( SIMD3<Float>( thumbPos.columns.3.x, thumbPos.columns.3.y, thumbPos.columns.3.z ), SIMD3<Float>( indexPos.columns.3.x, indexPos.columns.3.y, indexPos.columns.3.z ) ) await MainActor.run { self.isPinching = distance < 0.02 // Pinch detected when distance < 2cm } } } }}// Expected behavior:// - Left and right hand positions update in real time// - isPinching becomes true when thumb and index finger are within 2cm
Combining with SwiftUI Gestures
For entity interactions within a RealityView, SwiftUI gesture modifiers offer the cleanest approach.
struct InteractiveModelView: View { @State private var rotation: Rotation3D = .identity @State private var scale: Double = 1.0 var body: some View { RealityView { content in if let model = try? await Entity( named: "ProductModel", in: realityKitContentBundle ) { model.components.set(InputTargetComponent()) model.components.set( CollisionComponent( shapes: [.generateConvex( from: model )] ) ) content.add(model) } } // Rotation gesture .gesture( RotateGesture3D() .targetedToAnyEntity() .onChanged { value in let entity = value.entity entity.orientation = simd_quatf( value.rotation ) } ) // Pinch-to-scale gesture .gesture( MagnifyGesture() .targetedToAnyEntity() .onChanged { value in let entity = value.entity let newScale = Float( max(0.5, min(3.0, value.magnification)) ) entity.scale = SIMD3<Float>( repeating: newScale ) } ) }}// Expected behavior:// - 3D model rotates with two-hand rotation gestures// - Pinch in/out scales the model between 0.5x and 3.0x
Implementing Spatial Audio
Vision Pro's spatial audio engine reproduces natural 3D sound based on source positions in space. With RealityKit's audio components, you simply attach a sound source to an entity to get spatial audio working.
func attachSpatialAudio( to entity: Entity, audioFile: String) async { // Load spatial audio resource guard let resource = try? await AudioFileResource( named: audioFile, configuration: AudioFileResource.Configuration( shouldLoop: true, shouldRandomizeStartTime: false ) ) else { print("Failed to load audio: \(audioFile)") return } // Configure spatial audio component let audioSource = Entity() audioSource.spatialAudio = SpatialAudioComponent( directivity: .beam(focus: 0.5) // Directivity: beam focuses sound in a specific direction ) audioSource.spatialAudio?.gain = -10 // Volume in dB entity.addChild(audioSource) // Start playback audioSource.playAudio(resource)}// Expected behavior:// - Spatial audio plays based on the entity's position// - Volume increases as the user moves closer, decreases when moving away// - Directivity settings make sound loudest from the front
Performance Optimization Best Practices
visionOS apps run in real time. Frame rate drops cause discomfort (VR sickness), so performance optimization is critical.
3D Asset Optimization Checklist
Item
Recommended Value
Reason
Polygon count (per scene)
Under 100,000
Reduce GPU load
Texture size
Max 2048×2048
Limit memory consumption
LOD (Level of Detail)
3+ levels
Adjust draw calls by distance
Animation keyframes
30fps
Prevent interference with 60fps rendering
Memory Management and Entity Lifecycle
class SceneManager: ObservableObject { private var loadedEntities: [String: Entity] = [:] private let maxCachedEntities = 20 /// Lazy-load entities with LRU cache func loadEntity(named name: String) async -> Entity? { // Return from cache if available if let cached = loadedEntities[name] { return cached.clone(recursive: true) } // Load fresh guard let entity = try? await Entity( named: name, in: realityKitContentBundle ) else { return nil } // Evict oldest entry if cache is full if loadedEntities.count >= maxCachedEntities { let oldest = loadedEntities.keys.first! loadedEntities.removeValue(forKey: oldest) } loadedEntities[name] = entity return entity.clone(recursive: true) } /// Clean up on scene transitions func clearScene(content: RealityViewContent) { content.entities.forEach { entity in entity.removeFromParent() } // Clear entity cache as well loadedEntities.removeAll() }}// Expected behavior:// - 3D models managed via LRU cache, keeping memory usage bounded// - Entities and cache properly cleaned up on scene transitions
Profiling with Instruments
After opening your Rork Max-generated project in Xcode, use the RealityKit Trace template in Instruments to profile:
Render Time: Per-frame rendering duration (target: under 16.6ms)
Entity Count: Active entities in the scene
Texture Memory: Memory consumed by textures
Physics Simulation: Processing time for physics calculations
Maintaining a stable 90fps is the minimum bar for a comfortable spatial experience. If you see frequent frame drops, start by reducing polygon counts and compressing textures — these typically yield the biggest gains.
Prompt Engineering Tips for visionOS in Rork Max
Getting the best results from Rork Max for visionOS apps comes down to how you write your prompts.
Describing Spatial Layouts in Text
3D layouts are hard to communicate in text alone. Be explicit about the coordinate system (X: left/right, Y: up/down, Z: forward/back) and describe spatial relationships with numbers.
Place the main control panel as a Window 1.5 meters
in front of the user at eye level (Y=1.6m).
Add a Volume with a 3D globe model 0.8 meters
to the right of the panel.
The immersive space should display a starfield
environment at 10 meters distance in all directions.
Specifying Interaction Behavior
When the user looks at a planet entity for 1.5 seconds,
show a tooltip Window anchored 20cm above the entity.
When the user pinches the planet,
start a rotation animation at 10 degrees/second.
Two-hand scale gesture should resize between 0.3x and 5.0x.
By specifying trigger conditions, actions, and numerical parameters, you dramatically increase the likelihood that the AI generates the exact interaction you intended.
A Note from an Indie Developer
Key Takeaways
Building spatial computing apps for visionOS demands a different skillset from traditional mobile development. But with Rork Max's AI code generation, you can skip much of the SwiftUI + RealityKit boilerplate and focus on what matters — designing the experience and building your business logic.
Here are the key takeaways from this guide:
Use the three visionOS scene types (Window, Volume, Immersive Space) intentionally based on your app's needs
Understand RealityKit's ECS architecture and compose Entity functionality through Components
Combine hand tracking with SwiftUI gestures for intuitive spatial interactions
Use spatial audio to create a genuinely immersive sense of presence
Prioritize performance optimization to maintain a stable 90fps
The spatial computing market is still in its early stages, and getting in now gives you a real first-mover advantage. Start with a simple Volume app, then progressively add Immersive Space features as you gain confidence with the platform.
Share
Thank You for Reading
Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.