17 KiB
Dokumentasi Struktur Folder lib/
Gambaran Umum
Folder lib/ berisi semua utility libraries, helper functions, dan core logic aplikasi. Ini adalah "otak" dari aplikasi yang menangani AI pose detection, exercise recognition, authentication, dan database operations.
📁 Struktur Direktori
lib/
├── auth.tsx # Authentication Context & Utilities
├── mediapipe-shim.js # MediaPipe Polyfill
├── prisma.ts # Prisma Client Instance
├── pose/ # AI & Exercise Recognition Engine
│ ├── ExerciseRules.ts # Exercise Configuration & Rules
│ ├── HARCore.ts # Human Activity Recognition Core
│ ├── MathUtils.ts # Mathematical Utilities
│ ├── RehabCore.ts # Exercise Recognition & Counting
│ ├── RehabFSM.ts # Finite State Machines for Reps
│ ├── RepetitionCounter.ts # Legacy Rep Counter
│ └── XGBoostPredictor.ts # ML Model Predictor
├── prisma/ # Prisma Generated Client (Symlink)
└── prisma-gen/ # Prisma Generated Types
📄 File Root Level
auth.tsx
Fungsi: Context Provider untuk authentication dan session management
Isi Utama:
-
Interface:
User: Type definition untuk user object (id, name, role, coach_id)AuthContextType: Type untuk auth contextUserRole: 'COACH' | 'CLIENT'
-
Context:
AuthContext: React Context untuk state auth globalAuthProvider: Provider component yang wrap seluruh app
-
Methods:
login(userId: string): Login user berdasarkan ID, fetch data dari/api/users/[id]logout(): Clear session, hapus localStorage, reset state- Auto-load session dari localStorage saat app mount
Tech: React Context API, localStorage persistence
Size: ~1.8 KB
mediapipe-shim.js
Fungsi: Polyfill/Shim untuk MediaPipe compatibility
Isi:
- Menyediakan global objects yang dibutuhkan MediaPipe di browser
- Mengatasi module resolution issues
- Bridge antara MediaPipe WASM dan JavaScript environment
Use Case: Diload sebelum MediaPipe library untuk ensure compatibility
Size: ~381 bytes
prisma.ts
Fungsi: Singleton instance dari Prisma Client untuk database operations
Isi:
import { PrismaClient } from "../app/generated/client/client";
const globalForPrisma = global as unknown as { prisma: PrismaClient };
export const prisma = globalForPrisma.prisma || new PrismaClient();
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
Logic:
- Menggunakan singleton pattern untuk avoid multiple instances
- Di development, menyimpan instance di
globaluntuk hot-reload compatibility - Di production, create new instance sekali saja
Import Path: @/lib/prisma
Size: ~300 bytes
📁 Folder pose/ - AI Exercise Recognition Engine
Ini adalah core engine yang mendeteksi dan menganalisis gerakan exercise menggunakan AI dan heuristics.
ExerciseRules.ts
Fungsi: Konfigurasi dan aturan untuk setiap jenis latihan
Exports:
-
interface Landmark- Representasi titik pose dari MediaPipe
- Fields:
x,y,z,visibility?
-
interface ExerciseConfig- Schema konfigurasi untuk setiap exercise
- Fields:
name: Nama displaydetection: Kriteria untuk mendeteksi exercise typeshoulder_static: Range angle untuk static shouldershoulder_down: Range untuk shoulder downhip_static: Range untuk hip position
phase_type: 'start_down' | 'start_up' (starting position)dynamic_angles: Range angle untuk setiap fase movement- Contoh:
elbow_down: [140, 180],elbow_up: [0, 85]
- Contoh:
static_angles: Ideal angle untuk joints yang harus tetapwrist_distance: Range jarak pergelangan tanganconvex_hull: Area coverage body saat up/down
-
EXERCISE_CONFIGS(Constant Object)- Berisi konfigurasi untuk 7 exercise core:
bicep_curl: Bicep Curl- Phase: start_down (arms extended)
- Dynamic: Elbow flexion 140-180° (down) → 0-85° (up)
- Shoulder harus static (0-30°)
hammer_curl: Hammer Curl- Similar to bicep curl
- Wrist distance lebih ketat (0-0.2m)
shoulder_press: Overhead Press- Phase: start_down (shoulders)
- Elbow: 20-100° (down) → 150-180° (up)
- Hip harus tetap 165° (standing straight)
lateral_raises: Lateral Raises- Phase: start_down (arms at sides)
- Shoulder: 0-30° → 80-110° (T-pose)
- Elbow harus tetap straight (140-180°)
squat: Squat- Phase: start_up (standing)
- Hip/Knee: 160-180° (up) → 50-100° (down)
deadlift: Deadlift- Phase: start_down (floor)
- Hip: 45-100° → 160-180°
- Elbow tetap straight (170°)
lunges: Lunges- Phase: start_up
- Knee: 160-180° → 70-110°
- Berisi konfigurasi untuk 7 exercise core:
Use Case: Digunakan oleh RehabCore untuk validasi form dan counting reps
Size: ~5.1 KB
HARCore.ts
Fungsi: Human Activity Recognition - mendeteksi aktivitas umum (Standing/Sitting/Fall)
Class: HARCore
Fields:
predictor: XGBoostPredictor- ML model untuk klasifikasirehab: RehabCore- Exercise counter instancecurrentExercise: string | null- Exercise yang sedang ditrack
Methods:
-
setExercise(name: string)- Set exercise yang akan ditrack
- Normalize nama dari UI ke config key
- Contoh: "Bicep Curl" → "bicep_curl"
-
resetParams()- Reset counter tanpa menghapus exercise selection
- Calls
rehab.reset()
-
async process(landmarks, worldLandmarks)⭐ Main Method- Input:
landmarks: Array 33 pose keypoints (normalized)worldLandmarks: 3D coordinates in meters
- Output:
{ status: "Standing" | "Sitting" | "Fall Detected", confidence: number, exercise: string | null, reps: number, feedback: string, debug: { angles, scores } } - Logic:
- Extract 141 features dari landmarks
- Classify activity menggunakan XGBoost
- Jika exercise active, process dengan RehabCore
- Return combined result
- Input:
-
extractFeatures(landmarks): number[](Private)- Extract 141 features:
- 132 Raw Features: 33 landmarks × 4 (x, y, z, visibility)
- 9 Derived Features:
- 6 Angles: Left/Right Elbow, Hip, Knee
- 2 Ratios: Shoulder width, Hip width (relative to torso)
- 1 Alignment: Torso vertical cosine similarity
- Extract 141 features:
Tech Stack:
- XGBoost model untuk activity classification
- Heuristic rules untuk exercise recognition
- Angle calculation dari Math Utils
Size: ~5.9 KB
RehabCore.ts
Fungsi: Exercise Recognition & Rep Counting dengan form validation
Class: RehabCore
Fields:
counters: { [key: string]: RepFSM[] }- FSM instances per exerciseworldLandmarksCache: Vec3[]- Cache untuk 3D coordinatesDEVIATION_THRESHOLD = 15.0- Batas toleransi deviasi form (degrees)
Counter Map:
{
'bicep_curl': [BicepCurlCounter('left'), BicepCurlCounter('right')],
'hammer_curl': [HammerCurlCounter('left'), HammerCurlCounter('right')],
'shoulder_press': [OverheadPressCounter()],
'lateral_raises': [LateralRaiseCounter()],
'squat': [SquatCounter()],
'deadlift': [DeadliftCounter()],
'lunges': [LungeCounter()]
}
Methods:
-
reset()- Reset semua counters ke initial state
- Clear cache
-
validateExerciseType(configKey, features): string | null- ⚠️ 6-Way Wrong Exercise Detection
- Cek apakah pose sesuai dengan exercise yang diharapkan
- Return error message jika salah exercise
- Contoh: Jika program bicep curl tapi user lakukan squat → "Wrong Exercise: Detected lower body"
-
calculateDeviation(configKey, features, fsmState): { mae, isDeviating, details }- ⭐ Per-Rep Form Scoring
- Hitung MAE (Mean Absolute Error) dari ideal angles
- Compare current angles dengan config ranges
- Return:
mae: Average deviation dalam degreesisDeviating: Boolean (> DEVIATION_THRESHOLD)details: Array pesan koreksi spesifik
-
process(exerciseName, landmarks, worldLandmarks, frameTime)⭐ Main Method- Core rep counting logic
- Workflow:
- Normalize exercise name
- Lazy-load counters jika belum ada
- Compute features (angles, distances, dll)
- Wrong Exercise Detection
- Update FSM untuk bilateral sides (left/right)
- Form Deviation Analysis (per frame)
- Generate composite feedback
- Output:
{ left: { stage, angle, reps }, right: { stage, angle, reps }, scores: { deviation_mae }, feedback: "L: UP | R: DOWN | Knees Inward 🔴" }
-
getReps(exName): number- Get total reps (max dari left/right atau sum)
- Untuk bilateral: ambil yang lebih besar
- Untuk unilateral: langsung return
Key Features:
- ✅ Real-time rep detection menggunakan FSM
- ✅ Form quality scoring (MAE calculation)
- ✅ Wrong exercise detection
- ✅ Specific corrective feedback per frame
- ✅ Bilateral tracking (left/right independent)
Size: ~16.1 KB
RehabFSM.ts
Fungsi: Finite State Machines untuk setiap jenis exercise
Exports:
-
Helper Functions:
vec3(landmark): Vec3- Convert Landmark to 3D vectorcomputeFeatures(landmarks, worldLandmarks): PoseFeatures- Extract semua angles dan distances
- Return object dengan 20+ features
-
Base Class:
RepFSM(Abstract)- Fields:
state: "LOW" | "HIGH"reps: numberlastAngle: number
- Methods:
abstract shouldTransition(features): booleanupdate(features): voidreset(): void
- Fields:
-
Concrete FSMs (7 Classes):
BicepCurlCounter(side: 'left' | 'right')- Track elbow flexion angle
- LOW (140-180°) ↔ HIGH (0-85°)
- +1 rep saat kembali ke LOW
HammerCurlCounter(side: 'left' | 'right')- Similar to Bicep, sedikit berbeda thresholds
OverheadPressCounter()- Bilateral (min of left/right elbow)
- LOW: hands at shoulders
- HIGH: arms extended overhead
LateralRaiseCounter()- Track shoulder abduction (max of left/right)
- LOW: arms at sides → HIGH: T-pose
SquatCounter()- Track hip/knee flexion (min)
- HIGH: standing → LOW: squat depth
DeadliftCounter()- Track hip extension
- LOW: floor position → HIGH: lockout
LungeCounter()- Track knee flexion (min of both)
- Similar to squat
Logic Pattern:
if (state === "LOW" && angle < UP_THRESHOLD) {
state = "HIGH";
} else if (state === "HIGH" && angle > DOWN_THRESHOLD) {
state = "LOW";
reps++; // Rep completed!
}
Size: Variable (likely 5-10 KB based on 7 classes)
MathUtils.ts
Fungsi: Mathematical utility functions untuk pose analysis
Functions:
-
calculateAngle(a, b, c): number- Hitung angle di point B dari triangle ABC
- Input: 3 points dengan {x, y}
- Output: Angle dalam degrees (0-180)
- Formula:
arctangentmenggunakan vectors
-
calculateRangeDeviation(value, range, weight = 1.0): number- Hitung deviasi dari ideal range
- Jika value dalam range → return 0
- Jika di luar → return distance × weight
- Contoh:
value=90, range=[80,100]→ return 0 - Contoh:
value=110, range=[80,100]→ return 10
-
computeMAE(deviations): number- Mean Absolute Error
- Average dari array deviasi
- Digunakan untuk overall form score
Use Case:
- Digunakan di semua modules untuk angle calculation
- Form validation dan scoring
Size: ~500 bytes (estimasi)
XGBoostPredictor.ts
Fungsi: XGBoost Machine Learning model predictor untuk activity classification
Class: XGBoostPredictor
Purpose:
- Classify pose sebagai "Standing", "Sitting", atau "Fall Detected"
- Menggunakan pre-trained XGBoost model
Methods:
predict(features: number[]): number[]- Input: 141 features dari
HARCore.extractFeatures() - Output: Probability array [standingProb, sittingProb, fallProb]
- Model di-load dari embedded weights
- Input: 141 features dari
Tech:
- XGBoost model serialized ke JavaScript
- Likely menggunakan ONNX atau custom JSON format
Size: Likely large (10-50 KB) karena contain model weights
RepetitionCounter.ts
Fungsi: Legacy rep counter (kemungkinan deprecated)
Status: ⚠️ Likely tidak digunakan, digantikan oleh RehabFSM.ts
Reason:
RehabCoremenggunakan FSM dariRehabFSM.ts- File ini mungkin versi lama sebelum refactor
📁 Folder prisma/ dan prisma-gen/
Status: Auto-generated by Prisma CLI
prisma/client/
- Symlink atau copy dari
/app/generated/client - Prisma Client untuk browser compatibility
prisma-gen/
- Type definitions dan models
- Files:
browser.ts- Browser-compatible clientclient.ts- Main clientmodels.ts- Type definitionsenums.ts- Enum typesmodels/- Individual model files:activity_logs.tstraining_menus.tsuser_recaps.ts
PENTING: ❌ JANGAN EDIT MANUAL - Will be regenerated by prisma generate
🔑 Key Concepts & Data Flow
Complete Exercise Recognition Flow:
1. MediaPipe Pose Detection
└─> 33 Landmarks (x, y, z, visibility)
2. HARCore.process()
├─> Extract 141 Features
├─> XGBoost Prediction (Standing/Sitting/Fall)
└─> RehabCore.process()
├─> Compute Angles & Features
├─> Wrong Exercise Detection
├─> FSM Update (Rep Counting)
├─> Form Deviation Calculation (MAE)
└─> Generate Feedback Text
3. Return to UI
└─> { status, reps, feedback, scores: {deviation_mae} }
Per-Rep Tracking Flow (NEW):
Training Page (client/training/page.tsx)
├─> Frame Loop: predictWebcam()
│ ├─> Call har.process()
│ ├─> Accumulate MAE to repBuffer
│ └─> Capture feedback to repFeedbackBuffer
│
├─> Rep Completion Detection (res.reps > lastRepCount)
│ ├─> Calculate avgRepScore
│ ├─> Find dominant feedback
│ └─> Push to currentSetReps[{rep, score, feedback}]
│
└─> Set Completion
├─> Save to results state
└─> API POST to /api/recap
💡 Important Notes
Exercise Configuration:
- Semua config di
ExerciseRules.ts - Untuk tambah exercise baru:
- Add config di
EXERCISE_CONFIGS - Create FSM class di
RehabFSM.ts - Add entry di
COUNTER_MAPdiRehabCore.ts
- Add config di
Form Scoring:
- MAE (Mean Absolute Error) dalam degrees
- Thresholds:
- < 8° = Excellent
- < 15° = Good
- < 25° = Fair
- ≥ 25° = Needs Improvement
Wrong Exercise Detection:
- 6-way classification:
- Upper body dynamic (curls/press)
- Upper body static T-pose (lateral raises)
- Lower body squat pattern
- Lower body hinge pattern (deadlift)
- Lower body lunge pattern
- Unrecognized pose
Performance:
- Frame processing: ~10-30ms
- Feature extraction: O(n) dengan n=33 landmarks
- FSM updates: O(1) per exercise
- Real-time capable at 30 FPS
📊 Dependencies
lib/pose/
├── ExerciseRules.ts (Pure config, no deps)
├── MathUtils.ts (Pure math, no deps)
├── RehabFSM.ts
│ └── depends on: ExerciseRules, MathUtils
├── RehabCore.ts
│ └── depends on: ExerciseRules, RehabFSM, MathUtils
├── XGBoostPredictor.ts (Standalone ML model)
└── HARCore.ts
└── depends on: ALL above
lib/ (Root)
├── auth.tsx (React Context)
├── prisma.ts (Database client)
└── mediapipe-shim.js (Standalone polyfill)
🛠️ Maintenance Tips
- Update Exercise Config: Edit
ExerciseRules.ts→ Test di Monitor mode - Adjust Thresholds: Tweak angle ranges di config atau FSM classes
- Debug Form Scores: Check
res.debug.scoresdi browser console - Add New Exercise:
- Step 1: Config di
ExerciseRules.ts - Step 2: FSM class di
RehabFSM.ts - Step 3: Register di
RehabCore.tsCOUNTER_MAP - Step 4: Update UI exercise dropdown
- Step 1: Config di
- Performance Tuning: Optimize
extractFeatures()di HARCore jika lag
📈 Future Enhancements
- Add more exercises (Pull-ups, Push-ups, etc.)
- Implement velocity-based training (track rep speed)
- Add form correction animations/overlays
- Machine learning untuk auto-tune thresholds per user
- Export workout data ke CSV/PDF