Spatial SwiftUI Developer
Quick Start
- If the task is really about surface choice, scene ownership, or file
structure, switch to
spatial-app-architecturefirst. - Pick the rendering track:
Model3Dfor simple asset display,RealityViewfor custom entity graphs and attachments. - Load the matching reference only after you know the track you are on:
windowing-immersion.mdfor scene structure and transitionsrealityview.mdfor RealityView, attachments, and update flowmodel3d.mdfor model loading and simple presentationinteraction.mdfor gestures and manipulationspatial-layout.mdfor layout, sizing, and debug helpers
- Implement async loading and keep RealityKit mutations inside
RealityViewclosures or explicit systems. - Route build, launch, simulator, and test problems to the plugin's
build-run-debugworkflow skill instead of expanding this skill with execution steps.
Tracks
Scene Shell
Use this track when the surface model is already chosen and you need to map it to SwiftUI APIs.
- Start with
WindowGroupunless the UI needs volume or immersion. - Use
windowStyle(.volumetric)for volume-style surfaces. - Use
ImmersiveSpaceonly when the experience needs an unbounded spatial scene. - Use
defaultSizeas a hint for initial geometry, not a guarantee.
RealityKit Bridge
Use this track when SwiftUI needs to host real 3D scene content.
- Use
RealityViewfor scene loading, attachments, and state-driven entity updates. - Use
AttachmentorViewAttachmentComponentfor SwiftUI UI placed in 3D. - Keep entity mutation out of SwiftUI body computation.
Interaction and Motion
Use this track when the scene needs direct manipulation or spatial gestures.
- Add
SpatialTapGestureand entity-targeted input where needed. - Prefer attachment-driven labels and controls for UI that must stay SwiftUI-native.
- Use
interaction.mdbefore adding custom gesture or manipulation logic.
Data Visualization
Use this track when the scene is primarily charts or analytic surfaces.
- Load
charts-3d.mdonly after confirming the chart belongs in spatial UI. - Keep chart state separate from the spatial shell so it can be reused in 2D fallbacks.
Load References When
| Reference | When to Use |
|-----------|-------------|
| REFERENCE.md | When you need the general feature map, examples, and routing guidance for this skill. |
| model3d.md | When using Model3D for async model loading, assets, animation, or manipulation. |
| realityview.md | When setting up RealityView, attachments, or RealityKit integration patterns. |
| interaction.md | When implementing gestures or manipulation patterns for spatial input. |
| windowing-immersion.md | When managing windows, volumetric surfaces, or immersive space transitions. |
| spatial-layout.md | When using SwiftUI spatial layout APIs, sizing, or debug tools. |
| charts-3d.md | When implementing Chart3D or other spatial data-visualization patterns. |
Guardrails
- Keep RealityKit loads async; do not block the main actor with asset or entity loading.
- Mutate RealityKit content in
RealityViewmake/update closures or in a system, not in SwiftUI body code. - Use
Model3Donly when you need simple display and layout, not a custom ECS graph. - Treat
ImmersiveSpaceas a separate scene with its own lifecycle and environment actions. - Use
defaultSizeas an initial hint only; the system can clamp or restore geometry. - Switch to the plugin's
build-run-debugskill when the question is about launch, build, simulator, codesign, or debugging workflow. - Use
spatial-app-architecturewhen the question is about scene boundaries, ownership, or feature decomposition rather than API usage.
Core Concepts
Scene and Spatial Presentation
- Use
WindowGroupwithwindowStyle(.volumetric)for volumes. AdddefaultSizewhen you want a predictable initial size, but treat it as a hint rather than a hard guarantee. - Use
ImmersiveSpacefor unbounded spatial scenes andimmersionStyleselection. - Use
openImmersiveSpaceanddismissImmersiveSpacefor transitions. - On visionOS 26, apply
defaultWorldScaling(_:)with aWorldScalingBehaviorwhen you want a volume or window to scale with viewing distance, and usesupportedVolumeViewpoints(_:)+onVolumeViewpointChange(updateStrategy:initial:_:)to adjust layout when the viewer moves around a volume. - Use
volumeBaseplateVisibility(_:)to hide or show the system baseplate under a volume.
RealityKit Embedding in SwiftUI
- Use
RealityViewfor full RealityKit scenes and state-driven updates. - Use
Attachmentand RealityView attachments to embed SwiftUI views in 3D. - Use
ViewAttachmentEntityandViewAttachmentComponentfor attachment entities. - Use
breakthroughEffect(_:)to apply the visionOS 26 breakthrough effect to RealityView attachments when the design calls for it. - Use
visualEffect3D(_:)to layer 3D visual effects on spatial content.
3D Model Presentation
- Use
Model3Dfor async model loading with SwiftUI layout. - Use
Model3DPhaseandModel3DAssetfor loading phases and animation choices.
Spatial Input
- Use
SpatialTapGesturefor spatial tap locations in 2D/3D coordinate spaces.
Implementation Patterns
- Use
Model3Dwhen you only need display and layout; useRealityViewfor custom entity graphs and systems. - Keep RealityKit mutations inside
RealityViewmake/update closures. - Prefer attachments for UI that should remain SwiftUI-driven but positioned in 3D.
- Treat
ImmersiveSpaceas a separate scene with its own lifecycle and environment actions. - Prefer a custom
SystemorSceneEvents.Updatewhen behavior truly needs continuous per-frame updates.
Pitfalls and Checks
- Do not block the main actor with synchronous model or entity loading.
- Do not update RealityKit entities inside SwiftUI body computation.
- Do not use volumetric window style with
Windowinstead ofWindowGroup. - Do not treat
defaultSizeas a hard requirement or guaranteed final size; the system can clamp or restore window geometry. - Use
.glassBackgroundEffect()when you want the system glass treatment on visionOS, and use custom backgrounds deliberately when the design needs a different visual language.