From 819c9688e787a5fc70c1acfca8a86d752f05c8cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=27=C3=A9lectron=20rare?= <108685187+electron-rare@users.noreply.github.com> Date: Mon, 18 May 2026 21:43:27 +0200 Subject: [PATCH] feat(avlivebody-mac): 91-joint skeleton entity Yellow marker spheres pooled per pid; ARKit (x,y,z) -> RealityKit (x,-y,-z). Adapted .systemYellow to NSColor for macOS RealityKit Material.Color. Build deferred to T8. --- .../Sources/AVLiveBody/SkeletonEntity.swift | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 avlivebody-mac/Sources/AVLiveBody/SkeletonEntity.swift diff --git a/avlivebody-mac/Sources/AVLiveBody/SkeletonEntity.swift b/avlivebody-mac/Sources/AVLiveBody/SkeletonEntity.swift new file mode 100644 index 0000000..4392dc8 --- /dev/null +++ b/avlivebody-mac/Sources/AVLiveBody/SkeletonEntity.swift @@ -0,0 +1,57 @@ +import AVLiveWire +import AppKit +import Foundation +import RealityKit +import simd + +/// Renders 91-joint skeletons as yellow marker spheres. One marker +/// pool per pid. ARKit world coords -> RealityKit space (x, -y, -z). +@MainActor +final class SkeletonEntity { + let root = Entity() + + private static let jointCount = 91 + private static let markerRadius: Float = 0.012 + + private var pools: [Int: [ModelEntity]] = [:] + private let mesh = MeshResource.generateSphere(radius: markerRadius) + private let material = SimpleMaterial( + color: NSColor.systemYellow, roughness: 0.6, isMetallic: false) + + func update(_ skeletons: [Int: SkeletonPayload]) { + // Drop pools for pids no longer present. + for pid in pools.keys where skeletons[pid] == nil { + pools[pid]?.forEach { $0.removeFromParent() } + pools.removeValue(forKey: pid) + } + for (pid, payload) in skeletons { + let pool = pools[pid] ?? makePool() + pools[pid] = pool + let n = min(Self.jointCount, payload.joints.count, + payload.valid.count) + for i in 0..(j.x, -j.y, -j.z) + marker.isEnabled = true + } else { + marker.isEnabled = false + } + } + } + } + + private func makePool() -> [ModelEntity] { + var pool: [ModelEntity] = [] + pool.reserveCapacity(Self.jointCount) + for _ in 0..