From 67f347e705574b39c0700c3f04a8a0b336ae6ae1 Mon Sep 17 00:00:00 2001 From: clement Date: Tue, 30 Jun 2026 21:54:41 +0200 Subject: [PATCH] feat(iphone): emit skeleton topology on connect --- .../Sources/ARBodyTracker/ARBodySession.swift | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/iphone-arbody/ARBodyTracker.swiftpm/Sources/ARBodyTracker/ARBodySession.swift b/iphone-arbody/ARBodyTracker.swiftpm/Sources/ARBodyTracker/ARBodySession.swift index a2c0193..3525613 100644 --- a/iphone-arbody/ARBodyTracker.swiftpm/Sources/ARBodyTracker/ARBodySession.swift +++ b/iphone-arbody/ARBodyTracker.swiftpm/Sources/ARBodyTracker/ARBodySession.swift @@ -67,7 +67,14 @@ final class ARBodySession: NSObject, ObservableObject, ARSessionDelegate { super.init() session.delegate = self usb.onState = { [weak self] s in - Task { @MainActor in self?.usbState = s } + Task { @MainActor in + guard let self else { return } + let was = self.usbState + self.usbState = s + if s == .connected && was != .connected { + self.publishTopology() + } + } } videoEncoder.onPayload = { [weak self] payload in Task { @MainActor in @@ -338,4 +345,19 @@ final class ARBodySession: NSObject, ObservableObject, ARSessionDelegate { payload: p2.encoded()) } + /// Send the ARKit body joint names + parent indices once, so the Mac + /// renders bones generically. Static data — available before any body + /// is tracked, so it is safe to emit right after connect. + @MainActor + private func publishTopology() { + guard usbState == .connected else { return } + let def = ARSkeletonDefinition.defaultBody3D + let names = def.jointNames + let parents = def.parentIndices.map { Int16(clamping: $0) } + let payload = TopologyPayload(jointNames: names, parents: parents) + usb.send(tag: .topology, pid: -1, + timestamp: lastFrameTime, + payload: payload.encoded()) + } + }