Sample CodeiOS, iPadOS, Mac CatalystReviewed 2026-07-21View on Apple Developer

Using object capture assets in RealityKit

At a glance

Item Summary
Purpose Create a chess game using RealityKit and assets created using Object Capture.
App architecture ObjectCaptureSampleApp presents ContentView; the shared GameManager owns the chess scene and rules, while piece components and AnimationSystem drive Object Capture-derived entities and SwiftUI overlays forward user intent.
Main patterns SwiftUI scene composition, UI–RealityKit bridge, Observable state owner, Entity-component-system, Session owner boundary, Game manager plus ECS
Project style Code-rich sample with 24 scanned Metal, Swift file(s) and 2693 implementation line(s).

Project structure

Source bundle/
└── CaptureChess/
    ├── GameManager.swift  # GameManager, State
    ├── AnimationSystem.swift  # AnimationSystem
    ├── CaptureChessApp.swift  # ObjectCaptureSampleApp
    ├── SplashScreenView.swift  # SplashScreenView, RectangleGrid, RectangleRow
    ├── ContentView.swift  # ContentView, OverlayView, ContentView_Previews
    ├── Components.swift  # HasChessPiece, CheckerComponent, ChessPieceComponent
    └── ChessViewport.swift  # ChessViewport, GestureView

Structure observations

  • The runtime boundary is WindowGroup + SwiftUI/UIKit host; the tree is pruned to lifecycle, state, framework, rendering, and ECS files.
  • The source is Metal, Swift; role-named types and feature folders separate the major responsibilities.

Overall architecture

Reference code

CaptureChess/CaptureChessApp.swift:11 — executable or app-lifecycle anchor.

struct ObjectCaptureSampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

The diagram is a responsibility flow, not a claim that every adjacent node directly calls the next. It separates lifecycle, presentation, stable state, framework/session work, and the RealityKit entity graph.

Ownership and state

Ownership evidence

CaptureChess/GameManager.swift:17 — representative stored state or nearest verified lifecycle anchor.

    @Published var turn: ChessGame.Player = .player1
    
    @Published var selectedPiece: ChessPiece?
    @Published var game: ChessGame = ChessGame()
    
    @Published var okayToStart = false
    @Published var loadProgress: Float = 0
Owner Object or state Relationship Mutation authority
GameManager Player as turn owns value state The owning type coordinates writes
ContentView GameManager as gameManager receives a shared or non-owning reference The upstream owner controls lifetime; this scope may invoke the exposed mutable API
GameManager State as state owns value state The owning type coordinates writes
GameManager GameManager as shared creates and retains The owning type coordinates writes

Ownership is intentionally narrow: environment, bindings, observed objects, weak links, and delegate callbacks do not prove lifetime ownership. Initialized stored services and wrapper-managed state do; entities added inside a RealityKit content closure belong to that entity graph.

Class and protocol design

Type Responsibility Depends on or conforms to
ObjectCaptureSampleApp (CaptureChess/CaptureChessApp.swift:11) Declares app lifecycle and top-level dependency lifetime. App
ContentView (CaptureChess/ContentView.swift:10) Presents UI and forwards gestures or lifecycle events. View
GameManager (CaptureChess/GameManager.swift:13) Coordinates long-lived framework or cross-view work. ObservableObject
AnimationSystem (CaptureChess/AnimationSystem.swift:10) Updates entities matching a RealityKit component query. System
HasChessPiece (CaptureChess/Components.swift:10) Declares a replaceable capability or collaboration contract. Entity
CheckerComponent (CaptureChess/Components.swift:23) Stores RealityKit entity data. Component
ChessPieceComponent (CaptureChess/Components.swift:30) Stores RealityKit entity data. Component
GestureView (CaptureChess/ChessViewport.swift:91) Presents UI and forwards gestures or lifecycle events. UIView

Verified protocol-oriented seams: ChessPieceHasChessPiece. Framework conformances remain adapters, not proof of an app-wide protocol architecture.

Access control

Symbol Access Verified effect Likely rationale
private let gameManager: GameManager (CaptureChess/ChessViewport.swift:17) private Use stays inside the declaration and same-file extensions permitted by Swift. Inference: Hide lifecycle-sensitive state or an implementation step.
fileprivate func prepareTexture(_ texture: inout MTLTexture?, format pi... (CaptureChess/ChessViewport+Bloom.swift:46) fileprivate Use is limited to declarations in this source file. Inference: Share with same-file helpers without making the symbol module-wide.
public func incrementPiecesLoaded() { (CaptureChess/GameManager.swift:27) public The symbol is available to importing modules, subject to its containing type’s visibility. Inference: Expose an intentional package or cross-target surface.

No reviewed Swift access example uses private(set), open; declarations without a modifier are internal.

Reference code

CaptureChess/ChessViewport.swift:17 — representative visibility boundary.

class ChessViewport: ARView {
    // ...
    private let gameManager: GameManager
    // ...
}

Logic ownership and placement

Logic Owning type or file Placement rationale
Application/command lifecycle ObjectCaptureSampleApp The executable boundary determines app, controller, scene, or command lifetime.
Presentation and user intent ContentView The view/controller forwards input and owns only presentation-local work.
Shared feature state and commands GameManager A stable owner prevents view recomputation or callbacks from duplicating transitions.
Framework/session/render coordination AnimationSystem The role-named collaborator isolates long-lived or per-frame work from presentation code.
Per-entity data and repeated behavior CaptureChess/AnimationSystem.swift:10 Components carry data; the system queries and updates matching entities.
GPU and low-level resource work CaptureChess/MetalLibLoader.swift:13 Buffer, texture, shader, or frame-resource mutation stays in a rendering/compute boundary.

Design patterns

Pattern Source evidence Purpose or tradeoff
SwiftUI scene composition CaptureChess/CaptureChessApp.swift:11 Keeps windows, volumes, and immersive presentation visible at the app boundary.
UI–RealityKit bridge CaptureChess/ContentView.swift:10 Builds or hosts the RealityKit entity graph from SwiftUI or a platform view/controller lifecycle.
Observable state owner CaptureChess/GameManager.swift:13 Keeps shared feature state in a stable owner rather than in transient view values.
Entity-component-system CaptureChess/AnimationSystem.swift:10 Stores per-entity data in components and advances repeated behavior in registered systems.
Session owner boundary CaptureChess/AnimationSystem.swift:10 Keeps authorization, session lifetime, and framework callbacks in a stable model, manager, or controller.
Game manager plus ECS CaptureChess/GameManager.swift:12 Keeps chess rules and scene ownership in one manager while components and systems animate scanned piece assets.

Naming conventions

  • Role suffixes are evidence, not decoration: App: ObjectCaptureSampleApp; Manager: GameManager; System: AnimationSystem; Component: CheckerComponent, ChessPieceComponent; View: ContentView, GestureView, OverlayView, SplashScreenView.
  • ECS names pair data and behavior: components CheckerComponent, ChessPieceComponent; systems AnimationSystem.
  • Protocols: HasChessPiece.
  • Commands use verb-led methods: incrementPiecesLoaded, update, handleTap, handleDoubleTap, handlePan, handleRotation, handlePinch, moveBoard.
  • Files and folders use primary-type or responsibility names such as Views, Models, Rendering, Components, Systems, Packages, or feature names where those boundaries exist.

Architecture takeaways

  • Treat ObjectCaptureSampleApp as the owner of executable or scene lifecycle, not automatically as the owner of every entity created later.
  • Keep view/controller input near presentation, but move sessions, reconstruction, capture, rendering, shared game state, or documents into stable owners when their lifetime exceeds one callback or render pass.
  • Use components for per-entity data and systems for repeated simulation instead of centralizing every update in a view model or controller.

Source map

Source file Relevant symbols
CaptureChess/GameManager.swift:13 GameManager, State
CaptureChess/AnimationSystem.swift:10 AnimationSystem
CaptureChess/CaptureChessApp.swift:11 ObjectCaptureSampleApp
CaptureChess/SplashScreenView.swift:10 SplashScreenView, RectangleGrid, RectangleRow, EmptyCircle, SplashScreenView_Preview
CaptureChess/ContentView.swift:10 ContentView, OverlayView, ContentView_Previews
CaptureChess/Components.swift:10 HasChessPiece, CheckerComponent, ChessPieceComponent
CaptureChess/ChessViewport.swift:15 ChessViewport, GestureView