The panorama of computing is present process a profound transformation with the emergence of spatial computing platforms(VR and AR). As we step into this new period, the intersection of digital actuality, Augmented Actuality, and on-device machine studying presents unprecedented alternatives for builders to create experiences that seamlessly mix digital content material with the bodily world.
The introduction of visionOS marks a big milestone on this evolution. Apple’s Spatial Computing platform combines refined {hardware} capabilities with highly effective growth frameworks, enabling builders to construct functions that may perceive and work together with the bodily atmosphere in actual time. This convergence of spatial consciousness and on-device machine studying capabilities opens up new potentialities for object recognition and monitoring functions that had been beforehand difficult to implement.
What We’re Constructing
On this information, we’ll be constructing an app that showcases the facility of on-device machine studying in visionOS. We’ll create an app that may acknowledge and monitor a weight-reduction plan soda can in actual time, overlaying visible indicators and data instantly within the person’s discipline of view.

Our app will leverage a number of key applied sciences within the visionOS ecosystem. When a person runs the app, they’re introduced with a window containing a rotating 3D mannequin of our goal object together with utilization directions. As they appear round their atmosphere, the app constantly scans for weight-reduction plan soda cans. Upon detection, it shows dynamic bounding strains across the can and locations a floating textual content label above it, all whereas sustaining exact monitoring as the thing or person strikes by house.
Earlier than we start growth, let’s guarantee we have now the mandatory instruments and understanding in place. This tutorial requires:
- The most recent model of Xcode 16 with visionOS SDK put in
- visionOS 2.0 or later operating on an Apple Imaginative and prescient Professional system
- Primary familiarity with SwiftUI and the Swift programming language
The event course of will take us by a number of key levels, from capturing a 3D mannequin of our goal object to implementing real-time monitoring and visualization. Every stage builds upon the earlier one, supplying you with a radical understanding of growing options powered by on-device machine studying for visionOS.
Constructing the Basis: 3D Object Seize
Step one in creating our object recognition system includes capturing an in depth 3D mannequin of our goal object. Apple gives a robust app for this goal: RealityComposer, accessible for iOS by the App Retailer.
When capturing a 3D mannequin, environmental circumstances play a vital function within the high quality of our outcomes. Organising the seize atmosphere correctly ensures we get the very best information for our machine studying mannequin. A well-lit house with constant lighting helps the seize system precisely detect the thing’s options and dimensions. The weight-reduction plan soda can must be positioned on a floor with good distinction, making it simpler for the system to tell apart the thing’s boundaries.
The seize course of begins by launching the RealityComposer app and deciding on “Object Seize” from the accessible choices. The app guides us by positioning a bounding field round our goal object. This bounding field is vital because it defines the spatial boundaries of our seize quantity.

As soon as we’ve captured all the small print of the soda can with the assistance of the in-app information and processed the pictures, a .usdz file containing our 3D mannequin shall be created. This file format is particularly designed for AR/VR functions and accommodates not simply the visible illustration of our object, but in addition necessary data that shall be used within the coaching course of.
Coaching the Reference Mannequin
With our 3D mannequin in hand, we transfer to the subsequent essential part: coaching our recognition mannequin utilizing Create ML. Apple’s Create ML software gives a simple interface for coaching machine studying fashions, together with specialised templates for spatial computing functions.
To start the coaching course of, we launch Create ML and choose the “Object Monitoring” template from the spatial class. This template is particularly designed for coaching fashions that may acknowledge and monitor objects in three-dimensional house.

After creating a brand new challenge, we import our .usdz file into Create ML. The system robotically analyzes the 3D mannequin and extracts key options that shall be used for recognition. The interface gives choices for configuring how our object must be acknowledged in house, together with viewing angles and monitoring preferences.
When you’ve imported the 3d mannequin and analyzed it in varied angles, go forward and click on on “Prepare”. Create ML will course of our mannequin and start the coaching part. Throughout this part, the system learns to acknowledge our object from varied angles and underneath completely different circumstances. The coaching course of can take a number of hours because the system builds a complete understanding of our object’s traits.

The output of this coaching course of is a .referenceobject file, which accommodates the educated mannequin information optimized for real-time object detection in visionOS. This file encapsulates all of the realized options and recognition parameters that may allow our app to establish weight-reduction plan soda cans within the person’s atmosphere.
The profitable creation of our reference object marks an necessary milestone in our growth course of. We now have a educated mannequin able to recognizing our goal object in real-time, setting the stage for implementing the precise detection and visualization performance in our visionOS software.
Preliminary Venture Setup
Now that we have now our educated reference object, let’s arrange our visionOS challenge. Launch Xcode and choose “Create a brand new Xcode challenge”. Within the template selector, select visionOS underneath the platforms filter and choose “App”. This template gives the essential construction wanted for a visionOS software.

Within the challenge configuration dialog, configure your challenge with these major settings:
- Product Title: SodaTracker
- Preliminary Scene: Window
- Immersive Area Renderer: RealityKit
- Immersive Area: Blended
After challenge creation, we have to make a number of important modifications. First, delete the file named ToggleImmersiveSpaceButton.swift as we gained’t be utilizing it in our implementation.
Subsequent, we’ll add our beforehand created property to the challenge. In Xcode’s Venture Navigator, find the “RealityKitContent.rkassets” folder and add the 3D object file (“SodaModel.usdz” file). This 3D mannequin shall be utilized in our informative view. Create a brand new group named “ReferenceObjects” and add the “Weight-reduction plan Soda.referenceobject” file we generated utilizing Create ML.
The ultimate setup step is to configure the mandatory permission for object monitoring. Open your challenge’s Data.plist file and add a brand new key: NSWorldSensingUsageDescription. Set its worth to “Used to trace weight-reduction plan sodas”. This permission is required for the app to detect and monitor objects within the person’s atmosphere.
With these setup steps full, we have now a correctly configured visionOS challenge prepared for implementing our object monitoring performance.
Entry Level Implementation
Let’s begin with SodaTrackerApp.swift, which was robotically created once we arrange our visionOS challenge. We have to modify this file to help our object monitoring performance. Change the default implementation with the next code:
import SwiftUI
/**
SodaTrackerApp is the principle entry level for the appliance.
It configures the app's window and immersive house, and manages
the initialization of object detection capabilities.
The app robotically launches into an immersive expertise
the place customers can see Weight-reduction plan Soda cans being detected and highlighted
of their atmosphere.
*/
@fundamental
struct SodaTrackerApp: App {
/// Shared mannequin that manages object detection state
@StateObject personal var appModel = AppModel()
/// System atmosphere worth for launching immersive experiences
@Setting(.openImmersiveSpace) var openImmersiveSpace
var physique: some Scene {
WindowGroup {
ContentView()
.environmentObject(appModel)
.activity {
// Load and put together object detection capabilities
await appModel.initializeDetector()
}
.onAppear {
Job {
// Launch instantly into immersive expertise
await openImmersiveSpace(id: appModel.immersiveSpaceID)
}
}
}
.windowStyle(.plain)
.windowResizability(.contentSize)
// Configure the immersive house for object detection
ImmersiveSpace(id: appModel.immersiveSpaceID) {
ImmersiveView()
.atmosphere(appModel)
}
// Use blended immersion to mix digital content material with actuality
.immersionStyle(choice: .fixed(.blended), in: .blended)
// Conceal system UI for a extra immersive expertise
.persistentSystemOverlays(.hidden)
}
}
The important thing side of this implementation is the initialization and administration of our object detection system. When the app launches, we initialize our AppModel which handles the ARKit session and object monitoring setup. The initialization sequence is essential:
.activity {
await appModel.initializeDetector()
}
This asynchronous initialization masses our educated reference object and prepares the ARKit session for object monitoring. We guarantee this occurs earlier than opening the immersive house the place the precise detection will happen.
The immersive house configuration is especially necessary for object monitoring:
.immersionStyle(choice: .fixed(.blended), in: .blended)
The blended immersion model is crucial for our object monitoring implementation because it permits RealityKit to mix our visible indicators (bounding containers and labels) with the real-world atmosphere the place we’re detecting objects. This creates a seamless expertise the place digital content material precisely aligns with bodily objects within the person’s house.
With these modifications to SodaTrackerApp.swift, our app is able to start the thing detection course of, with ARKit, RealityKit, and our educated mannequin working collectively within the blended actuality atmosphere. Within the subsequent part, we’ll look at the core object detection performance in AppModel.swift, one other file that was created throughout challenge setup.
Core Detection Mannequin Implementation
AppModel.swift, created throughout challenge setup, serves as our core detection system. This file manages the ARKit session, masses our educated mannequin, and coordinates the thing monitoring course of. Let’s look at its implementation:
import SwiftUI
import RealityKit
import ARKit
/**
AppModel serves because the core mannequin for the soda can detection software.
It manages the ARKit session, handles object monitoring initialization,
and maintains the state of object detection all through the app's lifecycle.
This mannequin is designed to work with visionOS's object monitoring capabilities,
particularly optimized for detecting Weight-reduction plan Soda cans within the person's atmosphere.
*/
@MainActor
@Observable
class AppModel: ObservableObject {
/// Distinctive identifier for the immersive house the place object detection happens
let immersiveSpaceID = "SodaTracking"
/// ARKit session occasion that manages the core monitoring performance
/// This session coordinates with visionOS to course of spatial information
personal var arSession = ARKitSession()
/// Devoted supplier that handles the real-time monitoring of soda cans
/// This maintains the state of at present tracked objects
personal var sodaTracker: ObjectTrackingProvider?
/// Assortment of reference objects used for detection
/// These objects comprise the educated mannequin information for recognizing soda cans
personal var targetObjects: [ReferenceObject] = []
/**
Initializes the thing detection system by loading and getting ready
the reference object (Weight-reduction plan Soda can) from the app bundle.
This methodology masses a pre-trained mannequin that accommodates spatial and
visible details about the Weight-reduction plan Soda can we need to detect.
*/
func initializeDetector() async {
guard let objectURL = Bundle.fundamental.url(forResource: "Weight-reduction plan Soda", withExtension: "referenceobject") else {
print("Error: Didn't find reference object in bundle - guarantee Weight-reduction plan Soda.referenceobject exists")
return
}
do {
let referenceObject = attempt await ReferenceObject(from: objectURL)
self.targetObjects = [referenceObject]
} catch {
print("Error: Didn't initialize reference object: (error)")
}
}
/**
Begins the energetic object detection course of utilizing ARKit.
This methodology initializes the monitoring supplier with loaded reference objects
and begins the real-time detection course of within the person's atmosphere.
Returns: An ObjectTrackingProvider if efficiently initialized, nil in any other case
*/
func beginDetection() async -> ObjectTrackingProvider? {
guard !targetObjects.isEmpty else { return nil }
let tracker = ObjectTrackingProvider(referenceObjects: targetObjects)
do {
attempt await arSession.run([tracker])
self.sodaTracker = tracker
return tracker
} catch {
print("Error: Didn't initialize monitoring: (error)")
return nil
}
}
/**
Terminates the thing detection course of.
This methodology safely stops the ARKit session and cleans up
monitoring sources when object detection is not wanted.
*/
func endDetection() {
arSession.cease()
}
}
On the core of our implementation is ARKitSession, visionOS’s gateway to spatial computing capabilities. The @MainActor attribute ensures our object detection operations run on the principle thread, which is essential for synchronizing with the rendering pipeline.
personal var arSession = ARKitSession()
personal var sodaTracker: ObjectTrackingProvider?
personal var targetObjects: [ReferenceObject] = []
The ObjectTrackingProvider is a specialised element in visionOS that handles real-time object detection. It really works at the side of ReferenceObject situations, which comprise the spatial and visible data from our educated mannequin. We preserve these as personal properties to make sure correct lifecycle administration.
The initialization course of is especially necessary:
let referenceObject = attempt await ReferenceObject(from: objectURL)
self.targetObjects = [referenceObject]
Right here, we load our educated mannequin (the .referenceobject file we created in Create ML) right into a ReferenceObject occasion. This course of is asynchronous as a result of the system must parse and put together the mannequin information for real-time detection.
The beginDetection methodology units up the precise monitoring course of:
let tracker = ObjectTrackingProvider(referenceObjects: targetObjects)
attempt await arSession.run([tracker])
After we create the ObjectTrackingProvider, we move in our reference objects. The supplier makes use of these to ascertain the detection parameters — what to search for, what options to match, and the way to monitor the thing in 3D house. The ARKitSession.run name prompts the monitoring system, starting the real-time evaluation of the person’s atmosphere.
Immersive Expertise Implementation
ImmersiveView.swift, supplied in our preliminary challenge setup, manages the real-time object detection visualization within the person’s house. This view processes the continual stream of detection information and creates visible representations of detected objects. Right here’s the implementation:
import SwiftUI
import RealityKit
import ARKit
/**
ImmersiveView is liable for creating and managing the augmented actuality
expertise the place object detection happens. This view handles the real-time
visualization of detected soda cans within the person's atmosphere.
It maintains a group of visible representations for every detected object
and updates them in real-time as objects are detected, moved, or eliminated
from view.
*/
struct ImmersiveView: View {
/// Entry to the app's shared mannequin for object detection performance
@Setting(AppModel.self) personal var appModel
/// Root entity that serves because the father or mother for all AR content material
/// This entity gives a constant coordinate house for all visualizations
@State personal var sceneRoot = Entity()
/// Maps distinctive object identifiers to their visible representations
/// Permits environment friendly updating of particular object visualizations
@State personal var activeVisualizations: [UUID: ObjectVisualization] = [:]
var physique: some View {
RealityView { content material in
// Initialize the AR scene with our root entity
content material.add(sceneRoot)
Job {
// Start object detection and monitor adjustments
let detector = await appModel.beginDetection()
guard let detector else { return }
// Course of real-time updates for object detection
for await replace in detector.anchorUpdates {
let anchor = replace.anchor
let id = anchor.id
swap replace.occasion {
case .added:
// Object newly detected - create and add visualization
let visualization = ObjectVisualization(for: anchor)
activeVisualizations[id] = visualization
sceneRoot.addChild(visualization.entity)
case .up to date:
// Object moved - replace its place and orientation
activeVisualizations[id]?.refreshTracking(with: anchor)
case .eliminated:
// Object not seen - take away its visualization
activeVisualizations[id]?.entity.removeFromParent()
activeVisualizations.removeValue(forKey: id)
}
}
}
}
.onDisappear {
// Clear up AR sources when view is dismissed
cleanupVisualizations()
}
}
/**
Removes all energetic visualizations and stops object detection.
This ensures correct cleanup of AR sources when the view is not energetic.
*/
personal func cleanupVisualizations() {
for (_, visualization) in activeVisualizations {
visualization.entity.removeFromParent()
}
activeVisualizations.removeAll()
appModel.endDetection()
}
}
The core of our object monitoring visualization lies within the detector’s anchorUpdates stream. This ARKit function gives a steady move of object detection occasions:
for await replace in detector.anchorUpdates {
let anchor = replace.anchor
let id = anchor.id
swap replace.occasion {
case .added:
// Object first detected
case .up to date:
// Object place modified
case .eliminated:
// Object not seen
}
}
Every ObjectAnchor accommodates essential spatial information concerning the detected soda can, together with its place, orientation, and bounding field in 3D house. When a brand new object is detected (.added occasion), we create a visualization that RealityKit will render within the appropriate place relative to the bodily object. As the thing or person strikes, the .up to date occasions guarantee our digital content material stays completely aligned with the actual world.
Visible Suggestions System
Create a brand new file named ObjectVisualization.swift for dealing with the visible illustration of detected objects. This element is liable for creating and managing the bounding field and textual content overlay that seems round detected soda cans:
import RealityKit
import ARKit
import UIKit
import SwiftUI
/**
ObjectVisualization manages the visible parts that seem when a soda can is detected.
This class handles each the 3D textual content label that seems above the thing and the
bounding field that outlines the detected object in house.
*/
@MainActor
class ObjectVisualization {
/// Root entity that accommodates all visible parts
var entity: Entity
/// Entity particularly for the bounding field visualization
personal var boundingBox: Entity
/// Width of bounding field strains - 0.003 gives optimum visibility with out being too intrusive
personal let outlineWidth: Float = 0.003
init(for anchor: ObjectAnchor) {
entity = Entity()
boundingBox = Entity()
// Arrange the principle entity's rework based mostly on the detected object's place
entity.rework = Rework(matrix: anchor.originFromAnchorTransform)
entity.isEnabled = anchor.isTracked
createFloatingLabel(for: anchor)
setupBoundingBox(for: anchor)
refreshBoundingBoxGeometry(with: anchor)
}
/**
Creates a floating textual content label that hovers above the detected object.
The textual content makes use of Avenir Subsequent font for optimum readability in AR house and
is positioned barely above the thing for clear visibility.
*/
personal func createFloatingLabel(for anchor: ObjectAnchor) {
// 0.06 models gives optimum textual content dimension for viewing at typical distances
let labelSize: Float = 0.06
// Use Avenir Subsequent for its readability and trendy look in AR
let font = MeshResource.Font(identify: "Avenir Subsequent", dimension: CGFloat(labelSize))!
let textMesh = MeshResource.generateText("Weight-reduction plan Soda",
extrusionDepth: labelSize * 0.15,
font: font)
// Create a cloth that makes textual content clearly seen towards any background
var textMaterial = UnlitMaterial()
textMaterial.colour = .init(tint: .orange)
let textEntity = ModelEntity(mesh: textMesh, supplies: [textMaterial])
// Place textual content above object with sufficient clearance to keep away from intersection
textEntity.rework.translation = SIMD3(
anchor.boundingBox.heart.x - textMesh.bounds.max.x / 2,
anchor.boundingBox.extent.y + labelSize * 1.5,
0
)
entity.addChild(textEntity)
}
/**
Creates a bounding field visualization that outlines the detected object.
Makes use of a magenta colour transparency to supply a transparent
however non-distracting visible boundary across the detected soda can.
*/
personal func setupBoundingBox(for anchor: ObjectAnchor) {
let boxMesh = MeshResource.generateBox(dimension: [1.0, 1.0, 1.0])
// Create a single materials for all edges with magenta colour
let boundsMaterial = UnlitMaterial(colour: .magenta.withAlphaComponent(0.4))
// Create all edges with uniform look
for _ in 0..<12 {
let edge = ModelEntity(mesh: boxMesh, supplies: [boundsMaterial])
boundingBox.addChild(edge)
}
entity.addChild(boundingBox)
}
/**
Updates the visualization when the tracked object strikes.
This ensures the bounding field and textual content preserve correct positioning
relative to the bodily object being tracked.
*/
func refreshTracking(with anchor: ObjectAnchor) {
entity.isEnabled = anchor.isTracked
guard anchor.isTracked else { return }
entity.rework = Rework(matrix: anchor.originFromAnchorTransform)
refreshBoundingBoxGeometry(with: anchor)
}
/**
Updates the bounding field geometry to match the detected object's dimensions.
Creates a exact define that precisely matches the bodily object's boundaries
whereas sustaining the gradient visible impact.
*/
personal func refreshBoundingBoxGeometry(with anchor: ObjectAnchor) {
let extent = anchor.boundingBox.extent
boundingBox.rework.translation = anchor.boundingBox.heart
for (index, edge) in boundingBox.youngsters.enumerated() {
guard let edge = edge as? ModelEntity else { proceed }
swap index {
case 0...3: // Horizontal edges alongside width
edge.scale = SIMD3(extent.x, outlineWidth, outlineWidth)
edge.place = [
0,
extent.y / 2 * (index % 2 == 0 ? -1 : 1),
extent.z / 2 * (index < 2 ? -1 : 1)
]
case 4...7: // Vertical edges alongside peak
edge.scale = SIMD3(outlineWidth, extent.y, outlineWidth)
edge.place = [
extent.x / 2 * (index % 2 == 0 ? -1 : 1),
0,
extent.z / 2 * (index < 6 ? -1 : 1)
]
case 8...11: // Depth edges
edge.scale = SIMD3(outlineWidth, outlineWidth, extent.z)
edge.place = [
extent.x / 2 * (index % 2 == 0 ? -1 : 1),
extent.y / 2 * (index < 10 ? -1 : 1),
0
]
default:
break
}
}
}
}
The bounding field creation is a key side of our visualization. Reasonably than utilizing a single field mesh, we assemble 12 particular person edges that type a wireframe define. This method gives higher visible readability and permits for extra exact management over the looks. The perimeters are positioned utilizing SIMD3 vectors for environment friendly spatial calculations:
edge.place = [
extent.x / 2 * (index % 2 == 0 ? -1 : 1),
extent.y / 2 * (index < 10 ? -1 : 1),
0
]
This mathematical positioning ensures every edge aligns completely with the detected object’s dimensions. The calculation makes use of the thing’s extent (width, peak, depth) and creates a symmetrical association round its heart level.
This visualization system works at the side of our ImmersiveView to create real-time visible suggestions. Because the ImmersiveView receives place updates from ARKit, it calls refreshTracking on our visualization, which updates the rework matrices to keep up exact alignment between the digital overlays and the bodily object.
Informative View

ContentView.swift, supplied in our challenge template, handles the informational interface for our app. Right here’s the implementation:
import SwiftUI
import RealityKit
import RealityKitContent
/**
ContentView gives the principle window interface for the appliance.
Shows a rotating 3D mannequin of the goal object (Weight-reduction plan Soda can)
together with clear directions for customers on the way to use the detection function.
*/
struct ContentView: View {
// State to regulate the continual rotation animation
@State personal var rotation: Double = 0
var physique: some View {
VStack(spacing: 30) {
// 3D mannequin show with rotation animation
Model3D(named: "SodaModel", bundle: realityKitContentBundle)
.padding(.vertical, 20)
.body(width: 200, peak: 200)
.rotation3DEffect(
.levels(rotation),
axis: (x: 0, y: 1, z: 0)
)
.onAppear {
// Create steady rotation animation
withAnimation(.linear(length: 5.0).repeatForever(autoreverses: true)) {
rotation = 180
}
}
// Directions for customers
VStack(spacing: 15) {
Textual content("Weight-reduction plan Soda Detection")
.font(.title)
.fontWeight(.daring)
Textual content("Maintain your weight-reduction plan soda can in entrance of you to see it robotically detected and highlighted in your house.")
.font(.physique)
.multilineTextAlignment(.heart)
.foregroundColor(.secondary)
.padding(.horizontal)
}
}
.padding()
.body(maxWidth: 400)
}
}
This implementation shows our 3D-scanned soda mannequin (SodaModel.usdz) with a rotating animation, offering customers with a transparent reference of what the system is searching for. The rotation helps customers perceive the way to current the thing for optimum detection.
With these elements in place, our software now gives an entire object detection expertise. The system makes use of our educated mannequin to acknowledge weight-reduction plan soda cans, creates exact visible indicators in real-time, and gives clear person steering by the informational interface.
Conclusion

On this tutorial, we’ve constructed an entire object detection system for visionOS that showcases the combination of a number of highly effective applied sciences. Ranging from 3D object seize, by ML mannequin coaching in Create ML, to real-time detection utilizing ARKit and RealityKit, we’ve created an app that seamlessly detects and tracks objects within the person’s house.
This implementation represents just the start of what’s attainable with on-device machine studying in spatial computing. As {hardware} continues to evolve with extra highly effective Neural Engines and devoted ML accelerators and frameworks like Core ML mature, we’ll see more and more refined functions that may perceive and work together with our bodily world in real-time. The mixture of spatial computing and on-device ML opens up potentialities for functions starting from superior AR experiences to clever environmental understanding, all whereas sustaining person privateness and low latency.