Sample CodevisionOSReviewed 2026-07-21View on Apple Developer

Petite Asteroids: Building a volumetric visionOS game

At a glance

Item Summary
Purpose Use the latest RealityKit APIs to create a beautiful video game for visionOS.
App architecture A C/Objective-C header, Metal, Swift sample with the source-visible chain PetiteAsteroidsContentViewAppModelAudioCueSystemRealityKit / RealityKitContent APIs.
Main patterns No named application pattern supported by the extracted structure
Project style 113 scanned source file(s) across C/Objective-C header, Metal, Swift, organized around ranked entry, type, and file boundaries.
Execution model Source-visible boundaries: @MainActor, async declaration or closure, Task closure isolated to MainActor, Task, Sendable or @Sendable; none alone proves a background thread.
State/event model Source-visible mechanisms: NotificationCenter, @Observable, SwiftUI state property wrapper.
Key frameworks/packages RealityKit, RealityKitContent, SwiftUI, Combine, Foundation; these are source dependencies, not architecture labels.

Project structure

Source bundle/
├── PetiteAsteroids/
│   ├── PetiteAsteroids.swift
│   ├── AppModel.swift
│   ├── ECS/
│   │   ├── Camera/
│   │   │   └── RotationalCameraFollowComponent.swift
│   │   └── Character/
│   │       ├── CharacterMovementComponent.swift
│   │       └── CharacterProgressComponent.swift
│   └── Views/
│       └── FriendsView.swift
└── Packages/
    └── RealityKitContent/
        └── Sources/
            └── RealityKitContent/
                ├── CompoundCollisionMarkerComponent.swift
                ├── BakedDirectionalLightSourceComponent.swift
                ├── CharacterSpawnPointComponent.swift
                ├── CheckpointComponent.swift
                ├── DirectionalLightFaderComponent.swift
                └── DropShadowReceiverComponent.swift

Structure observations

  • Architecturally prominent files are ranked from entry points and role-named declarations; resource-only paths are omitted.
  • Primary languages: C/Objective-C header, Metal, Swift.
  • The verified tree contains 4 project/configuration file(s) and 123 source declaration(s).

Overall architecture

Reference code

PetiteAsteroids/PetiteAsteroids.swift:12 — architecture anchor

@main
struct PetiteAsteroids: App {
    // ...
    @State private var appModel = AppModel()
    // ...
}

Interpretation

The arrows summarize the source-visible entry, role-named types or folders, and framework direction; when nodes come from structural folders, the sequence is a high-level interpretation rather than proof that every adjacent node calls the next. Ownership is claimed only where the next section cites a stored property or assignment. The diagram is intentionally limited to the dominant path into visionOS.

Ownership and state

Ownership evidence

PetiteAsteroids/AppModel.swift:13 — stored dependency or nearest verified ownership anchor

struct GameAssetContainer: Component {
    let levels: [GameLevel: Entity]
    let characterAnimationRoot: Entity
}
Owner Object or state Relationship Mutation authority
GameAssetContainer Dictionary (levels) owns value state Initialized by the owner; the binding is immutable
GameAssetContainer Entity (characterAnimationRoot) stores or receives Initialized by the owner; the binding is immutable
AssetIdentifier String (name) owns value state Initialized by the owner; the binding is immutable
AssetIdentifier AssetType (type) stores or receives Initialized by the owner; the binding is immutable

Composition arrows indicate a source-visible construction expression or locally owned value state; aggregation means the owner stores or receives a dependency without proving exclusive lifetime ownership.

Concurrency, scheduling, and thread safety

Evidence limit: actor isolation, async/await, or Task creation does not by itself prove background-thread execution; Sendable conformance alone does not prove thread-safe mutation.

Concern Source mechanism Verified placement or handoff Evidence
Main isolation @MainActor The cited annotation marks its attached declaration or closure as main-actor isolated. Packages/RealityKitContent/Sources/RealityKitContent/SpeechBubbleTriggerComponent.swift:10
Suspension boundary async declaration or closure The source declares or crosses an asynchronous boundary; it does not by itself establish background execution. PetiteAsteroids/AppModel+LoadAssets.swift:13
Main isolation Task closure isolated to MainActor The cited operation explicitly enters a main-actor-isolated region. PetiteAsteroids/AppModel+OnReceiveNotification.swift:81
Task creation Task The source creates an unstructured task; surrounding context determines inherited actor isolation. PetiteAsteroids/AppModel+OnReceiveNotification.swift:81
Transfer contract Sendable or @Sendable The source declares a sendability boundary; this alone does not synchronize mutable state. PetiteAsteroids/AppModel.swift:34

@MainActor/MainActor.run, DispatchQueue.main, and RunLoop.main are reported as distinct isolation, queue, and event-loop mechanisms. A plain Task is kept separate from Task.detached; neither is labeled as a background thread.

Reference code

Packages/RealityKitContent/Sources/RealityKitContent/SpeechBubbleTriggerComponent.swift:10 — representative execution boundary

@MainActor
public struct SpeechBubbleTriggerComponent: Component, Codable {
    public var characterText: String = "Update the text..."
    public var timer: Float = 5.0
    // ...
}

State propagation, frameworks, and dependencies

Evidence limit: an import proves a source-level compilation dependency at the cited line; it does not prove runtime use, architectural adoption, or whether a Swift package is a direct application dependency.

Category Mechanism or module Verified role Evidence
State propagation NotificationCenter NotificationCenter distributes named process-local events. PetiteAsteroids/AppModel+OnReceiveNotification.swift:13
State propagation @Observable Observation macro publishes source-visible changes. PetiteAsteroids/AppModel.swift:75
State propagation SwiftUI state property wrapper A SwiftUI property wrapper supplies or observes UI state. PetiteAsteroids/ContentView.swift:13
Source import RealityKit The cited file imports this module; runtime use and architectural role are not inferred. Packages/RealityKitContent/Sources/RealityKitContent/BakedDirectionalLightSourceComponent.swift:8
Source import RealityKitContent The cited file imports this module; runtime use and architectural role are not inferred. PetiteAsteroids/AppModel+LoadAssets.swift:10
Source import SwiftUI The cited file imports this module; runtime use and architectural role are not inferred. PetiteAsteroids/AppModel+LoadAssets.swift:8
Source import Combine The cited file imports this module; runtime use and architectural role are not inferred. PetiteAsteroids/ECS/Audio/AudioCueSystem.swift:10
Source import Foundation The cited file imports this module; runtime use and architectural role are not inferred. Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.swift:8

receive(on:) describes downstream delivery scheduling, while subscribe(on:) describes upstream subscription/request/cancel scheduling. An import Combine alone establishes neither behavior nor a Store, reducer, Redux, or other application architecture.

Class and protocol design

PetiteAsteroids/AppModel.swift:76 — representative type boundary

@MainActor
@Observable
class AppModel {
    // ...
    var isDifficultyHard: Bool = false
    // ...
}
Type Responsibility Depends on or conforms to
AppModel Feature data or observable state Concrete collaborators/imported frameworks
CompoundCollisionMarkerComponent Stores entity-component data or behavior Component, Codable
RotationalCameraFollowComponent Stores entity-component data or behavior Component
CharacterMovementComponent Stores entity-component data or behavior Component
CharacterProgressComponent Stores entity-component data or behavior Component
FriendsView User-interface presentation and input forwarding View
FriendView User-interface presentation and input forwarding View
BakedDirectionalLightSourceComponent Stores entity-component data or behavior Component, Codable
CharacterSpawnPointComponent Stores entity-component data or behavior Component, Codable
CheckpointComponent Stores entity-component data or behavior Component, Codable

No local protocol conformance is claimed as protocol-oriented design; external framework conformances are listed only as dependencies.

Access control

Symbol Access Verified effect Likely rationale
BakedDirectionalLightSourceComponent (Packages/RealityKitContent/Sources/RealityKitContent/BakedDirectionalLightSourceComponent.swift:11) public The symbol is visible to importing modules. Inference: make the declaration available across a module or target boundary.
index (Packages/RealityKitContent/Sources/RealityKitContent/CheckpointComponent.swift:10) public The symbol is visible to importing modules. Inference: make the declaration available across a module or target boundary.
isClaimed (Packages/RealityKitContent/Sources/RealityKitContent/CheckpointComponent.swift:11) public The symbol is visible to importing modules. Inference: make the declaration available across a module or target boundary.
CheckpointComponent (Packages/RealityKitContent/Sources/RealityKitContent/CheckpointComponent.swift:12) public The symbol is visible to importing modules. Inference: make the declaration available across a module or target boundary.

Reference code

Packages/RealityKitContent/Sources/RealityKitContent/BakedDirectionalLightSourceComponent.swift:11 — representative boundary

    public init() {
    }

Swift declarations without a modifier are internal; explicit private, fileprivate, private(set), public, or open entries above are interpreted by language semantics. Objective-C/C samples instead rely on header and implementation boundaries, which are not equivalent to Swift lexical privacy.

Logic ownership and placement

Logic Owning type or file Placement rationale
Stores entity-component data or behavior AudioCueStorageComponent, AudioEventComponent, AudioResourcesComponent, BakedDirectionalLightSourceComponent The source’s Component suffix makes this role explicit.
Feature data or observable state AppModel The source’s Model suffix makes this role explicit.
Runs entity-component-system update logic AudioCueSystem, AudioEventSystem, BakedDirectionalLightShadowSystem, ButteAmbienceBlendSystem The source’s System suffix makes this role explicit.
User-interface presentation and input forwarding ContentView, FriendView, FriendsView, HighScoreView The source’s View suffix makes this role explicit.

Design patterns

Pattern Source evidence Purpose or tradeoff
No named application pattern PetiteAsteroids/PetiteAsteroids.swift:12 The verified source directly composes concrete framework types; this document avoids forcing a pattern name.

Main application flow

Reference code

PetiteAsteroids/AppModel+LoadAssets.swift:30loadGameAssets()

    func loadGameAssets() async {
        // ...
        root.components.set(GamePlayStateComponent.loadingAssets)
        await withTaskGroup(of: LoadResult.self) { loadAssetsTaskGroup in
            for asset in assetsToLoad {
                loadAssetsTaskGroup.addTask {
                    switch asset.type {
                        case .level, .character, .inputVisualizer:
                            guard let entity = try? await Entity(named: asset.name, in: realityKitContentBundle) else {
                                fatalError("Attempted to load entity \(asset.name), but failed.")
                            }
                            return LoadResult(entity: entity, type: asset.type)
                        case .audio:
                        do {
                            let audioResourcesComponent = try await AudioResourcesComponent.load()
                            return await LoadResult(entity: Entity(components: [audioResourcesComponent]), type: asset.type)
                        } catch {
                            fatalError("Attempted to load audio resources, but failed.")
                        }
                    }
                }
            }
            let (levels, characterAnimationRoot) = await prepareGameAssets(loadAssetsTaskGroup: loadAssetsTaskGroup)
            guard let characterAnimationRoot else {
                fatalError("Failed to load character animation root.")
            }
            let assetContainerComponent = GameAssetContainer(levels: levels,
                                                             characterAnimationRoot: characterAnimationRoot)
            root.components.set(assetContainerComponent)
        }
        root.components.set(GamePlayStateComponent.assetsLoaded)
    }

Naming conventions

  • Types: Component: AudioCueStorageComponent, AudioEventComponent, AudioResourcesComponent, BakedDirectionalLightSourceComponent, ButteAmbienceBlendComponent; Model: AppModel; System: AudioCueSystem, AudioEventSystem, BakedDirectionalLightShadowSystem, ButteAmbienceBlendSystem, CharacterAnimationSystem; View: ContentView, FriendView, FriendsView, HighScoreView, LoadingView.
  • Protocols: no local protocol declaration in the scanned source.
  • Methods: registerSystems, registerComponents, playLevel, updateAnimationTime.
  • Files: PetiteAsteroids/PetiteAsteroids.swift, PetiteAsteroids/AppModel.swift, Packages/RealityKitContent/Sources/RealityKitContent/CompoundCollisionMarkerComponent.swift, PetiteAsteroids/ECS/Camera/RotationalCameraFollowComponent.swift, PetiteAsteroids/ECS/Character/CharacterMovementComponent.swift, PetiteAsteroids/ECS/Character/CharacterProgressComponent.swift.

Architecture takeaways

  • PetiteAsteroids is the main source-visible entry or composition anchor for this sample.
  • Framework work reaches RealityKit, RealityKitContent, SwiftUI, CoreMedia through a deliberately small high-level chain; the detailed API graph remains inside the cited implementation files.
  • Stored-property evidence identifies lifecycle collaboration; it does not by itself prove exclusive object ownership.
  • Access-control conclusions separate verified language visibility from the likely design rationale.
  • The source does not justify labeling the design protocol-oriented.

Source map

Source file Relevant symbols
PetiteAsteroids/PetiteAsteroids.swift Cited implementation, PetiteAsteroids
PetiteAsteroids/AppModel.swift Cited implementation, AppModel, Sendable or @Sendable, @Observable, GameAssetContainer, GameLevel, AssetType, AssetIdentifier, LoadResult, RollInputMode, JumpInputMode
Packages/RealityKitContent/Sources/RealityKitContent/BakedDirectionalLightSourceComponent.swift Cited implementation, RealityKit, BakedDirectionalLightSourceComponent
Packages/RealityKitContent/Sources/RealityKitContent/CheckpointComponent.swift Cited implementation, CheckpointComponent
Packages/RealityKitContent/Sources/RealityKitContent/SpeechBubbleTriggerComponent.swift @MainActor, SpeechBubbleTriggerComponent
PetiteAsteroids/AppModel+LoadAssets.swift async declaration or closure, RealityKitContent, SwiftUI
PetiteAsteroids/AppModel+OnReceiveNotification.swift Task closure isolated to MainActor, Task, NotificationCenter
PetiteAsteroids/ContentView.swift SwiftUI state property wrapper, ContentView
PetiteAsteroids/ECS/Audio/AudioCueSystem.swift Combine, AudioCueSystem, AudioCue
Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.swift Foundation
Packages/RealityKitContent/Sources/RealityKitContent/CompoundCollisionMarkerComponent.swift GameCollisionGroup, GameCollisionMask, CompoundCollisionMarkerComponent
PetiteAsteroids/ECS/Camera/RotationalCameraFollowComponent.swift RotationalCameraFollowComponent, CameraParameterAnimation, CameraPoint, RotationalCameraMode
PetiteAsteroids/ECS/Character/CharacterMovementComponent.swift CharacterMovementComponent, CollisionClassification, CharacterMovementState
PetiteAsteroids/ECS/Character/CharacterProgressComponent.swift CollectedRockFriend, Breadcrumb, CharacterProgressComponent
PetiteAsteroids/Views/FriendsView.swift FriendsView, FriendView, GroundShadow
Packages/RealityKitContent/Sources/RealityKitContent/CharacterSpawnPointComponent.swift CharacterSpawnPointComponent