Files
Genarrative/src/services/useMocapInput.test.ts
五香丸子 5cc8293380
Some checks failed
CI / verify (push) Has been cancelled
feat: add child motion picture book stage tooling
2026-05-10 23:10:24 +08:00

125 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, test } from 'vitest';
import { parseMocapPacket, resolveMocapPalmCenter } from './useMocapInput';
describe('resolveMocapPalmCenter', () => {
test('优先用手腕和四个 MCP 点加权计算掌心派生点', () => {
const center = resolveMocapPalmCenter([
{ name: 'wrist', x: 0.1, y: 0.2 },
{ name: 'index_mcp', x: 0.3, y: 0.4 },
{ name: 'middle_mcp', x: 0.5, y: 0.6 },
{ name: 'ring_mcp', x: 0.7, y: 0.8 },
{ name: 'pinky_mcp', x: 0.9, y: 1 },
{ name: 'index_finger_tip', x: 1, y: 1 },
]);
expect(center?.x).toBeCloseTo(0.44);
expect(center?.y).toBeCloseTo(0.54);
});
test('可用掌心点少于三个时不返回掌心坐标', () => {
expect(
resolveMocapPalmCenter([
{ name: 'wrist', x: 0.1, y: 0.2 },
{ name: 'index_mcp', x: 0.3, y: 0.4 },
]),
).toBeNull();
});
});
describe('parseMocapPacket', () => {
test('解析手部数据时优先把 primaryHand 定位到掌心而不是腕部或指尖', () => {
const command = parseMocapPacket({
hands: [
{
state: 'open_palm',
x: 0.01,
y: 0.02,
landmarks: [
{ name: 'wrist', x: 0.1, y: 0.2 },
{ name: 'index_mcp', x: 0.3, y: 0.4 },
{ name: 'middle_mcp', x: 0.5, y: 0.6 },
{ name: 'ring_mcp', x: 0.7, y: 0.8 },
{ name: 'pinky_mcp', x: 0.9, y: 1 },
],
},
],
});
expect(command.primaryHand?.x).toBeCloseTo(0.44);
expect(command.primaryHand?.y).toBeCloseTo(0.54);
expect(command.primaryHand).toEqual(
expect.objectContaining({
state: 'open_palm',
source: 'palm_center',
}),
);
});
test('缺少足够掌心关键点时退回 wrist landmark再退回 hand 直出坐标', () => {
const landmarkFallback = parseMocapPacket({
hands: [
{
state: 'grab',
x: 0.9,
y: 0.8,
landmarks: [{ name: 'wrist', x: 0.25, y: 0.75 }],
},
],
});
expect(landmarkFallback.primaryHand).toEqual(
expect.objectContaining({x: 0.25, y: 0.75, source: 'landmark'}),
);
const directFallback = parseMocapPacket({
hands: [{ state: 'grab', x: 0.9, y: 0.8 }],
});
expect(directFallback.primaryHand).toEqual(
expect.objectContaining({x: 0.9, y: 0.8, source: 'direct'}),
);
});
test('解析 mocap frame 的身体中心和左右手来源', () => {
const command = parseMocapPacket({
schema_version: '1.0',
stream: { type: 'mocap.frame' },
general: {
body: {
center_norm: [0.34, 0.58],
},
},
actions: [{ gesture: 'wave-left-hand' }],
hands: [
{
label: 'Left',
state: 'open_palm',
landmarks: [
{ name: 'wrist', x: 0.21, y: 0.31 },
{ name: 'index_mcp', x: 0.25, y: 0.33 },
{ name: 'middle_mcp', x: 0.27, y: 0.34 },
{ name: 'ring_mcp', x: 0.28, y: 0.35 },
{ name: 'pinky_mcp', x: 0.29, y: 0.36 },
],
},
{
label: 'Right',
state: 'unknown',
x: 0.72,
y: 0.32,
},
],
});
expect(command.bodyCenter).toEqual({x: 0.34, y: 0.58});
expect(command.actions).toEqual(
expect.arrayContaining(['wave_left_hand', 'open_palm']),
);
expect(command.leftHand).toEqual(
expect.objectContaining({side: 'left', source: 'palm_center'}),
);
expect(command.rightHand).toEqual(
expect.objectContaining({x: 0.72, y: 0.32, side: 'right'}),
);
});
});