import { useHandTrackingSnapshot } from "@/hooks/handTracking/useHandTrackingSnapshot"; import { useDebugStore } from "@/hooks/debug/useDebugStore"; // MediaPipe indexes the 21 hand landmarks predictably: // 0 wrist, 1-4 thumb (base→tip), 5-8 index, 9-12 middle, 13-16 ring, 17-20 pinky. const FINGER_LANDMARKS: Array = [ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16], [17, 18, 19, 20], ]; const SKELETON_BONES: Array<[number, number]> = [ [0, 1], [1, 2], [2, 3], [3, 4], [0, 5], [5, 6], [6, 7], [7, 8], [5, 9], [9, 10], [10, 11], [11, 12], [9, 13], [13, 14], [14, 15], [15, 16], [13, 17], [17, 18], [18, 19], [19, 20], [0, 17], ]; const HAND_FILL = "#bfdbfe"; // blue-200, light interior const HAND_OUTLINE_COLOR = "#1e3a8a"; // blue-900, crisp dark outline const HAND_OUTLINE_RADIUS = 2; // px // Shrink the rendered hand around its centroid. Grab/physics keep using raw // landmarks elsewhere, so the silhouette is just visually smaller. const RENDER_SCALE = 0.65; const FINGER_THICKNESS_FACTOR = 0.08; // fraction of (scaled) hand length const WRIST_HALF_WIDTH = 0.28; const SKELETON_STROKE = "rgba(30, 58, 138, 0.22)"; const SKELETON_DOT_FILL = "rgba(30, 58, 138, 0.35)"; const FILTER_ID = "hand-tracking-outline"; export function HandTrackingVisualizer(): React.JSX.Element | null { const { hands, status } = useHandTrackingSnapshot(); const showHandTrackingModel = useDebugStore((debug) => debug.getShowHandTrackingModel(), ); if (status === "idle" || hands.length === 0 || showHandTrackingModel) { return null; } const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; return ( ); }