Author the machine exercise circuit with props and corrected hip machine motions
Fourteen Planet Fitness machine exercises join the rig library, each with authored motion, info page, and schematic equipment via the new props layer (scene shapes, cables, bars, pads) rendered in lockstep by render.py and the in-app figure renderer. Abductor and Adductor are authored face-on with the real seated machine motion — knees-bent legs swinging apart/together against knee pads — replacing the earlier middle-split depiction. The watch target now bundles the figure renderer and motion rigs too. Claude-Session: https://claude.ai/code/session_01LEoff8bXGBS83tK1c55Mf7
@@ -0,0 +1,23 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Abdominal</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 120.0 128.0 L 114.0 62.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 106.0 130.0 L 150.0 130.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 122.0 132.0 L 122.0 150.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 102.0 150.0 L 150.0 150.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 156.0 149.0 L 190.0 149.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 131.0 43.1 L 159.6 34.0 L 161.0 64.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 134.0 128.0 L 176.4 110.2 L 172.0 150.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 128.0 126.0 Q 123.5 82.7 125.0 41.1" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 125.0 41.1 L 153.6 32.0 L 155.0 62.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 128.0 126.0 L 171.2 110.1 L 168.0 150.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 158.0 77.0 L 158.0 49.0" stroke="#6b7180" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="127.8" cy="21.3" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="137.7" y1="22.7" x2="144.6" y2="23.7" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,23 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Abdominal</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 120.0 128.0 L 114.0 62.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 106.0 130.0 L 150.0 130.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 122.0 132.0 L 122.0 150.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 102.0 150.0 L 150.0 150.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 156.0 149.0 L 190.0 149.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 173.6 58.7 L 201.9 48.6 L 196.0 78.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 134.0 128.0 L 176.4 110.2 L 172.0 150.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 128.0 126.0 Q 123.1 76.0 167.6 56.7" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 167.6 56.7 L 195.9 46.6 L 190.0 76.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 128.0 126.0 L 171.2 110.1 L 168.0 150.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 193.0 91.0 L 193.0 63.0" stroke="#6b7180" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="186.2" cy="49.2" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="193.6" y1="55.9" x2="198.8" y2="60.5" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,40 @@
|
||||
# Abdominal
|
||||
|
||||
The seated crunch machine — loaded spinal flexion with the lower back
|
||||
supported.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based trunk flexion
|
||||
- **Targets:** Rectus abdominis, deep core
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit with the pads resting against your chest and your feet flat on the
|
||||
platform. Grip the handles lightly and set the seat so your hips stay tucked
|
||||
into the base of the back pad.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Contract your abs to curl your ribs down toward your pelvis, driving the
|
||||
chest pad forward.
|
||||
2. Pause at the bottom of the crunch, feeling the abs fully shortened.
|
||||
3. Return under control until the torso is tall again — don't let the weight
|
||||
yank you back up.
|
||||
|
||||
## Cues
|
||||
|
||||
- Curl the spine, don't just hinge at the hips — think "shorten the front".
|
||||
- Keep your lower back in contact with the pad throughout.
|
||||
- Let the abs move the weight; the arms only steady the handles.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Pulling with the arms or shoulders instead of the abs.
|
||||
- Hinging from the hips with a flat, rigid spine.
|
||||
- Rushing the return and bouncing out of the top.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight once all four sets of ten are a controlled curl; slow the lowering
|
||||
phase to three seconds for extra time under tension.
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "Abdominal",
|
||||
"primary": 2,
|
||||
"working": ["spine"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[120, 128], [114, 62]], "w": 8},
|
||||
{"kind": "line", "pts": [[106, 130], [150, 130]], "w": 8},
|
||||
{"kind": "line", "pts": [[122, 132], [122, 150]], "w": 4},
|
||||
{"kind": "line", "pts": [[102, 150], [150, 150]], "w": 4},
|
||||
{"kind": "line", "pts": [[156, 149], [190, 149]], "w": 5}
|
||||
]},
|
||||
{"type": "pad", "at": ["hand_r", "hand_l"], "angle": 90, "halfLen": 14, "w": 6}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 1.0,
|
||||
"root": [128, 126],
|
||||
"spine": [94, 90], "neck": 82, "gaze": -8,
|
||||
"arm_r": [-12, -52], "arm_l": [-12, -52],
|
||||
"leg_r": [-20, -90], "leg_l": [-20, -90],
|
||||
"pins": {"hand_r": [155, 62], "hand_l": [161, 64], "foot_r": [168, 150], "foot_l": [172, 150]}
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.0,
|
||||
"root": [128, 126],
|
||||
"spine": [80, 40], "neck": 22, "gaze": -42,
|
||||
"arm_r": [-12, -52], "arm_l": [-12, -52],
|
||||
"leg_r": [-20, -90], "leg_l": [-20, -90],
|
||||
"pins": {"hand_r": [190, 76], "hand_l": [196, 78], "foot_r": [168, 150], "foot_l": [172, 150]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 171 KiB |
@@ -0,0 +1,23 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Abdominal</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 120.0 128.0 L 114.0 62.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 106.0 130.0 L 150.0 130.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 122.0 132.0 L 122.0 150.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 102.0 150.0 L 150.0 150.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 156.0 149.0 L 190.0 149.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 173.6 58.7 L 201.9 48.6 L 196.0 78.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 134.0 128.0 L 176.4 110.2 L 172.0 150.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 128.0 126.0 Q 123.1 76.0 167.6 56.7" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 167.6 56.7 L 195.9 46.6 L 190.0 76.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 128.0 126.0 L 171.2 110.1 L 168.0 150.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 193.0 91.0 L 193.0 63.0" stroke="#6b7180" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="186.2" cy="49.2" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="193.6" y1="55.9" x2="198.8" y2="60.5" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Abductor</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<rect x="152" y="56" width="16" height="72" rx="5" fill="#c5cad4"/>
|
||||
<rect x="130" y="126" width="60" height="10" rx="3" fill="#c5cad4"/>
|
||||
<path d="M 136.0 78.0 L 136.0 108.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 188.0 78.0 L 188.0 108.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 213.0 110.0 L 213.0 132.0" stroke="#6b7180" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 107.0 110.0 L 107.0 132.0" stroke="#6b7180" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 166.0 33.0 L 145.9 55.3 L 141.8 85.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 166.0 118.0 L 120.1 121.3 L 140.0 156.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 160.0 116.0 Q 160.0 72.5 160.0 31.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 160.0 31.0 L 180.1 53.3 L 184.2 83.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 160.0 116.0 L 205.1 124.9 L 180.0 156.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="160.0" cy="11.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Abductor</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<rect x="152" y="56" width="16" height="72" rx="5" fill="#c5cad4"/>
|
||||
<rect x="130" y="126" width="60" height="10" rx="3" fill="#c5cad4"/>
|
||||
<path d="M 136.0 78.0 L 136.0 108.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 188.0 78.0 L 188.0 108.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 213.0 110.0 L 213.0 132.0" stroke="#6b7180" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 107.0 110.0 L 107.0 132.0" stroke="#6b7180" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 166.0 33.0 L 145.9 55.3 L 141.8 85.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 166.0 118.0 L 120.0 119.3 L 104.0 156.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 160.0 116.0 Q 160.0 72.5 160.0 31.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 160.0 31.0 L 180.1 53.3 L 184.2 83.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 160.0 116.0 L 206.0 117.3 L 216.0 156.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="160.0" cy="11.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,38 @@
|
||||
# Abductor
|
||||
|
||||
The seated hip-abduction machine — presses the knees apart to load the outer
|
||||
hips and glutes.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based hip abduction
|
||||
- **Targets:** Gluteus medius, gluteus minimus, outer thighs
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit with your legs inside the pads, back flat against the seat, and knees
|
||||
starting close together. Rest your hands on the seat sides and keep your torso
|
||||
upright.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Push your knees outward against the pads to spread the legs.
|
||||
2. Pause at the widest point, squeezing the outer hips and glutes.
|
||||
3. Bring the legs back together under control — resist the pads on the way in.
|
||||
|
||||
## Cues
|
||||
|
||||
- Stay upright; leaning forward hands the work to the lower back.
|
||||
- Drive the knees out through the outer hips, not by rocking the pelvis.
|
||||
- Control the return so the pads don't slam your knees closed.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Leaning forward to force the legs wider.
|
||||
- Letting the pads snap the knees back together.
|
||||
- Using a bouncy, momentum-driven range instead of steady tension.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight in small steps once all four sets of ten are smooth; pause two
|
||||
seconds at full spread to build end-range strength.
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "Abductor",
|
||||
"primary": 2,
|
||||
"working": ["leg_r", "leg_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "rect", "x": 152, "y": 56, "w": 16, "h": 72, "r": 5},
|
||||
{"kind": "rect", "x": 130, "y": 126, "w": 60, "h": 10, "r": 3},
|
||||
{"kind": "line", "pts": [[136, 78], [136, 108]], "w": 4, "color": "prop"},
|
||||
{"kind": "line", "pts": [[188, 78], [188, 108]], "w": 4, "color": "prop"},
|
||||
{"kind": "line", "pts": [[213, 110], [213, 132]], "w": 9, "color": "prop"},
|
||||
{"kind": "line", "pts": [[107, 110], [107, 132]], "w": 9, "color": "prop"}
|
||||
]}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.5, "tween": 1.1,
|
||||
"root": [160, 116],
|
||||
"spine": [90, 90], "neck": 90,
|
||||
"arm_r": [-48, -82], "arm_l": [-132, -98],
|
||||
"leg_r": [-22, 0], "leg_l": [-158, 0],
|
||||
"pins": {"foot_r": [180, 156], "foot_l": [140, 156]}
|
||||
},
|
||||
{
|
||||
"hold": 0.5, "tween": 1.1,
|
||||
"root": [160, 116],
|
||||
"spine": [90, 90], "neck": 90,
|
||||
"arm_r": [-48, -82], "arm_l": [-132, -98],
|
||||
"leg_r": [-22, 0], "leg_l": [-158, 0],
|
||||
"pins": {"foot_r": [216, 156], "foot_l": [104, 156]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 189 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Abductor</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<rect x="152" y="56" width="16" height="72" rx="5" fill="#c5cad4"/>
|
||||
<rect x="130" y="126" width="60" height="10" rx="3" fill="#c5cad4"/>
|
||||
<path d="M 136.0 78.0 L 136.0 108.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 188.0 78.0 L 188.0 108.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 213.0 110.0 L 213.0 132.0" stroke="#6b7180" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 107.0 110.0 L 107.0 132.0" stroke="#6b7180" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 166.0 33.0 L 145.9 55.3 L 141.8 85.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 166.0 118.0 L 120.0 119.3 L 104.0 156.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 160.0 116.0 Q 160.0 72.5 160.0 31.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 160.0 31.0 L 180.1 53.3 L 184.2 83.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 160.0 116.0 L 206.0 117.3 L 216.0 156.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="160.0" cy="11.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Adductor</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<rect x="152" y="56" width="16" height="72" rx="5" fill="#c5cad4"/>
|
||||
<rect x="130" y="126" width="60" height="10" rx="3" fill="#c5cad4"/>
|
||||
<path d="M 136.0 78.0 L 136.0 108.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 188.0 78.0 L 188.0 108.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 197.0 110.0 L 197.0 132.0" stroke="#6b7180" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 123.0 110.0 L 123.0 132.0" stroke="#6b7180" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 166.0 33.0 L 145.9 55.3 L 141.8 85.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 166.0 118.0 L 120.0 119.3 L 104.0 156.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 160.0 116.0 Q 160.0 72.5 160.0 31.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 160.0 31.0 L 180.1 53.3 L 184.2 83.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 160.0 116.0 L 206.0 117.3 L 216.0 156.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="160.0" cy="11.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Adductor</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<rect x="152" y="56" width="16" height="72" rx="5" fill="#c5cad4"/>
|
||||
<rect x="130" y="126" width="60" height="10" rx="3" fill="#c5cad4"/>
|
||||
<path d="M 136.0 78.0 L 136.0 108.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 188.0 78.0 L 188.0 108.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 197.0 110.0 L 197.0 132.0" stroke="#6b7180" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 123.0 110.0 L 123.0 132.0" stroke="#6b7180" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 166.0 33.0 L 145.9 55.3 L 141.8 85.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 166.0 118.0 L 120.1 121.3 L 140.0 156.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 160.0 116.0 Q 160.0 72.5 160.0 31.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 160.0 31.0 L 180.1 53.3 L 184.2 83.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 160.0 116.0 L 205.1 124.9 L 180.0 156.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="160.0" cy="11.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,39 @@
|
||||
# Adductor
|
||||
|
||||
The seated hip-adduction machine — squeezes the knees together to load the
|
||||
inner thighs.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based hip adduction
|
||||
- **Targets:** Adductors, inner thighs
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit with your legs placed outside the pads, back flat against the seat, and
|
||||
knees starting spread apart. Rest your hands on the seat sides and keep your
|
||||
torso upright.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Squeeze your knees together against the pads using your inner thighs.
|
||||
2. Pause when the knees nearly touch, holding the contraction.
|
||||
3. Let the legs spread back open under control — don't let the pads fling them
|
||||
apart.
|
||||
|
||||
## Cues
|
||||
|
||||
- Drive the movement from the inner thighs, not by rocking the hips.
|
||||
- Keep the torso upright and the back against the seat.
|
||||
- Control both directions; the opening phase trains the muscle too.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Letting the pads throw the legs open at the start of each rep.
|
||||
- Setting too wide a start range before the muscle is warm.
|
||||
- Fast, swinging reps that rely on momentum instead of the adductors.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight once all four sets of ten are controlled in both directions; pause
|
||||
two seconds with the knees together to strengthen the fully-shortened position.
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "Adductor",
|
||||
"primary": 2,
|
||||
"working": ["leg_r", "leg_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "rect", "x": 152, "y": 56, "w": 16, "h": 72, "r": 5},
|
||||
{"kind": "rect", "x": 130, "y": 126, "w": 60, "h": 10, "r": 3},
|
||||
{"kind": "line", "pts": [[136, 78], [136, 108]], "w": 4, "color": "prop"},
|
||||
{"kind": "line", "pts": [[188, 78], [188, 108]], "w": 4, "color": "prop"},
|
||||
{"kind": "line", "pts": [[197, 110], [197, 132]], "w": 9, "color": "prop"},
|
||||
{"kind": "line", "pts": [[123, 110], [123, 132]], "w": 9, "color": "prop"}
|
||||
]}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.5, "tween": 1.1,
|
||||
"root": [160, 116],
|
||||
"spine": [90, 90], "neck": 90,
|
||||
"arm_r": [-48, -82], "arm_l": [-132, -98],
|
||||
"leg_r": [-22, 0], "leg_l": [-158, 0],
|
||||
"pins": {"foot_r": [216, 156], "foot_l": [104, 156]}
|
||||
},
|
||||
{
|
||||
"hold": 0.5, "tween": 1.1,
|
||||
"root": [160, 116],
|
||||
"spine": [90, 90], "neck": 90,
|
||||
"arm_r": [-48, -82], "arm_l": [-132, -98],
|
||||
"leg_r": [-22, 0], "leg_l": [-158, 0],
|
||||
"pins": {"foot_r": [180, 156], "foot_l": [140, 156]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 196 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Adductor</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<rect x="152" y="56" width="16" height="72" rx="5" fill="#c5cad4"/>
|
||||
<rect x="130" y="126" width="60" height="10" rx="3" fill="#c5cad4"/>
|
||||
<path d="M 136.0 78.0 L 136.0 108.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 188.0 78.0 L 188.0 108.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 197.0 110.0 L 197.0 132.0" stroke="#6b7180" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 123.0 110.0 L 123.0 132.0" stroke="#6b7180" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 166.0 33.0 L 145.9 55.3 L 141.8 85.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 166.0 118.0 L 120.1 121.3 L 140.0 156.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 160.0 116.0 Q 160.0 72.5 160.0 31.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 160.0 31.0 L 180.1 53.3 L 184.2 83.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 160.0 116.0 L 205.1 124.9 L 180.0 156.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="160.0" cy="11.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Arm Curl</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 116.0 134.0 L 150.0 134.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 146.0 42.0 L 176.0 68.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 176.0 68.0 L 176.0 128.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 140.4 41.1 L 165.0 58.3 L 183.5 82.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 136.0 126.0 L 179.5 111.0 L 180.0 151.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 130.0 124.0 Q 130.8 80.5 134.4 39.1" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 134.4 39.1 L 159.0 56.3 L 177.5 80.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 130.0 124.0 L 173.8 110.1 L 176.0 150.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 180.5 87.0 L 180.5 75.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="137.2" cy="19.3" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="146.7" y1="22.4" x2="153.4" y2="24.6" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Arm Curl</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 116.0 134.0 L 150.0 134.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 146.0 42.0 L 176.0 68.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 176.0 68.0 L 176.0 128.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 140.4 41.1 L 165.0 58.3 L 142.7 38.3" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 136.0 126.0 L 179.5 111.0 L 180.0 151.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 130.0 124.0 Q 130.8 80.5 134.4 39.1" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 134.4 39.1 L 159.0 56.3 L 136.7 36.3" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 130.0 124.0 L 173.8 110.1 L 176.0 150.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 139.7 43.3 L 139.7 31.3" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="137.2" cy="19.3" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="146.7" y1="22.4" x2="153.4" y2="24.6" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,37 @@
|
||||
# Arm Curl
|
||||
|
||||
The seated machine curl — biceps isolation with the upper arms braced flat on
|
||||
the pad so only the forearms move.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based elbow flexion (isolation)
|
||||
- **Targets:** Biceps brachii, brachialis
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit with your upper arms flat along the pad and grip the handles. Start with
|
||||
your forearms extended down along the pad, elbows just short of locked.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Curl the handles up toward your shoulders, squeezing the biceps at the top.
|
||||
2. Keep your upper arms pinned to the pad — only the forearms move.
|
||||
3. Lower under control until the forearms are fully extended again.
|
||||
|
||||
## Cues
|
||||
|
||||
- Upper arms stay glued to the pad the entire rep.
|
||||
- Squeeze hard at the top, then resist the weight all the way down.
|
||||
- Wrists stay neutral — don't curl with the hands.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Rocking the torso or lifting the elbows to swing the weight up.
|
||||
- Cutting the lowering phase short and dropping the weight.
|
||||
- Not fully extending at the bottom, shortening the range.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight once all four sets of ten are strict; slow the lowering phase to
|
||||
three seconds before adding load again.
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "Arm Curl",
|
||||
"primary": 2,
|
||||
"working": ["arm_r", "arm_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[116, 134], [150, 134]], "w": 8},
|
||||
{"kind": "line", "pts": [[146, 42], [176, 68]], "w": 8},
|
||||
{"kind": "line", "pts": [[176, 68], [176, 128]], "w": 5}
|
||||
]},
|
||||
{"type": "bar", "at": ["hand_r", "hand_l"], "angle": 90, "halfLen": 6}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 1.0,
|
||||
"root": [130, 124],
|
||||
"spine": [88, 86], "neck": 82, "gaze": -18,
|
||||
"arm_r": [-35, -52], "arm_l": [-35, -52],
|
||||
"leg_r": [-8, -72], "leg_l": [-8, -72],
|
||||
"pins": {"foot_r": [176, 150], "foot_l": [180, 151]}
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.2,
|
||||
"root": [130, 124],
|
||||
"spine": [88, 86], "neck": 82, "gaze": -18,
|
||||
"arm_r": [-35, 138], "arm_l": [-35, 138],
|
||||
"leg_r": [-8, -72], "leg_l": [-8, -72],
|
||||
"pins": {"foot_r": [176, 150], "foot_l": [180, 151]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 118 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Arm Curl</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 116.0 134.0 L 150.0 134.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 146.0 42.0 L 176.0 68.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 176.0 68.0 L 176.0 128.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 140.4 41.1 L 165.0 58.3 L 142.7 38.3" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 136.0 126.0 L 179.5 111.0 L 180.0 151.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 130.0 124.0 Q 130.8 80.5 134.4 39.1" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 134.4 39.1 L 159.0 56.3 L 136.7 36.3" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 130.0 124.0 L 173.8 110.1 L 176.0 150.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 139.7 43.3 L 139.7 31.3" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="137.2" cy="19.3" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="146.7" y1="22.4" x2="153.4" y2="24.6" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,25 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Calfs</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 124.0 126.0 L 158.0 124.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 138.0 128.0 L 138.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 120.0 150.0 L 156.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<rect x="198" y="147" width="34" height="6" rx="1" fill="#c5cad4"/>
|
||||
<path d="M 183.0 62.0 L 183.0 124.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<rect x="170" y="121" width="27" height="7" rx="2" fill="#c5cad4"/>
|
||||
<path d="M 164.0 76.0 L 183.0 76.0" stroke="#6b7180" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 134.1 35.9 L 162.0 47.1 L 170.0 76.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 146.0 120.0 L 192.0 118.0 L 216.0 150.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 140.0 118.0 Q 131.0 75.4 128.1 33.9" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 128.1 33.9 L 155.7 45.8 L 166.0 74.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 140.0 118.0 L 186.0 117.6 L 212.0 148.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 207.2 150.8 L 220.8 147.2" stroke="#6b7180" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="131.6" cy="14.2" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="141.5" y1="15.9" x2="148.4" y2="17.1" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,25 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Calfs</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 124.0 126.0 L 158.0 124.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 138.0 128.0 L 138.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 120.0 150.0 L 156.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<rect x="198" y="147" width="34" height="6" rx="1" fill="#c5cad4"/>
|
||||
<path d="M 183.0 62.0 L 183.0 124.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<rect x="170" y="121" width="27" height="7" rx="2" fill="#c5cad4"/>
|
||||
<path d="M 164.0 76.0 L 183.0 76.0" stroke="#6b7180" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 134.1 35.9 L 162.0 47.1 L 170.0 76.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 146.0 120.0 L 190.9 109.9 L 216.0 141.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 140.0 118.0 Q 131.0 75.4 128.1 33.9" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 128.1 33.9 L 155.7 45.8 L 166.0 74.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 140.0 118.0 L 185.2 109.3 L 212.0 139.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 207.2 141.8 L 220.8 138.2" stroke="#6b7180" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="131.6" cy="14.2" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="141.5" y1="15.9" x2="148.4" y2="17.1" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,40 @@
|
||||
# Calfs
|
||||
|
||||
Seated heel raises through a full range — a deep stretch below the platform and
|
||||
a hard squeeze at the top.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based calf raise
|
||||
- **Targets:** Soleus, gastrocnemius
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit with the balls of your feet on the platform, heels hanging off the back
|
||||
edge, and the pad snug on your lower thighs just above the knees. Hold the pad
|
||||
handles lightly.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Raise your heels by contracting your calves, pressing up onto the balls of
|
||||
your feet against the pad.
|
||||
2. Pause at the top with the calves fully shortened.
|
||||
3. Slowly lower your heels below the platform level for a full stretch.
|
||||
|
||||
## Cues
|
||||
|
||||
- Chase the full range — a hard squeeze up top, a deep stretch at the bottom.
|
||||
- Drive through the balls of the feet, not the toes.
|
||||
- Control the tempo; the stretch under the platform is where the work is.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Bouncing through short, choppy reps instead of the full range.
|
||||
- Rocking the weight up with the hips instead of the calves.
|
||||
- Rushing the lowering and skipping the bottom stretch.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight in small increments once all four sets of ten are controlled;
|
||||
single-leg raises and paused reps at the stretched bottom build the hardest end
|
||||
of the range.
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "Calfs",
|
||||
"primary": 2,
|
||||
"working": ["leg_r", "leg_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[124, 126], [158, 124]], "w": 9},
|
||||
{"kind": "line", "pts": [[138, 128], [138, 150]], "w": 5},
|
||||
{"kind": "line", "pts": [[120, 150], [156, 150]], "w": 5},
|
||||
{"kind": "rect", "x": 198, "y": 147, "w": 34, "h": 6, "r": 1},
|
||||
{"kind": "line", "pts": [[183, 62], [183, 124]], "w": 4},
|
||||
{"kind": "rect", "x": 170, "y": 121, "w": 27, "h": 7, "r": 2},
|
||||
{"kind": "line", "pts": [[164, 76], [183, 76]], "w": 3, "color": "prop"}
|
||||
]},
|
||||
{"type": "pad", "at": ["foot_r", "foot_l"], "angle": 15, "halfLen": 7, "w": 5}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 0.9,
|
||||
"root": [140, 118],
|
||||
"spine": [100, 96], "neck": 80, "gaze": -10,
|
||||
"arm_r": [-40, -15], "arm_l": [-40, -15],
|
||||
"leg_r": [-18, -8], "leg_l": [-18, -8],
|
||||
"pins": {"hand_r": [166, 74], "hand_l": [170, 76], "foot_r": [212, 148], "foot_l": [216, 150]}
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.2,
|
||||
"root": [140, 118],
|
||||
"spine": [100, 96], "neck": 80, "gaze": -10,
|
||||
"arm_r": [-40, -15], "arm_l": [-40, -15],
|
||||
"leg_r": [-14, 4], "leg_l": [-14, 4],
|
||||
"pins": {"hand_r": [166, 74], "hand_l": [170, 76], "foot_r": [212, 139], "foot_l": [216, 141]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 156 KiB |
@@ -0,0 +1,25 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Calfs</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 124.0 126.0 L 158.0 124.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 138.0 128.0 L 138.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 120.0 150.0 L 156.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<rect x="198" y="147" width="34" height="6" rx="1" fill="#c5cad4"/>
|
||||
<path d="M 183.0 62.0 L 183.0 124.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<rect x="170" y="121" width="27" height="7" rx="2" fill="#c5cad4"/>
|
||||
<path d="M 164.0 76.0 L 183.0 76.0" stroke="#6b7180" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 134.1 35.9 L 162.0 47.1 L 170.0 76.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 146.0 120.0 L 190.9 109.9 L 216.0 141.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 140.0 118.0 Q 131.0 75.4 128.1 33.9" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 128.1 33.9 L 155.7 45.8 L 166.0 74.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 140.0 118.0 L 185.2 109.3 L 212.0 139.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 207.2 141.8 L 220.8 138.2" stroke="#6b7180" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="131.6" cy="14.2" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="141.5" y1="15.9" x2="148.4" y2="17.1" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Chest Press</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 114.0 132.0 L 86.0 40.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 106.0 133.0 L 146.0 133.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 122.0 135.0 L 122.0 151.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 108.0 151.0 L 138.0 151.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 104.3 40.9 L 99.1 70.5 L 122.1 51.2" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 122.0 124.0 L 166.5 112.3 L 162.0 152.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 116.0 122.0 Q 104.0 80.1 98.3 38.9" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 98.3 38.9 L 93.1 68.5 L 116.1 49.2" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 116.0 122.0 L 160.7 111.1 L 158.0 151.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 119.1 58.2 L 119.1 42.2" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="100.4" cy="19.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="110.4" y1="18.2" x2="117.3" y2="17.5" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Chest Press</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 114.0 132.0 L 86.0 40.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 106.0 133.0 L 146.0 133.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 122.0 135.0 L 122.0 151.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 108.0 151.0 L 138.0 151.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 104.3 40.9 L 134.1 44.1 L 163.2 51.3" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 122.0 124.0 L 166.5 112.3 L 162.0 152.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 116.0 122.0 Q 104.0 80.1 98.3 38.9" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 98.3 38.9 L 128.1 42.1 L 157.2 49.3" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 116.0 122.0 L 160.7 111.1 L 158.0 151.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 160.2 58.3 L 160.2 42.3" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="100.4" cy="19.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="110.4" y1="18.2" x2="117.3" y2="17.5" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,38 @@
|
||||
# Chest Press
|
||||
|
||||
The seated horizontal press — the machine bench press, pushing the handles
|
||||
forward from the chest.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based horizontal press
|
||||
- **Targets:** Pectorals, anterior deltoids, triceps
|
||||
|
||||
## Setup
|
||||
|
||||
Adjust the seat so the handles sit at mid-chest height. Grip the handles, set
|
||||
your back against the pad, and keep your wrists straight and stacked over the
|
||||
forearms.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Push the handles forward until your arms are nearly extended — stop short of
|
||||
locking the elbows.
|
||||
2. Pause briefly, then return slowly until the handles are back at your chest.
|
||||
3. Keep your shoulder blades gently pinned to the pad throughout.
|
||||
|
||||
## Cues
|
||||
|
||||
- Drive through the palms; wrists stay straight, not bent back.
|
||||
- Don't let the elbows drop far below the handles at the bottom.
|
||||
- Return under control — resist the weight rather than letting it pull you back.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Letting the elbows sink too low, straining the shoulders.
|
||||
- Bouncing the handles at the chest to start the next rep.
|
||||
- Locking the elbows hard at full extension.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight in small plates once all four sets of ten are controlled; alternate
|
||||
to a single-arm press to expose and correct side-to-side differences.
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "Chest Press",
|
||||
"primary": 2,
|
||||
"working": ["arm_r", "arm_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[114, 132], [86, 40]], "w": 8},
|
||||
{"kind": "line", "pts": [[106, 133], [146, 133]], "w": 8},
|
||||
{"kind": "line", "pts": [[122, 135], [122, 151]], "w": 5},
|
||||
{"kind": "line", "pts": [[108, 151], [138, 151]], "w": 4}
|
||||
]},
|
||||
{"type": "bar", "at": ["hand_r", "hand_l"], "angle": 90, "halfLen": 8}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 1.1,
|
||||
"root": [116, 122],
|
||||
"spine": [104, 100], "neck": 84, "gaze": 5,
|
||||
"arm_r": [-100, 40], "arm_l": [-100, 40],
|
||||
"leg_r": [-22, -72], "leg_l": [-22, -72],
|
||||
"pins": {"foot_r": [158, 151], "foot_l": [162, 152]}
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.1,
|
||||
"root": [116, 122],
|
||||
"spine": [104, 100], "neck": 84, "gaze": 5,
|
||||
"arm_r": [-6, -14], "arm_l": [-6, -14],
|
||||
"leg_r": [-22, -72], "leg_l": [-22, -72],
|
||||
"pins": {"foot_r": [158, 151], "foot_l": [162, 152]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 147 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Chest Press</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 114.0 132.0 L 86.0 40.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 106.0 133.0 L 146.0 133.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 122.0 135.0 L 122.0 151.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 108.0 151.0 L 138.0 151.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 104.3 40.9 L 134.1 44.1 L 163.2 51.3" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 122.0 124.0 L 166.5 112.3 L 162.0 152.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 116.0 122.0 Q 104.0 80.1 98.3 38.9" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 98.3 38.9 L 128.1 42.1 L 157.2 49.3" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 116.0 122.0 L 160.7 111.1 L 158.0 151.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 160.2 58.3 L 160.2 42.3" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="100.4" cy="19.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="110.4" y1="18.2" x2="117.3" y2="17.5" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,23 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Lat Pull Down</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 126.0 130.0 L 162.0 130.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 124.0 130.0 L 124.0 56.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 124.0 56.0 L 198.0 12.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<rect x="170" y="112" width="40" height="7" rx="3" fill="#c5cad4"/>
|
||||
<path d="M 198.0 8.0 L 200.0 25.0" stroke="#c5cad4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 153.7 39.1 L 173.5 16.5 L 202.0 26.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 156.0 124.0 L 200.2 111.1 L 197.0 151.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 150.0 122.0 Q 146.6 78.6 147.7 37.1" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 147.7 37.1 L 169.1 16.0 L 198.0 24.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 150.0 122.0 L 194.4 110.0 L 193.0 150.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 172.0 25.0 L 228.0 25.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="149.5" cy="17.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="155.2" y1="8.9" x2="159.2" y2="3.2" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,23 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Lat Pull Down</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 126.0 130.0 L 162.0 130.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 124.0 130.0 L 124.0 56.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 124.0 56.0 L 198.0 12.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<rect x="170" y="112" width="40" height="7" rx="3" fill="#c5cad4"/>
|
||||
<path d="M 198.0 8.0 L 167.0 67.0" stroke="#c5cad4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 153.7 39.1 L 139.1 65.3 L 169.0 68.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 156.0 124.0 L 200.2 111.1 L 197.0 151.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 150.0 122.0 Q 146.6 78.6 147.7 37.1" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 147.7 37.1 L 135.1 64.2 L 165.0 66.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 150.0 122.0 L 194.4 110.0 L 193.0 150.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 139.0 67.0 L 195.0 67.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="149.5" cy="17.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="158.2" y1="12.1" x2="164.2" y2="8.6" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,37 @@
|
||||
# Lat Pull Down
|
||||
|
||||
The seated vertical pull — building width through the lats with a bar driven
|
||||
down from overhead.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based vertical pull
|
||||
- **Targets:** Latissimus dorsi, mid-back, rear delts, biceps
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit upright with your knees secured under the pad and feet flat. Grip the bar
|
||||
wider than shoulder-width, arms fully extended overhead, torso just off vertical.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Pull the bar down to your upper chest, driving your elbows down and back.
|
||||
2. Squeeze your shoulder blades together at the bottom and pause briefly.
|
||||
3. Return the bar overhead under control until your arms are fully extended.
|
||||
|
||||
## Cues
|
||||
|
||||
- Lead with the elbows, not the hands — think "elbows to the ribs".
|
||||
- Squeeze the shoulder blades down and together at the bottom.
|
||||
- Keep the torso tall; only a slight lean back, never a swing.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Leaning back excessively and turning it into a row.
|
||||
- Using momentum to yank the bar down.
|
||||
- Stopping short — not pulling the bar all the way to the chest.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight once all four sets of ten are clean; progress to a wider or neutral
|
||||
grip, then to strict pull-ups as pulling strength builds.
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "Lat Pull Down",
|
||||
"primary": 2,
|
||||
"working": ["arm_r", "arm_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[126, 130], [162, 130]], "w": 8},
|
||||
{"kind": "line", "pts": [[124, 130], [124, 56]], "w": 5},
|
||||
{"kind": "line", "pts": [[124, 56], [198, 12]], "w": 5},
|
||||
{"kind": "rect", "x": 170, "y": 112, "w": 40, "h": 7, "r": 3}
|
||||
]},
|
||||
{"type": "cable", "from": [198, 8], "to": ["hand_r", "hand_l"]},
|
||||
{"type": "bar", "at": ["hand_r", "hand_l"], "halfLen": 28}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 1.0,
|
||||
"root": [150, 122],
|
||||
"spine": [93, 90], "neck": 85, "gaze": 55,
|
||||
"arm_r": [20, 10], "arm_l": [20, 10],
|
||||
"leg_r": [-12, -80], "leg_l": [-12, -80],
|
||||
"pins": {"hand_r": [198, 24], "hand_l": [202, 26],
|
||||
"foot_r": [193, 150], "foot_l": [197, 151]}
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.2,
|
||||
"root": [150, 122],
|
||||
"spine": [93, 90], "neck": 85, "gaze": 30,
|
||||
"arm_r": [-115, -20], "arm_l": [-115, -20],
|
||||
"leg_r": [-12, -80], "leg_l": [-12, -80],
|
||||
"pins": {"hand_r": [165, 66], "hand_l": [169, 68],
|
||||
"foot_r": [193, 150], "foot_l": [197, 151]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 164 KiB |
@@ -0,0 +1,23 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Lat Pull Down</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 126.0 130.0 L 162.0 130.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 124.0 130.0 L 124.0 56.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 124.0 56.0 L 198.0 12.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<rect x="170" y="112" width="40" height="7" rx="3" fill="#c5cad4"/>
|
||||
<path d="M 198.0 8.0 L 167.0 67.0" stroke="#c5cad4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 153.7 39.1 L 139.1 65.3 L 169.0 68.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 156.0 124.0 L 200.2 111.1 L 197.0 151.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 150.0 122.0 Q 146.6 78.6 147.7 37.1" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 147.7 37.1 L 135.1 64.2 L 165.0 66.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 150.0 122.0 L 194.4 110.0 L 193.0 150.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 139.0 67.0 L 195.0 67.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="149.5" cy="17.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="158.2" y1="12.1" x2="164.2" y2="8.6" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,25 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Leg Curl</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 110.0 122.0 L 86.0 48.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 104.0 124.0 L 166.0 120.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 130.0 105.0 L 158.0 106.0" stroke="#c5cad4" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 108.0 126.0 L 108.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 160.0 124.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 104.0 150.0 L 166.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="114.0" cy="90.0" r="3.5" fill="#6b7180"/>
|
||||
<path id="arm_l" d="M 97.7 37.2 L 105.5 66.2 L 120.5 92.2" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 124.0 118.0 L 169.3 110.0 L 209.2 107.2" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 118.0 116.0 Q 101.7 75.6 91.7 35.2" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 91.7 35.2 L 99.5 64.2 L 114.5 90.2" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 118.0 116.0 L 163.3 108.0 L 203.2 105.2" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 205.6 97.2 L 206.8 115.2" stroke="#6b7180" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="97.2" cy="16.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="106.6" y1="19.4" x2="113.2" y2="21.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,25 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Leg Curl</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 110.0 122.0 L 86.0 48.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 104.0 124.0 L 166.0 120.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 130.0 105.0 L 158.0 106.0" stroke="#c5cad4" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 108.0 126.0 L 108.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 160.0 124.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 104.0 150.0 L 166.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="114.0" cy="90.0" r="3.5" fill="#6b7180"/>
|
||||
<path id="arm_l" d="M 97.7 37.2 L 105.5 66.2 L 120.5 92.2" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 124.0 118.0 L 169.3 110.0 L 165.8 149.9" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 118.0 116.0 Q 101.7 75.6 91.7 35.2" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 91.7 35.2 L 99.5 64.2 L 114.5 90.2" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 118.0 116.0 L 163.3 108.0 L 159.8 147.9" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 171.8 149.6 L 153.8 148.1" stroke="#6b7180" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="97.2" cy="16.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="106.6" y1="19.4" x2="113.2" y2="21.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,37 @@
|
||||
# Leg Curl
|
||||
|
||||
Isolated hamstring work — the heels curl toward the glutes while a pad locks
|
||||
the thighs in place.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based isolation (knee flexion)
|
||||
- **Targets:** Hamstrings (biceps femoris, semitendinosus, semimembranosus)
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit (or lie face down, depending on the version) with the thigh pad locked over
|
||||
your legs and the roller behind your ankles. Start with the legs extended.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Curl your legs toward your glutes, driving through the hamstrings.
|
||||
2. Squeeze hard at the fully bent position.
|
||||
3. Return the roller under control until the legs are extended again.
|
||||
|
||||
## Cues
|
||||
|
||||
- Focus on hamstring engagement — feel the pull behind the knee, not the back.
|
||||
- Keep your hips and back still against the pad; no arching to cheat.
|
||||
- Curl through the full range, all the way to the glutes.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Arching the lower back to yank the weight up.
|
||||
- Using momentum instead of a controlled curl.
|
||||
- Cutting the range short and never reaching full flexion.
|
||||
|
||||
## Progression
|
||||
|
||||
Add load once all four sets of ten are controlled; single-leg curls for
|
||||
asymmetry, or a slow eccentric to overload the lengthening hamstring.
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "Leg Curl",
|
||||
"primary": 2,
|
||||
"working": ["leg_r", "leg_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[110, 122], [86, 48]], "w": 9},
|
||||
{"kind": "line", "pts": [[104, 124], [166, 120]], "w": 9},
|
||||
{"kind": "line", "pts": [[130, 105], [158, 106]], "w": 7},
|
||||
{"kind": "line", "pts": [[108, 126], [108, 150]], "w": 5},
|
||||
{"kind": "line", "pts": [[160, 124], [160, 150]], "w": 5},
|
||||
{"kind": "line", "pts": [[104, 150], [166, 150]], "w": 5},
|
||||
{"kind": "circle", "c": [114, 90], "r": 3.5, "fill": true, "color": "prop"}
|
||||
]},
|
||||
{"type": "pad", "at": ["foot_r", "foot_l"], "halfLen": 9}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 1.0,
|
||||
"root": [118, 116],
|
||||
"spine": [110, 106], "neck": 74, "gaze": -20,
|
||||
"arm_r": [-75, -60], "arm_l": [-75, -60],
|
||||
"leg_r": [10, 4], "leg_l": [10, 4]
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.2,
|
||||
"root": [118, 116],
|
||||
"spine": [110, 106], "neck": 74, "gaze": -20,
|
||||
"arm_r": [-75, -60], "arm_l": [-75, -60],
|
||||
"leg_r": [10, -95], "leg_l": [10, -95]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 172 KiB |
@@ -0,0 +1,25 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Leg Curl</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 110.0 122.0 L 86.0 48.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 104.0 124.0 L 166.0 120.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 130.0 105.0 L 158.0 106.0" stroke="#c5cad4" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 108.0 126.0 L 108.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 160.0 124.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 104.0 150.0 L 166.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="114.0" cy="90.0" r="3.5" fill="#6b7180"/>
|
||||
<path id="arm_l" d="M 97.7 37.2 L 105.5 66.2 L 120.5 92.2" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 124.0 118.0 L 169.3 110.0 L 165.8 149.9" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 118.0 116.0 Q 101.7 75.6 91.7 35.2" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 91.7 35.2 L 99.5 64.2 L 114.5 90.2" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 118.0 116.0 L 163.3 108.0 L 159.8 147.9" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 171.8 149.6 L 153.8 148.1" stroke="#6b7180" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="97.2" cy="16.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="106.6" y1="19.4" x2="113.2" y2="21.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Leg Extension</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 110.0 122.0 L 86.0 48.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 104.0 124.0 L 166.0 120.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 108.0 126.0 L 108.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 160.0 124.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 104.0 150.0 L 166.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="114.0" cy="90.0" r="3.5" fill="#6b7180"/>
|
||||
<path id="arm_l" d="M 97.7 37.2 L 105.5 66.2 L 120.5 92.2" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 124.0 118.0 L 169.3 110.0 L 174.2 149.7" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 118.0 116.0 Q 101.7 75.6 91.7 35.2" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 91.7 35.2 L 99.5 64.2 L 114.5 90.2" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 118.0 116.0 L 163.3 108.0 L 168.2 147.7" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 180.1 147.6 L 162.2 149.8" stroke="#6b7180" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="97.2" cy="16.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="106.6" y1="19.4" x2="113.2" y2="21.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Leg Extension</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 110.0 122.0 L 86.0 48.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 104.0 124.0 L 166.0 120.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 108.0 126.0 L 108.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 160.0 124.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 104.0 150.0 L 166.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="114.0" cy="90.0" r="3.5" fill="#6b7180"/>
|
||||
<path id="arm_l" d="M 97.7 37.2 L 105.5 66.2 L 120.5 92.2" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 124.0 118.0 L 169.3 110.0 L 209.2 107.2" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 118.0 116.0 Q 101.7 75.6 91.7 35.2" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 91.7 35.2 L 99.5 64.2 L 114.5 90.2" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 118.0 116.0 L 163.3 108.0 L 203.2 105.2" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 205.6 97.2 L 206.8 115.2" stroke="#6b7180" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="97.2" cy="16.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="106.6" y1="19.4" x2="113.2" y2="21.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,40 @@
|
||||
# Leg Extension
|
||||
|
||||
Isolated quadriceps work — the knee opens against the roller while the hips
|
||||
stay pinned to the seat.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based isolation (knee extension)
|
||||
- **Targets:** Quadriceps (rectus femoris, vastus lateralis/medialis)
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit upright with your back flat against the pad and align your knees with the
|
||||
machine's pivot point. Hook the roller pad against the front of your ankles,
|
||||
hands resting on the side grips.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Extend your legs to a straightened position — stop just short of snapping
|
||||
the knees into lockout.
|
||||
2. Pause briefly at the top with the quads squeezed hard.
|
||||
3. Lower the roller back down with control to the start.
|
||||
|
||||
## Cues
|
||||
|
||||
- Knees stack over the pivot — realign the seat if they sit forward or back.
|
||||
- Hips glued to the seat; if they lift, the weight is too heavy.
|
||||
- Own the lowering — no free-falling back to the stack.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Jerky, momentum-driven reps instead of a smooth extension.
|
||||
- Lifting the hips off the seat to swing the weight up.
|
||||
- Slamming into a locked knee at the top.
|
||||
|
||||
## Progression
|
||||
|
||||
Add load in small increments once all four sets of ten are smooth; single-leg
|
||||
extensions for asymmetry, or a paused top / slow eccentric for more time under
|
||||
tension.
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "Leg Extension",
|
||||
"primary": 2,
|
||||
"working": ["leg_r", "leg_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[110, 122], [86, 48]], "w": 9},
|
||||
{"kind": "line", "pts": [[104, 124], [166, 120]], "w": 9},
|
||||
{"kind": "line", "pts": [[108, 126], [108, 150]], "w": 5},
|
||||
{"kind": "line", "pts": [[160, 124], [160, 150]], "w": 5},
|
||||
{"kind": "line", "pts": [[104, 150], [166, 150]], "w": 5},
|
||||
{"kind": "circle", "c": [114, 90], "r": 3.5, "fill": true, "color": "prop"}
|
||||
]},
|
||||
{"type": "pad", "at": ["foot_r", "foot_l"], "halfLen": 9}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 1.0,
|
||||
"root": [118, 116],
|
||||
"spine": [110, 106], "neck": 74, "gaze": -20,
|
||||
"arm_r": [-75, -60], "arm_l": [-75, -60],
|
||||
"leg_r": [10, -83], "leg_l": [10, -83]
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.2,
|
||||
"root": [118, 116],
|
||||
"spine": [110, 106], "neck": 74, "gaze": -20,
|
||||
"arm_r": [-75, -60], "arm_l": [-75, -60],
|
||||
"leg_r": [10, 4], "leg_l": [10, 4]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 169 KiB |
@@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Leg Extension</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 110.0 122.0 L 86.0 48.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 104.0 124.0 L 166.0 120.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 108.0 126.0 L 108.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 160.0 124.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 104.0 150.0 L 166.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="114.0" cy="90.0" r="3.5" fill="#6b7180"/>
|
||||
<path id="arm_l" d="M 97.7 37.2 L 105.5 66.2 L 120.5 92.2" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 124.0 118.0 L 169.3 110.0 L 209.2 107.2" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 118.0 116.0 Q 101.7 75.6 91.7 35.2" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 91.7 35.2 L 99.5 64.2 L 114.5 90.2" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 118.0 116.0 L 163.3 108.0 L 203.2 105.2" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 205.6 97.2 L 206.8 115.2" stroke="#6b7180" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="97.2" cy="16.0" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="106.6" y1="19.4" x2="113.2" y2="21.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Leg Press</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 134.0 123.0 L 96.0 36.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 126.0 127.0 L 156.0 122.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 138.0 130.0 L 138.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 118.0 150.0 L 158.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 142.0 90.0 L 142.0 78.0" stroke="#c5cad4" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="142.0" cy="77.0" r="3.5" fill="#6b7180"/>
|
||||
<path id="arm_l" d="M 111.4 40.4 L 119.2 69.4 L 147.4 79.6" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 146.0 118.0 L 161.7 74.8 L 189.0 104.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 140.0 116.0 Q 119.6 77.5 105.4 38.4" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 105.4 38.4 L 113.2 67.4 L 141.4 77.6" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 140.0 116.0 L 157.1 73.3 L 185.0 102.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 186.3 123.0 L 187.7 83.0" stroke="#6b7180" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="110.6" cy="19.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="120.3" y1="21.7" x2="127.0" y2="23.5" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Leg Press</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 134.0 123.0 L 96.0 36.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 126.0 127.0 L 156.0 122.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 138.0 130.0 L 138.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 118.0 150.0 L 158.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 142.0 90.0 L 142.0 78.0" stroke="#c5cad4" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="142.0" cy="77.0" r="3.5" fill="#6b7180"/>
|
||||
<path id="arm_l" d="M 111.4 40.4 L 119.2 69.4 L 147.4 79.6" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 146.0 118.0 L 185.1 93.7 L 224.0 103.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 140.0 116.0 Q 119.6 77.5 105.4 38.4" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 105.4 38.4 L 113.2 67.4 L 141.4 77.6" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 140.0 116.0 L 180.6 94.3 L 220.0 101.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 221.3 122.0 L 222.7 82.0" stroke="#6b7180" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="110.6" cy="19.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="120.3" y1="21.7" x2="127.0" y2="23.5" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,39 @@
|
||||
# Leg Press
|
||||
|
||||
The seated machine squat — maximum lower-body load with the back fully
|
||||
supported.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based compound push
|
||||
- **Targets:** Quadriceps, glutes, hamstrings
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit with your back and hips flat against the pad. Place your feet
|
||||
shoulder-width on the platform, heels never floating. Adjust the seat so your
|
||||
knees start near 90°.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Press through your heels until your legs are nearly straight — stop short
|
||||
of locking the knees.
|
||||
2. Pause briefly, then bend the knees to return under control.
|
||||
3. Keep your back and hips glued to the pad the whole rep.
|
||||
|
||||
## Cues
|
||||
|
||||
- Drive through the heels, not the toes.
|
||||
- Knees track over the feet — don't let them cave inward.
|
||||
- Lower back stays on the pad; if the hips curl up, you've gone too deep.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Locking the knees hard at the top.
|
||||
- Bouncing out of the bottom.
|
||||
- Letting the hips roll off the pad at the bottom of the rep.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight in small plates once all four sets of ten are controlled; single-leg
|
||||
presses for asymmetry work.
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "Leg Press",
|
||||
"primary": 2,
|
||||
"working": ["leg_r", "leg_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[134, 123], [96, 36]], "w": 9},
|
||||
{"kind": "line", "pts": [[126, 127], [156, 122]], "w": 9},
|
||||
{"kind": "line", "pts": [[138, 130], [138, 150]], "w": 5},
|
||||
{"kind": "line", "pts": [[118, 150], [158, 150]], "w": 5},
|
||||
{"kind": "line", "pts": [[142, 90], [142, 78]], "w": 3},
|
||||
{"kind": "circle", "c": [142, 77], "r": 3.5, "fill": true, "color": "prop"}
|
||||
]},
|
||||
{"type": "pad", "at": ["foot_r", "foot_l"], "angle": 88, "halfLen": 20, "w": 6}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 1.0,
|
||||
"root": [140, 116],
|
||||
"spine": [116, 112], "neck": 75, "gaze": -15,
|
||||
"arm_r": [-75, -20], "arm_l": [-75, -20],
|
||||
"leg_r": [40, -58], "leg_l": [40, -58],
|
||||
"pins": {"foot_r": [185, 102], "foot_l": [189, 104]}
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.2,
|
||||
"root": [140, 116],
|
||||
"spine": [116, 112], "neck": 75, "gaze": -15,
|
||||
"arm_r": [-75, -20], "arm_l": [-75, -20],
|
||||
"leg_r": [20, -5], "leg_l": [20, -5],
|
||||
"pins": {"foot_r": [220, 101], "foot_l": [224, 103]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 164 KiB |
@@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Leg Press</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 134.0 123.0 L 96.0 36.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 126.0 127.0 L 156.0 122.0" stroke="#c5cad4" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 138.0 130.0 L 138.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 118.0 150.0 L 158.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 142.0 90.0 L 142.0 78.0" stroke="#c5cad4" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="142.0" cy="77.0" r="3.5" fill="#6b7180"/>
|
||||
<path id="arm_l" d="M 111.4 40.4 L 119.2 69.4 L 147.4 79.6" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 146.0 118.0 L 185.1 93.7 L 224.0 103.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 140.0 116.0 Q 119.6 77.5 105.4 38.4" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 105.4 38.4 L 113.2 67.4 L 141.4 77.6" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 140.0 116.0 L 180.6 94.3 L 220.0 101.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 221.3 122.0 L 222.7 82.0" stroke="#6b7180" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="110.6" cy="19.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="120.3" y1="21.7" x2="127.0" y2="23.5" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,20 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Rotary</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 138.0 130.0 L 182.0 130.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 160.0 132.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 144.0 150.0 L 176.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 141.9 42.6 L 147.9 72.0 L 118.0 74.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 166.0 124.0 L 164.7 170.0 L 130.0 150.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 160.0 122.0 Q 151.2 79.3 135.9 40.6" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 135.9 40.6 L 141.9 70.0 L 112.0 72.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 160.0 122.0 L 154.1 167.6 L 190.0 150.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 115.0 87.0 L 115.0 59.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="129.4" cy="21.7" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,20 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Rotary</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 138.0 130.0 L 182.0 130.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 160.0 132.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 144.0 150.0 L 176.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 190.1 42.6 L 172.8 67.1 L 202.0 74.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 166.0 124.0 L 164.7 170.0 L 130.0 150.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 160.0 122.0 Q 168.8 79.3 184.1 40.6" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 184.1 40.6 L 178.1 70.0 L 208.0 72.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 160.0 122.0 L 154.1 167.6 L 190.0 150.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 205.0 87.0 L 205.0 59.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="190.6" cy="21.7" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,39 @@
|
||||
# Rotary
|
||||
|
||||
The rotary torso machine — controlled trunk rotation that isolates the
|
||||
obliques.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based trunk rotation
|
||||
- **Targets:** Obliques, deep core
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit tall with your hips squared and locked against the pads. Rest your
|
||||
forearms on the pads and grip the handle in front of your chest so the trunk,
|
||||
not the arms, drives the machine.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Rotate your torso to one side in a smooth, controlled arc, keeping your hips
|
||||
still.
|
||||
2. Pause at the end of the range without letting the weight pull you further.
|
||||
3. Return through center and rotate to the other side with the same control.
|
||||
|
||||
## Cues
|
||||
|
||||
- Twist from the waist — the obliques generate the movement, not the arms.
|
||||
- Keep the hips and pelvis pinned; only the trunk turns.
|
||||
- Move slowly; momentum steals the work from the obliques.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Throwing the weight with momentum instead of controlling the twist.
|
||||
- Pushing with the arms rather than rotating the trunk.
|
||||
- Letting the hips swing along with the torso.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight once both sides move with equal control; pause two seconds at full
|
||||
rotation to kill any momentum.
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "Rotary",
|
||||
"primary": 1,
|
||||
"working": ["spine"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[138, 130], [182, 130]], "w": 8},
|
||||
{"kind": "line", "pts": [[160, 132], [160, 150]], "w": 5},
|
||||
{"kind": "line", "pts": [[144, 150], [176, 150]], "w": 5}
|
||||
]},
|
||||
{"type": "bar", "at": ["hand_r", "hand_l"], "angle": 90, "halfLen": 14}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 1.0,
|
||||
"root": [160, 122],
|
||||
"spine": [104, 109], "neck": 109,
|
||||
"arm_r": [-50, -85], "arm_l": [-55, -90],
|
||||
"leg_r": [-62, -82], "leg_l": [-118, -98],
|
||||
"pins": {"hand_r": [112, 72], "hand_l": [118, 74], "foot_r": [190, 150], "foot_l": [130, 150]}
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.0,
|
||||
"root": [160, 122],
|
||||
"spine": [76, 71], "neck": 71,
|
||||
"arm_r": [-125, -95], "arm_l": [-130, -90],
|
||||
"leg_r": [-62, -82], "leg_l": [-118, -98],
|
||||
"pins": {"hand_r": [208, 72], "hand_l": [202, 74], "foot_r": [190, 150], "foot_l": [130, 150]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 172 KiB |
@@ -0,0 +1,20 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Rotary</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 138.0 130.0 L 182.0 130.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 160.0 132.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 144.0 150.0 L 176.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 141.9 42.6 L 147.9 72.0 L 118.0 74.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 166.0 124.0 L 164.7 170.0 L 130.0 150.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 160.0 122.0 Q 151.2 79.3 135.9 40.6" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 135.9 40.6 L 141.9 70.0 L 112.0 72.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 160.0 122.0 L 154.1 167.6 L 190.0 150.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 115.0 87.0 L 115.0 59.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="129.4" cy="21.7" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -52,6 +52,48 @@ changing data, never artwork.
|
||||
natural arcs and bone lengths never distort. The last frame tweens back to
|
||||
the first (looping). Asymmetric timing carries technique: leg raises lower
|
||||
slowly (`tween` 1.4 s down, 0.6 s up).
|
||||
- **Face-on figures** — `gaze` is optional: a frame without it faces the
|
||||
viewer and draws no nose tick. Used by exercises whose motion is lateral
|
||||
(abductor/adductor), where a side view would hide the movement.
|
||||
|
||||
## The props layer
|
||||
|
||||
Machines and free weights are data too: an optional top-level `"props"` array
|
||||
adds an equipment layer around the figure. `scene` shapes and `cable`s draw
|
||||
*behind* the figure in a recessive gray; joint-attached items (`bar`,
|
||||
`dumbbell`, `pad`) draw *over* the limbs in a darker gray and follow the
|
||||
resolved hand/foot positions every frame — a pinned foot pressing a `pad`
|
||||
carries the platform with it through the tween for free. The figure stays the
|
||||
hero: props are schematic silhouettes (a seat, a backrest, one handle), never
|
||||
scale drawings of the machine.
|
||||
|
||||
```json
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[134, 123], [96, 36]], "w": 9},
|
||||
{"kind": "rect", "x": 54, "y": 104, "w": 40, "h": 8, "r": 3},
|
||||
{"kind": "circle", "c": [142, 77], "r": 3.5, "fill": true, "color": "prop"}
|
||||
]},
|
||||
{"type": "cable", "from": [190, 8], "to": ["hand_r", "hand_l"]},
|
||||
{"type": "bar", "at": ["hand_r", "hand_l"], "halfLen": 26, "plateR": 0},
|
||||
{"type": "dumbbell", "at": "hand_r"},
|
||||
{"type": "pad", "at": ["foot_r", "foot_l"], "angle": 88, "halfLen": 20, "w": 6}
|
||||
]
|
||||
```
|
||||
|
||||
- **`scene`** — static shapes in canvas coordinates: `line` (polyline, stroke
|
||||
width `w`), `circle` (`fill: false` for an outline), `rect` (filled, corner
|
||||
radius `r`). A shape may set `"color": "prop"` to use the darker
|
||||
attached-item gray (e.g. a fixed handle the hands rest on).
|
||||
- **`cable`** — a thin line from a fixed anchor `from` to a moving joint `to`;
|
||||
the machine's pulley line.
|
||||
- **`bar` / `dumbbell` / `pad`** — a segment centered on the joint(s) in
|
||||
`at` (a single extremity, or the midpoint of `["hand_r", "hand_l"]`).
|
||||
`bar` lies at a fixed world `angle` (default 0 = horizontal — in side view a
|
||||
two-handed bar is drawn horizontal by convention); `dumbbell` and `pad`
|
||||
default to perpendicular to the lower bone (forearm/shin), or take an
|
||||
explicit `angle`. `plateR` puts filled discs on both ends (dumbbells default
|
||||
to 4.5). A prop whose limb is hidden that frame simply isn't drawn.
|
||||
- The same math is the plan for the app: a small SwiftUI renderer consumes
|
||||
`body.json` + `motion.json` and tweens angles on the lower half of the
|
||||
exercise screen (the paged timer flow occupies only the top half).
|
||||
@@ -61,9 +103,12 @@ changing data, never artwork.
|
||||
- **Right vs left limb** — the one rule that never bends: the figure's
|
||||
**right**-side limbs are dark (`#3a3f4b`), its **left**-side limbs are light
|
||||
(`#a9afba`) and drawn *behind* the body. Working limbs keep the split:
|
||||
right = teal `#0d9488`, left = light teal `#86cfc5`. Every render embeds a
|
||||
small `R —` / `L —` legend, so opposite-limb moves (bird dog, dead bug) are
|
||||
visibly opposite: one dark-teal limb, one light-teal limb.
|
||||
right = teal `#0d9488`, left = light teal `#86cfc5`. Opposite-limb moves
|
||||
(bird dog, dead bug) read as visibly opposite: one dark-teal limb, one
|
||||
light-teal limb. `render.py` reference renders embed a small `R —` / `L —`
|
||||
legend for the rig author; the in-app renderer deliberately omits it — the
|
||||
labels are only anatomically true for right-facing figures, and the
|
||||
contrast alone carries the meaning.
|
||||
- **Facing / front-of-torso** — the head carries a **nose tick** (`gaze`
|
||||
angle); the belly is on that side. Prone noses point at the floor, supine
|
||||
at the ceiling. The head is drawn last, filled opaque, so overhead arms
|
||||
@@ -83,7 +128,7 @@ python3 render.py --sheet # + contact-sheet.png of every key frame
|
||||
python3 render.py --demo # + demo-sheet.png: profile / flip / theme variants
|
||||
python3 render.py --figure=female # render with another body profile
|
||||
python3 render.py --flip # mirror the figure (faces the other way)
|
||||
python3 render.py --export # copy body.json + <Name>.motion.json app resources
|
||||
python3 render.py --export # copy body.json + <Name>.motion.json + <Name>.info.md app resources
|
||||
```
|
||||
|
||||
`render.py` needs only Pillow (for GIFs/sheets; the SVGs have no dependency).
|
||||
@@ -91,7 +136,9 @@ The library lives at the repo root, outside every target's source folders —
|
||||
same-named files per entry (`info.md`, `visual.svg`) would collide in Xcode's
|
||||
flat resource copy, so the library itself never enters the app bundle. Only
|
||||
the `--export` copies ship: `body.json` plus uniquely-named
|
||||
`<Name>.motion.json` files in `Workouts/Resources/ExerciseMotions/`, consumed
|
||||
by the in-app SwiftUI renderer (`Workouts/ExerciseFigure/`). Re-run
|
||||
`python3 render.py --export` after editing any motion; the library stays the
|
||||
source of truth.
|
||||
`<Name>.motion.json` and `<Name>.info.md` files in
|
||||
`Workouts/Resources/ExerciseMotions/`, consumed by the in-app SwiftUI renderer
|
||||
(`Workouts/ExerciseFigure/`) and the exercise-library reference screen
|
||||
(`ExerciseInfo.swift` parses the info pages). Re-run
|
||||
`python3 render.py --export` after editing any motion or info page; the
|
||||
library stays the source of truth.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Seated Row</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 122.0 132.0 L 156.0 132.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 159.0 46.0 L 157.0 96.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 176.0 150.0 L 206.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 244.0 120.0 L 202.0 63.0" stroke="#c5cad4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 155.6 39.6 L 185.6 40.3 L 204.0 64.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 146.0 124.0 L 189.5 109.1 L 192.0 149.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 140.0 122.0 Q 142.7 78.5 149.6 37.6" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 149.6 37.6 L 179.5 40.1 L 200.0 62.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 140.0 122.0 L 183.9 108.2 L 188.0 148.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 202.0 70.0 L 202.0 56.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="153.1" cy="17.9" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="163.0" y1="17.0" x2="170.0" y2="16.4" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Seated Row</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 122.0 132.0 L 156.0 132.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 159.0 46.0 L 157.0 96.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 176.0 150.0 L 206.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 244.0 120.0 L 160.0 73.0" stroke="#c5cad4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 155.6 39.6 L 134.8 61.2 L 162.0 74.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 146.0 124.0 L 189.5 109.1 L 192.0 149.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 140.0 122.0 Q 142.7 78.5 149.6 37.6" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 149.6 37.6 L 130.3 60.5 L 158.0 72.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 140.0 122.0 L 183.9 108.2 L 188.0 148.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 160.0 80.0 L 160.0 66.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="153.1" cy="17.9" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="163.0" y1="17.0" x2="170.0" y2="16.4" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,37 @@
|
||||
# Seated Row
|
||||
|
||||
The seated horizontal pull — thickness for the mid-back by driving the elbows
|
||||
straight back against the chest pad.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based horizontal pull
|
||||
- **Targets:** Mid-back, latissimus dorsi, rear delts, biceps
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit with your chest firmly against the pad and feet on the footrest. Grip the
|
||||
handles with your arms extended forward toward the anchor.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Pull straight back, keeping your elbows close to your body.
|
||||
2. Drive the handles to your ribs and retract your shoulder blades hard.
|
||||
3. Return to full extension under control without rounding your back.
|
||||
|
||||
## Cues
|
||||
|
||||
- Retract the shoulder blades first, then the arms follow.
|
||||
- Elbows stay tucked, tracing a line along your sides.
|
||||
- Chest stays glued to the pad the whole rep.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Rounding the back to reach forward at the extension.
|
||||
- Flaring the elbows out wide instead of driving them back.
|
||||
- Heaving with the whole torso instead of pulling with the back.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight once all four sets of ten are controlled; vary the grip width to
|
||||
shift emphasis between the lats and the mid-back.
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "Seated Row",
|
||||
"primary": 2,
|
||||
"working": ["arm_r", "arm_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[122, 132], [156, 132]], "w": 8},
|
||||
{"kind": "line", "pts": [[159, 46], [157, 96]], "w": 8},
|
||||
{"kind": "line", "pts": [[176, 150], [206, 150]], "w": 5}
|
||||
]},
|
||||
{"type": "cable", "from": [244, 120], "to": ["hand_r", "hand_l"]},
|
||||
{"type": "bar", "at": ["hand_r", "hand_l"], "angle": 90, "halfLen": 7}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 1.0,
|
||||
"root": [140, 122],
|
||||
"spine": [85, 82], "neck": 80, "gaze": 5,
|
||||
"arm_r": [-10, -25], "arm_l": [-10, -25],
|
||||
"leg_r": [-8, -75], "leg_l": [-8, -75],
|
||||
"pins": {"hand_r": [200, 62], "hand_l": [204, 64],
|
||||
"foot_r": [188, 148], "foot_l": [192, 149]}
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.2,
|
||||
"root": [140, 122],
|
||||
"spine": [85, 82], "neck": 80, "gaze": 5,
|
||||
"arm_r": [-120, -35], "arm_l": [-120, -35],
|
||||
"leg_r": [-8, -75], "leg_l": [-8, -75],
|
||||
"pins": {"hand_r": [158, 72], "hand_l": [162, 74],
|
||||
"foot_r": [188, 148], "foot_l": [192, 149]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 156 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Seated Row</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 122.0 132.0 L 156.0 132.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 159.0 46.0 L 157.0 96.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 176.0 150.0 L 206.0 150.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 244.0 120.0 L 160.0 73.0" stroke="#c5cad4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 155.6 39.6 L 134.8 61.2 L 162.0 74.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 146.0 124.0 L 189.5 109.1 L 192.0 149.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 140.0 122.0 Q 142.7 78.5 149.6 37.6" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 149.6 37.6 L 130.3 60.5 L 158.0 72.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 140.0 122.0 L 183.9 108.2 L 188.0 148.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 160.0 80.0 L 160.0 66.0" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="153.1" cy="17.9" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="163.0" y1="17.0" x2="170.0" y2="16.4" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Shoulder Press</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 116.0 140.0 L 88.0 50.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 110.0 141.0 L 148.0 141.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 126.0 143.0 L 126.0 151.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 110.0 151.0 L 142.0 151.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 101.1 50.8 L 116.1 76.8 L 116.1 46.8" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 126.0 132.0 L 167.4 112.0 L 168.0 152.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 120.0 130.0 Q 103.0 89.8 95.1 48.8" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 95.1 48.8 L 110.1 74.8 L 110.1 44.8" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 120.0 130.0 L 161.9 111.1 L 164.0 151.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 103.1 45.8 L 123.1 45.8" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="98.6" cy="29.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="108.5" y1="27.8" x2="115.4" y2="26.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Shoulder Press</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 116.0 140.0 L 88.0 50.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 110.0 141.0 L 148.0 141.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 126.0 143.0 L 126.0 151.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 110.0 151.0 L 142.0 151.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 101.1 50.8 L 118.8 26.6 L 143.0 8.9" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 126.0 132.0 L 167.4 112.0 L 168.0 152.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 120.0 130.0 Q 103.0 89.8 95.1 48.8" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 95.1 48.8 L 112.8 24.6 L 137.0 6.9" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 120.0 130.0 L 161.9 111.1 L 164.0 151.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 130.0 7.9 L 150.0 7.9" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="98.6" cy="29.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="108.5" y1="27.8" x2="115.4" y2="26.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,39 @@
|
||||
# Shoulder Press
|
||||
|
||||
The seated overhead press — vertical pushing strength with the trunk braced
|
||||
against the pad.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based vertical press
|
||||
- **Targets:** Deltoids, triceps, upper trapezius
|
||||
|
||||
## Setup
|
||||
|
||||
Sit with your back against the pad and grip the handles just outside
|
||||
shoulder-width, elbows bent so the handles start at shoulder height. Plant your
|
||||
feet flat and set your ribs down over your hips.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Press the handles straight up until your arms are nearly extended — stop
|
||||
short of locking out the elbows.
|
||||
2. Pause at the top without shrugging, then lower under control back to shoulder
|
||||
height.
|
||||
3. Keep your neck relaxed and your back flat on the pad the whole rep.
|
||||
|
||||
## Cues
|
||||
|
||||
- Press up, not forward — the handles travel over the shoulders.
|
||||
- Keep the ribs down; don't arch the lower back to help the press.
|
||||
- Shoulders stay set — avoid shrugging the handles up with the traps.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Locking the elbows hard at the top.
|
||||
- Shrugging the shoulders to finish the press.
|
||||
- Arching the lower back off the pad as the weight gets heavy.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight in small increments once all four sets of ten are smooth; move to a
|
||||
single-arm press for even loading and extra core demand.
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "Shoulder Press",
|
||||
"primary": 2,
|
||||
"working": ["arm_r", "arm_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[116, 140], [88, 50]], "w": 8},
|
||||
{"kind": "line", "pts": [[110, 141], [148, 141]], "w": 8},
|
||||
{"kind": "line", "pts": [[126, 143], [126, 151]], "w": 5},
|
||||
{"kind": "line", "pts": [[110, 151], [142, 151]], "w": 4}
|
||||
]},
|
||||
{"type": "bar", "at": ["hand_r", "hand_l"], "halfLen": 10}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 1.1,
|
||||
"root": [120, 130],
|
||||
"spine": [110, 104], "neck": 80, "gaze": 8,
|
||||
"arm_r": [-60, 90], "arm_l": [-60, 90],
|
||||
"leg_r": [-25, -72], "leg_l": [-25, -72],
|
||||
"pins": {"foot_r": [164, 151], "foot_l": [168, 152]}
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.1,
|
||||
"root": [120, 130],
|
||||
"spine": [110, 104], "neck": 80, "gaze": 8,
|
||||
"arm_r": [54, 36], "arm_l": [54, 36],
|
||||
"leg_r": [-25, -72], "leg_l": [-25, -72],
|
||||
"pins": {"foot_r": [164, 151], "foot_l": [168, 152]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 151 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Shoulder Press</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 116.0 140.0 L 88.0 50.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 110.0 141.0 L 148.0 141.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 126.0 143.0 L 126.0 151.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 110.0 151.0 L 142.0 151.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 101.1 50.8 L 118.8 26.6 L 143.0 8.9" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 126.0 132.0 L 167.4 112.0 L 168.0 152.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 120.0 130.0 Q 103.0 89.8 95.1 48.8" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 95.1 48.8 L 112.8 24.6 L 137.0 6.9" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 120.0 130.0 L 161.9 111.1 L 164.0 151.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 130.0 7.9 L 150.0 7.9" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="98.6" cy="29.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="108.5" y1="27.8" x2="115.4" y2="26.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Tricep Press</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 116.0 134.0 L 92.0 42.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 108.0 135.0 L 146.0 135.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 124.0 137.0 L 124.0 151.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 110.0 151.0 L 140.0 151.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 110.7 42.1 L 116.9 71.4 L 142.9 56.4" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 124.0 126.0 L 168.1 112.8 L 160.0 152.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 118.0 124.0 Q 109.7 81.3 104.7 40.1" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 104.7 40.1 L 110.9 69.4 L 136.9 54.4" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 118.0 124.0 L 162.3 111.5 L 156.0 151.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 139.9 61.4 L 139.9 49.4" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="106.1" cy="20.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="116.0" y1="19.1" x2="123.0" y2="18.3" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Tricep Press</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 116.0 134.0 L 92.0 42.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 108.0 135.0 L 146.0 135.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 124.0 137.0 L 124.0 151.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 110.0 151.0 L 140.0 151.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 110.7 42.1 L 116.9 71.4 L 118.0 101.4" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 124.0 126.0 L 168.1 112.8 L 160.0 152.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 118.0 124.0 Q 109.7 81.3 104.7 40.1" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 104.7 40.1 L 110.9 69.4 L 112.0 99.4" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 118.0 124.0 L 162.3 111.5 L 156.0 151.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 115.0 106.4 L 115.0 94.4" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="106.1" cy="20.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="116.0" y1="19.1" x2="123.0" y2="18.3" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,39 @@
|
||||
# Tricep Press
|
||||
|
||||
The seated press-down — elbows pinned to the sides, driving the handles from the
|
||||
chest to full extension.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based elbow extension
|
||||
- **Targets:** Triceps brachii
|
||||
|
||||
## Setup
|
||||
|
||||
Sit tall with your back on the pad and your upper arms tucked close to your
|
||||
sides. Take the handles at chest height with your elbows bent to about a right
|
||||
angle.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Press the handles down by straightening your elbows, keeping your upper arms
|
||||
still against your sides.
|
||||
2. Extend fully without snapping the elbows, pausing briefly at the bottom.
|
||||
3. Let the handles rise back to chest height under control, elbows staying
|
||||
tucked.
|
||||
|
||||
## Cues
|
||||
|
||||
- Only the forearms move — the upper arms stay glued to the torso.
|
||||
- Keep the motion controlled; don't fling the handles down.
|
||||
- Squeeze the triceps at the bottom rather than leaning your weight in.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Flaring the elbows out away from the sides.
|
||||
- Using the shoulders or bodyweight to drive the handles down.
|
||||
- Cutting the extension short and never reaching full lockout.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight in small increments once all four sets of ten are clean; slow the
|
||||
lowering phase to three seconds to add time under tension for the triceps.
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "Tricep Press",
|
||||
"primary": 2,
|
||||
"working": ["arm_r", "arm_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[116, 134], [92, 42]], "w": 8},
|
||||
{"kind": "line", "pts": [[108, 135], [146, 135]], "w": 8},
|
||||
{"kind": "line", "pts": [[124, 137], [124, 151]], "w": 5},
|
||||
{"kind": "line", "pts": [[110, 151], [140, 151]], "w": 4}
|
||||
]},
|
||||
{"type": "bar", "at": ["hand_r", "hand_l"], "angle": 90, "halfLen": 6}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 1.1,
|
||||
"root": [118, 124],
|
||||
"spine": [100, 98], "neck": 86, "gaze": 6,
|
||||
"arm_r": [-78, 30], "arm_l": [-78, 30],
|
||||
"leg_r": [-24, -74], "leg_l": [-24, -74],
|
||||
"pins": {"foot_r": [156, 151], "foot_l": [160, 152]}
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.1,
|
||||
"root": [118, 124],
|
||||
"spine": [100, 98], "neck": 86, "gaze": 6,
|
||||
"arm_r": [-78, -88], "arm_l": [-78, -88],
|
||||
"leg_r": [-24, -74], "leg_l": [-24, -74],
|
||||
"pins": {"foot_r": [156, 151], "foot_l": [160, 152]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 182 KiB |
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
|
||||
<title>Tricep Press</title>
|
||||
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 116.0 134.0 L 92.0 42.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 108.0 135.0 L 146.0 135.0" stroke="#c5cad4" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 124.0 137.0 L 124.0 151.0" stroke="#c5cad4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 110.0 151.0 L 140.0 151.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_l" d="M 110.7 42.1 L 116.9 71.4 L 118.0 101.4" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_l" d="M 124.0 126.0 L 168.1 112.8 L 160.0 152.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="spine" d="M 118.0 124.0 Q 109.7 81.3 104.7 40.1" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="arm_r" d="M 104.7 40.1 L 110.9 69.4 L 112.0 99.4" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="leg_r" d="M 118.0 124.0 L 162.3 111.5 L 156.0 151.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 115.0 106.4 L 115.0 94.4" stroke="#6b7180" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle id="head" cx="106.1" cy="20.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
|
||||
<line id="nose" x1="116.0" y1="19.1" x2="123.0" y2="18.3" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">
|
||||
<line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="264" y="20">R</text>
|
||||
<line x1="282" y1="16" x2="298" y2="16" stroke="#a9afba" stroke-width="4" stroke-linecap="round"/>
|
||||
<text x="304" y="20">L</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 270 KiB |
@@ -32,11 +32,13 @@ PALETTES = {
|
||||
"right": "#3a3f4b", "left": "#a9afba",
|
||||
"right_working": "#0d9488", "left_working": "#86cfc5",
|
||||
"ground": "#b9bec9", "legend_text": "#6b7180", "head_fill": "white",
|
||||
"equipment": "#c5cad4", "prop": "#6b7180",
|
||||
},
|
||||
"indigo": {
|
||||
"right": "#3a3f4b", "left": "#a9afba",
|
||||
"right_working": "#4f46e5", "left_working": "#a5b4fc",
|
||||
"ground": "#b9bec9", "legend_text": "#6b7180", "head_fill": "white",
|
||||
"equipment": "#c5cad4", "prop": "#6b7180",
|
||||
},
|
||||
}
|
||||
WIDTHS = {"right": 6, "left": 5, "spine": 6, "head": 6, "nose": 4}
|
||||
@@ -55,6 +57,8 @@ LIMBS = { # limb -> (attach joint, [bone length keys], pin key)
|
||||
|
||||
ANGLE_KEYS = ["spine", "neck", "gaze", "arm_r", "arm_l", "leg_r", "leg_l"]
|
||||
|
||||
JOINT_LIMB = {"hand_r": "arm_r", "hand_l": "arm_l", "foot_r": "leg_r", "foot_l": "leg_l"}
|
||||
|
||||
|
||||
def bodies():
|
||||
return json.loads((LIB / "body.json").read_text())
|
||||
@@ -153,12 +157,14 @@ def geometry(frame, body, hide=(), flip=False):
|
||||
re-solved so planted hands/feet hold exactly through tweens."""
|
||||
at = attach_points(frame, body, flip)
|
||||
head = walk(at["neck"], [frame["neck"]], [body["neck"]])[1]
|
||||
nose_tip = walk(head, [frame["gaze"]], [body["headR"] + 7])[1]
|
||||
geo = {"head": head, "nose": nose_tip, "headR": body["headR"],
|
||||
geo = {"head": head, "headR": body["headR"],
|
||||
"spine": [at["pelvis"],
|
||||
(2 * at["mid"][0] - (at["pelvis"][0] + at["neck"][0]) / 2,
|
||||
2 * at["mid"][1] - (at["pelvis"][1] + at["neck"][1]) / 2),
|
||||
at["neck"]]}
|
||||
# `gaze` is optional: a frame without it faces the viewer, so no nose tick.
|
||||
if "gaze" in frame:
|
||||
geo["nose"] = walk(head, [frame["gaze"]], [body["headR"] + 7])[1]
|
||||
for limb, (joint, bone_keys, pin) in LIMBS.items():
|
||||
if limb not in frame or limb in hide:
|
||||
continue
|
||||
@@ -206,6 +212,134 @@ def timeline(norms, fps=20):
|
||||
return frames
|
||||
|
||||
|
||||
# -------------------------------------------------------------------- props
|
||||
# Equipment layer (see SYSTEM.md): `scene` shapes and `cable`s draw behind the
|
||||
# figure in the recessive equipment gray; joint-attached items (`bar`,
|
||||
# `dumbbell`, `pad`) draw over the limbs in the darker prop gray, following
|
||||
# the resolved hand/foot positions frame by frame.
|
||||
|
||||
def flip_props(props, width):
|
||||
"""Mirror the props horizontally, matching flip_frame. Joint-attached props
|
||||
follow the mirrored limbs automatically; only fixed coordinates and world
|
||||
angles need mirroring."""
|
||||
def fx(p):
|
||||
return [width - p[0], p[1]]
|
||||
out = []
|
||||
for prop in props:
|
||||
p = json.loads(json.dumps(prop))
|
||||
if p["type"] == "scene":
|
||||
for s in p["shapes"]:
|
||||
if s["kind"] == "line":
|
||||
s["pts"] = [fx(pt) for pt in s["pts"]]
|
||||
elif s["kind"] == "circle":
|
||||
s["c"] = fx(s["c"])
|
||||
elif s["kind"] == "rect":
|
||||
s["x"] = width - s["x"] - s["w"]
|
||||
elif p["type"] == "cable":
|
||||
p["from"] = fx(p["from"])
|
||||
elif p["type"] in ("bar", "pad") and "angle" in p:
|
||||
p["angle"] = 180 - p["angle"]
|
||||
out.append(p)
|
||||
return out
|
||||
|
||||
|
||||
def joint_points(geo, ref):
|
||||
"""Resolve a joint ref — `"hand_r"` or a `["hand_r", "hand_l"]` midpoint —
|
||||
to (point, lower-bone unit direction). None when the limb isn't drawn."""
|
||||
names = ref if isinstance(ref, list) else [ref]
|
||||
pts, direction = [], None
|
||||
for name in names:
|
||||
limb = geo.get(JOINT_LIMB[name])
|
||||
if not limb:
|
||||
return None, None
|
||||
pts.append(limb[-1])
|
||||
if direction is None:
|
||||
a, b = limb[-2], limb[-1]
|
||||
d = math.hypot(b[0] - a[0], b[1] - a[1]) or 1.0
|
||||
direction = ((b[0] - a[0]) / d, (b[1] - a[1]) / d)
|
||||
return ((sum(p[0] for p in pts) / len(pts),
|
||||
sum(p[1] for p in pts) / len(pts)), direction)
|
||||
|
||||
|
||||
def resolve_props(props, geo):
|
||||
"""Props -> drawable primitives for one frame: (background, foreground)."""
|
||||
bg, fg = [], []
|
||||
for p in props or []:
|
||||
t = p["type"]
|
||||
if t == "scene":
|
||||
for s in p["shapes"]:
|
||||
bg.append(dict(s, color=s.get("color", "equipment")))
|
||||
elif t == "cable":
|
||||
end, _ = joint_points(geo, p["to"])
|
||||
if end:
|
||||
bg.append({"kind": "line", "pts": [list(p["from"]), list(end)],
|
||||
"w": p.get("w", 2), "color": "equipment"})
|
||||
elif t in ("bar", "dumbbell", "pad"):
|
||||
c, d = joint_points(geo, p["at"])
|
||||
if not c:
|
||||
continue
|
||||
if t == "bar" or "angle" in p:
|
||||
ux, uy = dirv(p.get("angle", 0)) # fixed world angle
|
||||
else:
|
||||
ux, uy = -d[1], d[0] # perpendicular to the lower bone
|
||||
h = p.get("halfLen", {"bar": 24, "dumbbell": 7, "pad": 8}[t])
|
||||
a = (c[0] - ux * h, c[1] - uy * h)
|
||||
b = (c[0] + ux * h, c[1] + uy * h)
|
||||
fg.append({"kind": "line", "pts": [a, b],
|
||||
"w": p.get("w", {"bar": 4, "dumbbell": 3, "pad": 7}[t]),
|
||||
"color": "prop"})
|
||||
plate = p.get("plateR", 4.5 if t == "dumbbell" else 0)
|
||||
if plate:
|
||||
for e in (a, b):
|
||||
fg.append({"kind": "circle", "c": list(e), "r": plate,
|
||||
"fill": True, "color": "prop"})
|
||||
return bg, fg
|
||||
|
||||
|
||||
def svg_prims(prims, colors):
|
||||
lines = []
|
||||
for p in prims:
|
||||
color = colors[p["color"]]
|
||||
if p["kind"] == "line":
|
||||
d = "M " + " L ".join(f"{x:.1f} {y:.1f}" for x, y in p["pts"])
|
||||
lines.append(f' <path d="{d}" stroke="{color}" stroke-width="{p.get("w", 4)}"'
|
||||
f' stroke-linecap="round" stroke-linejoin="round"/>')
|
||||
elif p["kind"] == "circle":
|
||||
cx, cy = p["c"]
|
||||
if p.get("fill"):
|
||||
lines.append(f' <circle cx="{cx:.1f}" cy="{cy:.1f}" r="{p["r"]}" fill="{color}"/>')
|
||||
else:
|
||||
lines.append(f' <circle cx="{cx:.1f}" cy="{cy:.1f}" r="{p["r"]}"'
|
||||
f' stroke="{color}" stroke-width="{p.get("w", 3)}"/>')
|
||||
elif p["kind"] == "rect":
|
||||
lines.append(f' <rect x="{p["x"]}" y="{p["y"]}" width="{p["w"]}" height="{p["h"]}"'
|
||||
f' rx="{p.get("r", 2)}" fill="{colors[p.get("color", "equipment")]}"/>')
|
||||
return lines
|
||||
|
||||
|
||||
def draw_prims(d, prims, colors, scale):
|
||||
for p in prims:
|
||||
color = colors[p["color"]]
|
||||
if p["kind"] == "line":
|
||||
pts = [(x * scale, y * scale) for x, y in p["pts"]]
|
||||
w = p.get("w", 4) * scale
|
||||
d.line(pts, fill=color, width=w, joint="curve")
|
||||
for x, y in (pts[0], pts[-1]):
|
||||
d.ellipse([x - w / 2, y - w / 2, x + w / 2, y + w / 2], fill=color)
|
||||
elif p["kind"] == "circle":
|
||||
cx, cy = p["c"][0] * scale, p["c"][1] * scale
|
||||
r = p["r"] * scale
|
||||
if p.get("fill"):
|
||||
d.ellipse([cx - r, cy - r, cx + r, cy + r], fill=color)
|
||||
else:
|
||||
d.ellipse([cx - r, cy - r, cx + r, cy + r], outline=color,
|
||||
width=p.get("w", 3) * scale)
|
||||
elif p["kind"] == "rect":
|
||||
x, y = p["x"] * scale, p["y"] * scale
|
||||
d.rounded_rectangle([x, y, x + p["w"] * scale, y + p["h"] * scale],
|
||||
radius=p.get("r", 2) * scale, fill=color)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------- drawing
|
||||
|
||||
def part_style(part, working, colors):
|
||||
@@ -233,20 +367,24 @@ def nose_segment(geo):
|
||||
return (hx + ux * r, hy + uy * r), (hx + ux * (r + 7), hy + uy * (r + 7))
|
||||
|
||||
|
||||
def svg_for_frame(name, geo, working, colors):
|
||||
def svg_for_frame(name, geo, working, colors, props=None):
|
||||
bg, fg = resolve_props(props, geo)
|
||||
w, h = CANVAS
|
||||
parts = [f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {w} {h}" fill="none">',
|
||||
f' <title>{name}</title>',
|
||||
f' <line x1="16" y1="{GROUND_Y + 4}" x2="{w - 16}" y2="{GROUND_Y + 4}"'
|
||||
f' stroke="{colors["ground"]}" stroke-width="3" stroke-linecap="round"/>']
|
||||
parts += svg_prims(bg, colors)
|
||||
for part in PART_ORDER:
|
||||
if part == "head":
|
||||
parts += svg_prims(fg, colors)
|
||||
hx, hy = geo["head"]
|
||||
(sx, sy), (ex, ey) = nose_segment(geo)
|
||||
parts.append(f' <circle id="head" cx="{hx:.1f}" cy="{hy:.1f}" r="{geo["headR"]}"'
|
||||
f' fill="{colors["head_fill"]}" stroke="{colors["right"]}" stroke-width="{WIDTHS["head"]}"/>')
|
||||
parts.append(f' <line id="nose" x1="{sx:.1f}" y1="{sy:.1f}" x2="{ex:.1f}" y2="{ey:.1f}"'
|
||||
f' stroke="{colors["right"]}" stroke-width="{WIDTHS["nose"]}" stroke-linecap="round"/>')
|
||||
if "nose" in geo:
|
||||
(sx, sy), (ex, ey) = nose_segment(geo)
|
||||
parts.append(f' <line id="nose" x1="{sx:.1f}" y1="{sy:.1f}" x2="{ex:.1f}" y2="{ey:.1f}"'
|
||||
f' stroke="{colors["right"]}" stroke-width="{WIDTHS["nose"]}" stroke-linecap="round"/>')
|
||||
continue
|
||||
if part not in geo:
|
||||
continue
|
||||
@@ -269,9 +407,10 @@ def svg_for_frame(name, geo, working, colors):
|
||||
return "\n".join(parts) + "\n"
|
||||
|
||||
|
||||
def draw_geo(geo, working, colors, scale=2, font=None):
|
||||
def draw_geo(geo, working, colors, scale=2, font=None, props=None):
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
bg, fg = resolve_props(props, geo)
|
||||
w, h = CANVAS[0] * scale, CANVAS[1] * scale
|
||||
img = Image.new("RGB", (w, h), "white")
|
||||
d = ImageDraw.Draw(img)
|
||||
@@ -284,13 +423,16 @@ def draw_geo(geo, working, colors, scale=2, font=None):
|
||||
d.ellipse([x - r, y - r, x + r, y + r], fill=color)
|
||||
|
||||
line([(16, GROUND_Y + 4), (CANVAS[0] - 16, GROUND_Y + 4)], colors["ground"], 3)
|
||||
draw_prims(d, bg, colors, scale)
|
||||
for part in PART_ORDER:
|
||||
if part == "head":
|
||||
draw_prims(d, fg, colors, scale)
|
||||
hx, hy = geo["head"]
|
||||
r, sw = geo["headR"] * scale, WIDTHS["head"] * scale
|
||||
d.ellipse([hx * scale - r, hy * scale - r, hx * scale + r, hy * scale + r],
|
||||
fill=colors["head_fill"], outline=colors["right"], width=sw)
|
||||
line(list(nose_segment(geo)), colors["right"], WIDTHS["nose"])
|
||||
if "nose" in geo:
|
||||
line(list(nose_segment(geo)), colors["right"], WIDTHS["nose"])
|
||||
continue
|
||||
if part not in geo:
|
||||
continue
|
||||
@@ -325,8 +467,9 @@ def load_motion(folder):
|
||||
|
||||
def export_app_resources(folders):
|
||||
"""Write the app's bundled copies: body.json plus one `<Name>.motion.json`
|
||||
per library entry. Unique basenames — Xcode copies resources flat, so the
|
||||
per-entry motion.json files can't ship under their own folder names."""
|
||||
and one `<Name>.info.md` per library entry. Unique basenames — Xcode copies
|
||||
resources flat, so the per-entry motion.json/info.md files can't ship under
|
||||
their own folder names."""
|
||||
out = LIB.parent / "Workouts" / "Resources" / "ExerciseMotions"
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
(out / "body.json").write_text((LIB / "body.json").read_text())
|
||||
@@ -335,6 +478,10 @@ def export_app_resources(folders):
|
||||
(out / f"{motion['name']}.motion.json").write_text(
|
||||
(folder / "motion.json").read_text())
|
||||
print(f" exported {motion['name']}.motion.json")
|
||||
info = folder / "info.md"
|
||||
if info.exists():
|
||||
(out / f"{motion['name']}.info.md").write_text(info.read_text())
|
||||
print(f" exported {motion['name']}.info.md")
|
||||
print(f" exported body.json -> {out}")
|
||||
|
||||
|
||||
@@ -343,6 +490,9 @@ def render_exercise(folder, figure="neutral", flip=False):
|
||||
body = bodies()[figure]
|
||||
working = set(motion.get("working", []))
|
||||
hide = set(motion.get("hide", []))
|
||||
props = motion.get("props", [])
|
||||
if flip:
|
||||
props = flip_props(props, CANVAS[0])
|
||||
norms = [normalize(kf, body, flip) for kf in motion["frames"]]
|
||||
geos = [geometry(n, body, hide, flip) for n in norms]
|
||||
|
||||
@@ -351,14 +501,14 @@ def render_exercise(folder, figure="neutral", flip=False):
|
||||
for old in frames_dir.glob("frame-*.svg"):
|
||||
old.unlink()
|
||||
colors = PALETTES["default"]
|
||||
svgs = [svg_for_frame(motion["name"], g, working, colors) for g in geos]
|
||||
svgs = [svg_for_frame(motion["name"], g, working, colors, props) for g in geos]
|
||||
for i, svg in enumerate(svgs, start=1):
|
||||
(frames_dir / f"frame-{i}.svg").write_text(svg)
|
||||
(folder / "visual.svg").write_text(svgs[motion.get("primary", 1) - 1])
|
||||
|
||||
try:
|
||||
font = legend_font()
|
||||
imgs = [draw_geo(geometry(n, body, hide, flip), working, colors, font=font)
|
||||
imgs = [draw_geo(geometry(n, body, hide, flip), working, colors, font=font, props=props)
|
||||
for n in timeline(norms)]
|
||||
imgs[0].save(folder / "preview.gif", save_all=True, append_images=imgs[1:],
|
||||
duration=50, loop=0)
|
||||
@@ -367,7 +517,7 @@ def render_exercise(folder, figure="neutral", flip=False):
|
||||
print(f" {motion['name']}: Pillow missing — SVGs written, preview.gif skipped")
|
||||
|
||||
|
||||
def contact_sheet(folders, figure="neutral"):
|
||||
def contact_sheet(folders, figure="neutral", out=None):
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
font = legend_font()
|
||||
@@ -376,11 +526,12 @@ def contact_sheet(folders, figure="neutral"):
|
||||
for folder in folders:
|
||||
motion = load_motion(folder)
|
||||
working, hide = set(motion.get("working", [])), set(motion.get("hide", []))
|
||||
props = motion.get("props", [])
|
||||
for i, kf in enumerate(motion["frames"], start=1):
|
||||
geo = geometry(normalize(kf, body), body, hide)
|
||||
cells.append((f"{motion['name']} {i}/{len(motion['frames'])}",
|
||||
draw_geo(geo, working, PALETTES["default"], font=font)))
|
||||
save_sheet(cells, LIB / "contact-sheet.png")
|
||||
draw_geo(geo, working, PALETTES["default"], font=font, props=props)))
|
||||
save_sheet(cells, Path(out) if out else LIB / "contact-sheet.png")
|
||||
|
||||
|
||||
def demo_sheet(folder):
|
||||
@@ -397,9 +548,10 @@ def demo_sheet(folder):
|
||||
cells = []
|
||||
for label, figure, flip, palette in variants:
|
||||
body = bodies()[figure]
|
||||
props = flip_props(motion.get("props", []), CANVAS[0]) if flip else motion.get("props", [])
|
||||
geo = geometry(normalize(kf, body, flip), body, hide, flip)
|
||||
cells.append((f"{motion['name']} — {label}",
|
||||
draw_geo(geo, working, PALETTES[palette], font=font)))
|
||||
draw_geo(geo, working, PALETTES[palette], font=font, props=props)))
|
||||
save_sheet(cells, LIB / "demo-sheet.png", cols=2)
|
||||
|
||||
|
||||
@@ -422,9 +574,12 @@ def main():
|
||||
flags = [a for a in sys.argv[1:] if a.startswith("--")]
|
||||
names = [a for a in sys.argv[1:] if not a.startswith("--")]
|
||||
figure = "neutral"
|
||||
sheet = None # False = off, None+flag = default path, str = custom path
|
||||
for f in flags:
|
||||
if f.startswith("--figure="):
|
||||
figure = f.split("=", 1)[1]
|
||||
elif f.startswith("--sheet"):
|
||||
sheet = f.split("=", 1)[1] if "=" in f else True
|
||||
folders = ([LIB / n for n in names] if names
|
||||
else sorted(p.parent for p in LIB.glob("*/motion.json")))
|
||||
if "--export" in flags:
|
||||
@@ -432,8 +587,8 @@ def main():
|
||||
return
|
||||
for folder in folders:
|
||||
render_exercise(folder, figure=figure, flip="--flip" in flags)
|
||||
if "--sheet" in flags:
|
||||
contact_sheet(folders, figure=figure)
|
||||
if sheet:
|
||||
contact_sheet(folders, figure=figure, out=None if sheet is True else sheet)
|
||||
if "--demo" in flags:
|
||||
demo_sheet(folders[0] if names else LIB / "Bird Dog")
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import SwiftUI
|
||||
///
|
||||
/// Draw order matters: left limbs behind, spine, right limbs, then the head filled
|
||||
/// opaque with the background color so overhead arms pass behind the face — plus the
|
||||
/// nose tick (gaze) and the small R/L legend that makes opposite-limb moves readable.
|
||||
/// nose tick (gaze).
|
||||
|
||||
/// Everything the renderer needs for one exercise, resolved once from the bundle.
|
||||
struct FigureAnimation {
|
||||
@@ -22,6 +22,8 @@ struct FigureAnimation {
|
||||
let working: Set<String>
|
||||
/// Limbs fully occluded in this view — never drawn.
|
||||
let hide: Set<String>
|
||||
/// Equipment layer (see SYSTEM.md "The props layer").
|
||||
let props: [MotionProp]
|
||||
let bodyProfile: ExerciseBodyProfile
|
||||
|
||||
init?(exerciseName: String) {
|
||||
@@ -32,6 +34,7 @@ struct FigureAnimation {
|
||||
self.timeline = timeline
|
||||
self.working = Set(resources.motion.working ?? [])
|
||||
self.hide = Set(resources.motion.hide ?? [])
|
||||
self.props = resources.motion.props ?? []
|
||||
self.bodyProfile = resources.body
|
||||
}
|
||||
|
||||
@@ -96,6 +99,9 @@ struct ExerciseFigureView: View {
|
||||
CGPoint(x: Self.designSize.width - 16, y: Self.groundY + 4)],
|
||||
color: .figureGround, width: 3)
|
||||
|
||||
// Equipment behind the figure: scene shapes and cables.
|
||||
drawBackgroundProps(&ctx, geo)
|
||||
|
||||
// Left limbs (behind), spine, right limbs.
|
||||
drawLimb(&ctx, geo, .armL)
|
||||
drawLimb(&ctx, geo, .legL)
|
||||
@@ -103,6 +109,9 @@ struct ExerciseFigureView: View {
|
||||
drawLimb(&ctx, geo, .armR)
|
||||
drawLimb(&ctx, geo, .legR)
|
||||
|
||||
// Joint-attached equipment over the limbs (bars, dumbbells, pads).
|
||||
drawAttachedProps(&ctx, geo)
|
||||
|
||||
// Head last, filled with the background color so limbs pass behind the face.
|
||||
let r = geo.headRadius
|
||||
let headRect = CGRect(x: geo.headCenter.x - r, y: geo.headCenter.y - r,
|
||||
@@ -110,9 +119,9 @@ struct ExerciseFigureView: View {
|
||||
let headPath = Path(ellipseIn: headRect)
|
||||
ctx.fill(headPath, with: .color(.figureHeadFill))
|
||||
ctx.stroke(headPath, with: .color(.figureRight), lineWidth: 6)
|
||||
stroke(&ctx, [geo.noseStart, geo.noseEnd], color: .figureRight, width: 4)
|
||||
|
||||
drawLegend(&ctx)
|
||||
if let noseStart = geo.noseStart, let noseEnd = geo.noseEnd {
|
||||
stroke(&ctx, [noseStart, noseEnd], color: .figureRight, width: 4)
|
||||
}
|
||||
}
|
||||
|
||||
private func drawLimb(_ ctx: inout GraphicsContext, _ geo: FigureGeometry, _ limb: FigureLimb) {
|
||||
@@ -129,19 +138,103 @@ struct ExerciseFigureView: View {
|
||||
style: StrokeStyle(lineWidth: 6, lineCap: .round, lineJoin: .round))
|
||||
}
|
||||
|
||||
/// Small `R — / L —` legend in the top-right corner, so opposite-limb moves are
|
||||
/// visibly opposite.
|
||||
private func drawLegend(_ ctx: inout GraphicsContext) {
|
||||
let lx = Self.designSize.width - 78
|
||||
stroke(&ctx, [CGPoint(x: lx, y: 16), CGPoint(x: lx + 16, y: 16)],
|
||||
color: .figureRight, width: 4)
|
||||
stroke(&ctx, [CGPoint(x: lx + 40, y: 16), CGPoint(x: lx + 56, y: 16)],
|
||||
color: .figureLeft, width: 4)
|
||||
let legendFont = Font.system(size: 11)
|
||||
ctx.draw(Text("R").font(legendFont).foregroundStyle(.secondary),
|
||||
at: CGPoint(x: lx + 22, y: 16), anchor: .leading)
|
||||
ctx.draw(Text("L").font(legendFont).foregroundStyle(.secondary),
|
||||
at: CGPoint(x: lx + 62, y: 16), anchor: .leading)
|
||||
// MARK: Props
|
||||
|
||||
/// The extremity point a prop follows (plus the lower-bone unit direction for
|
||||
/// perpendicular items). Nil when any referenced limb isn't drawn this frame.
|
||||
private func jointAnchor(_ geo: FigureGeometry, _ ref: PropJointRef) -> (point: CGPoint, direction: CGVector)? {
|
||||
var points: [CGPoint] = []
|
||||
var direction: CGVector?
|
||||
for name in ref.names {
|
||||
guard let limb = FigureLimb.allCases.first(where: { $0.pinKey == name }),
|
||||
let chain = geo.limbs[limb], chain.count >= 2 else { return nil }
|
||||
let a = chain[chain.count - 2]
|
||||
let b = chain[chain.count - 1]
|
||||
points.append(b)
|
||||
if direction == nil {
|
||||
let d = max(hypot(b.x - a.x, b.y - a.y), 1)
|
||||
direction = CGVector(dx: (b.x - a.x) / d, dy: (b.y - a.y) / d)
|
||||
}
|
||||
}
|
||||
guard let direction, !points.isEmpty else { return nil }
|
||||
let center = CGPoint(x: points.reduce(0) { $0 + $1.x } / CGFloat(points.count),
|
||||
y: points.reduce(0) { $0 + $1.y } / CGFloat(points.count))
|
||||
return (center, direction)
|
||||
}
|
||||
|
||||
private func drawBackgroundProps(_ ctx: inout GraphicsContext, _ geo: FigureGeometry) {
|
||||
for prop in figure.props {
|
||||
switch prop.type {
|
||||
case "scene":
|
||||
for shape in prop.shapes ?? [] { drawSceneShape(&ctx, shape) }
|
||||
case "cable":
|
||||
guard let from = prop.from, from.count == 2, let to = prop.to,
|
||||
let anchor = jointAnchor(geo, to) else { continue }
|
||||
stroke(&ctx, [CGPoint(x: from[0], y: from[1]), anchor.point],
|
||||
color: .figureEquipment, width: prop.w ?? 2)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Bars sit at a fixed world angle (default horizontal); dumbbells and pads
|
||||
/// default to perpendicular to the lower bone. Kept 1:1 with the reference
|
||||
/// renderer's `resolve_props` — change them in lockstep.
|
||||
private func drawAttachedProps(_ ctx: inout GraphicsContext, _ geo: FigureGeometry) {
|
||||
for prop in figure.props {
|
||||
let defaults: (halfLen: Double, width: Double, plateR: Double)
|
||||
switch prop.type {
|
||||
case "bar": defaults = (24, 4, 0)
|
||||
case "dumbbell": defaults = (7, 3, 4.5)
|
||||
case "pad": defaults = (8, 7, 0)
|
||||
default: continue
|
||||
}
|
||||
guard let at = prop.at, let anchor = jointAnchor(geo, at) else { continue }
|
||||
let axis: CGVector
|
||||
if prop.type == "bar" || prop.angle != nil {
|
||||
axis = MotionSolver.direction(prop.angle ?? 0)
|
||||
} else {
|
||||
axis = CGVector(dx: -anchor.direction.dy, dy: anchor.direction.dx)
|
||||
}
|
||||
let h = prop.halfLen ?? defaults.halfLen
|
||||
let a = CGPoint(x: anchor.point.x - axis.dx * h, y: anchor.point.y - axis.dy * h)
|
||||
let b = CGPoint(x: anchor.point.x + axis.dx * h, y: anchor.point.y + axis.dy * h)
|
||||
stroke(&ctx, [a, b], color: .figureProp, width: prop.w ?? defaults.width)
|
||||
let plateR = prop.plateR ?? defaults.plateR
|
||||
if plateR > 0 {
|
||||
for end in [a, b] {
|
||||
let rect = CGRect(x: end.x - plateR, y: end.y - plateR,
|
||||
width: 2 * plateR, height: 2 * plateR)
|
||||
ctx.fill(Path(ellipseIn: rect), with: .color(.figureProp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func drawSceneShape(_ ctx: inout GraphicsContext, _ shape: PropSceneShape) {
|
||||
let color: Color = shape.color == "prop" ? .figureProp : .figureEquipment
|
||||
switch shape.kind {
|
||||
case "line":
|
||||
guard let pts = shape.pts else { return }
|
||||
stroke(&ctx, pts.compactMap { $0.count == 2 ? CGPoint(x: $0[0], y: $0[1]) : nil },
|
||||
color: color, width: shape.w ?? 4)
|
||||
case "circle":
|
||||
guard let c = shape.c, c.count == 2, let r = shape.r else { return }
|
||||
let rect = CGRect(x: c[0] - r, y: c[1] - r, width: 2 * r, height: 2 * r)
|
||||
if shape.fill ?? true {
|
||||
ctx.fill(Path(ellipseIn: rect), with: .color(color))
|
||||
} else {
|
||||
ctx.stroke(Path(ellipseIn: rect), with: .color(color), lineWidth: shape.w ?? 3)
|
||||
}
|
||||
case "rect":
|
||||
guard let x = shape.x, let y = shape.y, let w = shape.w, let h = shape.h else { return }
|
||||
let path = Path(roundedRect: CGRect(x: x, y: y, width: w, height: h),
|
||||
cornerRadius: shape.r ?? 2)
|
||||
ctx.fill(path, with: .color(color))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func color(for part: String, isLeft: Bool) -> Color {
|
||||
@@ -163,44 +256,50 @@ struct ExerciseFigureView: View {
|
||||
|
||||
/// The reference palette (`render.py`), made dark-mode adaptive: the prominent right
|
||||
/// side stays strong (near-black → light gray), the recessive left side stays muted,
|
||||
/// and the working teals brighten/desaturate so they read on black.
|
||||
/// and the working teals brighten/desaturate so they read on black. watchOS has no
|
||||
/// dynamic-provider `UIColor` and renders on black, so it takes the dark variant
|
||||
/// verbatim.
|
||||
private extension Color {
|
||||
static func figure(light: (Double, Double, Double), dark: (Double, Double, Double)) -> Color {
|
||||
#if os(watchOS)
|
||||
Color(red: dark.0, green: dark.1, blue: dark.2)
|
||||
#else
|
||||
Color(UIColor { traits in
|
||||
traits.userInterfaceStyle == .dark
|
||||
? UIColor(red: dark.0, green: dark.1, blue: dark.2, alpha: 1)
|
||||
: UIColor(red: light.0, green: light.1, blue: light.2, alpha: 1)
|
||||
})
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Right-side limbs, head, nose — the prominent stroke (`#3a3f4b`).
|
||||
static let figureRight = Color(UIColor { traits in
|
||||
traits.userInterfaceStyle == .dark
|
||||
? UIColor(red: 0.76, green: 0.79, blue: 0.83, alpha: 1)
|
||||
: UIColor(red: 0.23, green: 0.25, blue: 0.29, alpha: 1)
|
||||
})
|
||||
static let figureRight = figure(light: (0.23, 0.25, 0.29), dark: (0.76, 0.79, 0.83))
|
||||
|
||||
/// Left-side limbs, drawn behind — the recessive stroke (`#a9afba`).
|
||||
static let figureLeft = Color(UIColor { traits in
|
||||
traits.userInterfaceStyle == .dark
|
||||
? UIColor(red: 0.36, green: 0.39, blue: 0.43, alpha: 1)
|
||||
: UIColor(red: 0.66, green: 0.69, blue: 0.73, alpha: 1)
|
||||
})
|
||||
static let figureLeft = figure(light: (0.66, 0.69, 0.73), dark: (0.36, 0.39, 0.43))
|
||||
|
||||
/// Working right-side parts — teal accent (`#0d9488`).
|
||||
static let figureRightWorking = Color(UIColor { traits in
|
||||
traits.userInterfaceStyle == .dark
|
||||
? UIColor(red: 0.18, green: 0.83, blue: 0.75, alpha: 1)
|
||||
: UIColor(red: 0.05, green: 0.58, blue: 0.53, alpha: 1)
|
||||
})
|
||||
static let figureRightWorking = figure(light: (0.05, 0.58, 0.53), dark: (0.18, 0.83, 0.75))
|
||||
|
||||
/// Working left-side parts — light teal (`#86cfc5`), kept more muted than the
|
||||
/// right so the R/L hierarchy holds in both modes.
|
||||
static let figureLeftWorking = Color(UIColor { traits in
|
||||
traits.userInterfaceStyle == .dark
|
||||
? UIColor(red: 0.31, green: 0.56, blue: 0.52, alpha: 1)
|
||||
: UIColor(red: 0.53, green: 0.81, blue: 0.77, alpha: 1)
|
||||
})
|
||||
static let figureLeftWorking = figure(light: (0.53, 0.81, 0.77), dark: (0.31, 0.56, 0.52))
|
||||
|
||||
/// Scene equipment — seats, benches, frames, cables (`#c5cad4`); sits behind
|
||||
/// the figure, one step lighter than the ground line.
|
||||
static let figureEquipment = figure(light: (0.77, 0.79, 0.83), dark: (0.25, 0.27, 0.31))
|
||||
|
||||
/// Joint-attached items — bars, dumbbells, pads (`#6b7180`); darker than the
|
||||
/// scene so the thing being moved reads over the limbs.
|
||||
static let figureProp = figure(light: (0.42, 0.44, 0.50), dark: (0.55, 0.58, 0.63))
|
||||
|
||||
/// Ground line (`#b9bec9`).
|
||||
static let figureGround = Color(UIColor { traits in
|
||||
traits.userInterfaceStyle == .dark
|
||||
? UIColor(red: 0.29, green: 0.31, blue: 0.36, alpha: 1)
|
||||
: UIColor(red: 0.73, green: 0.75, blue: 0.79, alpha: 1)
|
||||
})
|
||||
static let figureGround = figure(light: (0.73, 0.75, 0.79), dark: (0.29, 0.31, 0.36))
|
||||
|
||||
/// Opaque head fill — the screen background, so limbs pass behind the face.
|
||||
#if os(watchOS)
|
||||
static let figureHeadFill = Color.black
|
||||
#else
|
||||
static let figureHeadFill = Color(.systemBackground)
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
//
|
||||
// ExerciseInfo.swift
|
||||
// Workouts
|
||||
//
|
||||
// Copyright 2026 Rouslan Zenetl. All Rights Reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Parsed form of an exercise's authored `info.md` (see `Exercise Library/SYSTEM.md`):
|
||||
/// a one-paragraph summary, the Category/Type/Targets metadata bullets, then the
|
||||
/// instructional sections (Setup, Execution, Cues, Common Mistakes, Progression…).
|
||||
/// The library's markdown is uniform, so this parses the known shape rather than
|
||||
/// general Markdown — SwiftUI's inline-Markdown `Text` can't render headers/lists,
|
||||
/// and the app wants the structure (target chips, numbered steps) anyway.
|
||||
struct ExerciseInfo {
|
||||
/// The intro paragraph(s) between the `# Title` and the metadata bullets.
|
||||
var summary: String
|
||||
var category: String?
|
||||
var type: String?
|
||||
/// The comma-separated `**Targets:**` values, split for chip rendering.
|
||||
var targets: [String]
|
||||
var sections: [Section]
|
||||
|
||||
struct Section {
|
||||
var title: String
|
||||
var items: [Item]
|
||||
}
|
||||
|
||||
/// One block within a section, preserving the authored list flavor: numbered
|
||||
/// steps render with their ordinal, bullets with a dot, paragraphs plain.
|
||||
enum Item {
|
||||
case step(String)
|
||||
case bullet(String)
|
||||
case paragraph(String)
|
||||
|
||||
var text: String {
|
||||
switch self {
|
||||
case .step(let s), .bullet(let s), .paragraph(let s): s
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ExerciseInfo {
|
||||
/// Parse the library's `info.md` shape. Hard-wrapped lines are rejoined: a line
|
||||
/// that doesn't start a new block (heading, list marker, blank) continues the
|
||||
/// previous one, matching how Markdown renders soft breaks.
|
||||
static func parse(markdown: String) -> ExerciseInfo {
|
||||
var summaryLines: [String] = []
|
||||
var category: String?
|
||||
var type: String?
|
||||
var targets: [String] = []
|
||||
var sections: [Section] = []
|
||||
|
||||
var currentSection: Section?
|
||||
var currentItem: Item?
|
||||
|
||||
func metadataValue(_ line: String, key: String) -> String? {
|
||||
let prefix = "- **\(key):**"
|
||||
guard line.hasPrefix(prefix) else { return nil }
|
||||
return String(line.dropFirst(prefix.count)).trimmingCharacters(in: .whitespaces)
|
||||
}
|
||||
|
||||
func flushItem() {
|
||||
guard let item = currentItem else { return }
|
||||
currentItem = nil
|
||||
if currentSection != nil {
|
||||
currentSection?.items.append(item)
|
||||
} else if case .paragraph(let text) = item {
|
||||
summaryLines.append(text)
|
||||
}
|
||||
}
|
||||
|
||||
func flushSection() {
|
||||
flushItem()
|
||||
if let section = currentSection { sections.append(section) }
|
||||
currentSection = nil
|
||||
}
|
||||
|
||||
func append(to item: Item?, _ text: String) -> Item? {
|
||||
switch item {
|
||||
case .step(let s): .step(s + " " + text)
|
||||
case .bullet(let s): .bullet(s + " " + text)
|
||||
case .paragraph(let s): .paragraph(s + " " + text)
|
||||
case nil: .paragraph(text)
|
||||
}
|
||||
}
|
||||
|
||||
for rawLine in markdown.components(separatedBy: .newlines) {
|
||||
let line = rawLine.trimmingCharacters(in: .whitespaces)
|
||||
|
||||
if line.isEmpty {
|
||||
flushItem()
|
||||
} else if line.hasPrefix("## ") {
|
||||
flushSection()
|
||||
currentSection = Section(title: String(line.dropFirst(3)), items: [])
|
||||
} else if line.hasPrefix("# ") {
|
||||
continue // the document title duplicates the exercise name
|
||||
} else if currentSection == nil,
|
||||
let value = metadataValue(line, key: "Category") {
|
||||
flushItem()
|
||||
category = value
|
||||
} else if currentSection == nil,
|
||||
let value = metadataValue(line, key: "Type") {
|
||||
flushItem()
|
||||
type = value
|
||||
} else if currentSection == nil,
|
||||
let value = metadataValue(line, key: "Targets") {
|
||||
flushItem()
|
||||
targets = value.components(separatedBy: ",")
|
||||
.map { $0.trimmingCharacters(in: .whitespaces) }
|
||||
.filter { !$0.isEmpty }
|
||||
} else if let range = line.range(of: #"^\d+\.\s+"#, options: .regularExpression) {
|
||||
flushItem()
|
||||
currentItem = .step(String(line[range.upperBound...]))
|
||||
} else if line.hasPrefix("- ") {
|
||||
flushItem()
|
||||
currentItem = .bullet(String(line.dropFirst(2)))
|
||||
} else {
|
||||
// Continuation of a hard-wrapped block (or the start of a paragraph).
|
||||
currentItem = append(to: currentItem, line)
|
||||
}
|
||||
}
|
||||
flushSection()
|
||||
|
||||
return ExerciseInfo(
|
||||
summary: summaryLines.joined(separator: "\n\n"),
|
||||
category: category,
|
||||
type: type,
|
||||
targets: targets,
|
||||
sections: sections
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds and parses the bundled `<Exercise Name>.info.md` exported next to the
|
||||
/// motion rigs by `render.py --export`.
|
||||
enum ExerciseInfoLibrary {
|
||||
/// The parsed info for `exerciseName`, or `nil` when none is bundled.
|
||||
static func info(for exerciseName: String) -> ExerciseInfo? {
|
||||
guard
|
||||
let url = Bundle.main.url(forResource: exerciseName, withExtension: "info.md"),
|
||||
let markdown = try? String(contentsOf: url, encoding: .utf8)
|
||||
else { return nil }
|
||||
return ExerciseInfo.parse(markdown: markdown)
|
||||
}
|
||||
}
|
||||
@@ -39,9 +39,81 @@ struct ExerciseMotion: Codable {
|
||||
let working: [String]?
|
||||
/// Limbs fully occluded in this view — never drawn.
|
||||
let hide: [String]?
|
||||
/// Equipment layer: scene shapes and cables behind the figure, joint-attached
|
||||
/// items (bar/dumbbell/pad) over the limbs. See SYSTEM.md "The props layer".
|
||||
let props: [MotionProp]?
|
||||
let frames: [MotionKeyFrame]
|
||||
}
|
||||
|
||||
/// A prop's joint reference: one extremity (`"hand_r"`) or the midpoint of two
|
||||
/// (`["foot_r", "foot_l"]`). Extremity keys match the pin keys.
|
||||
enum PropJointRef: Codable {
|
||||
case single(String)
|
||||
case midpoint([String])
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
if let name = try? container.decode(String.self) {
|
||||
self = .single(name)
|
||||
} else {
|
||||
self = .midpoint(try container.decode([String].self))
|
||||
}
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
switch self {
|
||||
case .single(let name): try container.encode(name)
|
||||
case .midpoint(let names): try container.encode(names)
|
||||
}
|
||||
}
|
||||
|
||||
var names: [String] {
|
||||
switch self {
|
||||
case .single(let name): [name]
|
||||
case .midpoint(let names): names
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// One static shape of a `scene` prop, in canvas coordinates.
|
||||
struct PropSceneShape: Codable {
|
||||
let kind: String // "line" | "circle" | "rect"
|
||||
/// line: polyline points; `w` is the stroke width.
|
||||
let pts: [[Double]]?
|
||||
let w: Double?
|
||||
/// circle: center + radius; `fill` false draws an outline.
|
||||
let c: [Double]?
|
||||
let r: Double?
|
||||
let fill: Bool?
|
||||
/// rect: origin + size (`w`/`h`), corner radius `r`; always filled.
|
||||
let x: Double?
|
||||
let y: Double?
|
||||
let h: Double?
|
||||
/// Optional palette override: `"prop"` for the darker attached-item gray.
|
||||
let color: String?
|
||||
}
|
||||
|
||||
/// One equipment prop. `type` selects the flavor; the other fields apply per type
|
||||
/// (mirroring the reference renderer's `resolve_props`).
|
||||
struct MotionProp: Codable {
|
||||
let type: String // "scene" | "cable" | "bar" | "dumbbell" | "pad"
|
||||
/// scene: the static shapes.
|
||||
let shapes: [PropSceneShape]?
|
||||
/// cable: fixed anchor `[x, y]` → moving joint `to`.
|
||||
let from: [Double]?
|
||||
let to: PropJointRef?
|
||||
/// bar/dumbbell/pad: the joint(s) the item is centered on.
|
||||
let at: PropJointRef?
|
||||
/// Fixed world angle (degrees, y-up). Default: bars are horizontal;
|
||||
/// dumbbells/pads sit perpendicular to the lower bone.
|
||||
let angle: Double?
|
||||
let halfLen: Double?
|
||||
let w: Double?
|
||||
/// End-disc radius (dumbbell plates default 4.5; bars none).
|
||||
let plateR: Double?
|
||||
}
|
||||
|
||||
/// A key frame of absolute joint angles. Limbs listed in the motion's `hide` may be
|
||||
/// absent entirely; a two-element array is `[upper, lower]` bone angles.
|
||||
struct MotionKeyFrame: Codable {
|
||||
@@ -56,8 +128,9 @@ struct MotionKeyFrame: Codable {
|
||||
let spine: [Double]
|
||||
/// Head direction from the neck joint.
|
||||
let neck: Double
|
||||
/// Nose-tick direction (the belly is on that side).
|
||||
let gaze: Double
|
||||
/// Nose-tick direction (the belly is on that side). Absent when the figure
|
||||
/// faces the viewer — no nose is drawn.
|
||||
let gaze: Double?
|
||||
let armR: [Double]?
|
||||
let armL: [Double]?
|
||||
let legR: [Double]?
|
||||
|
||||
@@ -60,7 +60,8 @@ struct FigurePose {
|
||||
var root: CGPoint
|
||||
var spine: [Double]
|
||||
var neck: Double
|
||||
var gaze: Double
|
||||
/// Absent for figures facing the viewer — no nose tick.
|
||||
var gaze: Double?
|
||||
var limbs: [FigureLimb: [Double]]
|
||||
var pins: [String: CGPoint]
|
||||
var hold: Double
|
||||
@@ -89,8 +90,9 @@ struct FigureAttachments {
|
||||
struct FigureGeometry {
|
||||
var headCenter: CGPoint
|
||||
var headRadius: Double
|
||||
var noseStart: CGPoint
|
||||
var noseEnd: CGPoint
|
||||
/// Nil when the pose has no gaze (face-on view).
|
||||
var noseStart: CGPoint?
|
||||
var noseEnd: CGPoint?
|
||||
/// Quadratic Bézier through pelvis → mid → neck (control = 2·mid − (pelvis+neck)/2).
|
||||
var spineStart: CGPoint
|
||||
var spineControl: CGPoint
|
||||
@@ -213,7 +215,7 @@ enum MotionSolver {
|
||||
y: a.root.y + (b.root.y - a.root.y) * t),
|
||||
spine: zip(a.spine, b.spine).map { lerpAngle($0, $1, t) },
|
||||
neck: lerpAngle(a.neck, b.neck, t),
|
||||
gaze: lerpAngle(a.gaze, b.gaze, t),
|
||||
gaze: (a.gaze != nil && b.gaze != nil) ? lerpAngle(a.gaze!, b.gaze!, t) : nil,
|
||||
limbs: limbs, pins: pins, hold: a.hold, tween: a.tween
|
||||
)
|
||||
}
|
||||
@@ -223,12 +225,16 @@ enum MotionSolver {
|
||||
static func geometry(of pose: FigurePose, body: ExerciseBodyProfile, hide: Set<String>) -> FigureGeometry {
|
||||
let at = attachments(root: pose.root, spine: pose.spine, body: body)
|
||||
let head = walk(from: at.neck, angles: [pose.neck], lengths: [body.neck])[1]
|
||||
let noseTip = walk(from: head, angles: [pose.gaze], lengths: [body.headR + 7])[1]
|
||||
// Nose tick: 7pt outward from the head rim along the gaze direction.
|
||||
let d = max(hypot(noseTip.x - head.x, noseTip.y - head.y), 1)
|
||||
let ux = (noseTip.x - head.x) / d
|
||||
let uy = (noseTip.y - head.y) / d
|
||||
let r = body.headR
|
||||
// Nose tick: 7pt outward from the head rim along the gaze direction
|
||||
// (omitted for face-on poses without a gaze).
|
||||
var noseStart: CGPoint?
|
||||
var noseEnd: CGPoint?
|
||||
if let gaze = pose.gaze {
|
||||
let d = direction(gaze)
|
||||
noseStart = CGPoint(x: head.x + d.dx * r, y: head.y + d.dy * r)
|
||||
noseEnd = CGPoint(x: head.x + d.dx * (r + 7), y: head.y + d.dy * (r + 7))
|
||||
}
|
||||
|
||||
var limbs: [FigureLimb: [CGPoint]] = [:]
|
||||
for (limb, authored) in pose.limbs where !hide.contains(limb.rawValue) {
|
||||
@@ -244,8 +250,8 @@ enum MotionSolver {
|
||||
return FigureGeometry(
|
||||
headCenter: head,
|
||||
headRadius: r,
|
||||
noseStart: CGPoint(x: head.x + ux * r, y: head.y + uy * r),
|
||||
noseEnd: CGPoint(x: head.x + ux * (r + 7), y: head.y + uy * (r + 7)),
|
||||
noseStart: noseStart,
|
||||
noseEnd: noseEnd,
|
||||
spineStart: at.pelvis,
|
||||
spineControl: CGPoint(x: 2 * at.mid.x - (at.pelvis.x + at.neck.x) / 2,
|
||||
y: 2 * at.mid.y - (at.pelvis.y + at.neck.y) / 2),
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# Abdominal
|
||||
|
||||
The seated crunch machine — loaded spinal flexion with the lower back
|
||||
supported.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based trunk flexion
|
||||
- **Targets:** Rectus abdominis, deep core
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit with the pads resting against your chest and your feet flat on the
|
||||
platform. Grip the handles lightly and set the seat so your hips stay tucked
|
||||
into the base of the back pad.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Contract your abs to curl your ribs down toward your pelvis, driving the
|
||||
chest pad forward.
|
||||
2. Pause at the bottom of the crunch, feeling the abs fully shortened.
|
||||
3. Return under control until the torso is tall again — don't let the weight
|
||||
yank you back up.
|
||||
|
||||
## Cues
|
||||
|
||||
- Curl the spine, don't just hinge at the hips — think "shorten the front".
|
||||
- Keep your lower back in contact with the pad throughout.
|
||||
- Let the abs move the weight; the arms only steady the handles.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Pulling with the arms or shoulders instead of the abs.
|
||||
- Hinging from the hips with a flat, rigid spine.
|
||||
- Rushing the return and bouncing out of the top.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight once all four sets of ten are a controlled curl; slow the lowering
|
||||
phase to three seconds for extra time under tension.
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "Abdominal",
|
||||
"primary": 2,
|
||||
"working": ["spine"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[120, 128], [114, 62]], "w": 8},
|
||||
{"kind": "line", "pts": [[106, 130], [150, 130]], "w": 8},
|
||||
{"kind": "line", "pts": [[122, 132], [122, 150]], "w": 4},
|
||||
{"kind": "line", "pts": [[102, 150], [150, 150]], "w": 4},
|
||||
{"kind": "line", "pts": [[156, 149], [190, 149]], "w": 5}
|
||||
]},
|
||||
{"type": "pad", "at": ["hand_r", "hand_l"], "angle": 90, "halfLen": 14, "w": 6}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 1.0,
|
||||
"root": [128, 126],
|
||||
"spine": [94, 90], "neck": 82, "gaze": -8,
|
||||
"arm_r": [-12, -52], "arm_l": [-12, -52],
|
||||
"leg_r": [-20, -90], "leg_l": [-20, -90],
|
||||
"pins": {"hand_r": [155, 62], "hand_l": [161, 64], "foot_r": [168, 150], "foot_l": [172, 150]}
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.0,
|
||||
"root": [128, 126],
|
||||
"spine": [80, 40], "neck": 22, "gaze": -42,
|
||||
"arm_r": [-12, -52], "arm_l": [-12, -52],
|
||||
"leg_r": [-20, -90], "leg_l": [-20, -90],
|
||||
"pins": {"hand_r": [190, 76], "hand_l": [196, 78], "foot_r": [168, 150], "foot_l": [172, 150]}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Abductor
|
||||
|
||||
The seated hip-abduction machine — presses the knees apart to load the outer
|
||||
hips and glutes.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based hip abduction
|
||||
- **Targets:** Gluteus medius, gluteus minimus, outer thighs
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit with your legs inside the pads, back flat against the seat, and knees
|
||||
starting close together. Rest your hands on the seat sides and keep your torso
|
||||
upright.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Push your knees outward against the pads to spread the legs.
|
||||
2. Pause at the widest point, squeezing the outer hips and glutes.
|
||||
3. Bring the legs back together under control — resist the pads on the way in.
|
||||
|
||||
## Cues
|
||||
|
||||
- Stay upright; leaning forward hands the work to the lower back.
|
||||
- Drive the knees out through the outer hips, not by rocking the pelvis.
|
||||
- Control the return so the pads don't slam your knees closed.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Leaning forward to force the legs wider.
|
||||
- Letting the pads snap the knees back together.
|
||||
- Using a bouncy, momentum-driven range instead of steady tension.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight in small steps once all four sets of ten are smooth; pause two
|
||||
seconds at full spread to build end-range strength.
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "Abductor",
|
||||
"primary": 2,
|
||||
"working": ["leg_r", "leg_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "rect", "x": 152, "y": 56, "w": 16, "h": 72, "r": 5},
|
||||
{"kind": "rect", "x": 130, "y": 126, "w": 60, "h": 10, "r": 3},
|
||||
{"kind": "line", "pts": [[136, 78], [136, 108]], "w": 4, "color": "prop"},
|
||||
{"kind": "line", "pts": [[188, 78], [188, 108]], "w": 4, "color": "prop"},
|
||||
{"kind": "line", "pts": [[213, 110], [213, 132]], "w": 9, "color": "prop"},
|
||||
{"kind": "line", "pts": [[107, 110], [107, 132]], "w": 9, "color": "prop"}
|
||||
]}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.5, "tween": 1.1,
|
||||
"root": [160, 116],
|
||||
"spine": [90, 90], "neck": 90,
|
||||
"arm_r": [-48, -82], "arm_l": [-132, -98],
|
||||
"leg_r": [-22, 0], "leg_l": [-158, 0],
|
||||
"pins": {"foot_r": [180, 156], "foot_l": [140, 156]}
|
||||
},
|
||||
{
|
||||
"hold": 0.5, "tween": 1.1,
|
||||
"root": [160, 116],
|
||||
"spine": [90, 90], "neck": 90,
|
||||
"arm_r": [-48, -82], "arm_l": [-132, -98],
|
||||
"leg_r": [-22, 0], "leg_l": [-158, 0],
|
||||
"pins": {"foot_r": [216, 156], "foot_l": [104, 156]}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
# Adductor
|
||||
|
||||
The seated hip-adduction machine — squeezes the knees together to load the
|
||||
inner thighs.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based hip adduction
|
||||
- **Targets:** Adductors, inner thighs
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit with your legs placed outside the pads, back flat against the seat, and
|
||||
knees starting spread apart. Rest your hands on the seat sides and keep your
|
||||
torso upright.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Squeeze your knees together against the pads using your inner thighs.
|
||||
2. Pause when the knees nearly touch, holding the contraction.
|
||||
3. Let the legs spread back open under control — don't let the pads fling them
|
||||
apart.
|
||||
|
||||
## Cues
|
||||
|
||||
- Drive the movement from the inner thighs, not by rocking the hips.
|
||||
- Keep the torso upright and the back against the seat.
|
||||
- Control both directions; the opening phase trains the muscle too.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Letting the pads throw the legs open at the start of each rep.
|
||||
- Setting too wide a start range before the muscle is warm.
|
||||
- Fast, swinging reps that rely on momentum instead of the adductors.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight once all four sets of ten are controlled in both directions; pause
|
||||
two seconds with the knees together to strengthen the fully-shortened position.
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "Adductor",
|
||||
"primary": 2,
|
||||
"working": ["leg_r", "leg_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "rect", "x": 152, "y": 56, "w": 16, "h": 72, "r": 5},
|
||||
{"kind": "rect", "x": 130, "y": 126, "w": 60, "h": 10, "r": 3},
|
||||
{"kind": "line", "pts": [[136, 78], [136, 108]], "w": 4, "color": "prop"},
|
||||
{"kind": "line", "pts": [[188, 78], [188, 108]], "w": 4, "color": "prop"},
|
||||
{"kind": "line", "pts": [[197, 110], [197, 132]], "w": 9, "color": "prop"},
|
||||
{"kind": "line", "pts": [[123, 110], [123, 132]], "w": 9, "color": "prop"}
|
||||
]}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.5, "tween": 1.1,
|
||||
"root": [160, 116],
|
||||
"spine": [90, 90], "neck": 90,
|
||||
"arm_r": [-48, -82], "arm_l": [-132, -98],
|
||||
"leg_r": [-22, 0], "leg_l": [-158, 0],
|
||||
"pins": {"foot_r": [216, 156], "foot_l": [104, 156]}
|
||||
},
|
||||
{
|
||||
"hold": 0.5, "tween": 1.1,
|
||||
"root": [160, 116],
|
||||
"spine": [90, 90], "neck": 90,
|
||||
"arm_r": [-48, -82], "arm_l": [-132, -98],
|
||||
"leg_r": [-22, 0], "leg_l": [-158, 0],
|
||||
"pins": {"foot_r": [180, 156], "foot_l": [140, 156]}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# Arm Curl
|
||||
|
||||
The seated machine curl — biceps isolation with the upper arms braced flat on
|
||||
the pad so only the forearms move.
|
||||
|
||||
- **Category:** Main circuit
|
||||
- **Type:** Machine-based elbow flexion (isolation)
|
||||
- **Targets:** Biceps brachii, brachialis
|
||||
- **Prescription:** 4 × 10
|
||||
|
||||
## Setup
|
||||
|
||||
Sit with your upper arms flat along the pad and grip the handles. Start with
|
||||
your forearms extended down along the pad, elbows just short of locked.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Curl the handles up toward your shoulders, squeezing the biceps at the top.
|
||||
2. Keep your upper arms pinned to the pad — only the forearms move.
|
||||
3. Lower under control until the forearms are fully extended again.
|
||||
|
||||
## Cues
|
||||
|
||||
- Upper arms stay glued to the pad the entire rep.
|
||||
- Squeeze hard at the top, then resist the weight all the way down.
|
||||
- Wrists stay neutral — don't curl with the hands.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Rocking the torso or lifting the elbows to swing the weight up.
|
||||
- Cutting the lowering phase short and dropping the weight.
|
||||
- Not fully extending at the bottom, shortening the range.
|
||||
|
||||
## Progression
|
||||
|
||||
Add weight once all four sets of ten are strict; slow the lowering phase to
|
||||
three seconds before adding load again.
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "Arm Curl",
|
||||
"primary": 2,
|
||||
"working": ["arm_r", "arm_l"],
|
||||
"hide": [],
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[116, 134], [150, 134]], "w": 8},
|
||||
{"kind": "line", "pts": [[146, 42], [176, 68]], "w": 8},
|
||||
{"kind": "line", "pts": [[176, 68], [176, 128]], "w": 5}
|
||||
]},
|
||||
{"type": "bar", "at": ["hand_r", "hand_l"], "angle": 90, "halfLen": 6}
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"hold": 0.4, "tween": 1.0,
|
||||
"root": [130, 124],
|
||||
"spine": [88, 86], "neck": 82, "gaze": -18,
|
||||
"arm_r": [-35, -52], "arm_l": [-35, -52],
|
||||
"leg_r": [-8, -72], "leg_l": [-8, -72],
|
||||
"pins": {"foot_r": [176, 150], "foot_l": [180, 151]}
|
||||
},
|
||||
{
|
||||
"hold": 0.4, "tween": 1.2,
|
||||
"root": [130, 124],
|
||||
"spine": [88, 86], "neck": 82, "gaze": -18,
|
||||
"arm_r": [-35, 138], "arm_l": [-35, 138],
|
||||
"leg_r": [-8, -72], "leg_l": [-8, -72],
|
||||
"pins": {"foot_r": [176, 150], "foot_l": [180, 151]}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Bird Dog
|
||||
|
||||
Anti-rotation drill — extend opposite limbs while the hips and spine refuse to
|
||||
twist.
|
||||
|
||||
- **Category:** Warm-up and main circuit
|
||||
- **Type:** Anti-rotation
|
||||
- **Targets:** Spinal erectors, glutes, deep core, shoulder stability
|
||||
- **Prescription:** Warm-up 8 per side; main circuit 3 × 8–10 per side, slow
|
||||
|
||||
## Setup
|
||||
|
||||
On all fours: hands under shoulders, knees under hips, spine neutral, gaze at
|
||||
the floor.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Brace, then reach one arm forward and the *opposite* leg back until both are
|
||||
in line with the torso.
|
||||
2. Pause for a beat at full extension — hips stay square to the floor.
|
||||
3. Return under control and switch sides.
|
||||
|
||||
## Cues
|
||||
|
||||
- Imagine a cup of water balanced on the lower back — nothing spills.
|
||||
- Reach *long*, not high: heel pushes back, knuckles push forward.
|
||||
- Slow, no momentum; the pause is where the work happens.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Hips rotating open as the leg lifts.
|
||||
- Lifting the leg above hip height and arching the lower back.
|
||||
- Racing through reps.
|
||||
|
||||
## Progression
|
||||
|
||||
Single limb only (arm *or* leg) → opposite arm + leg → paused 3-count hold →
|
||||
elbow-to-knee touch under the body between reps → hands on an unstable surface
|
||||