{
  "name": "Exercise Form Rules 2026 (joint-angle thresholds from open-source trackers)",
  "version": "2026.1",
  "publisher": "AIFitnessAPI (aifitnessapi.com)",
  "license": "CC BY 4.0",
  "methodology": "The joint-angle and ratio thresholds that 4 licensed open-source exercise trackers (Ultralytics AIGym (workouts monitoring solution), AGPL-3.0; Pose Trainer (Steven Chen and Richard Yang), GPL-3.0; Exercise-Correction (Ngô Hồng Quốc Bảo), MIT; PythonExcercisePoseEstimation (thphuc05), MIT) use to count reps, check form and time holds, read from their code on 2026-11-05. Every value was captured by the generator from the verbatim line in \"quote\", after that line was found in the fetched file; \"usage\" is the line that applies it and \"measureQuote\" the line that computes what it is compared with, both checked the same way. Values are null where no source read states a number, with the reason in nullReason. These are the projects' own choices for their own camera setups and models, measured as 2D angles in the image; they are not biomechanical standards, coaching or medical advice. The sources' own code is under their licenses; this dataset quotes single lines of it as evidence.",
  "generatedFrom": "src/data/formRules.ts (generated by scripts/fetch-form-rules.mjs, then by scripts/build-datasets.mjs)",
  "isBasedOn": [
    "https://github.com/ultralytics/ultralytics",
    "https://github.com/stevenzchen/pose-trainer",
    "https://github.com/NgoQuocBao1010/Exercise-Correction",
    "https://github.com/thphuc05/PythonExcercisePoseEstimation"
  ],
  "sourceReadOn": "2026-11-05",
  "fields": {
    "id": "Stable row id",
    "exercise": "Exercise slug",
    "exerciseName": "Exercise name",
    "purpose": "rep-count (a phase boundary), form-check (an error rule) or hold (an isometric rule)",
    "role": "top, bottom, depth, range, minimum, maximum, lockout, frames, or top-and-bottom for a null rep-count row",
    "measure": "joint-angle, segment-angle, range-of-motion, ratio or frames",
    "joint": "The joint or quantity measured",
    "points": "The points as the source names them, vertex in the middle for a three-point angle",
    "keypointIndices": "COCO 17 indices where the source names indices; resolved to names through this site's keypoint dataset",
    "comparison": "How the source compares the measured value with the threshold (>, <, >=, <=, within)",
    "value": "The threshold, captured from quote; null where no source states one",
    "value2": "Upper bound of a within range",
    "unit": "degrees, ratio or frames",
    "meaning": "What crossing the value does in the source (this site's wording; usage is the evidence)",
    "sourceProject": "The project the value was read from",
    "sourceRepo": "Its repository",
    "license": "Its license, as its LICENSE file states",
    "source": "The file and line on GitHub",
    "quote": "The verbatim line the value was captured from",
    "usage": "The verbatim line that applies the value",
    "measureQuote": "The verbatim line that computes the measured quantity",
    "reasonQuote": "For a null row: the verbatim line that shows why the source states no number",
    "nullReason": "Why the value is null",
    "page": "This site's row"
  },
  "stats": {
    "totalItems": 25,
    "withValue": 22,
    "null": 3,
    "exercises": 7
  },
  "items": [
    {
      "id": "squat-knee-top-thphuc05",
      "exercise": "squat",
      "exerciseName": "Squat",
      "purpose": "rep-count",
      "role": "top",
      "measure": "joint-angle",
      "joint": "knee",
      "points": "hip; knee; ankle",
      "keypointIndices": null,
      "comparison": ">",
      "value": 160,
      "value2": null,
      "unit": "degrees",
      "meaning": "Back at the top (standing): knee angle above this, together with the hip angle above its own top value, ends a rep.",
      "sourceProject": "PythonExcercisePoseEstimation (thphuc05)",
      "sourceRepo": "https://github.com/thphuc05/PythonExcercisePoseEstimation",
      "license": "MIT",
      "source": "https://github.com/thphuc05/PythonExcercisePoseEstimation/blob/main/pose_estimation.py#L49",
      "quote": "ExerciseConfig(name=\"Squat\", knee_angle_up=160, knee_angle_down_entry=100,",
      "usage": "if knee_angle > cfg.knee_angle_up and hip_angle > cfg.hip_angle_up:",
      "measureQuote": "knee_angle = calculate_angle(hip, knee, ankle)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-squat-knee-top-thphuc05"
    },
    {
      "id": "squat-knee-bottom-thphuc05",
      "exercise": "squat",
      "exerciseName": "Squat",
      "purpose": "rep-count",
      "role": "bottom",
      "measure": "joint-angle",
      "joint": "knee",
      "points": "hip; knee; ankle",
      "keypointIndices": null,
      "comparison": "<",
      "value": 100,
      "value2": null,
      "unit": "degrees",
      "meaning": "Going down: knee angle below this, from the top, enters the down phase.",
      "sourceProject": "PythonExcercisePoseEstimation (thphuc05)",
      "sourceRepo": "https://github.com/thphuc05/PythonExcercisePoseEstimation",
      "license": "MIT",
      "source": "https://github.com/thphuc05/PythonExcercisePoseEstimation/blob/main/pose_estimation.py#L49",
      "quote": "ExerciseConfig(name=\"Squat\", knee_angle_up=160, knee_angle_down_entry=100,",
      "usage": "if knee_angle < cfg.knee_angle_down_entry and stage == \"up\":",
      "measureQuote": "knee_angle = calculate_angle(hip, knee, ankle)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-squat-knee-bottom-thphuc05"
    },
    {
      "id": "squat-hip-top-thphuc05",
      "exercise": "squat",
      "exerciseName": "Squat",
      "purpose": "rep-count",
      "role": "top",
      "measure": "joint-angle",
      "joint": "hip",
      "points": "knee; hip; shoulder",
      "keypointIndices": null,
      "comparison": ">",
      "value": 160,
      "value2": null,
      "unit": "degrees",
      "meaning": "Back at the top: hip angle above this is also required to end a rep.",
      "sourceProject": "PythonExcercisePoseEstimation (thphuc05)",
      "sourceRepo": "https://github.com/thphuc05/PythonExcercisePoseEstimation",
      "license": "MIT",
      "source": "https://github.com/thphuc05/PythonExcercisePoseEstimation/blob/main/pose_estimation.py#L49",
      "quote": "knee_angle_down_entry=100, # Squat hip_angle_up=160, correct_knee_max=95",
      "usage": "if knee_angle > cfg.knee_angle_up and hip_angle > cfg.hip_angle_up:",
      "measureQuote": "hip_angle = calculate_angle(knee, hip, shouder)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-squat-hip-top-thphuc05"
    },
    {
      "id": "squat-knee-depth-thphuc05",
      "exercise": "squat",
      "exerciseName": "Squat",
      "purpose": "form-check",
      "role": "depth",
      "measure": "joint-angle",
      "joint": "knee",
      "points": "hip; knee; ankle",
      "keypointIndices": null,
      "comparison": "<",
      "value": 95,
      "value2": null,
      "unit": "degrees",
      "meaning": "Depth: the smallest knee angle of the rep must fall below this (with the hip and hip-drop checks) for the rep to be marked correct.",
      "sourceProject": "PythonExcercisePoseEstimation (thphuc05)",
      "sourceRepo": "https://github.com/thphuc05/PythonExcercisePoseEstimation",
      "license": "MIT",
      "source": "https://github.com/thphuc05/PythonExcercisePoseEstimation/blob/main/pose_estimation.py#L49",
      "quote": "knee_angle_down_entry=100, # Squat hip_angle_up=160, correct_knee_max=95",
      "usage": "if is_hip_drop and min_knee_angle < cfg.correct_knee_max and min_hip_angle < cfg.correct_hip_max:",
      "measureQuote": "knee_angle = calculate_angle(hip, knee, ankle)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-squat-knee-depth-thphuc05"
    },
    {
      "id": "squat-hip-depth-thphuc05",
      "exercise": "squat",
      "exerciseName": "Squat",
      "purpose": "form-check",
      "role": "depth",
      "measure": "joint-angle",
      "joint": "hip",
      "points": "knee; hip; shoulder",
      "keypointIndices": null,
      "comparison": "<",
      "value": 95,
      "value2": null,
      "unit": "degrees",
      "meaning": "Depth: the smallest hip angle of the rep must fall below this (with the knee check) for the rep to be marked correct.",
      "sourceProject": "PythonExcercisePoseEstimation (thphuc05)",
      "sourceRepo": "https://github.com/thphuc05/PythonExcercisePoseEstimation",
      "license": "MIT",
      "source": "https://github.com/thphuc05/PythonExcercisePoseEstimation/blob/main/pose_estimation.py#L50",
      "quote": "correct_knee_max=95, correct_hip_max=95, hip_drop_min=0.08)",
      "usage": "if is_hip_drop and min_knee_angle < cfg.correct_knee_max and min_hip_angle < cfg.correct_hip_max:",
      "measureQuote": "hip_angle = calculate_angle(knee, hip, shouder)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-squat-hip-depth-thphuc05"
    },
    {
      "id": "squat-stance-ratio-exercise-correction",
      "exercise": "squat",
      "exerciseName": "Squat",
      "purpose": "form-check",
      "role": "range",
      "measure": "ratio",
      "joint": "stance",
      "points": null,
      "keypointIndices": null,
      "comparison": "within",
      "value": 1.2,
      "value2": 2.8,
      "unit": "ratio",
      "meaning": "Foot placement: foot width divided by shoulder width must fall within this range.",
      "sourceProject": "Exercise-Correction (Ngô Hồng Quốc Bảo)",
      "sourceRepo": "https://github.com/NgoQuocBao1010/Exercise-Correction",
      "license": "MIT",
      "source": "https://github.com/NgoQuocBao1010/Exercise-Correction/blob/main/web/server/detection/squat.py#L162",
      "quote": "FOOT_SHOULDER_RATIO_THRESHOLDS = [1.2, 2.8]",
      "usage": "if min_ratio_foot_shoulder <= foot_shoulder_ratio <= max_ratio_foot_shoulder:",
      "measureQuote": "foot_shoulder_ratio = round(foot_width / shoulder_width, 1)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-squat-stance-ratio-exercise-correction"
    },
    {
      "id": "push-up-elbow-top-ultralytics",
      "exercise": "push-up",
      "exerciseName": "Push-up",
      "purpose": "rep-count",
      "role": "top",
      "measure": "joint-angle",
      "joint": "elbow",
      "points": "right_shoulder; right_elbow; right_wrist",
      "keypointIndices": "6; 8; 10",
      "comparison": ">",
      "value": 145,
      "value2": null,
      "unit": "degrees",
      "meaning": "Up: angle above this sets the stage to up. The documented default keypoints are for push-ups.",
      "sourceProject": "Ultralytics AIGym (workouts monitoring solution)",
      "sourceRepo": "https://github.com/ultralytics/ultralytics",
      "license": "AGPL-3.0",
      "source": "https://github.com/ultralytics/ultralytics/blob/main/ultralytics/solutions/config.py#L79",
      "quote": "up_angle: float = 145.0",
      "usage": "elif state[\"angle\"] > self.up_angle:",
      "measureQuote": "kpts=[6, 8, 10],  # keypoints for monitoring specific exercise, by default it's for pushup",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-push-up-elbow-top-ultralytics"
    },
    {
      "id": "push-up-elbow-bottom-ultralytics",
      "exercise": "push-up",
      "exerciseName": "Push-up",
      "purpose": "rep-count",
      "role": "bottom",
      "measure": "joint-angle",
      "joint": "elbow",
      "points": "right_shoulder; right_elbow; right_wrist",
      "keypointIndices": "6; 8; 10",
      "comparison": "<",
      "value": 90,
      "value2": null,
      "unit": "degrees",
      "meaning": "Down: angle below this sets the stage to down, and counts a rep if the stage was up (the source counts on reaching the bottom, not on the return).",
      "sourceProject": "Ultralytics AIGym (workouts monitoring solution)",
      "sourceRepo": "https://github.com/ultralytics/ultralytics",
      "license": "AGPL-3.0",
      "source": "https://github.com/ultralytics/ultralytics/blob/main/ultralytics/solutions/config.py#L80",
      "quote": "down_angle: float = 90.0",
      "usage": "if state[\"angle\"] < self.down_angle: if state[\"stage\"] == \"up\": state[\"count\"] += 1",
      "measureQuote": "kpts=[6, 8, 10],  # keypoints for monitoring specific exercise, by default it's for pushup",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-push-up-elbow-bottom-ultralytics"
    },
    {
      "id": "push-up-elbow-top-thphuc05",
      "exercise": "push-up",
      "exerciseName": "Push-up",
      "purpose": "rep-count",
      "role": "top",
      "measure": "joint-angle",
      "joint": "elbow",
      "points": "wrist; elbow; shoulder",
      "keypointIndices": null,
      "comparison": ">",
      "value": 160,
      "value2": null,
      "unit": "degrees",
      "meaning": "Up: elbow angle above this, with the body straight, ends a rep.",
      "sourceProject": "PythonExcercisePoseEstimation (thphuc05)",
      "sourceRepo": "https://github.com/thphuc05/PythonExcercisePoseEstimation",
      "license": "MIT",
      "source": "https://github.com/thphuc05/PythonExcercisePoseEstimation/blob/main/pose_estimation.py#L52",
      "quote": "ExerciseConfig(name=\"PushUp\", elbow_angle_up=160, elbow_angle_down_entry=90,",
      "usage": "if elbow_angle > cfg.elbow_angle_up:",
      "measureQuote": "elbow_angle = calculate_angle(wrist, elbow, shouder)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-push-up-elbow-top-thphuc05"
    },
    {
      "id": "push-up-elbow-bottom-thphuc05",
      "exercise": "push-up",
      "exerciseName": "Push-up",
      "purpose": "rep-count",
      "role": "bottom",
      "measure": "joint-angle",
      "joint": "elbow",
      "points": "wrist; elbow; shoulder",
      "keypointIndices": null,
      "comparison": "<",
      "value": 90,
      "value2": null,
      "unit": "degrees",
      "meaning": "Down: elbow angle below this, from the top, enters the down phase.",
      "sourceProject": "PythonExcercisePoseEstimation (thphuc05)",
      "sourceRepo": "https://github.com/thphuc05/PythonExcercisePoseEstimation",
      "license": "MIT",
      "source": "https://github.com/thphuc05/PythonExcercisePoseEstimation/blob/main/pose_estimation.py#L52",
      "quote": "ExerciseConfig(name=\"PushUp\", elbow_angle_up=160, elbow_angle_down_entry=90,",
      "usage": "if elbow_angle < cfg.elbow_angle_down_entry and stage == \"up\":",
      "measureQuote": "elbow_angle = calculate_angle(wrist, elbow, shouder)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-push-up-elbow-bottom-thphuc05"
    },
    {
      "id": "push-up-elbow-depth-thphuc05",
      "exercise": "push-up",
      "exerciseName": "Push-up",
      "purpose": "form-check",
      "role": "depth",
      "measure": "joint-angle",
      "joint": "elbow",
      "points": "wrist; elbow; shoulder",
      "keypointIndices": null,
      "comparison": "<",
      "value": 90,
      "value2": null,
      "unit": "degrees",
      "meaning": "Depth: the smallest elbow angle of the rep must fall below this for the rep to be marked correct.",
      "sourceProject": "PythonExcercisePoseEstimation (thphuc05)",
      "sourceRepo": "https://github.com/thphuc05/PythonExcercisePoseEstimation",
      "license": "MIT",
      "source": "https://github.com/thphuc05/PythonExcercisePoseEstimation/blob/main/pose_estimation.py#L53",
      "quote": "correct_elbow_max=90, body_straight_min=160)",
      "usage": "if min_elbow_angle < cfg.correct_elbow_max:",
      "measureQuote": "elbow_angle = calculate_angle(wrist, elbow, shouder)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-push-up-elbow-depth-thphuc05"
    },
    {
      "id": "push-up-body-line-thphuc05",
      "exercise": "push-up",
      "exerciseName": "Push-up",
      "purpose": "form-check",
      "role": "minimum",
      "measure": "joint-angle",
      "joint": "body-line",
      "points": "shoulder; hip; ankle",
      "keypointIndices": null,
      "comparison": ">",
      "value": 160,
      "value2": null,
      "unit": "degrees",
      "meaning": "Straight body: the shoulder-hip-ankle angle must stay above this for the source to track the rep at all.",
      "sourceProject": "PythonExcercisePoseEstimation (thphuc05)",
      "sourceRepo": "https://github.com/thphuc05/PythonExcercisePoseEstimation",
      "license": "MIT",
      "source": "https://github.com/thphuc05/PythonExcercisePoseEstimation/blob/main/pose_estimation.py#L53",
      "quote": "correct_elbow_max=90, body_straight_min=160)",
      "usage": "is_body_straight = body_line_angle > cfg.body_straight_min",
      "measureQuote": "body_line_angle = calculate_angle(shouder, hip, ankle)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-push-up-body-line-thphuc05"
    },
    {
      "id": "lunge-knee-bottom-range-exercise-correction",
      "exercise": "lunge",
      "exerciseName": "Lunge",
      "purpose": "form-check",
      "role": "range",
      "measure": "joint-angle",
      "joint": "knee",
      "points": "hip; knee; ankle",
      "keypointIndices": null,
      "comparison": "within",
      "value": 60,
      "value2": 125,
      "unit": "degrees",
      "meaning": "At the bottom (the source's down stage): each knee angle must fall within this range, or the rep is flagged with a knee-angle error.",
      "sourceProject": "Exercise-Correction (Ngô Hồng Quốc Bảo)",
      "sourceRepo": "https://github.com/NgoQuocBao1010/Exercise-Correction",
      "license": "MIT",
      "source": "https://github.com/NgoQuocBao1010/Exercise-Correction/blob/main/web/server/detection/lunge.py#L183",
      "quote": "KNEE_ANGLE_THRESHOLD = [60, 125]",
      "usage": "if angle_thresholds[0] <= results[\"right\"][\"angle\"] <= angle_thresholds[1]:",
      "measureQuote": "results[\"right\"][\"angle\"] = calculate_angle(right_hip, right_knee, right_ankle)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-lunge-knee-bottom-range-exercise-correction"
    },
    {
      "id": "lunge-rep-count-null",
      "exercise": "lunge",
      "exerciseName": "Lunge",
      "purpose": "rep-count",
      "role": "top-and-bottom",
      "measure": "joint-angle",
      "joint": "knee",
      "points": "hip; knee; ankle",
      "keypointIndices": null,
      "comparison": null,
      "value": null,
      "value2": null,
      "unit": "degrees",
      "meaning": "Top and bottom knee angles for counting lunge reps.",
      "sourceProject": "Exercise-Correction (Ngô Hồng Quốc Bảo)",
      "sourceRepo": "https://github.com/NgoQuocBao1010/Exercise-Correction",
      "license": "MIT",
      "source": "https://github.com/NgoQuocBao1010/Exercise-Correction/blob/main/web/server/detection/lunge.py#L178",
      "quote": null,
      "usage": null,
      "measureQuote": null,
      "reasonQuote": "STAGE_ML_MODEL_PATH = get_static_file_url(\"model/lunge_stage_model.pkl\")",
      "nullReason": "The one licensed lunge source read counts lunge stages with a trained classifier, not an angle threshold, so it states no top or bottom angle. The peer-reviewed state-machine definition cited on /motion/lunge-detection-pose-estimation is on a host the build environment could not reach on the fetch date.",
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-lunge-rep-count-null"
    },
    {
      "id": "plank-hip-hold-thphuc05",
      "exercise": "plank",
      "exerciseName": "Plank",
      "purpose": "hold",
      "role": "minimum",
      "measure": "joint-angle",
      "joint": "hip",
      "points": "knee; hip; shoulder",
      "keypointIndices": null,
      "comparison": ">",
      "value": 160,
      "value2": null,
      "unit": "degrees",
      "meaning": "Hold: the hip angle must stay above this; dropping below stops the hold timer.",
      "sourceProject": "PythonExcercisePoseEstimation (thphuc05)",
      "sourceRepo": "https://github.com/thphuc05/PythonExcercisePoseEstimation",
      "license": "MIT",
      "source": "https://github.com/thphuc05/PythonExcercisePoseEstimation/blob/main/pose_estimation.py#L51",
      "quote": "ExerciseConfig(name=\"Plank\", plank_hip_min=160, hold_frames_required=60)",
      "usage": "if hip_angle > cfg.plank_hip_min:",
      "measureQuote": "hip_angle = calculate_angle(knee, hip, shouder)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-plank-hip-hold-thphuc05"
    },
    {
      "id": "plank-hold-frames-thphuc05",
      "exercise": "plank",
      "exerciseName": "Plank",
      "purpose": "hold",
      "role": "frames",
      "measure": "frames",
      "joint": null,
      "points": null,
      "keypointIndices": null,
      "comparison": ">=",
      "value": 60,
      "value2": null,
      "unit": "frames",
      "meaning": "Hold start: the hip rule must hold for this many consecutive frames before the timer starts (the source's comment says 2 s at 30 fps).",
      "sourceProject": "PythonExcercisePoseEstimation (thphuc05)",
      "sourceRepo": "https://github.com/thphuc05/PythonExcercisePoseEstimation",
      "license": "MIT",
      "source": "https://github.com/thphuc05/PythonExcercisePoseEstimation/blob/main/pose_estimation.py#L51",
      "quote": "ExerciseConfig(name=\"Plank\", plank_hip_min=160, hold_frames_required=60)",
      "usage": "if down_frame_counter >= cfg.hold_frames_required and not timer_running:",
      "measureQuote": "down_frame_counter += 1",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-plank-hold-frames-thphuc05"
    },
    {
      "id": "bicep-curl-elbow-top-exercise-correction",
      "exercise": "bicep-curl",
      "exerciseName": "Bicep curl",
      "purpose": "rep-count",
      "role": "top",
      "measure": "joint-angle",
      "joint": "elbow",
      "points": "shoulder; elbow; wrist",
      "keypointIndices": null,
      "comparison": ">",
      "value": 120,
      "value2": null,
      "unit": "degrees",
      "meaning": "Arm extended (the source's down stage): elbow angle above this.",
      "sourceProject": "Exercise-Correction (Ngô Hồng Quốc Bảo)",
      "sourceRepo": "https://github.com/NgoQuocBao1010/Exercise-Correction",
      "license": "MIT",
      "source": "https://github.com/NgoQuocBao1010/Exercise-Correction/blob/main/web/server/detection/bicep_curl.py#L244",
      "quote": "STAGE_DOWN_THRESHOLD = 120",
      "usage": "if bicep_curl_angle > self.stage_down_threshold:",
      "measureQuote": "bicep_curl_angle = int(calculate_angle(self.shoulder, self.elbow, self.wrist))",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-bicep-curl-elbow-top-exercise-correction"
    },
    {
      "id": "bicep-curl-elbow-bottom-exercise-correction",
      "exercise": "bicep-curl",
      "exerciseName": "Bicep curl",
      "purpose": "rep-count",
      "role": "bottom",
      "measure": "joint-angle",
      "joint": "elbow",
      "points": "shoulder; elbow; wrist",
      "keypointIndices": null,
      "comparison": "<",
      "value": 100,
      "value2": null,
      "unit": "degrees",
      "meaning": "Curled (the source's up stage): elbow angle below this, after the arm was extended, counts a rep (the source counts on reaching the curl, not on the return).",
      "sourceProject": "Exercise-Correction (Ngô Hồng Quốc Bảo)",
      "sourceRepo": "https://github.com/NgoQuocBao1010/Exercise-Correction",
      "license": "MIT",
      "source": "https://github.com/NgoQuocBao1010/Exercise-Correction/blob/main/web/server/detection/bicep_curl.py#L243",
      "quote": "STAGE_UP_THRESHOLD = 100",
      "usage": "elif bicep_curl_angle < self.stage_up_threshold and self.stage == \"down\":",
      "measureQuote": "bicep_curl_angle = int(calculate_angle(self.shoulder, self.elbow, self.wrist))",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-bicep-curl-elbow-bottom-exercise-correction"
    },
    {
      "id": "bicep-curl-peak-exercise-correction",
      "exercise": "bicep-curl",
      "exerciseName": "Bicep curl",
      "purpose": "form-check",
      "role": "depth",
      "measure": "joint-angle",
      "joint": "elbow",
      "points": "shoulder; elbow; wrist",
      "keypointIndices": null,
      "comparison": "<",
      "value": 60,
      "value2": null,
      "unit": "degrees",
      "meaning": "Full range: a rep whose smallest elbow angle is this or more is flagged as a peak-contraction error.",
      "sourceProject": "Exercise-Correction (Ngô Hồng Quốc Bảo)",
      "sourceRepo": "https://github.com/NgoQuocBao1010/Exercise-Correction",
      "license": "MIT",
      "source": "https://github.com/NgoQuocBao1010/Exercise-Correction/blob/main/web/server/detection/bicep_curl.py#L247",
      "quote": "PEAK_CONTRACTION_THRESHOLD = 60",
      "usage": "and self.peak_contraction_angle >= self.peak_contraction_threshold",
      "measureQuote": "bicep_curl_angle = int(calculate_angle(self.shoulder, self.elbow, self.wrist))",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-bicep-curl-peak-exercise-correction"
    },
    {
      "id": "bicep-curl-upper-arm-exercise-correction",
      "exercise": "bicep-curl",
      "exerciseName": "Bicep curl",
      "purpose": "form-check",
      "role": "maximum",
      "measure": "segment-angle",
      "joint": "upper-arm-vertical",
      "points": "elbow; shoulder; vertical",
      "keypointIndices": null,
      "comparison": "<=",
      "value": 40,
      "value2": null,
      "unit": "degrees",
      "meaning": "Loose upper arm: an angle between the upper arm and the vertical above this is flagged as an error.",
      "sourceProject": "Exercise-Correction (Ngô Hồng Quốc Bảo)",
      "sourceRepo": "https://github.com/NgoQuocBao1010/Exercise-Correction",
      "license": "MIT",
      "source": "https://github.com/NgoQuocBao1010/Exercise-Correction/blob/main/web/server/detection/bicep_curl.py#L251",
      "quote": "LOOSE_UPPER_ARM_ANGLE_THRESHOLD = 40",
      "usage": "if ground_upper_arm_angle > self.loose_upper_arm_angle_threshold:",
      "measureQuote": "calculate_angle(self.elbow, self.shoulder, shoulder_projection)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-bicep-curl-upper-arm-exercise-correction"
    },
    {
      "id": "bicep-curl-elbow-peak-pose-trainer",
      "exercise": "bicep-curl",
      "exerciseName": "Bicep curl",
      "purpose": "form-check",
      "role": "depth",
      "measure": "joint-angle",
      "joint": "elbow",
      "points": "shoulder; elbow; wrist",
      "keypointIndices": null,
      "comparison": "<=",
      "value": 70,
      "value2": null,
      "unit": "degrees",
      "meaning": "Full range: if the smallest elbow angle over the set is above this, the set is flagged as not curled all the way up.",
      "sourceProject": "Pose Trainer (Steven Chen and Richard Yang)",
      "sourceRepo": "https://github.com/stevenzchen/pose-trainer",
      "license": "GPL-3.0",
      "source": "https://github.com/stevenzchen/pose-trainer/blob/master/evaluate.py#L77",
      "quote": "if upper_arm_forearm_min > 70.0:",
      "usage": "You are not curling the weight all the way to the top, up to your shoulders.",
      "measureQuote": "upper_arm_forearm_angles = np.degrees(np.arccos(np.clip(np.sum(np.multiply(upper_arm_vecs, forearm_vecs), axis=1), -1.0, 1.0)))",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-bicep-curl-elbow-peak-pose-trainer"
    },
    {
      "id": "bicep-curl-upper-arm-range-pose-trainer",
      "exercise": "bicep-curl",
      "exerciseName": "Bicep curl",
      "purpose": "form-check",
      "role": "maximum",
      "measure": "range-of-motion",
      "joint": "upper-arm-torso",
      "points": "shoulder; elbow; hip; neck",
      "keypointIndices": null,
      "comparison": "<=",
      "value": 35,
      "value2": null,
      "unit": "degrees",
      "meaning": "Upper arm still: if the upper-arm-to-torso angle varies by more than this over the set, the set is flagged for shoulder rotation.",
      "sourceProject": "Pose Trainer (Steven Chen and Richard Yang)",
      "sourceRepo": "https://github.com/stevenzchen/pose-trainer",
      "license": "GPL-3.0",
      "source": "https://github.com/stevenzchen/pose-trainer/blob/master/evaluate.py#L72",
      "quote": "if upper_arm_torso_range > 35.0:",
      "usage": "Your upper arm shows significant rotation around the shoulder when curling.",
      "measureQuote": "upper_arm_torso_range = np.max(upper_arm_torso_angles) - np.min(upper_arm_torso_angles)",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-bicep-curl-upper-arm-range-pose-trainer"
    },
    {
      "id": "shoulder-press-lockout-pose-trainer",
      "exercise": "shoulder-press",
      "exerciseName": "Shoulder press",
      "purpose": "form-check",
      "role": "lockout",
      "measure": "joint-angle",
      "joint": "elbow",
      "points": "shoulder; elbow; wrist",
      "keypointIndices": null,
      "comparison": ">=",
      "value": 178,
      "value2": null,
      "unit": "degrees",
      "meaning": "Lockout: if the largest elbow angle over the set is below this, the set is flagged as not pressed all the way up.",
      "sourceProject": "Pose Trainer (Steven Chen and Richard Yang)",
      "sourceRepo": "https://github.com/stevenzchen/pose-trainer",
      "license": "GPL-3.0",
      "source": "https://github.com/stevenzchen/pose-trainer/blob/master/evaluate.py#L257",
      "quote": "if upper_forearm_angle < 178:",
      "usage": "You are not lifting the weight all the way up. Extend your arms through the full range of motion.",
      "measureQuote": "print(\"Max upper arm and forearm angle: \", np.max(upper_arm_forearm_angles))",
      "reasonQuote": null,
      "nullReason": null,
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-shoulder-press-lockout-pose-trainer"
    },
    {
      "id": "shoulder-press-rep-count-null",
      "exercise": "shoulder-press",
      "exerciseName": "Shoulder press",
      "purpose": "rep-count",
      "role": "top-and-bottom",
      "measure": "joint-angle",
      "joint": "elbow",
      "points": "shoulder; elbow; wrist",
      "keypointIndices": null,
      "comparison": null,
      "value": null,
      "value2": null,
      "unit": "degrees",
      "meaning": "Top and bottom elbow angles for counting shoulder-press reps.",
      "sourceProject": "Pose Trainer (Steven Chen and Richard Yang)",
      "sourceRepo": "https://github.com/stevenzchen/pose-trainer",
      "license": "GPL-3.0",
      "source": "https://github.com/stevenzchen/pose-trainer/blob/master/evaluate.py#L244",
      "quote": null,
      "usage": null,
      "measureQuote": null,
      "reasonQuote": "print(\"Max upper arm and forearm angle: \", np.max(upper_arm_forearm_angles))",
      "nullReason": "The one licensed shoulder-press source read judges a whole recorded set by its largest elbow angle and counts no reps, so it states no bottom position and no per-rep top. No other licensed source read gives one.",
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-shoulder-press-rep-count-null"
    },
    {
      "id": "deadlift-rep-count-null",
      "exercise": "deadlift",
      "exerciseName": "Deadlift",
      "purpose": "rep-count",
      "role": "top-and-bottom",
      "measure": "joint-angle",
      "joint": "hip",
      "points": "shoulder; hip; knee",
      "keypointIndices": null,
      "comparison": null,
      "value": null,
      "value2": null,
      "unit": "degrees",
      "meaning": "Top and bottom hip angles for counting deadlift reps.",
      "sourceProject": null,
      "sourceRepo": null,
      "license": null,
      "source": null,
      "quote": null,
      "usage": null,
      "measureQuote": null,
      "reasonQuote": null,
      "nullReason": "No licensed open-source deadlift rule could be read: the two deadlift repositories found ship no LICENSE file. The peer-reviewed state-machine definition cited on /motion/deadlift-pose-estimation is on a host the build environment could not reach on the fetch date, so its thresholds are not copied; it is listed in ops/sources/form-rules.txt for a snapshot run.",
      "page": "https://aifitnessapi.com/tools/exercise-form-rules#rule-deadlift-rep-count-null"
    }
  ]
}