diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b9d466..5b88023 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ **July 2026** -Form guides are now viewed from a slight elevation, with the floor drawn as a plane the figure stands on. +Form guides are now viewed from a slight elevation, with an exercise mat under the figure that turns with the camera. The stick figure now has broader, more human proportions with a visible shoulder girdle and pelvis. diff --git a/Exercise Library/Abdominal/frames/frame-1.svg b/Exercise Library/Abdominal/frames/frame-1.svg index d866148..6ec8e41 100644 --- a/Exercise Library/Abdominal/frames/frame-1.svg +++ b/Exercise Library/Abdominal/frames/frame-1.svg @@ -1,6 +1,6 @@ Abdominal - + diff --git a/Exercise Library/Abdominal/frames/frame-2.svg b/Exercise Library/Abdominal/frames/frame-2.svg index e73aebd..b336ec9 100644 --- a/Exercise Library/Abdominal/frames/frame-2.svg +++ b/Exercise Library/Abdominal/frames/frame-2.svg @@ -1,6 +1,6 @@ Abdominal - + diff --git a/Exercise Library/Abdominal/preview.gif b/Exercise Library/Abdominal/preview.gif index 213838a..71b5b34 100644 Binary files a/Exercise Library/Abdominal/preview.gif and b/Exercise Library/Abdominal/preview.gif differ diff --git a/Exercise Library/Abdominal/visual.svg b/Exercise Library/Abdominal/visual.svg index e73aebd..b336ec9 100644 --- a/Exercise Library/Abdominal/visual.svg +++ b/Exercise Library/Abdominal/visual.svg @@ -1,6 +1,6 @@ Abdominal - + diff --git a/Exercise Library/Abductor/frames/frame-1.svg b/Exercise Library/Abductor/frames/frame-1.svg index 337069a..e01cdd7 100644 --- a/Exercise Library/Abductor/frames/frame-1.svg +++ b/Exercise Library/Abductor/frames/frame-1.svg @@ -1,6 +1,6 @@ Abductor - + diff --git a/Exercise Library/Abductor/frames/frame-2.svg b/Exercise Library/Abductor/frames/frame-2.svg index 5e57c73..11d270b 100644 --- a/Exercise Library/Abductor/frames/frame-2.svg +++ b/Exercise Library/Abductor/frames/frame-2.svg @@ -1,6 +1,6 @@ Abductor - + diff --git a/Exercise Library/Abductor/preview.gif b/Exercise Library/Abductor/preview.gif index 9fb7b18..4905e72 100644 Binary files a/Exercise Library/Abductor/preview.gif and b/Exercise Library/Abductor/preview.gif differ diff --git a/Exercise Library/Abductor/visual.svg b/Exercise Library/Abductor/visual.svg index 5e57c73..11d270b 100644 --- a/Exercise Library/Abductor/visual.svg +++ b/Exercise Library/Abductor/visual.svg @@ -1,6 +1,6 @@ Abductor - + diff --git a/Exercise Library/Adductor/frames/frame-1.svg b/Exercise Library/Adductor/frames/frame-1.svg index 2d7a391..13116ee 100644 --- a/Exercise Library/Adductor/frames/frame-1.svg +++ b/Exercise Library/Adductor/frames/frame-1.svg @@ -1,6 +1,6 @@ Adductor - + diff --git a/Exercise Library/Adductor/frames/frame-2.svg b/Exercise Library/Adductor/frames/frame-2.svg index 67edb7c..8616e78 100644 --- a/Exercise Library/Adductor/frames/frame-2.svg +++ b/Exercise Library/Adductor/frames/frame-2.svg @@ -1,6 +1,6 @@ Adductor - + diff --git a/Exercise Library/Adductor/preview.gif b/Exercise Library/Adductor/preview.gif index b6b6690..40919c8 100644 Binary files a/Exercise Library/Adductor/preview.gif and b/Exercise Library/Adductor/preview.gif differ diff --git a/Exercise Library/Adductor/visual.svg b/Exercise Library/Adductor/visual.svg index 67edb7c..8616e78 100644 --- a/Exercise Library/Adductor/visual.svg +++ b/Exercise Library/Adductor/visual.svg @@ -1,6 +1,6 @@ Adductor - + diff --git a/Exercise Library/Arm Curl/frames/frame-1.svg b/Exercise Library/Arm Curl/frames/frame-1.svg index a807f37..dd39282 100644 --- a/Exercise Library/Arm Curl/frames/frame-1.svg +++ b/Exercise Library/Arm Curl/frames/frame-1.svg @@ -1,6 +1,6 @@ Arm Curl - + diff --git a/Exercise Library/Arm Curl/frames/frame-2.svg b/Exercise Library/Arm Curl/frames/frame-2.svg index 18064b1..df9b48a 100644 --- a/Exercise Library/Arm Curl/frames/frame-2.svg +++ b/Exercise Library/Arm Curl/frames/frame-2.svg @@ -1,6 +1,6 @@ Arm Curl - + diff --git a/Exercise Library/Arm Curl/preview.gif b/Exercise Library/Arm Curl/preview.gif index 79d160a..fb46a70 100644 Binary files a/Exercise Library/Arm Curl/preview.gif and b/Exercise Library/Arm Curl/preview.gif differ diff --git a/Exercise Library/Arm Curl/visual.svg b/Exercise Library/Arm Curl/visual.svg index 18064b1..df9b48a 100644 --- a/Exercise Library/Arm Curl/visual.svg +++ b/Exercise Library/Arm Curl/visual.svg @@ -1,6 +1,6 @@ Arm Curl - + diff --git a/Exercise Library/Bird Dog/frames/frame-1.svg b/Exercise Library/Bird Dog/frames/frame-1.svg index 1faf224..15c2b74 100644 --- a/Exercise Library/Bird Dog/frames/frame-1.svg +++ b/Exercise Library/Bird Dog/frames/frame-1.svg @@ -1,6 +1,6 @@ Bird Dog - + diff --git a/Exercise Library/Bird Dog/frames/frame-2.svg b/Exercise Library/Bird Dog/frames/frame-2.svg index 42a0060..843299b 100644 --- a/Exercise Library/Bird Dog/frames/frame-2.svg +++ b/Exercise Library/Bird Dog/frames/frame-2.svg @@ -1,6 +1,6 @@ Bird Dog - + diff --git a/Exercise Library/Bird Dog/frames/frame-3.svg b/Exercise Library/Bird Dog/frames/frame-3.svg index 1faf224..15c2b74 100644 --- a/Exercise Library/Bird Dog/frames/frame-3.svg +++ b/Exercise Library/Bird Dog/frames/frame-3.svg @@ -1,6 +1,6 @@ Bird Dog - + diff --git a/Exercise Library/Bird Dog/frames/frame-4.svg b/Exercise Library/Bird Dog/frames/frame-4.svg index dbf49c1..e84c0f4 100644 --- a/Exercise Library/Bird Dog/frames/frame-4.svg +++ b/Exercise Library/Bird Dog/frames/frame-4.svg @@ -1,6 +1,6 @@ Bird Dog - + diff --git a/Exercise Library/Bird Dog/preview.gif b/Exercise Library/Bird Dog/preview.gif index 962f06a..852c180 100644 Binary files a/Exercise Library/Bird Dog/preview.gif and b/Exercise Library/Bird Dog/preview.gif differ diff --git a/Exercise Library/Bird Dog/visual.svg b/Exercise Library/Bird Dog/visual.svg index 42a0060..843299b 100644 --- a/Exercise Library/Bird Dog/visual.svg +++ b/Exercise Library/Bird Dog/visual.svg @@ -1,6 +1,6 @@ Bird Dog - + diff --git a/Exercise Library/Calfs/frames/frame-1.svg b/Exercise Library/Calfs/frames/frame-1.svg index ce2aa8c..cb158c8 100644 --- a/Exercise Library/Calfs/frames/frame-1.svg +++ b/Exercise Library/Calfs/frames/frame-1.svg @@ -1,6 +1,6 @@ Calfs - + diff --git a/Exercise Library/Calfs/frames/frame-2.svg b/Exercise Library/Calfs/frames/frame-2.svg index 1b20024..a37332d 100644 --- a/Exercise Library/Calfs/frames/frame-2.svg +++ b/Exercise Library/Calfs/frames/frame-2.svg @@ -1,6 +1,6 @@ Calfs - + diff --git a/Exercise Library/Calfs/preview.gif b/Exercise Library/Calfs/preview.gif index 8024f21..2c2c443 100644 Binary files a/Exercise Library/Calfs/preview.gif and b/Exercise Library/Calfs/preview.gif differ diff --git a/Exercise Library/Calfs/visual.svg b/Exercise Library/Calfs/visual.svg index 1b20024..a37332d 100644 --- a/Exercise Library/Calfs/visual.svg +++ b/Exercise Library/Calfs/visual.svg @@ -1,6 +1,6 @@ Calfs - + diff --git a/Exercise Library/Cat-Cow/frames/frame-1.svg b/Exercise Library/Cat-Cow/frames/frame-1.svg index 7b5dde3..ba0b3bb 100644 --- a/Exercise Library/Cat-Cow/frames/frame-1.svg +++ b/Exercise Library/Cat-Cow/frames/frame-1.svg @@ -1,6 +1,6 @@ Cat-Cow - + diff --git a/Exercise Library/Cat-Cow/frames/frame-2.svg b/Exercise Library/Cat-Cow/frames/frame-2.svg index 61d90cb..ef3c031 100644 --- a/Exercise Library/Cat-Cow/frames/frame-2.svg +++ b/Exercise Library/Cat-Cow/frames/frame-2.svg @@ -1,6 +1,6 @@ Cat-Cow - + diff --git a/Exercise Library/Cat-Cow/orbit.gif b/Exercise Library/Cat-Cow/orbit.gif new file mode 100644 index 0000000..5242c96 Binary files /dev/null and b/Exercise Library/Cat-Cow/orbit.gif differ diff --git a/Exercise Library/Cat-Cow/preview.gif b/Exercise Library/Cat-Cow/preview.gif index 6137a55..5958202 100644 Binary files a/Exercise Library/Cat-Cow/preview.gif and b/Exercise Library/Cat-Cow/preview.gif differ diff --git a/Exercise Library/Cat-Cow/visual.svg b/Exercise Library/Cat-Cow/visual.svg index 7b5dde3..ba0b3bb 100644 --- a/Exercise Library/Cat-Cow/visual.svg +++ b/Exercise Library/Cat-Cow/visual.svg @@ -1,6 +1,6 @@ Cat-Cow - + diff --git a/Exercise Library/Chest Press/frames/frame-1.svg b/Exercise Library/Chest Press/frames/frame-1.svg index 969cb85..da7e3a8 100644 --- a/Exercise Library/Chest Press/frames/frame-1.svg +++ b/Exercise Library/Chest Press/frames/frame-1.svg @@ -1,6 +1,6 @@ Chest Press - + diff --git a/Exercise Library/Chest Press/frames/frame-2.svg b/Exercise Library/Chest Press/frames/frame-2.svg index 4e2a747..1f6f46c 100644 --- a/Exercise Library/Chest Press/frames/frame-2.svg +++ b/Exercise Library/Chest Press/frames/frame-2.svg @@ -1,6 +1,6 @@ Chest Press - + diff --git a/Exercise Library/Chest Press/preview.gif b/Exercise Library/Chest Press/preview.gif index 7fb20aa..b0eb3b9 100644 Binary files a/Exercise Library/Chest Press/preview.gif and b/Exercise Library/Chest Press/preview.gif differ diff --git a/Exercise Library/Chest Press/visual.svg b/Exercise Library/Chest Press/visual.svg index 4e2a747..1f6f46c 100644 --- a/Exercise Library/Chest Press/visual.svg +++ b/Exercise Library/Chest Press/visual.svg @@ -1,6 +1,6 @@ Chest Press - + diff --git a/Exercise Library/Dead Bug/frames/frame-1.svg b/Exercise Library/Dead Bug/frames/frame-1.svg index e983772..c028a16 100644 --- a/Exercise Library/Dead Bug/frames/frame-1.svg +++ b/Exercise Library/Dead Bug/frames/frame-1.svg @@ -1,6 +1,6 @@ Dead Bug - + diff --git a/Exercise Library/Dead Bug/frames/frame-2.svg b/Exercise Library/Dead Bug/frames/frame-2.svg index 9dffaaa..3ea6a3d 100644 --- a/Exercise Library/Dead Bug/frames/frame-2.svg +++ b/Exercise Library/Dead Bug/frames/frame-2.svg @@ -1,6 +1,6 @@ Dead Bug - + diff --git a/Exercise Library/Dead Bug/frames/frame-3.svg b/Exercise Library/Dead Bug/frames/frame-3.svg index e983772..c028a16 100644 --- a/Exercise Library/Dead Bug/frames/frame-3.svg +++ b/Exercise Library/Dead Bug/frames/frame-3.svg @@ -1,6 +1,6 @@ Dead Bug - + diff --git a/Exercise Library/Dead Bug/frames/frame-4.svg b/Exercise Library/Dead Bug/frames/frame-4.svg index abd63c8..62051f6 100644 --- a/Exercise Library/Dead Bug/frames/frame-4.svg +++ b/Exercise Library/Dead Bug/frames/frame-4.svg @@ -1,6 +1,6 @@ Dead Bug - + diff --git a/Exercise Library/Dead Bug/preview.gif b/Exercise Library/Dead Bug/preview.gif index 5a14020..76c621e 100644 Binary files a/Exercise Library/Dead Bug/preview.gif and b/Exercise Library/Dead Bug/preview.gif differ diff --git a/Exercise Library/Dead Bug/visual.svg b/Exercise Library/Dead Bug/visual.svg index 9dffaaa..3ea6a3d 100644 --- a/Exercise Library/Dead Bug/visual.svg +++ b/Exercise Library/Dead Bug/visual.svg @@ -1,6 +1,6 @@ Dead Bug - + diff --git a/Exercise Library/Hollow Body Hold/frames/frame-1.svg b/Exercise Library/Hollow Body Hold/frames/frame-1.svg index 10e6f00..41ddc9f 100644 --- a/Exercise Library/Hollow Body Hold/frames/frame-1.svg +++ b/Exercise Library/Hollow Body Hold/frames/frame-1.svg @@ -1,6 +1,6 @@ Hollow Body Hold - + diff --git a/Exercise Library/Hollow Body Hold/frames/frame-2.svg b/Exercise Library/Hollow Body Hold/frames/frame-2.svg index e287eed..c52b749 100644 --- a/Exercise Library/Hollow Body Hold/frames/frame-2.svg +++ b/Exercise Library/Hollow Body Hold/frames/frame-2.svg @@ -1,6 +1,6 @@ Hollow Body Hold - + diff --git a/Exercise Library/Hollow Body Hold/preview.gif b/Exercise Library/Hollow Body Hold/preview.gif index 4f277c8..5c79bf3 100644 Binary files a/Exercise Library/Hollow Body Hold/preview.gif and b/Exercise Library/Hollow Body Hold/preview.gif differ diff --git a/Exercise Library/Hollow Body Hold/visual.svg b/Exercise Library/Hollow Body Hold/visual.svg index e287eed..c52b749 100644 --- a/Exercise Library/Hollow Body Hold/visual.svg +++ b/Exercise Library/Hollow Body Hold/visual.svg @@ -1,6 +1,6 @@ Hollow Body Hold - + diff --git a/Exercise Library/Lat Pull Down/frames/frame-1.svg b/Exercise Library/Lat Pull Down/frames/frame-1.svg index 323ea59..e28b024 100644 --- a/Exercise Library/Lat Pull Down/frames/frame-1.svg +++ b/Exercise Library/Lat Pull Down/frames/frame-1.svg @@ -1,6 +1,6 @@ Lat Pull Down - + diff --git a/Exercise Library/Lat Pull Down/frames/frame-2.svg b/Exercise Library/Lat Pull Down/frames/frame-2.svg index f61b8b8..5368fb5 100644 --- a/Exercise Library/Lat Pull Down/frames/frame-2.svg +++ b/Exercise Library/Lat Pull Down/frames/frame-2.svg @@ -1,6 +1,6 @@ Lat Pull Down - + diff --git a/Exercise Library/Lat Pull Down/preview.gif b/Exercise Library/Lat Pull Down/preview.gif index 2fd197c..b14b6f3 100644 Binary files a/Exercise Library/Lat Pull Down/preview.gif and b/Exercise Library/Lat Pull Down/preview.gif differ diff --git a/Exercise Library/Lat Pull Down/visual.svg b/Exercise Library/Lat Pull Down/visual.svg index f61b8b8..5368fb5 100644 --- a/Exercise Library/Lat Pull Down/visual.svg +++ b/Exercise Library/Lat Pull Down/visual.svg @@ -1,6 +1,6 @@ Lat Pull Down - + diff --git a/Exercise Library/Leg Curl/frames/frame-1.svg b/Exercise Library/Leg Curl/frames/frame-1.svg index d1c465d..9d3afe7 100644 --- a/Exercise Library/Leg Curl/frames/frame-1.svg +++ b/Exercise Library/Leg Curl/frames/frame-1.svg @@ -1,6 +1,6 @@ Leg Curl - + diff --git a/Exercise Library/Leg Curl/frames/frame-2.svg b/Exercise Library/Leg Curl/frames/frame-2.svg index bc8d4a3..3317dfd 100644 --- a/Exercise Library/Leg Curl/frames/frame-2.svg +++ b/Exercise Library/Leg Curl/frames/frame-2.svg @@ -1,6 +1,6 @@ Leg Curl - + diff --git a/Exercise Library/Leg Curl/preview.gif b/Exercise Library/Leg Curl/preview.gif index 7acb147..69e07cc 100644 Binary files a/Exercise Library/Leg Curl/preview.gif and b/Exercise Library/Leg Curl/preview.gif differ diff --git a/Exercise Library/Leg Curl/visual.svg b/Exercise Library/Leg Curl/visual.svg index bc8d4a3..3317dfd 100644 --- a/Exercise Library/Leg Curl/visual.svg +++ b/Exercise Library/Leg Curl/visual.svg @@ -1,6 +1,6 @@ Leg Curl - + diff --git a/Exercise Library/Leg Extension/frames/frame-1.svg b/Exercise Library/Leg Extension/frames/frame-1.svg index 221b04b..200de12 100644 --- a/Exercise Library/Leg Extension/frames/frame-1.svg +++ b/Exercise Library/Leg Extension/frames/frame-1.svg @@ -1,6 +1,6 @@ Leg Extension - + diff --git a/Exercise Library/Leg Extension/frames/frame-2.svg b/Exercise Library/Leg Extension/frames/frame-2.svg index 4ceaf18..b79a653 100644 --- a/Exercise Library/Leg Extension/frames/frame-2.svg +++ b/Exercise Library/Leg Extension/frames/frame-2.svg @@ -1,6 +1,6 @@ Leg Extension - + diff --git a/Exercise Library/Leg Extension/preview.gif b/Exercise Library/Leg Extension/preview.gif index a49fdd3..eef14fa 100644 Binary files a/Exercise Library/Leg Extension/preview.gif and b/Exercise Library/Leg Extension/preview.gif differ diff --git a/Exercise Library/Leg Extension/visual.svg b/Exercise Library/Leg Extension/visual.svg index 4ceaf18..b79a653 100644 --- a/Exercise Library/Leg Extension/visual.svg +++ b/Exercise Library/Leg Extension/visual.svg @@ -1,6 +1,6 @@ Leg Extension - + diff --git a/Exercise Library/Leg Press/frames/frame-1.svg b/Exercise Library/Leg Press/frames/frame-1.svg index 31152ca..b95fdb0 100644 --- a/Exercise Library/Leg Press/frames/frame-1.svg +++ b/Exercise Library/Leg Press/frames/frame-1.svg @@ -1,6 +1,6 @@ Leg Press - + diff --git a/Exercise Library/Leg Press/frames/frame-2.svg b/Exercise Library/Leg Press/frames/frame-2.svg index d8a03d1..eb0f2a9 100644 --- a/Exercise Library/Leg Press/frames/frame-2.svg +++ b/Exercise Library/Leg Press/frames/frame-2.svg @@ -1,6 +1,6 @@ Leg Press - + diff --git a/Exercise Library/Leg Press/preview.gif b/Exercise Library/Leg Press/preview.gif index 8d3ad35..7550326 100644 Binary files a/Exercise Library/Leg Press/preview.gif and b/Exercise Library/Leg Press/preview.gif differ diff --git a/Exercise Library/Leg Press/visual.svg b/Exercise Library/Leg Press/visual.svg index d8a03d1..eb0f2a9 100644 --- a/Exercise Library/Leg Press/visual.svg +++ b/Exercise Library/Leg Press/visual.svg @@ -1,6 +1,6 @@ Leg Press - + diff --git a/Exercise Library/Leg Raises/frames/frame-1.svg b/Exercise Library/Leg Raises/frames/frame-1.svg index bd6a149..a5197cc 100644 --- a/Exercise Library/Leg Raises/frames/frame-1.svg +++ b/Exercise Library/Leg Raises/frames/frame-1.svg @@ -1,6 +1,6 @@ Leg Raises - + diff --git a/Exercise Library/Leg Raises/frames/frame-2.svg b/Exercise Library/Leg Raises/frames/frame-2.svg index 521b283..2fe14f0 100644 --- a/Exercise Library/Leg Raises/frames/frame-2.svg +++ b/Exercise Library/Leg Raises/frames/frame-2.svg @@ -1,6 +1,6 @@ Leg Raises - + diff --git a/Exercise Library/Leg Raises/preview.gif b/Exercise Library/Leg Raises/preview.gif index 1de2144..8b1a25a 100644 Binary files a/Exercise Library/Leg Raises/preview.gif and b/Exercise Library/Leg Raises/preview.gif differ diff --git a/Exercise Library/Leg Raises/visual.svg b/Exercise Library/Leg Raises/visual.svg index bd6a149..a5197cc 100644 --- a/Exercise Library/Leg Raises/visual.svg +++ b/Exercise Library/Leg Raises/visual.svg @@ -1,6 +1,6 @@ Leg Raises - + diff --git a/Exercise Library/Plank/frames/frame-1.svg b/Exercise Library/Plank/frames/frame-1.svg index 7666465..1ec5e5c 100644 --- a/Exercise Library/Plank/frames/frame-1.svg +++ b/Exercise Library/Plank/frames/frame-1.svg @@ -1,6 +1,6 @@ Plank - + diff --git a/Exercise Library/Plank/frames/frame-2.svg b/Exercise Library/Plank/frames/frame-2.svg index fda4352..b5cf1ac 100644 --- a/Exercise Library/Plank/frames/frame-2.svg +++ b/Exercise Library/Plank/frames/frame-2.svg @@ -1,6 +1,6 @@ Plank - + diff --git a/Exercise Library/Plank/preview.gif b/Exercise Library/Plank/preview.gif index be5a48d..4c0e044 100644 Binary files a/Exercise Library/Plank/preview.gif and b/Exercise Library/Plank/preview.gif differ diff --git a/Exercise Library/Plank/visual.svg b/Exercise Library/Plank/visual.svg index fda4352..b5cf1ac 100644 --- a/Exercise Library/Plank/visual.svg +++ b/Exercise Library/Plank/visual.svg @@ -1,6 +1,6 @@ Plank - + diff --git a/Exercise Library/Reverse Crunch/frames/frame-1.svg b/Exercise Library/Reverse Crunch/frames/frame-1.svg index b886e6e..1067b1b 100644 --- a/Exercise Library/Reverse Crunch/frames/frame-1.svg +++ b/Exercise Library/Reverse Crunch/frames/frame-1.svg @@ -1,6 +1,6 @@ Reverse Crunch - + diff --git a/Exercise Library/Reverse Crunch/frames/frame-2.svg b/Exercise Library/Reverse Crunch/frames/frame-2.svg index cae658b..84c2939 100644 --- a/Exercise Library/Reverse Crunch/frames/frame-2.svg +++ b/Exercise Library/Reverse Crunch/frames/frame-2.svg @@ -1,6 +1,6 @@ Reverse Crunch - + diff --git a/Exercise Library/Reverse Crunch/preview.gif b/Exercise Library/Reverse Crunch/preview.gif index db6281a..bf0bcc5 100644 Binary files a/Exercise Library/Reverse Crunch/preview.gif and b/Exercise Library/Reverse Crunch/preview.gif differ diff --git a/Exercise Library/Reverse Crunch/visual.svg b/Exercise Library/Reverse Crunch/visual.svg index cae658b..84c2939 100644 --- a/Exercise Library/Reverse Crunch/visual.svg +++ b/Exercise Library/Reverse Crunch/visual.svg @@ -1,6 +1,6 @@ Reverse Crunch - + diff --git a/Exercise Library/Rotary/frames/frame-1.svg b/Exercise Library/Rotary/frames/frame-1.svg index e213352..7d9391f 100644 --- a/Exercise Library/Rotary/frames/frame-1.svg +++ b/Exercise Library/Rotary/frames/frame-1.svg @@ -1,6 +1,6 @@ Rotary - + diff --git a/Exercise Library/Rotary/frames/frame-2.svg b/Exercise Library/Rotary/frames/frame-2.svg index 1d6026d..0993ca3 100644 --- a/Exercise Library/Rotary/frames/frame-2.svg +++ b/Exercise Library/Rotary/frames/frame-2.svg @@ -1,6 +1,6 @@ Rotary - + diff --git a/Exercise Library/Rotary/preview.gif b/Exercise Library/Rotary/preview.gif index 402bdf4..42e1f74 100644 Binary files a/Exercise Library/Rotary/preview.gif and b/Exercise Library/Rotary/preview.gif differ diff --git a/Exercise Library/Rotary/visual.svg b/Exercise Library/Rotary/visual.svg index e213352..7d9391f 100644 --- a/Exercise Library/Rotary/visual.svg +++ b/Exercise Library/Rotary/visual.svg @@ -1,6 +1,6 @@ Rotary - + diff --git a/Exercise Library/SYSTEM.md b/Exercise Library/SYSTEM.md index e68b53d..64b2953 100644 --- a/Exercise Library/SYSTEM.md +++ b/Exercise Library/SYSTEM.md @@ -79,11 +79,14 @@ never touches a motion script** — proportions are the skeleton's problem. proportions. Face-on machines (abductor/adductor, rotary torso) author genuine abduction or spine rotation and let projection do the rest. The camera can also orbit while the motion loops (`--orbit`). -- **Elevation** — the default viewpoint pitches down 10° (`CAMERA_PITCH`; - override per motion via `"camera": {"pitch": ...}`), so the floor reads as - a plane — drawn as a rectangle — and near/far contacts straddle it. - Elevation is pure presentation: pins solve in the flat authored view and - the *posed* body tilts, so authored canvas targets never go out of reach. +- **Elevation & the mat** — the default viewpoint pitches down 10° + (`CAMERA_PITCH`; override per motion via `"camera": {"pitch": ...}`), and + the ground is drawn as an **exercise mat**: a world-space quad sized to the + motion's footprint (`mat_bounds`) that rotates with the camera about the + figure — a long rectangle in profile, a parallelogram mid-orbit, end-on + when face-on. Near/far contacts straddle it. Elevation is pure + presentation: pins solve in the flat authored view and the *posed* body + tilts, so authored canvas targets never go out of reach. - **Feet** — each leg ends in a foot bone off the ankle. Dorsiflexion 0 keeps the foot perpendicular to the shin (right for standing, seated machines, planks); kneeling poses trail it back (−55), raises point it. diff --git a/Exercise Library/Seated Row/frames/frame-1.svg b/Exercise Library/Seated Row/frames/frame-1.svg index 1df21c6..b925a5f 100644 --- a/Exercise Library/Seated Row/frames/frame-1.svg +++ b/Exercise Library/Seated Row/frames/frame-1.svg @@ -1,6 +1,6 @@ Seated Row - + diff --git a/Exercise Library/Seated Row/frames/frame-2.svg b/Exercise Library/Seated Row/frames/frame-2.svg index e922f73..420c339 100644 --- a/Exercise Library/Seated Row/frames/frame-2.svg +++ b/Exercise Library/Seated Row/frames/frame-2.svg @@ -1,6 +1,6 @@ Seated Row - + diff --git a/Exercise Library/Seated Row/preview.gif b/Exercise Library/Seated Row/preview.gif index 3dd82f2..5941330 100644 Binary files a/Exercise Library/Seated Row/preview.gif and b/Exercise Library/Seated Row/preview.gif differ diff --git a/Exercise Library/Seated Row/visual.svg b/Exercise Library/Seated Row/visual.svg index e922f73..420c339 100644 --- a/Exercise Library/Seated Row/visual.svg +++ b/Exercise Library/Seated Row/visual.svg @@ -1,6 +1,6 @@ Seated Row - + diff --git a/Exercise Library/Shoulder Press/frames/frame-1.svg b/Exercise Library/Shoulder Press/frames/frame-1.svg index 6a127bf..5b72aa8 100644 --- a/Exercise Library/Shoulder Press/frames/frame-1.svg +++ b/Exercise Library/Shoulder Press/frames/frame-1.svg @@ -1,6 +1,6 @@ Shoulder Press - + diff --git a/Exercise Library/Shoulder Press/frames/frame-2.svg b/Exercise Library/Shoulder Press/frames/frame-2.svg index 9bc4e03..8942caa 100644 --- a/Exercise Library/Shoulder Press/frames/frame-2.svg +++ b/Exercise Library/Shoulder Press/frames/frame-2.svg @@ -1,6 +1,6 @@ Shoulder Press - + diff --git a/Exercise Library/Shoulder Press/preview.gif b/Exercise Library/Shoulder Press/preview.gif index 2d3d65c..885d6f5 100644 Binary files a/Exercise Library/Shoulder Press/preview.gif and b/Exercise Library/Shoulder Press/preview.gif differ diff --git a/Exercise Library/Shoulder Press/visual.svg b/Exercise Library/Shoulder Press/visual.svg index 9bc4e03..8942caa 100644 --- a/Exercise Library/Shoulder Press/visual.svg +++ b/Exercise Library/Shoulder Press/visual.svg @@ -1,6 +1,6 @@ Shoulder Press - + diff --git a/Exercise Library/Side Plank/frames/frame-1.svg b/Exercise Library/Side Plank/frames/frame-1.svg index f91e782..fa8c57f 100644 --- a/Exercise Library/Side Plank/frames/frame-1.svg +++ b/Exercise Library/Side Plank/frames/frame-1.svg @@ -1,6 +1,6 @@ Side Plank - + diff --git a/Exercise Library/Side Plank/frames/frame-2.svg b/Exercise Library/Side Plank/frames/frame-2.svg index 8ebeb57..18bbfa0 100644 --- a/Exercise Library/Side Plank/frames/frame-2.svg +++ b/Exercise Library/Side Plank/frames/frame-2.svg @@ -1,6 +1,6 @@ Side Plank - + diff --git a/Exercise Library/Side Plank/preview.gif b/Exercise Library/Side Plank/preview.gif index b361f3c..802abcd 100644 Binary files a/Exercise Library/Side Plank/preview.gif and b/Exercise Library/Side Plank/preview.gif differ diff --git a/Exercise Library/Side Plank/visual.svg b/Exercise Library/Side Plank/visual.svg index 8ebeb57..18bbfa0 100644 --- a/Exercise Library/Side Plank/visual.svg +++ b/Exercise Library/Side Plank/visual.svg @@ -1,6 +1,6 @@ Side Plank - + diff --git a/Exercise Library/Tricep Press/frames/frame-1.svg b/Exercise Library/Tricep Press/frames/frame-1.svg index a6e74f0..a23007e 100644 --- a/Exercise Library/Tricep Press/frames/frame-1.svg +++ b/Exercise Library/Tricep Press/frames/frame-1.svg @@ -1,6 +1,6 @@ Tricep Press - + diff --git a/Exercise Library/Tricep Press/frames/frame-2.svg b/Exercise Library/Tricep Press/frames/frame-2.svg index dc95e0c..bdd8b2c 100644 --- a/Exercise Library/Tricep Press/frames/frame-2.svg +++ b/Exercise Library/Tricep Press/frames/frame-2.svg @@ -1,6 +1,6 @@ Tricep Press - + diff --git a/Exercise Library/Tricep Press/preview.gif b/Exercise Library/Tricep Press/preview.gif index 35f7acf..b041c74 100644 Binary files a/Exercise Library/Tricep Press/preview.gif and b/Exercise Library/Tricep Press/preview.gif differ diff --git a/Exercise Library/Tricep Press/visual.svg b/Exercise Library/Tricep Press/visual.svg index dc95e0c..bdd8b2c 100644 --- a/Exercise Library/Tricep Press/visual.svg +++ b/Exercise Library/Tricep Press/visual.svg @@ -1,6 +1,6 @@ Tricep Press - + diff --git a/Exercise Library/render.py b/Exercise Library/render.py index 13020f3..8e4ba3a 100644 --- a/Exercise Library/render.py +++ b/Exercise Library/render.py @@ -102,7 +102,7 @@ def _bucket(depth): return round(depth / DEPTH_BUCKET) -def frame_geometry(nf, prof, cam, flipped=False, pitch=CAMERA_PITCH): +def frame_geometry(nf, prof, cam, flipped=False, pitch=CAMERA_PITCH, mat=None): """Resolve one normalized frame into drawable 2D geometry. Returns (nf with IK-resolved angles and original pins, geo, order, shade): @@ -167,6 +167,18 @@ def frame_geometry(nf, prof, cam, flipped=False, pitch=CAMERA_PITCH): geo["girdle"] = [attach("shoulder_l", "arm_l"), neck_b, attach("shoulder_r", "arm_r")] geo["pelvisBar"] = [attach("hip_l", "leg_l"), pelvis, attach("hip_r", "leg_r")] + # The exercise mat: a world-space quad on the ground plane, rotating with + # the camera about the figure's vertical axis (`mat` = screen-x bounds of + # the motion's footprint in the authored view). + if mat is not None: + yg = -(GROUND_Y + 4 - anchor[1]) + rc = K.mmul(K.rot_x(pitch), K.rot_y(-cam)) + geo["floor"] = [scr(K.mvec(rc, (dx, yg, dz))[:2] + (0,)) + for dx, dz in ((mat[0] - anchor[0], FLOOR_HALF_DEPTH), + (mat[1] - anchor[0], FLOOR_HALF_DEPTH), + (mat[1] - anchor[0], -FLOOR_HALF_DEPTH), + (mat[0] - anchor[0], -FLOOR_HALF_DEPTH))] + # The nose tick rides the head's anterior axis; it foreshortens naturally # and disappears when the face points at (or away from) the camera. nd = p["nose_dir"] @@ -183,6 +195,19 @@ def frame_geometry(nf, prof, cam, flipped=False, pitch=CAMERA_PITCH): return work, geo, order, shade +def mat_bounds(norms, prof, cam, pitch=CAMERA_PITCH): + """The motion's footprint in the authored view: min/max screen x of every + figure point across the key frames, padded - the exercise mat spans it.""" + lo, hi = float("inf"), float("-inf") + for nf in norms: + _, geo, _, _ = frame_geometry(nf, prof, cam, pitch=pitch) + xs = [geo["head"][0] - geo["headR"], geo["head"][0] + geo["headR"]] + for part in ("arm_r", "arm_l", "leg_r", "leg_l", "spine", "girdle", "pelvisBar"): + xs += [pt[0] for pt in geo.get(part, [])] + lo, hi = min(lo, min(xs)), max(hi, max(xs)) + return lo - 12, hi + 12 + + def ease(t): return 3 * t * t - 2 * t * t * t @@ -345,13 +370,15 @@ def draw_prims(d, prims, colors, scale): # ------------------------------------------------------------------- drawing -def floor_rect_svg(colors): - """The floor plane under the elevated camera: a rectangle straddling the - ground line (the old horizontal line was the pitch-zero degenerate case).""" - fh = FLOOR_HALF_DEPTH * math.sin(math.radians(CAMERA_PITCH)) - return (f' ') +def floor_svg(geo, colors): + """The exercise mat: a world-space quad on the ground plane, sized to the + motion's footprint and rotating with the camera.""" + quad = geo.get("floor") + if not quad: + return "" + d = "M " + " L ".join(f"{x:.1f} {y:.1f}" for x, y in quad) + " Z" + return (f' ') def part_style(part, working, colors, shade): @@ -378,7 +405,7 @@ def svg_for_frame(name, geo, order, shade, working, colors, props=None): w, h = CANVAS parts = [f'', f' {name}', - floor_rect_svg(colors)] + floor_svg(geo, colors)] parts += svg_prims(bg, colors) for part in order: if part == "head": @@ -431,10 +458,8 @@ def draw_geo(geo, order, shade, working, colors, scale=2, font=None, props=None) for x, y in (pts[0], pts[-1]): d.ellipse([x - r, y - r, x + r, y + r], fill=color) - fh = FLOOR_HALF_DEPTH * math.sin(math.radians(CAMERA_PITCH)) - d.rounded_rectangle([16 * scale, (GROUND_Y + 4 - fh) * scale, - (CANVAS[0] - 16) * scale, (GROUND_Y + 4 + fh) * scale], - radius=3 * scale, outline=colors["ground"], width=3 * scale) + if geo.get("floor"): + line(geo["floor"] + geo["floor"][:1], colors["ground"], 3) draw_prims(d, bg, colors, scale) for part in order: if part == "head": @@ -511,8 +536,10 @@ def render_exercise(folder, figure="neutral", flip=False, strict=False): hide = set(motion.get("hide", [])) norms, prof, cam, pitch, props = prepare(motion, figure, flip, strict) + mat = mat_bounds(norms, prof, cam, pitch) + def geometry(nf): - _, geo, order, shade = frame_geometry(nf, prof, cam, flip, pitch) + _, geo, order, shade = frame_geometry(nf, prof, cam, flip, pitch, mat) for limb in hide: geo.pop(limb, None) return geo, order, shade @@ -520,7 +547,7 @@ def render_exercise(folder, figure="neutral", flip=False, strict=False): resolved = [] key_geos = [] for nf in norms: - out, geo, order, shade = frame_geometry(nf, prof, cam, flip, pitch) + out, geo, order, shade = frame_geometry(nf, prof, cam, flip, pitch, mat) for limb in hide: geo.pop(limb, None) resolved.append(out) @@ -559,6 +586,7 @@ def render_orbit(folder, figure="neutral"): hide = set(motion.get("hide", [])) norms, prof, cam, pitch, props = prepare(motion, figure) resolved = [frame_geometry(nf, prof, cam, pitch=pitch)[0] for nf in norms] + mat = mat_bounds(norms, prof, cam, pitch) font = legend_font() colors = PALETTES["default"] ticks = timeline(resolved) @@ -569,7 +597,7 @@ def render_orbit(folder, figure="neutral"): # then rotate the posed body - never re-pin in the rotated view. posed, _, _, _ = frame_geometry(nf, prof, cam, pitch=pitch) posed["pins"] = {} - _, geo, order, shade = frame_geometry(posed, prof, yaw, pitch=pitch) + _, geo, order, shade = frame_geometry(posed, prof, yaw, pitch=pitch, mat=mat) for limb in hide: geo.pop(limb, None) imgs.append(draw_geo(geo, order, shade, working, colors, font=font, props=props)) @@ -585,8 +613,9 @@ def contact_sheet(folders, figure="neutral", out=None): motion = load_motion(folder) working, hide = set(motion.get("working", [])), set(motion.get("hide", [])) norms, prof, cam, pitch, props = prepare(motion, figure) + mat = mat_bounds(norms, prof, cam, pitch) for i, nf in enumerate(norms, start=1): - _, geo, order, shade = frame_geometry(nf, prof, cam, pitch=pitch) + _, geo, order, shade = frame_geometry(nf, prof, cam, pitch=pitch, mat=mat) for limb in hide: geo.pop(limb, None) cells.append((f"{motion['name']} {i}/{len(norms)}", @@ -611,7 +640,8 @@ def demo_sheet(folder): cells = [] for label, figure, flip, palette in variants: norms, prof, cam, pitch, props = prepare(motion, figure, flip) - _, geo, order, shade = frame_geometry(norms[idx], prof, cam, flip, pitch) + mat = mat_bounds(norms, prof, cam, pitch) + _, geo, order, shade = frame_geometry(norms[idx], prof, cam, flip, pitch, mat) for limb in hide: geo.pop(limb, None) cells.append((f"{motion['name']} — {label}", diff --git a/Workouts/ExerciseFigure/ExerciseFigureView.swift b/Workouts/ExerciseFigure/ExerciseFigureView.swift index d5bf8f9..77386bc 100644 --- a/Workouts/ExerciseFigure/ExerciseFigureView.swift +++ b/Workouts/ExerciseFigure/ExerciseFigureView.swift @@ -109,13 +109,16 @@ struct ExerciseFigureView: View { let geo = figure.geometry(at: time) - // The floor plane under the elevated camera: a rectangle straddling the - // ground line (a horizontal line is the pitch-zero degenerate case). - let floorHalf = MotionSolver.floorHalfDepth * sin(figure.timeline.pitch * .pi / 180) - let floor = CGRect(x: 16, y: Self.groundY + 4 - floorHalf, - width: Self.designSize.width - 32, height: 2 * floorHalf) - ctx.stroke(Path(roundedRect: floor, cornerRadius: 3), with: .color(.figureGround), - style: StrokeStyle(lineWidth: 3, lineCap: .round, lineJoin: .round)) + // The exercise mat: a ground-plane quad sized to the motion's footprint, + // rotating with the camera about the figure. + if let floorQuad = geo.floor, let first = floorQuad.first { + var path = Path() + path.addLines(floorQuad) + path.addLine(to: first) + path.closeSubpath() + ctx.stroke(path, with: .color(.figureGround), + style: StrokeStyle(lineWidth: 3, lineCap: .round, lineJoin: .round)) + } // Equipment behind the figure: scene shapes and cables. drawBackgroundProps(&ctx, geo) diff --git a/Workouts/ExerciseFigure/MotionSolver.swift b/Workouts/ExerciseFigure/MotionSolver.swift index 0279b5b..92af64a 100644 --- a/Workouts/ExerciseFigure/MotionSolver.swift +++ b/Workouts/ExerciseFigure/MotionSolver.swift @@ -163,6 +163,9 @@ struct FigureGeometry { /// right attach, far offsets included so the bars meet the drawn limbs exactly. var girdle: [CGPoint] var pelvisBar: [CGPoint] + /// The exercise mat: a world-space quad on the ground plane, sized to the + /// motion's footprint and rotating with the camera. Nil when no mat was given. + var floor: [CGPoint]? /// Attach → elbow/knee → hand (arms: 3 points); hip → knee → ankle → toe (legs: 4). var limbs: [FigureLimb: [CGPoint]] /// Parts far-to-near, `"head"` always last (`"spine"`, `"arm_r"`, … then `"head"`). @@ -403,11 +406,14 @@ enum MotionSolver { /// The standard slightly-elevated viewpoint: the camera pitches down a touch so /// the floor reads as a plane. Kept 1:1 with the reference renderer's CAMERA_PITCH. static let defaultPitch: Double = 10 - /// Floor plane half-depth; its projected height is `floorHalfDepth · sin(pitch)`. + /// Exercise-mat half-depth (into the screen) and the ground line's canvas y, + /// shared with the reference renderer. static let floorHalfDepth: Double = 30 + static let groundY: Double = 152 static func frameGeometry(_ nf: NormalizedFrame, prof: SkeletonProfile, cam: Double, - pitch: Double = MotionSolver.defaultPitch) -> (NormalizedFrame, FigureGeometry) { + pitch: Double = MotionSolver.defaultPitch, + mat: (lo: Double, hi: Double)? = nil) -> (NormalizedFrame, FigureGeometry) { let p0 = pose(nf, prof: prof, cam: cam, camPitch: pitch) var shade: [FigureLimb: Shade] = [:] for (right, left) in pairs { @@ -475,12 +481,23 @@ enum MotionSolver { func attachPoint(_ v: Vec3, _ limb: FigureLimb) -> CGPoint { scr(v, shade[limb] == .far ? off : .zero) } + // The exercise mat: a ground-plane quad rotating with the camera about the + // figure's vertical axis (`mat` = footprint bounds in the authored view). + var floor: [CGPoint]? + if let mat { + let yg = -(groundY + 4 - anchor.y) + let rc = Mat3.rotX(pitch).times(Mat3.rotY(-cam)) + floor = [(mat.lo, floorHalfDepth), (mat.hi, floorHalfDepth), + (mat.hi, -floorHalfDepth), (mat.lo, -floorHalfDepth)].map { dx, dz in + scr(rc.apply(Vec3(dx - anchor.x, yg, dz))) + } + } let geo = FigureGeometry( headCenter: head, headRadius: prof.headR, noseStart: noseStart, noseEnd: noseEnd, spineStart: pelvis, spineControl: control, spineEnd: neckB, girdle: [attachPoint(p.shoulderL, .armL), neckB, attachPoint(p.shoulderR, .armR)], pelvisBar: [attachPoint(p.hipL, .legL), pelvis, attachPoint(p.hipR, .legR)], - limbs: limbs, order: order, shade: shade) + floor: floor, limbs: limbs, order: order, shade: shade) return (resolved, geo) } } @@ -494,13 +511,29 @@ struct MotionTimeline { let cam: Double let pitch: Double let duration: Double + /// The motion's footprint in the authored view (min/max screen x of every figure + /// point across the key frames, padded) — the exercise mat spans it. + let mat: (lo: Double, hi: Double) init?(motion: ExerciseMotion, profile: SkeletonProfile) { let cam = motion.camera?.yaw ?? 0 let pitch = motion.camera?.pitch ?? MotionSolver.defaultPitch let norms = motion.frames.map { MotionSolver.normalize($0) } guard !norms.isEmpty else { return nil } - let resolved = norms.map { MotionSolver.frameGeometry($0, prof: profile, cam: cam, pitch: pitch).0 } + var resolved: [NormalizedFrame] = [] + var lo = Double.infinity, hi = -Double.infinity + for norm in norms { + let (frame, geo) = MotionSolver.frameGeometry(norm, prof: profile, cam: cam, pitch: pitch) + resolved.append(frame) + var xs: [Double] = [Double(geo.headCenter.x) - geo.headRadius, + Double(geo.headCenter.x) + geo.headRadius, + Double(geo.spineStart.x), Double(geo.spineControl.x), + Double(geo.spineEnd.x)] + xs += (geo.girdle + geo.pelvisBar).map { Double($0.x) } + xs += geo.limbs.values.flatMap { $0.map { Double($0.x) } } + lo = min(lo, xs.min() ?? lo) + hi = max(hi, xs.max() ?? hi) + } let duration = resolved.reduce(0) { $0 + $1.hold + $1.tween } guard duration > 0 else { return nil } self.resolved = resolved @@ -508,6 +541,7 @@ struct MotionTimeline { self.cam = cam self.pitch = pitch self.duration = duration + self.mat = (lo - 12, hi + 12) } /// The resolved frame (or eased tween) at wall-clock `time`, looping every @@ -535,10 +569,10 @@ struct MotionTimeline { func geometry(at time: Double, yawOffset: Double = 0) -> FigureGeometry { let frame = frame(at: time) guard yawOffset != 0 else { - return MotionSolver.frameGeometry(frame, prof: profile, cam: cam, pitch: pitch).1 + return MotionSolver.frameGeometry(frame, prof: profile, cam: cam, pitch: pitch, mat: mat).1 } var posed = MotionSolver.frameGeometry(frame, prof: profile, cam: cam, pitch: pitch).0 posed.pins = [:] - return MotionSolver.frameGeometry(posed, prof: profile, cam: cam + yawOffset, pitch: pitch).1 + return MotionSolver.frameGeometry(posed, prof: profile, cam: cam + yawOffset, pitch: pitch, mat: mat).1 } }