DockKit
Framework for integrating with motorized camera stands and gimbals that
physically track subjects by rotating the iPhone. DockKit handles motor
control, subject detection, and framing so camera apps get 360-degree pan
and 90-degree tilt tracking with no additional code. Apps can override
system tracking to supply custom observations, control motors directly,
or adjust framing. iOS 17+, Swift 6.3.
Contents
Workflow
- Gate the feature on DockKit availability and a connected compatible accessory; plan physical-device verification.
- Start and retain the accessory session, observe lifecycle events, and choose system tracking or custom tracking.
- For custom tracking, provide observations at the supported cadence with valid camera geometry and confidence.
- Disable system tracking before direct motor commands, enforce limits, and restore the intended mode afterward.
- Verify disconnect/reconnect, tracking loss, subject changes, thermal/battery state, and cancellation.
Route by Task
- Read core implementation details for accessory discovery, system/custom tracking, framing, motor control, animations, events, and battery state.
- Read extended DockKit patterns for Vision integration, service architecture, observation pipelines, and custom animations.
Core Decisions
- Do not mix system subject tracking and direct motor control concurrently.
- Treat camera intrinsics, orientation, and observation coordinates as explicit inputs.
- Rate-limit tracking observations and motor/animation commands.
- Restore safe tracking state after lifecycle transitions and failures.
Common Mistakes
DON'T: Control motors without disabling system tracking
// WRONG -- system tracking fights manual commands
try await accessory.setAngularVelocity(velocity)
// CORRECT -- disable system tracking first
try await DockAccessoryManager.shared.setSystemTrackingEnabled(false)
try await accessory.setAngularVelocity(velocity)
DON'T: Assume tracking state persists across lifecycle events
// WRONG -- state may have reset after backgrounding
func applicationDidBecomeActive() {
// Assume custom tracking is still active
}
// CORRECT -- re-set tracking state on foreground
func applicationDidBecomeActive() {
Task {
try await DockAccessoryManager.shared.setSystemTrackingEnabled(false)
}
}
DON'T: Call track() outside the recommended rate
// WRONG -- calling once per second is too slow
try await accessory.track(observations, cameraInformation: cameraInfo)
// (called at 1 fps)
// CORRECT -- call at 10-30 fps
// Hook into AVCaptureVideoDataOutputSampleBufferDelegate for per-frame calls
DON'T: Spam orientation or animation calls
DockKit can throw .frameRateTooHigh if animate(motion:) or
setOrientation(_:duration:relative:) is called more than twice per second.
Set a trajectory, observe its Progress, and avoid tight command loops.
DON'T: Forget to restore tracking after animations
// WRONG -- tracking stays disabled after animation
try await DockAccessoryManager.shared.setSystemTrackingEnabled(false)
let progress = try await accessory.animate(motion: .kapow)
// CORRECT -- restore tracking when animation completes
try await DockAccessoryManager.shared.setSystemTrackingEnabled(false)
let progress = try await accessory.animate(motion: .kapow)
while !progress.isFinished && !progress.isCancelled {
try await Task.sleep(for: .milliseconds(100))
}
try await DockAccessoryManager.shared.setSystemTrackingEnabled(true)
DON'T: Use DockKit in Simulator
DockKit requires a physical DockKit-compatible accessory. Guard
initialization and provide fallback behavior when no accessory is
available.
Review Checklist
References
1---2name: dockkit3description: Control motorized camera docks and enable intelligent subject tracking using DockKit. Use when discovering DockKit-compatible accessories, implementing camera subject tracking for faces or bodies, controlling dock motors for pan and tilt, configuring framing behavior, setting regions of interest, or building video apps with automatic camera tracking.4---56# DockKit78Framework for integrating with motorized camera stands and gimbals that9physically track subjects by rotating the iPhone. DockKit handles motor10control, subject detection, and framing so camera apps get 360-degree pan11and 90-degree tilt tracking with no additional code. Apps can override12system tracking to supply custom observations, control motors directly,13or adjust framing. iOS 17+, Swift 6.3.1415## Contents1617- [Workflow](#workflow)18- [Route by Task](#route-by-task)19- [Core Decisions](#core-decisions)20- [Common Mistakes](#common-mistakes)21- [Review Checklist](#review-checklist)22- [References](#references)2324## Workflow25261. Gate the feature on DockKit availability and a connected compatible accessory; plan physical-device verification.272. Start and retain the accessory session, observe lifecycle events, and choose system tracking or custom tracking.283. For custom tracking, provide observations at the supported cadence with valid camera geometry and confidence.294. Disable system tracking before direct motor commands, enforce limits, and restore the intended mode afterward.305. Verify disconnect/reconnect, tracking loss, subject changes, thermal/battery state, and cancellation.3132## Route by Task3334- Read [core implementation details](references/core-implementation.md) for accessory discovery, system/custom tracking, framing, motor control, animations, events, and battery state.35- Read [extended DockKit patterns](references/dockkit-patterns.md) for Vision integration, service architecture, observation pipelines, and custom animations.3637## Core Decisions3839- Do not mix system subject tracking and direct motor control concurrently.40- Treat camera intrinsics, orientation, and observation coordinates as explicit inputs.41- Rate-limit tracking observations and motor/animation commands.42- Restore safe tracking state after lifecycle transitions and failures.4344## Common Mistakes4546### DON'T: Control motors without disabling system tracking4748```swift49// WRONG -- system tracking fights manual commands50try await accessory.setAngularVelocity(velocity)5152// CORRECT -- disable system tracking first53try await DockAccessoryManager.shared.setSystemTrackingEnabled(false)54try await accessory.setAngularVelocity(velocity)55```5657### DON'T: Assume tracking state persists across lifecycle events5859```swift60// WRONG -- state may have reset after backgrounding61func applicationDidBecomeActive() {62 // Assume custom tracking is still active63}6465// CORRECT -- re-set tracking state on foreground66func applicationDidBecomeActive() {67 Task {68 try await DockAccessoryManager.shared.setSystemTrackingEnabled(false)69 }70}71```7273### DON'T: Call track() outside the recommended rate7475```swift76// WRONG -- calling once per second is too slow77try await accessory.track(observations, cameraInformation: cameraInfo)78// (called at 1 fps)7980// CORRECT -- call at 10-30 fps81// Hook into AVCaptureVideoDataOutputSampleBufferDelegate for per-frame calls82```8384### DON'T: Spam orientation or animation calls8586DockKit can throw `.frameRateTooHigh` if `animate(motion:)` or87`setOrientation(_:duration:relative:)` is called more than twice per second.88Set a trajectory, observe its `Progress`, and avoid tight command loops.8990### DON'T: Forget to restore tracking after animations9192```swift93// WRONG -- tracking stays disabled after animation94try await DockAccessoryManager.shared.setSystemTrackingEnabled(false)95let progress = try await accessory.animate(motion: .kapow)9697// CORRECT -- restore tracking when animation completes98try await DockAccessoryManager.shared.setSystemTrackingEnabled(false)99let progress = try await accessory.animate(motion: .kapow)100while !progress.isFinished && !progress.isCancelled {101 try await Task.sleep(for: .milliseconds(100))102}103try await DockAccessoryManager.shared.setSystemTrackingEnabled(true)104```105106### DON'T: Use DockKit in Simulator107108DockKit requires a physical DockKit-compatible accessory. Guard109initialization and provide fallback behavior when no accessory is110available.111112## Review Checklist113114- [ ] `import DockKit` present where needed115- [ ] Subscribed to `accessoryStateChanges` to detect dock/undock events116- [ ] Handled both `.docked` and `.undocked` states117- [ ] System tracking disabled before custom tracking or motor control118- [ ] System tracking restored after animations complete119- [ ] Custom observations supplied at 10-30 fps120- [ ] `animate` and `setOrientation` commands limited to 2 calls per second121- [ ] Observation `rect` uses normalized coordinates (lower-left origin)122- [ ] Camera information is built inline from the active `AVCaptureDevice` and current sample buffer123- [ ] Observation type choice names `.humanFace`, `.humanBody`, and `.object`124- [ ] `@unknown default` handled in all switch statements over DockKit enums125- [ ] Motion limits set if restricting accessory range of motion126- [ ] Tracking state re-applied after app returns to foreground127- [ ] `accessoryEvents` guarded with `#available(iOS 17.4, *)`128- [ ] `trackingStates` and `batteryStates` guarded with `#available(iOS 18.0, *)`129- [ ] Battery UI preserves `BatteryState.name` for multi-battery docks130- [ ] No DockKit code paths executed in Simulator builds131132## References133134- Extended patterns (Vision integration, service architecture, custom animations): [references/dockkit-patterns.md](references/dockkit-patterns.md)135- Error handling and unit testing: [references/dockkit-errors-and-testing.md](references/dockkit-errors-and-testing.md)136- [DockKit framework](https://sosumi.ai/documentation/dockkit)137- [DockAccessoryManager](https://sosumi.ai/documentation/dockkit/dockaccessorymanager)138- [DockAccessory](https://sosumi.ai/documentation/dockkit/dockaccessory)139- [Controlling a DockKit accessory using your camera app](https://sosumi.ai/documentation/dockkit/controlling-a-dockkit-accessory-using-your-camera-app)140- [Track custom objects in a frame](https://sosumi.ai/documentation/dockkit/track-custom-objects-in-a-frame)141- [Modify rotation and positioning programmatically](https://sosumi.ai/documentation/dockkit/modify-rotation-and-positioning-behavior-programmatically)142- [Integrate with motorized iPhone stands using DockKit -- WWDC23](https://sosumi.ai/videos/play/wwdc2023/10304/)143- [What's new in DockKit -- WWDC24](https://sosumi.ai/videos/play/wwdc2024/10164/)144- [Core implementation details](references/core-implementation.md) -- setup, API wiring, and focused implementation recipes moved out of the entrypoint.