Sample CodevisionOSReviewed 2026-07-21View on Apple Developer

Canyon Crosser: Building a volumetric hike-planning app

At a glance

Item Summary
Purpose Create a hike planning app using SwiftUI and RealityKit.
App architecture CanyonCrosserApp composes WindowGroup + volumetric window around ContentView; AppModel holds shared experience state and RealityKit components and systems own per-entity behavior.
Main patterns SwiftUI scene composition, SwiftUI–RealityKit bridge, Observable state owner, Entity-component-system, Protocol capability boundary
Project style Code-rich sample with 85 scanned Swift file(s) and 5099 Swift line(s); resources and generated assets are excluded from those counts.

Project structure

Source bundle/
├── CanyonCrosser/CanyonCrosserApp.swift  # CanyonCrosserApp
├── CanyonCrosser/Views/Progress Slider/WeatherOrTimeView.swift  # WeatherOrTimeView, Display, WeatherAndTime
├── CanyonCrosser/Models/AppModel/AppModel.swift  # LoadingError, AppModel
├── CanyonCrosser/Models/AppPhaseModel.swift  # AppPhaseModel, AppPhase
├── CanyonCrosser/ContentView.swift  # ContentView
├── Packages/RealityKitContent/Sources/RealityKitContent/ValueGradient.swift  # Interpolatable, ValueGradient
├── CanyonCrosser/ECS/ClippingMarginPercentageComponent.swift  # ClippingMarginPercentageComponent, Environment, Values
├── CanyonCrosser/ECS/FeatheringSystem.swift  # FadingCloudComponent, FeatheringSystem
└── Packages/RealityKitContent/Package.realitycomposerpro/ProjectData/main.json  # authored RealityKit content

Structure observations

  • The runtime boundary is WindowGroup + volumetric window; the pruned tree lists only files that explain lifecycle, state, or framework integration.
  • App code is split into role-named views, models, managers, providers, components, or systems.
  • Authored .reality or Reality Composer Pro content is a real implementation boundary; Swift loads or drives it rather than reproducing its entity graph.

Overall architecture

Reference code

CanyonCrosser/CanyonCrosserApp.swift:12 — the app or executable entry declares the outer scene lifecycle.

struct CanyonCrosserApp: App {
    // ...
}

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

Ownership evidence

CanyonCrosser/CanyonCrosserApp.swift:13 — representative stored state or the nearest verified lifecycle anchor.

    @State private var appModel: AppModel = AppModel()
Owner Object or state Relationship Mutation authority
CanyonCrosserApp AppModel as appModel creates and retains Only the declaring scope writes
CanyonCrosserApp AppPhaseModel as appPhaseModel creates and retains Only the declaring scope writes
ContentView AppPhaseModel as appPhaseModel receives a shared/non-owning reference The upstream owner controls lifetime; this scope may invoke its mutable API
AppModel AnimationPlaybackController as hikerAnimationController stores and coordinates 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
CanyonCrosserApp (CanyonCrosser/CanyonCrosserApp.swift:12) Declares app scenes and top-level dependency lifetime. App
ContentView (CanyonCrosser/ContentView.swift:11) Presents UI and forwards gestures or lifecycle events. View
AppModel (CanyonCrosser/Models/AppModel/AppModel.swift:21) Owns observable feature state and domain transitions. Sendable
Interpolatable (Packages/RealityKitContent/Sources/RealityKitContent/ValueGradient.swift:8) Declares a replaceable capability or lifecycle contract. Concrete framework collaborators
ClippingMarginPercentageComponent (CanyonCrosser/ECS/ClippingMarginPercentageComponent.swift:11) Stores RealityKit entity data. Component
FadingCloudComponent (CanyonCrosser/ECS/FeatheringSystem.swift:11) Stores RealityKit entity data. Component
FeatheringSystem (CanyonCrosser/ECS/FeatheringSystem.swift:13) Updates matching RealityKit entities. System

Verified protocol-oriented seams: DoubleInterpolatable, FloatInterpolatable, SIMD3<Float>Interpolatable, SIMD4<Float>Interpolatable. Framework conformances remain adapters, not proof of an app-wide protocol architecture.

Access control

Symbol Access Verified effect Likely rationale
@State private var appModel: AppModel = AppModel() (CanyonCrosser/CanyonCrosserApp.swift:13) private Use is restricted to the declaration and same-file extensions permitted by Swift. Inference: Hide implementation details and lifecycle-sensitive state.
fileprivate mutating func set(name: String, value newValue: MaterialPar... (CanyonCrosser/ECS/FeatheringSystem.swift:44) fileprivate Use is restricted to declarations in this source file. Inference: Share a helper across same-file extensions without making it module-wide.
public let trailEntityPath: String (CanyonCrosser/Models/Hike.swift:16) public The declaration is available to importing modules, subject to its containing type’s visibility. Inference: Satisfy a cross-target or framework-facing surface without implying subclassability.

No reviewed declaration uses private(set), open; unmodified Swift declarations are internal.

Reference code

CanyonCrosser/CanyonCrosserApp.swift:13 — representative visibility boundary.

    @State private var appModel: AppModel = AppModel()

Logic ownership and placement

Logic Owning type or file Placement rationale
Scene declaration and dependency lifetime CanyonCrosserApp The App/entry boundary determines window, volume, and immersive-space lifetime.
Presentation, attachments, and gestures ContentView SwiftUI view code forwards user intent and RealityView lifecycle events.
Shared feature state and commands AppModel A role-named owner prevents sibling views from duplicating transitions.
Per-frame entity behavior CanyonCrosser/ECS/FeatheringSystem.swift:13 RealityKit systems query component data instead of centralizing every entity update in SwiftUI.

Design patterns

Pattern Source evidence Purpose or tradeoff
SwiftUI scene composition CanyonCrosser/CanyonCrosserApp.swift:12 Keeps windows, volumes, and immersive-space lifecycle visible at the app boundary.
SwiftUI–RealityKit bridge CanyonCrosser/Views/Grand Canyon/GrandCanyonView.swift:63 Builds and updates a RealityKit entity graph from SwiftUI lifecycle closures.
Observable state owner CanyonCrosser/Models/AppModel/AppModel.swift:21 Shares feature state across multiple views without moving framework resources into view values.
Entity-component-system CanyonCrosser/ECS/FeatheringSystem.swift:13 Stores per-entity data in components and advances behavior in registered RealityKit systems.
Protocol capability boundary Packages/RealityKitContent/Sources/RealityKitContent/ValueGradient.swift:8 Defines a local capability used by multiple concrete types; this is the verified protocol-oriented seam.

Naming conventions

  • Role suffixes are evidence, not decoration: App: CanyonCrosserApp; Model: AppModel, AppPhaseModel, CarouselModel; View: BackButtonView, CarouselBodyView, CarouselLabelView, CarouselView, CompactControlsView.
  • ECS names pair data and behavior: components ClippingMarginPercentageComponent, FadingCloudComponent, HikePlaybackStateComponent, HikeTimingComponent; systems FeatheringSystem, HikeSystem, LightRotationSystem, TimeOfDaySystem.
  • Protocols: Interpolatable.
  • Commands use verb-led methods: fadeInClouds, fadeOutClouds, getHikerAnimationPlaybackController, setHikerVisibility.
  • Files generally match their primary type; Views, Models, Managers, Providers, Components, Systems, and Packages folders describe architectural roles where present.

Architecture takeaways

  • Treat CanyonCrosserApp as 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.
  • Use RealityKit components for per-entity data and systems for repeated simulation instead of a monolithic view model.

Source map

Source file Relevant symbols
CanyonCrosser/CanyonCrosserApp.swift:12 CanyonCrosserApp
CanyonCrosser/Views/Progress Slider/WeatherOrTimeView.swift:10 WeatherOrTimeView, Display, WeatherAndTime, TimeLabel, WeatherLabel
CanyonCrosser/Models/AppModel/AppModel.swift:12 LoadingError, AppModel
CanyonCrosser/Models/AppPhaseModel.swift:11 AppPhaseModel, AppPhase
CanyonCrosser/ContentView.swift:11 ContentView
Packages/RealityKitContent/Sources/RealityKitContent/ValueGradient.swift:8 Interpolatable, ValueGradient
CanyonCrosser/ECS/ClippingMarginPercentageComponent.swift:11 ClippingMarginPercentageComponent, Environment, Values
CanyonCrosser/ECS/FeatheringSystem.swift:11 FadingCloudComponent, FeatheringSystem