Skip to content

PhotoLab

PhotoLab — Claude Context

Internal diagnostic tool for testing and visualizing all Enobarbus trackers. Not shipped to users. Depends on Horatio + Enobarbus only (no Ariel, Touchstone, or camera/Bluetooth entitlements beyond basic camera access).

Purpose

Live camera overlay showing tracking data from all Enobarbus trackers — hands, body, face, relationships, depth — with ARKit auto-selection when hardware supports it. Used to validate tracker accuracy, coordinate transforms, and source data before wiring into Prospero/Caliban/Hecate.

Files

File Role
PhotoLabApp.swift @main entry point
ContentView.swift ZStack orchestrator: camera preview (Vision or ARKit), tracking overlays, controls, data panel, calibration
Models/PhotoLabState.swift @Observable central state: all trackers, session management, backend selection, Combine bridges
Views/TrackingControlsView.swift Top bar: mode picker, camera switch, toggle buttons, ARKit badges, calibrate button

Architecture

Backend Selection

PhotoLabState.preferredBackend(for:) auto-selects ARKit when hardware supports it: - Face mode: ARKit if TrueDepth available (52 blend shapes vs Vision's 11) - Body mode: ARKit if A12+ (91 joints vs Vision's 19) - Hands mode: Always Vision (ARKit hand tracking is visionOS-only) - All mode: ARKit for the richer tracker + Vision fallback for the other

Session Lifecycle

  • start() → picks backend → creates VisionTrackingSession or ARTrackingSession → registers handlers
  • changeTrackingMode() → tears down and restarts if backend changes, otherwise re-registers handlers
  • switchCamera() → Vision only (ARKit controls its own camera)
  • Camera switch button is disabled when ARKit is active

Data Flow

VisionTrackingSession (CameraManager)  ─or─  ARTrackingSession (ARSession)
         │                                           │
    CMSampleBuffer                          ARFrame.capturedImage
    → processFrame                          → processPixelBuffer (hands)
                                            → onFaceAnchorsUpdated (ARKitFaceTracker)
                                            → onBodyAnchorsUpdated (ARKitBodyTracker)
         │                                           │
         └───────── @Published inputSources ─────────┘
                          │
                    Combine bridges
                          │
                  @Observable state properties
                   (handSources, bodySources, faceSources, relationshipSources)
                          │
                  allActiveSources → SourceDataView

UI State

  • trackingMode: hands/body/face/relationships/all
  • trackingBackend: vision/arkit (auto-selected, shown via badge)
  • showConfidence: label overlays
  • showDataPanel: SourceDataView at bottom
  • showStabilized: PositionStabilizer filtering
  • showCalibration: T-pose calibration sheet
  • dataFrozen: pause data panel updates

Rules

  • No Ariel or Touchstone imports — this is a tracking-only diagnostic tool.
  • Overlay views come from Enobarbus Views/ — don't duplicate them here.
  • ARKit tracker Combine bridges must check trackingBackend to avoid overwriting sources from the wrong backend.