142 lines
5.0 KiB
TypeScript
142 lines
5.0 KiB
TypeScript
|
|
export interface Landmark {
|
|
x: number;
|
|
y: number;
|
|
z: number;
|
|
visibility?: number;
|
|
}
|
|
|
|
export interface AnglesDict {
|
|
[key: string]: number;
|
|
}
|
|
|
|
export type FormValidationResult = {
|
|
valid: boolean;
|
|
feedback: string[];
|
|
};
|
|
|
|
// Expanded Configuration Interface to match Python
|
|
export interface ExerciseConfig {
|
|
name: string;
|
|
// Core Identification
|
|
detection: {
|
|
shoulder_static?: [number, number];
|
|
shoulder_down?: [number, number];
|
|
hip_static?: [number, number];
|
|
};
|
|
// Counting Logic
|
|
phase_type: 'start_down' | 'start_up';
|
|
dynamic_angles: {
|
|
[key: string]: [number, number]; // e.g., elbow_up: [0, 60]
|
|
};
|
|
// Scoring & Validation
|
|
static_angles?: { [key: string]: number }; // Ideal static angle
|
|
wrist_distance?: [number, number];
|
|
convex_hull?: {
|
|
up?: [number, number];
|
|
down?: [number, number];
|
|
};
|
|
|
|
// Legacy support (optional)
|
|
form_rules?: Array<(landmarks: Landmark[], angles: AnglesDict, side?: 'left' | 'right') => FormValidationResult>;
|
|
}
|
|
|
|
export const EXERCISE_CONFIGS: { [key: string]: ExerciseConfig } = {
|
|
'bicep_curl': {
|
|
name: "Bicep Curl",
|
|
phase_type: 'start_down',
|
|
detection: { shoulder_static: [0, 30] },
|
|
dynamic_angles: {
|
|
'elbow_down': [140, 180],
|
|
'elbow_up': [0, 85],
|
|
'shoulder_down': [0, 30],
|
|
'shoulder_up': [0, 60]
|
|
},
|
|
static_angles: { 'shoulder_r': 15, 'shoulder_l': 15 },
|
|
wrist_distance: [0, 0.3],
|
|
convex_hull: { down: [0, 0.05], up: [0.05, 0.2] }
|
|
},
|
|
'hammer_curl': {
|
|
name: "Hammer Curl",
|
|
phase_type: 'start_down',
|
|
detection: { shoulder_static: [0, 30] },
|
|
dynamic_angles: {
|
|
'elbow_down': [120, 180],
|
|
'elbow_up': [0, 85], // Similar to bicep, maybe slightly different in 3D but same in 2D
|
|
'shoulder_down': [0, 30],
|
|
'shoulder_up': [0, 60]
|
|
},
|
|
static_angles: { 'shoulder_r': 15, 'shoulder_l': 15 },
|
|
wrist_distance: [0, 0.2], // Hammer curl usually keeps weights closer?
|
|
convex_hull: { down: [0, 0.05], up: [0.05, 0.2] }
|
|
},
|
|
'shoulder_press': { // Overhead Press
|
|
name: "Overhead Press",
|
|
phase_type: 'start_down', // Starts at shoulders, goes UP. Actually "Down" state is hands at shoulders. "Up" is hands in air.
|
|
detection: { shoulder_down: [50, 120] }, // Relaxed detection
|
|
dynamic_angles: {
|
|
'elbow_down': [20, 100], // Relaxed bottom position (can stop at chin level)
|
|
'elbow_up': [150, 180], // Relaxed lockout (sometimes 140 is enough)
|
|
'shoulder_down': [40, 110], // Relaxed shoulder range
|
|
'shoulder_up': [130, 180] // Relaxed top range
|
|
},
|
|
static_angles: { 'hip_r': 165, 'hip_l': 165 }, // Standing straight
|
|
wrist_distance: [0, 0.3],
|
|
convex_hull: { down: [0.05, 0.15], up: [0.15, 0.3] }
|
|
},
|
|
'lateral_raises': {
|
|
name: "Lateral Raises",
|
|
phase_type: 'start_down', // Arms at sides
|
|
detection: {},
|
|
dynamic_angles: {
|
|
'shoulder_down': [0, 30],
|
|
'shoulder_up': [80, 110], // T-pose
|
|
'elbow_down': [140, 180], // Straight arm
|
|
'elbow_up': [140, 180] // Keep arms straight
|
|
},
|
|
static_angles: { 'elbow_r': 160, 'elbow_l': 160 },
|
|
convex_hull: { down: [0, 0.1], up: [0.2, 0.4] } // Wide hull when arms up
|
|
},
|
|
'squat': {
|
|
name: "Squat",
|
|
phase_type: 'start_up', // Standing -> Squat -> Standing
|
|
detection: {},
|
|
dynamic_angles: {
|
|
'hip_up': [160, 180], // Standing
|
|
'hip_down': [50, 100], // Squat depth
|
|
'knee_up': [160, 180],
|
|
'knee_down': [50, 100]
|
|
},
|
|
static_angles: { 'shoulder_r': 20, 'shoulder_l': 20 }, // Torso relatively upright
|
|
convex_hull: { up: [0.1, 0.2], down: [0.05, 0.15] } // Hull shrinks when squatting? Or stays same?
|
|
},
|
|
'deadlift': {
|
|
name: "Deadlift",
|
|
// Actually deadlift starts on floor. So 'start_down' (hips low) -> 'up' (hips high/standing).
|
|
phase_type: 'start_down', // Down (at floor) -> Up (Standing). Warning: Logic usually assumes "Down" means "Rest/Start".
|
|
detection: {},
|
|
dynamic_angles: {
|
|
'hip_down': [45, 100], // Hips flexed at bottom
|
|
'hip_up': [160, 180], // Hips extended at top
|
|
'knee_down': [60, 120], // Knees bent
|
|
'knee_up': [160, 180] // Knees locked
|
|
},
|
|
static_angles: { 'elbow_r': 170, 'elbow_l': 170 }, // Arms straight
|
|
convex_hull: { down: [0.1, 0.2], up: [0.1, 0.2] }
|
|
},
|
|
'lunges': {
|
|
name: "Lunges",
|
|
phase_type: 'start_up', // Standing -> Lunge -> Standing
|
|
detection: {},
|
|
dynamic_angles: {
|
|
'knee_up': [160, 180], // Standing
|
|
'knee_down': [70, 110], // Lunge depth
|
|
'hip_up': [160, 180],
|
|
'hip_down': [70, 110]
|
|
},
|
|
static_angles: {},
|
|
convex_hull: {}
|
|
}
|
|
};
|
|
|