Incorporating real-world surroundings in an immersive experience
At a glance
| Item | Summary |
|---|---|
| Purpose | Create an immersive experience by making your app’s content respond to the local shape of the world. |
| App architecture | SceneReconstructionExampleApp composes ImmersiveSpace around CubeMeshInteraction; EntityModel coordinates ARKit provider updates and maps anchors into RealityKit content. |
| Main patterns | SwiftUI scene composition, SwiftUI–RealityKit bridge, Explicit immersive-space lifecycle, Observable state owner, Provider session boundary, Async update consumer |
| Project style | Code-light sample with 4 scanned Swift file(s) and 258 Swift line(s); resources and generated assets are excluded from those counts. |
Project structure
Source bundle/
└── SceneReconstructionExample/
├── SceneReconstructionExampleApp.swift # SceneReconstructionExampleApp
├── EntityModel.swift # EntityModel
├── CubeMeshInteraction.swift # CubeMeshInteraction
└── Extensions.swift # func
Structure observations
- The runtime boundary is ImmersiveSpace; the pruned tree lists only files that explain lifecycle, state, or framework integration.
- App code is compact; any explicit model, provider, or entity owner is still shown below rather than collapsed into view-local state.
Overall architecture
flowchart LR
SceneReconstructionExampleApp_1["SceneReconstructionExampleApp"]
ImmersiveSpace_2["ImmersiveSpace"]
CubeMeshInteraction_3["CubeMeshInteraction"]
EntityModel_4["EntityModel"]
RealityView_entity_graph_5["RealityView entity graph"]
ARKit_providers___RealityKit_6["ARKit providers + RealityKit"]
SceneReconstructionExampleApp_1 --> ImmersiveSpace_2
ImmersiveSpace_2 --> CubeMeshInteraction_3
CubeMeshInteraction_3 --> EntityModel_4
EntityModel_4 --> RealityView_entity_graph_5
RealityView_entity_graph_5 --> ARKit_providers___RealityKit_6
Reference code
SceneReconstructionExample/SceneReconstructionExampleApp.swift:13 — the app or executable entry declares the outer scene lifecycle.
struct SceneReconstructionExampleApp: App {
@State private var model = EntityModel()
var body: some Scene {
ImmersiveSpace(id: cubeMeshInteractionID) {
CubeMeshInteraction()
.environment(model)
}
}
}The diagram is a responsibility flow, not a claim that every adjacent node directly calls the next. It keeps scene ownership, shared state, RealityKit content, and framework-provider work at separate levels.
Ownership and state
classDiagram
SceneReconstructionExampleApp *-- EntityModel : model
EntityModel *-- ARKitSession : session
CubeMeshInteraction o-- EntityModel : model
EntityModel *-- HandTrackingProvider : handTracking
Ownership evidence
SceneReconstructionExample/SceneReconstructionExampleApp.swift:14 — representative stored state or the nearest verified lifecycle anchor.
@State private var model = EntityModel()
var body: some Scene {
ImmersiveSpace(id: cubeMeshInteractionID) {
CubeMeshInteraction()
.environment(model)
}
}| Owner | Object or state | Relationship | Mutation authority |
|---|---|---|---|
SceneReconstructionExampleApp |
EntityModel as model |
creates and retains | Only the declaring scope writes |
EntityModel |
ARKitSession as session |
creates and retains | The owning type coordinates writes |
CubeMeshInteraction |
EntityModel as model |
receives a shared/non-owning reference | The upstream owner controls lifetime; this scope may invoke its mutable API |
EntityModel |
HandTrackingProvider as handTracking |
creates and retains | The owning type coordinates writes |
Ownership here is deliberately narrow: @Environment and weak references are shared links, initialized @State or stored services are lifecycle ownership, and a RealityView content closure owns additions to its entity graph without making the SwiftUI view a reference-type owner.
Class and protocol design
| Type | Responsibility | Depends on or conforms to |
|---|---|---|
SceneReconstructionExampleApp (SceneReconstructionExample/SceneReconstructionExampleApp.swift:13) |
Declares app scenes and top-level dependency lifetime. | App |
CubeMeshInteraction (SceneReconstructionExample/CubeMeshInteraction.swift:17) |
Presents UI and forwards gestures or lifecycle events. | View |
EntityModel (SceneReconstructionExample/EntityModel.swift:14) |
Owns observable feature state and domain transitions. | Concrete framework collaborators |
The source defines no local substitution protocol in the reviewed boundary. Its protocol use is framework-facing (App, View, RealityKit/ARKit protocols, or platform adapters), so this document does not label the whole app protocol-oriented.
Access control
| Symbol | Access | Verified effect | Likely rationale |
|---|---|---|---|
private var meshEntities = [UUID: ModelEntity]() (SceneReconstructionExample/EntityModel.swift:21) |
private |
Use is restricted to the declaration and same-file extensions permitted by Swift. | Inference: Hide implementation details and lifecycle-sensitive state. |
No reviewed declaration uses fileprivate, private(set), public, open; unmodified Swift declarations are internal.
Reference code
SceneReconstructionExample/EntityModel.swift:21 — representative visibility boundary.
private var meshEntities = [UUID: ModelEntity]()
private let fingerEntities: [HandAnchor.Chirality: ModelEntity] = [
.left: .createFingertip(),
.right: .createFingertip()
]Logic ownership and placement
| Logic | Owning type or file | Placement rationale |
|---|---|---|
| Scene declaration and dependency lifetime | SceneReconstructionExampleApp |
The App/entry boundary determines window, volume, and immersive-space lifetime. |
| Presentation, attachments, and gestures | CubeMeshInteraction |
SwiftUI view code forwards user intent and RealityView lifecycle events. |
| Shared feature state and commands | EntityModel |
A role-named owner prevents sibling views from duplicating transitions. |
| Tracking authorization and update streams | SceneReconstructionExample/EntityModel.swift:15 |
Provider lifetime and async updates remain outside render-only view code. |
Design patterns
| Pattern | Source evidence | Purpose or tradeoff |
|---|---|---|
| SwiftUI scene composition | SceneReconstructionExample/SceneReconstructionExampleApp.swift:13 |
Keeps windows, volumes, and immersive-space lifecycle visible at the app boundary. |
| SwiftUI–RealityKit bridge | SceneReconstructionExample/CubeMeshInteraction.swift:22 |
Builds and updates a RealityKit entity graph from SwiftUI lifecycle closures. |
| Explicit immersive-space lifecycle | SceneReconstructionExample/SceneReconstructionExampleApp.swift:17 |
Makes immersive presentation a scene transition rather than hidden global state. |
| Observable state owner | SceneReconstructionExample/EntityModel.swift:14 |
Shares feature state across multiple views without moving framework resources into view values. |
| Provider session boundary | SceneReconstructionExample/EntityModel.swift:15 |
Owns provider lifetime separately from the SwiftUI view tree. |
| Async update consumer | SceneReconstructionExample/EntityModel.swift:48 |
Consumes provider or event streams in cancellable structured tasks. |
Naming conventions
- Role suffixes are evidence, not decoration: App:
SceneReconstructionExampleApp; Model:EntityModel. - Protocols: no app-defined protocol in the reviewed source.
- Commands use verb-led methods:
setupContentEntity,processHandUpdates,processReconstructionUpdates,monitorSessionEvents,addCube,createFingertip. - Files generally match their primary type;
Views,Models,Managers,Providers,Components,Systems, andPackagesfolders describe architectural roles where present.
Architecture takeaways
- Treat
SceneReconstructionExampleAppas the owner of scene declarations, not as the owner of every RealityKit entity created later. - Keep view-local interaction in SwiftUI, but move provider sessions, playback resources, shared game state, or transport state into a stable owner when their lifetime exceeds one render pass.
- Run ARKit providers for the scene lifetime and consume their asynchronous updates in cancellable tasks; map anchors to entities at the boundary.
- Model immersive-space open, transition, and close states explicitly so windows and immersive content cannot drift apart.
- The compact source does not justify adding repository, coordinator, or protocol layers beyond the model, provider, or view boundary the sample actually declares.
Source map
| Source file | Relevant symbols |
|---|---|
SceneReconstructionExample/SceneReconstructionExampleApp.swift:13 |
SceneReconstructionExampleApp |
SceneReconstructionExample/EntityModel.swift:14 |
EntityModel |
SceneReconstructionExample/CubeMeshInteraction.swift:17 |
CubeMeshInteraction |
SceneReconstructionExample/Extensions.swift:13 |
ModelEntity.createFingertip() |