Tracking and visualizing hand movement
At a glance
| Item | Summary |
|---|---|
| Purpose | Use hand-tracking anchors to display a visual representation of hand transforms in visionOS. |
| App architecture | HandTracking composes WindowGroup + ImmersiveSpace around MainView; HandTrackingSystem coordinates ARKit provider updates and maps anchors into RealityKit content. |
| Main patterns | SwiftUI scene composition, SwiftUI–RealityKit bridge, Explicit immersive-space lifecycle, Entity-component-system, Provider session boundary, Async update consumer |
| Project style | Code-rich sample with 8 scanned Swift file(s) and 310 Swift line(s); resources and generated assets are excluded from those counts. |
Project structure
Source bundle/
└── RealityKit-HandTracking/
├── App/
│ └── HandTracking.swift # HandTracking
├── Components/
│ └── HandTrackingComponent.swift # HandTrackingComponent
├── Systems/
│ └── HandTrackingSystem.swift # HandTrackingSystem
├── Views/
│ ├── HandTrackingView.swift # HandTrackingView
│ └── MainView.swift # MainView
└── Entities/
├── Bone.swift # Bone
├── Finger.swift # Finger
└── Hand.swift # Hand
Structure observations
- The runtime boundary is WindowGroup + ImmersiveSpace; 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.
Overall architecture
flowchart LR
HandTracking_1["HandTracking"]
WindowGroup___ImmersiveSpace_2["WindowGroup + ImmersiveSpace"]
MainView_3["MainView"]
HandTrackingSystem_4["HandTrackingSystem"]
RealityView_entity_graph_5["RealityView entity graph"]
ARKit_providers___RealityKit_6["ARKit providers + RealityKit"]
HandTracking_1 --> WindowGroup___ImmersiveSpace_2
WindowGroup___ImmersiveSpace_2 --> MainView_3
MainView_3 --> HandTrackingSystem_4
HandTrackingSystem_4 --> RealityView_entity_graph_5
RealityView_entity_graph_5 --> ARKit_providers___RealityKit_6
Reference code
RealityKit-HandTracking/App/HandTracking.swift:11 — the app or executable entry declares the outer scene lifecycle.
struct HandTracking: 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
classDiagram
HandTrackingSystem *-- ARKitSession : arSession
HandTrackingSystem *-- HandTrackingProvider : handTracking
HandTrackingComponent --> Chirality : chirality
HandTrackingSystem --> HandAnchor : latestLeftHand
Ownership evidence
RealityKit-HandTracking/Systems/HandTrackingSystem.swift:13 — representative stored state or the nearest verified lifecycle anchor.
static var arSession = ARKitSession()
/// The provider instance for hand-tracking.
static let handTracking = HandTrackingProvider()
/// The most recent anchor that the provider detects on the left hand.
static var latestLeftHand: HandAnchor?| Owner | Object or state | Relationship | Mutation authority |
|---|---|---|---|
HandTrackingSystem |
ARKitSession as arSession |
creates and retains | The owning type coordinates writes |
HandTrackingSystem |
HandTrackingProvider as handTracking |
creates and retains | The owning type coordinates writes |
HandTrackingComponent |
Chirality as chirality |
stores and coordinates | The owning type coordinates writes |
HandTrackingSystem |
HandAnchor as latestLeftHand |
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 |
|---|---|---|
HandTracking (RealityKit-HandTracking/App/HandTracking.swift:11) |
Declares app scenes and top-level dependency lifetime. | App |
MainView (RealityKit-HandTracking/Views/MainView.swift:10) |
Presents UI and forwards gestures or lifecycle events. | View |
HandTrackingSystem (RealityKit-HandTracking/Systems/HandTrackingSystem.swift:11) |
Updates matching RealityKit entities. | System |
HandTrackingComponent (RealityKit-HandTracking/Components/HandTrackingComponent.swift:11) |
Stores RealityKit entity data. | Component |
HandTrackingView (RealityKit-HandTracking/Views/HandTrackingView.swift:13) |
Presents UI and forwards gestures or lifecycle events. | View |
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 |
|---|
No reviewed declaration uses fileprivate, private(set), public, open; unmodified Swift declarations are internal.
Reference code
RealityKit-HandTracking/App/HandTracking.swift:11 — representative visibility boundary.
struct HandTracking: App {
// ...
}Logic ownership and placement
| Logic | Owning type or file | Placement rationale |
|---|---|---|
| Scene declaration and dependency lifetime | HandTracking |
The App/entry boundary determines window, volume, and immersive-space lifetime. |
| Presentation, attachments, and gestures | MainView |
SwiftUI view code forwards user intent and RealityView lifecycle events. |
| Shared feature state and commands | HandTrackingSystem |
A role-named owner prevents sibling views from duplicating transitions. |
| Tracking authorization and update streams | RealityKit-HandTracking/Systems/HandTrackingSystem.swift:13 |
Provider lifetime and async updates remain outside render-only view code. |
| Per-frame entity behavior | RealityKit-HandTracking/Systems/HandTrackingSystem.swift:11 |
RealityKit systems query component data instead of centralizing every entity update in SwiftUI. |
Design patterns
| Pattern | Source evidence | Purpose or tradeoff |
|---|---|---|
| SwiftUI scene composition | RealityKit-HandTracking/App/HandTracking.swift:11 |
Keeps windows, volumes, and immersive-space lifecycle visible at the app boundary. |
| SwiftUI–RealityKit bridge | RealityKit-HandTracking/Views/HandTrackingView.swift:16 |
Builds and updates a RealityKit entity graph from SwiftUI lifecycle closures. |
| Explicit immersive-space lifecycle | RealityKit-HandTracking/App/HandTracking.swift:18 |
Makes immersive presentation a scene transition rather than hidden global state. |
| Entity-component-system | RealityKit-HandTracking/Systems/HandTrackingSystem.swift:11 |
Stores per-entity data in components and advances behavior in registered RealityKit systems. |
| Provider session boundary | RealityKit-HandTracking/Systems/HandTrackingSystem.swift:13 |
Owns provider lifetime separately from the SwiftUI view tree. |
| Async update consumer | RealityKit-HandTracking/Systems/HandTrackingSystem.swift:40 |
Consumes provider or event streams in cancellable structured tasks. |
Naming conventions
- Role suffixes are evidence, not decoration: View:
HandTrackingView,MainView. - ECS names pair data and behavior: components
HandTrackingComponent; systemsHandTrackingSystem. - Protocols: no app-defined protocol in the reviewed source.
- Commands use verb-led methods:
runSession,update,addJoints,makeHandEntities. - Files generally match their primary type;
Views,Models,Managers,Providers,Components,Systems, andPackagesfolders describe architectural roles where present.
Architecture takeaways
- Treat
HandTrackingas 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.
- Use RealityKit components for per-entity data and systems for repeated simulation instead of a monolithic view model.
- Model immersive-space open, transition, and close states explicitly so windows and immersive content cannot drift apart.
Source map
| Source file | Relevant symbols |
|---|---|
RealityKit-HandTracking/App/HandTracking.swift:11 |
HandTracking |
RealityKit-HandTracking/Components/HandTrackingComponent.swift:11 |
HandTrackingComponent |
RealityKit-HandTracking/Systems/HandTrackingSystem.swift:11 |
HandTrackingSystem |
RealityKit-HandTracking/Views/HandTrackingView.swift:13 |
HandTrackingView |
RealityKit-HandTracking/Views/MainView.swift:10 |
MainView |
RealityKit-HandTracking/Entities/Bone.swift:8 |
Bone |
RealityKit-HandTracking/Entities/Finger.swift:8 |
Finger |
RealityKit-HandTracking/Entities/Hand.swift:11 |
Hand |