Files
La-Fabrik/src/components/ui/HandTrackingVisualizer.tsx
T
2026-04-29 10:34:11 +02:00

78 lines
1.9 KiB
TypeScript

import { useHandTrackingSnapshot } from "@/hooks/useHandTrackingSnapshot";
const HAND_CONNECTIONS: 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],
];
export function HandTrackingVisualizer(): React.JSX.Element | null {
const { hands, status } = useHandTrackingSnapshot();
if (status === "idle" || hands.length === 0) {
return null;
}
return (
<svg className="hand-tracking-visualizer" aria-hidden="true">
{hands.map((hand, handIndex) => {
const landmarks = hand.landmarks ?? [];
if (landmarks.length === 0) return null;
const color = hand.isFist ? "#facc15" : "#38bdf8";
return (
<g key={`${hand.handedness}-${handIndex}`}>
{HAND_CONNECTIONS.map(([from, to]) => {
const fromPoint = landmarks[from];
const toPoint = landmarks[to];
if (!fromPoint || !toPoint) return null;
return (
<line
key={`${from}-${to}`}
x1={`${(1 - fromPoint.x) * 100}%`}
y1={`${fromPoint.y * 100}%`}
x2={`${(1 - toPoint.x) * 100}%`}
y2={`${toPoint.y * 100}%`}
stroke={color}
strokeWidth="2"
strokeLinecap="round"
/>
);
})}
{landmarks.map((landmark, landmarkIndex) => (
<circle
key={landmarkIndex}
cx={`${(1 - landmark.x) * 100}%`}
cy={`${landmark.y * 100}%`}
r={landmarkIndex === 8 ? 5 : 3}
fill={landmarkIndex === 8 ? "#ffffff" : color}
/>
))}
</g>
);
})}
</svg>
);
}