Surface machine settings in the exercise library and refine machine rigs

Library detail screens now lead with the user's recorded machine settings
(per-split when they disagree, empty-state card for machine-based entries)
and append the weight progression chart. Starter seeds mark machine
exercises with an empty machineSettings list so the settings UI lights up
before first use. The figure rig gains a frontal body profile for face-on
machines, props that can ride mid joints (knees/elbows), and an
alternating four-frame Bird Dog loop.

Claude-Session: https://claude.ai/code/session_01LEoff8bXGBS83tK1c55Mf7
This commit is contained in:
2026-07-06 18:35:15 -04:00
parent ff1ffbb1f6
commit 669ecf1259
76 changed files with 733 additions and 268 deletions
+5 -6
View File
@@ -3,15 +3,14 @@
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <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="152" y="56" width="16" height="72" rx="5" fill="#c5cad4"/>
<rect x="130" y="126" width="60" height="10" rx="3" 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 160.0 136.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="6" 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="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="leg_l" d="M 166.0 118.0 L 160.3 139.3 L 160.3 165.3" 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="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="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"/> <path id="leg_r" d="M 160.0 116.0 L 165.7 137.3 L 165.7 163.3" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 165.7 150.3 L 165.7 124.3" stroke="#6b7180" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 160.3 152.3 L 160.3 126.3" stroke="#6b7180" 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"/> <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"> <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"/> <line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

+5 -6
View File
@@ -3,15 +3,14 @@
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <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="152" y="56" width="16" height="72" rx="5" fill="#c5cad4"/>
<rect x="130" y="126" width="60" height="10" rx="3" 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 160.0 136.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="6" 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="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="leg_l" d="M 166.0 118.0 L 146.9 129.0 L 146.9 155.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="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="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"/> <path id="leg_r" d="M 160.0 116.0 L 179.1 127.0 L 179.1 153.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 179.1 140.0 L 179.1 114.0" stroke="#6b7180" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 146.9 142.0 L 146.9 116.0" stroke="#6b7180" 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"/> <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"> <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"/> <line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

+7 -9
View File
@@ -1,17 +1,17 @@
{ {
"name": "Abductor", "name": "Abductor",
"primary": 2, "primary": 2,
"figure": "frontal",
"working": ["leg_r", "leg_l"], "working": ["leg_r", "leg_l"],
"hide": [], "hide": [],
"props": [ "props": [
{"type": "scene", "shapes": [ {"type": "scene", "shapes": [
{"kind": "rect", "x": 152, "y": 56, "w": 16, "h": 72, "r": 5}, {"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": "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": [[160, 136], [160, 150]], "w": 6}
{"kind": "line", "pts": [[188, 78], [188, 108]], "w": 4, "color": "prop"}, ]},
{"kind": "line", "pts": [[213, 110], [213, 132]], "w": 9, "color": "prop"}, {"type": "pad", "at": ["knee_r"], "angle": 90, "halfLen": 13, "w": 6},
{"kind": "line", "pts": [[107, 110], [107, 132]], "w": 9, "color": "prop"} {"type": "pad", "at": ["knee_l"], "angle": 90, "halfLen": 13, "w": 6}
]}
], ],
"frames": [ "frames": [
{ {
@@ -19,16 +19,14 @@
"root": [160, 116], "root": [160, 116],
"spine": [90, 90], "neck": 90, "spine": [90, 90], "neck": 90,
"arm_r": [-48, -82], "arm_l": [-132, -98], "arm_r": [-48, -82], "arm_l": [-132, -98],
"leg_r": [-22, 0], "leg_l": [-158, 0], "leg_r": [-75, -90], "leg_l": [-105, -90]
"pins": {"foot_r": [180, 156], "foot_l": [140, 156]}
}, },
{ {
"hold": 0.5, "tween": 1.1, "hold": 0.5, "tween": 1.1,
"root": [160, 116], "root": [160, 116],
"spine": [90, 90], "neck": 90, "spine": [90, 90], "neck": 90,
"arm_r": [-48, -82], "arm_l": [-132, -98], "arm_r": [-48, -82], "arm_l": [-132, -98],
"leg_r": [-22, 0], "leg_l": [-158, 0], "leg_r": [-30, -90], "leg_l": [-150, -90]
"pins": {"foot_r": [216, 156], "foot_l": [104, 156]}
} }
] ]
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 164 KiB

+5 -6
View File
@@ -3,15 +3,14 @@
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <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="152" y="56" width="16" height="72" rx="5" fill="#c5cad4"/>
<rect x="130" y="126" width="60" height="10" rx="3" 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 160.0 136.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="6" 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="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="leg_l" d="M 166.0 118.0 L 146.9 129.0 L 146.9 155.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="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="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"/> <path id="leg_r" d="M 160.0 116.0 L 179.1 127.0 L 179.1 153.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 179.1 140.0 L 179.1 114.0" stroke="#6b7180" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 146.9 142.0 L 146.9 116.0" stroke="#6b7180" 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"/> <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"> <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"/> <line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

+5 -6
View File
@@ -3,15 +3,14 @@
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <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="152" y="56" width="16" height="72" rx="5" fill="#c5cad4"/>
<rect x="130" y="126" width="60" height="10" rx="3" 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 160.0 136.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="6" 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="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="leg_l" d="M 166.0 118.0 L 146.9 129.0 L 146.9 155.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="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="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"/> <path id="leg_r" d="M 160.0 116.0 L 179.1 127.0 L 179.1 153.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 179.1 140.0 L 179.1 114.0" stroke="#6b7180" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 146.9 142.0 L 146.9 116.0" stroke="#6b7180" 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"/> <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"> <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"/> <line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

+5 -6
View File
@@ -3,15 +3,14 @@
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <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="152" y="56" width="16" height="72" rx="5" fill="#c5cad4"/>
<rect x="130" y="126" width="60" height="10" rx="3" 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 160.0 136.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="6" 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="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="leg_l" d="M 166.0 118.0 L 160.3 139.3 L 160.3 165.3" 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="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="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"/> <path id="leg_r" d="M 160.0 116.0 L 165.7 137.3 L 165.7 163.3" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 165.7 150.3 L 165.7 124.3" stroke="#6b7180" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 160.3 152.3 L 160.3 126.3" stroke="#6b7180" 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"/> <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"> <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"/> <line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

+7 -9
View File
@@ -1,17 +1,17 @@
{ {
"name": "Adductor", "name": "Adductor",
"primary": 2, "primary": 2,
"figure": "frontal",
"working": ["leg_r", "leg_l"], "working": ["leg_r", "leg_l"],
"hide": [], "hide": [],
"props": [ "props": [
{"type": "scene", "shapes": [ {"type": "scene", "shapes": [
{"kind": "rect", "x": 152, "y": 56, "w": 16, "h": 72, "r": 5}, {"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": "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": [[160, 136], [160, 150]], "w": 6}
{"kind": "line", "pts": [[188, 78], [188, 108]], "w": 4, "color": "prop"}, ]},
{"kind": "line", "pts": [[197, 110], [197, 132]], "w": 9, "color": "prop"}, {"type": "pad", "at": ["knee_r"], "angle": 90, "halfLen": 13, "w": 6},
{"kind": "line", "pts": [[123, 110], [123, 132]], "w": 9, "color": "prop"} {"type": "pad", "at": ["knee_l"], "angle": 90, "halfLen": 13, "w": 6}
]}
], ],
"frames": [ "frames": [
{ {
@@ -19,16 +19,14 @@
"root": [160, 116], "root": [160, 116],
"spine": [90, 90], "neck": 90, "spine": [90, 90], "neck": 90,
"arm_r": [-48, -82], "arm_l": [-132, -98], "arm_r": [-48, -82], "arm_l": [-132, -98],
"leg_r": [-22, 0], "leg_l": [-158, 0], "leg_r": [-30, -90], "leg_l": [-150, -90]
"pins": {"foot_r": [216, 156], "foot_l": [104, 156]}
}, },
{ {
"hold": 0.5, "tween": 1.1, "hold": 0.5, "tween": 1.1,
"root": [160, 116], "root": [160, 116],
"spine": [90, 90], "neck": 90, "spine": [90, 90], "neck": 90,
"arm_r": [-48, -82], "arm_l": [-132, -98], "arm_r": [-48, -82], "arm_l": [-132, -98],
"leg_r": [-22, 0], "leg_l": [-158, 0], "leg_r": [-75, -90], "leg_l": [-105, -90]
"pins": {"foot_r": [180, 156], "foot_l": [140, 156]}
} }
] ]
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 KiB

After

Width:  |  Height:  |  Size: 165 KiB

+5 -6
View File
@@ -3,15 +3,14 @@
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <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="152" y="56" width="16" height="72" rx="5" fill="#c5cad4"/>
<rect x="130" y="126" width="60" height="10" rx="3" 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 160.0 136.0 L 160.0 150.0" stroke="#c5cad4" stroke-width="6" 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="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="leg_l" d="M 166.0 118.0 L 160.3 139.3 L 160.3 165.3" 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="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="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"/> <path id="leg_r" d="M 160.0 116.0 L 165.7 137.3 L 165.7 163.3" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 165.7 150.3 L 165.7 124.3" stroke="#6b7180" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 160.3 152.3 L 160.3 126.3" stroke="#6b7180" 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"/> <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"> <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"/> <line x1="242" y1="16" x2="258" y2="16" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

+5 -5
View File
@@ -2,14 +2,14 @@
<title>Arm Curl</title> <title>Arm Curl</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <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 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 136.0 52.0 L 164.0 70.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 d="M 164.0 70.0 L 164.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="arm_l" d="M 140.4 41.1 L 165.0 58.3 L 180.9 83.8" 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="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="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="arm_r" d="M 134.4 39.1 L 159.0 56.3 L 174.9 81.8" 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 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"/> <path d="M 177.9 88.8 L 177.9 76.8" 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"/> <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"/> <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"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

+5 -5
View File
@@ -2,14 +2,14 @@
<title>Arm Curl</title> <title>Arm Curl</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <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 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 136.0 52.0 L 164.0 70.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 d="M 164.0 70.0 L 164.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="arm_l" d="M 140.4 41.1 L 165.0 58.3 L 184.3 35.4" 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="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="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="arm_r" d="M 134.4 39.1 L 159.0 56.3 L 178.3 33.4" 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 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"/> <path d="M 181.3 40.4 L 181.3 28.4" 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"/> <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"/> <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"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

+4 -4
View File
@@ -6,8 +6,8 @@
"props": [ "props": [
{"type": "scene", "shapes": [ {"type": "scene", "shapes": [
{"kind": "line", "pts": [[116, 134], [150, 134]], "w": 8}, {"kind": "line", "pts": [[116, 134], [150, 134]], "w": 8},
{"kind": "line", "pts": [[146, 42], [176, 68]], "w": 8}, {"kind": "line", "pts": [[136, 52], [164, 70]], "w": 8},
{"kind": "line", "pts": [[176, 68], [176, 128]], "w": 5} {"kind": "line", "pts": [[164, 70], [164, 128]], "w": 5}
]}, ]},
{"type": "bar", "at": ["hand_r", "hand_l"], "angle": 90, "halfLen": 6} {"type": "bar", "at": ["hand_r", "hand_l"], "angle": 90, "halfLen": 6}
], ],
@@ -16,7 +16,7 @@
"hold": 0.4, "tween": 1.0, "hold": 0.4, "tween": 1.0,
"root": [130, 124], "root": [130, 124],
"spine": [88, 86], "neck": 82, "gaze": -18, "spine": [88, 86], "neck": 82, "gaze": -18,
"arm_r": [-35, -52], "arm_l": [-35, -52], "arm_r": [-35, -58], "arm_l": [-35, -58],
"leg_r": [-8, -72], "leg_l": [-8, -72], "leg_r": [-8, -72], "leg_l": [-8, -72],
"pins": {"foot_r": [176, 150], "foot_l": [180, 151]} "pins": {"foot_r": [176, 150], "foot_l": [180, 151]}
}, },
@@ -24,7 +24,7 @@
"hold": 0.4, "tween": 1.2, "hold": 0.4, "tween": 1.2,
"root": [130, 124], "root": [130, 124],
"spine": [88, 86], "neck": 82, "gaze": -18, "spine": [88, 86], "neck": 82, "gaze": -18,
"arm_r": [-35, 138], "arm_l": [-35, 138], "arm_r": [-35, 50], "arm_l": [-35, 50],
"leg_r": [-8, -72], "leg_l": [-8, -72], "leg_r": [-8, -72], "leg_l": [-8, -72],
"pins": {"foot_r": [176, 150], "foot_l": [180, 151]} "pins": {"foot_r": [176, 150], "foot_l": [180, 151]}
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 136 KiB

+5 -5
View File
@@ -2,14 +2,14 @@
<title>Arm Curl</title> <title>Arm Curl</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <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 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 136.0 52.0 L 164.0 70.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 d="M 164.0 70.0 L 164.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="arm_l" d="M 140.4 41.1 L 165.0 58.3 L 184.3 35.4" 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="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="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="arm_r" d="M 134.4 39.1 L 159.0 56.3 L 178.3 33.4" 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 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"/> <path d="M 181.3 40.4 L 181.3 28.4" 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"/> <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"/> <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"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

+2 -2
View File
@@ -1,11 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
<title>Bird Dog</title> <title>Bird Dog</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
<path id="arm_l" d="M 112.0 94.7 L 116.1 124.4 L 111.0 154.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/> <path id="arm_l" d="M 112.0 94.7 L 116.1 124.4 L 111.0 154.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_l" d="M 196.0 108.0 L 201.6 153.7 L 241.6 153.7" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/> <path id="leg_l" d="M 196.0 108.0 L 201.6 153.7 L 241.6 153.7" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="spine" d="M 190.0 106.0 Q 147.0 99.2 106.0 92.7" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="spine" d="M 190.0 106.0 Q 147.0 99.2 106.0 92.7" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="arm_r" d="M 106.0 92.7 L 110.1 122.4 L 105.0 152.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="arm_r" d="M 106.0 92.7 L 110.1 122.4 L 105.0 152.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_r" d="M 190.0 106.0 L 195.6 151.7 L 235.6 151.7" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="leg_r" d="M 190.0 106.0 L 195.6 151.7 L 235.6 151.7" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<circle id="head" cx="86.2" cy="95.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/> <circle id="head" cx="86.2" cy="95.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
<line id="nose" x1="77.1" y1="99.4" x2="70.8" y2="102.3" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/> <line id="nose" x1="77.1" y1="99.4" x2="70.8" y2="102.3" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

+2 -2
View File
@@ -1,11 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
<title>Bird Dog</title> <title>Bird Dog</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
<path id="arm_l" d="M 112.0 94.7 L 116.1 124.4 L 111.0 154.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/> <path id="arm_l" d="M 112.0 94.7 L 116.1 124.4 L 111.0 154.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_l" d="M 196.0 108.0 L 240.4 96.1 L 279.1 85.7" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/> <path id="leg_l" d="M 196.0 108.0 L 240.4 96.1 L 279.1 85.7" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="spine" d="M 190.0 106.0 Q 147.0 99.2 106.0 92.7" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="spine" d="M 190.0 106.0 Q 147.0 99.2 106.0 92.7" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="arm_r" d="M 106.0 92.7 L 77.7 82.9 L 49.3 73.2" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="arm_r" d="M 106.0 92.7 L 77.7 82.9 L 49.3 73.2" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_r" d="M 190.0 106.0 L 195.6 151.7 L 235.6 151.7" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="leg_r" d="M 190.0 106.0 L 195.6 151.7 L 235.6 151.7" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<circle id="head" cx="86.2" cy="95.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/> <circle id="head" cx="86.2" cy="95.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
<line id="nose" x1="76.5" y1="97.7" x2="69.8" y2="99.5" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/> <line id="nose" x1="76.5" y1="97.7" x2="69.8" y2="99.5" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
<title>Bird Dog</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
<path id="arm_l" d="M 112.0 94.7 L 116.1 124.4 L 111.0 154.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_l" d="M 196.0 108.0 L 201.6 153.7 L 241.6 153.7" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="spine" d="M 190.0 106.0 Q 147.0 99.2 106.0 92.7" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="arm_r" d="M 106.0 92.7 L 110.1 122.4 L 105.0 152.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_r" d="M 190.0 106.0 L 195.6 151.7 L 235.6 151.7" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<circle id="head" cx="86.2" cy="95.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
<line id="nose" x1="77.1" y1="99.4" x2="70.8" y2="102.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: 1.5 KiB

@@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
<title>Bird Dog</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
<path id="arm_l" d="M 112.0 94.7 L 83.7 84.9 L 55.3 75.2" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_l" d="M 196.0 108.0 L 201.6 153.7 L 241.6 153.7" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="spine" d="M 190.0 106.0 Q 147.0 99.2 106.0 92.7" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="arm_r" d="M 106.0 92.7 L 110.1 122.4 L 105.0 152.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_r" d="M 190.0 106.0 L 234.4 94.1 L 273.1 83.7" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<circle id="head" cx="86.2" cy="95.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
<line id="nose" x1="76.5" y1="97.7" x2="69.8" y2="99.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: 1.5 KiB

+17 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "Bird Dog", "name": "Bird Dog",
"primary": 2, "primary": 2,
"working": ["arm_r", "leg_l"], "working": ["arm_r", "leg_l", "arm_l", "leg_r"],
"frames": [ "frames": [
{ {
"hold": 0.5, "tween": 0.8, "hold": 0.5, "tween": 0.8,
@@ -18,6 +18,22 @@
"arm_r": [161, 161], "arm_l": [-90, -90], "arm_r": [161, 161], "arm_l": [-90, -90],
"leg_r": [-83, 0], "leg_l": [15, 15], "leg_r": [-83, 0], "leg_l": [15, 15],
"pins": {"hand_l": [111, 154]} "pins": {"hand_l": [111, 154]}
},
{
"hold": 0.5, "tween": 0.8,
"root": [190, 106],
"spine": [171, 171], "neck": 187, "gaze": 205,
"arm_r": [-90, -90], "arm_l": [-90, -90],
"leg_r": [-83, 0], "leg_l": [-83, 0],
"pins": {"hand_r": [105, 152], "hand_l": [111, 154]}
},
{
"hold": 1.4, "tween": 0.8,
"root": [190, 106],
"spine": [171, 171], "neck": 187, "gaze": 195,
"arm_r": [-90, -90], "arm_l": [161, 161],
"leg_r": [15, 15], "leg_l": [-83, 0],
"pins": {"hand_r": [105, 152]}
} }
] ]
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 212 KiB

+2 -2
View File
@@ -1,11 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
<title>Bird Dog</title> <title>Bird Dog</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
<path id="arm_l" d="M 112.0 94.7 L 116.1 124.4 L 111.0 154.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/> <path id="arm_l" d="M 112.0 94.7 L 116.1 124.4 L 111.0 154.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_l" d="M 196.0 108.0 L 240.4 96.1 L 279.1 85.7" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/> <path id="leg_l" d="M 196.0 108.0 L 240.4 96.1 L 279.1 85.7" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="spine" d="M 190.0 106.0 Q 147.0 99.2 106.0 92.7" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="spine" d="M 190.0 106.0 Q 147.0 99.2 106.0 92.7" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="arm_r" d="M 106.0 92.7 L 77.7 82.9 L 49.3 73.2" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="arm_r" d="M 106.0 92.7 L 77.7 82.9 L 49.3 73.2" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_r" d="M 190.0 106.0 L 195.6 151.7 L 235.6 151.7" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="leg_r" d="M 190.0 106.0 L 195.6 151.7 L 235.6 151.7" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<circle id="head" cx="86.2" cy="95.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/> <circle id="head" cx="86.2" cy="95.1" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
<line id="nose" x1="76.5" y1="97.7" x2="69.8" y2="99.5" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/> <line id="nose" x1="76.5" y1="97.7" x2="69.8" y2="99.5" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

+2 -2
View File
@@ -5,14 +5,14 @@
<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 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"/> <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"/> <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"/> <path d="M 183.0 62.0 L 183.0 122.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 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="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="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="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="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 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 175.0 117.8 L 203.0 117.8" stroke="#6b7180" stroke-width="7" 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"/> <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"/> <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"/> <line id="nose" x1="141.5" y1="15.9" x2="148.4" y2="17.1" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

+2 -2
View File
@@ -5,14 +5,14 @@
<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 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"/> <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"/> <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"/> <path d="M 183.0 62.0 L 183.0 122.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 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="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="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="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="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 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 174.0 109.6 L 202.0 109.6" stroke="#6b7180" stroke-width="7" 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"/> <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"/> <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"/> <line id="nose" x1="141.5" y1="15.9" x2="148.4" y2="17.1" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

+2 -2
View File
@@ -9,10 +9,10 @@
{"kind": "line", "pts": [[138, 128], [138, 150]], "w": 5}, {"kind": "line", "pts": [[138, 128], [138, 150]], "w": 5},
{"kind": "line", "pts": [[120, 150], [156, 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": "rect", "x": 198, "y": 147, "w": 34, "h": 6, "r": 1},
{"kind": "line", "pts": [[183, 62], [183, 124]], "w": 4}, {"kind": "line", "pts": [[183, 62], [183, 122]], "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"} {"kind": "line", "pts": [[164, 76], [183, 76]], "w": 3, "color": "prop"}
]}, ]},
{"type": "pad", "at": ["knee_r", "knee_l"], "angle": 0, "halfLen": 14, "w": 7},
{"type": "pad", "at": ["foot_r", "foot_l"], "angle": 15, "halfLen": 7, "w": 5} {"type": "pad", "at": ["foot_r", "foot_l"], "angle": 15, "halfLen": 7, "w": 5}
], ],
"frames": [ "frames": [
Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 163 KiB

+2 -2
View File
@@ -5,14 +5,14 @@
<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 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"/> <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"/> <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"/> <path d="M 183.0 62.0 L 183.0 122.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 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="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="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="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="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 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 174.0 109.6 L 202.0 109.6" stroke="#6b7180" stroke-width="7" 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"/> <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"/> <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"/> <line id="nose" x1="141.5" y1="15.9" x2="148.4" y2="17.1" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

+2 -2
View File
@@ -1,11 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
<title>Dead Bug</title> <title>Dead Bug</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
<path id="arm_l" d="M 106.0 150.0 L 106.0 120.0 L 106.0 90.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/> <path id="arm_l" d="M 106.0 150.0 L 106.0 120.0 L 106.0 90.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_l" d="M 191.0 150.0 L 211.2 108.7 L 250.6 115.6" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/> <path id="leg_l" d="M 191.0 150.0 L 211.2 108.7 L 250.6 115.6" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="spine" d="M 185.0 148.0 Q 141.5 148.0 100.0 148.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="spine" d="M 185.0 148.0 Q 141.5 148.0 100.0 148.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="arm_r" d="M 100.0 148.0 L 100.0 118.0 L 100.0 88.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="arm_r" d="M 100.0 148.0 L 100.0 118.0 L 100.0 88.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_r" d="M 185.0 148.0 L 205.2 106.7 L 244.6 113.6" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="leg_r" d="M 185.0 148.0 L 205.2 106.7 L 244.6 113.6" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<circle id="head" cx="80.4" cy="143.8" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/> <circle id="head" cx="80.4" cy="143.8" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
<line id="nose" x1="80.4" y1="133.8" x2="80.4" y2="126.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/> <line id="nose" x1="80.4" y1="133.8" x2="80.4" y2="126.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

+2 -2
View File
@@ -1,11 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
<title>Dead Bug</title> <title>Dead Bug</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
<path id="arm_l" d="M 106.0 150.0 L 106.0 120.0 L 106.0 90.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/> <path id="arm_l" d="M 106.0 150.0 L 106.0 120.0 L 106.0 90.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_l" d="M 191.0 150.0 L 235.2 137.3 L 273.7 126.3" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/> <path id="leg_l" d="M 191.0 150.0 L 235.2 137.3 L 273.7 126.3" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="spine" d="M 185.0 148.0 Q 141.5 148.0 100.0 148.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="spine" d="M 185.0 148.0 Q 141.5 148.0 100.0 148.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="arm_r" d="M 100.0 148.0 L 78.8 126.8 L 57.6 105.6" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="arm_r" d="M 100.0 148.0 L 78.8 126.8 L 57.6 105.6" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_r" d="M 185.0 148.0 L 205.2 106.7 L 244.6 113.6" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="leg_r" d="M 185.0 148.0 L 205.2 106.7 L 244.6 113.6" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<circle id="head" cx="80.4" cy="143.8" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/> <circle id="head" cx="80.4" cy="143.8" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
<line id="nose" x1="80.4" y1="133.8" x2="80.4" y2="126.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/> <line id="nose" x1="80.4" y1="133.8" x2="80.4" y2="126.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
<title>Dead Bug</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
<path id="arm_l" d="M 106.0 150.0 L 106.0 120.0 L 106.0 90.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_l" d="M 191.0 150.0 L 211.2 108.7 L 250.6 115.6" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="spine" d="M 185.0 148.0 Q 141.5 148.0 100.0 148.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="arm_r" d="M 100.0 148.0 L 100.0 118.0 L 100.0 88.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_r" d="M 185.0 148.0 L 205.2 106.7 L 244.6 113.6" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<circle id="head" cx="80.4" cy="143.8" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
<line id="nose" x1="80.4" y1="133.8" x2="80.4" y2="126.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: 1.5 KiB

@@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
<title>Dead Bug</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
<path id="arm_l" d="M 106.0 150.0 L 84.8 128.8 L 63.6 107.6" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_l" d="M 191.0 150.0 L 211.2 108.7 L 250.6 115.6" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="spine" d="M 185.0 148.0 Q 141.5 148.0 100.0 148.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="arm_r" d="M 100.0 148.0 L 100.0 118.0 L 100.0 88.0" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_r" d="M 185.0 148.0 L 229.2 135.3 L 267.7 124.3" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<circle id="head" cx="80.4" cy="143.8" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
<line id="nose" x1="80.4" y1="133.8" x2="80.4" y2="126.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: 1.5 KiB

+15 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "Dead Bug", "name": "Dead Bug",
"primary": 2, "primary": 2,
"working": ["arm_r", "leg_l"], "working": ["arm_r", "leg_l", "arm_l", "leg_r"],
"frames": [ "frames": [
{ {
"hold": 0.5, "tween": 0.8, "hold": 0.5, "tween": 0.8,
@@ -16,6 +16,20 @@
"spine": [180, 180], "neck": 168, "gaze": 90, "spine": [180, 180], "neck": 168, "gaze": 90,
"arm_r": [135, 135], "arm_l": [90, 90], "arm_r": [135, 135], "arm_l": [90, 90],
"leg_r": [64, -10], "leg_l": [16, 16] "leg_r": [64, -10], "leg_l": [16, 16]
},
{
"hold": 0.5, "tween": 0.8,
"root": [185, 148],
"spine": [180, 180], "neck": 168, "gaze": 90,
"arm_r": [90, 90], "arm_l": [90, 90],
"leg_r": [64, -10], "leg_l": [64, -10]
},
{
"hold": 0.9, "tween": 0.8,
"root": [185, 148],
"spine": [180, 180], "neck": 168, "gaze": 90,
"arm_r": [90, 90], "arm_l": [135, 135],
"leg_r": [16, 16], "leg_l": [64, -10]
} }
] ]
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 188 KiB

+2 -2
View File
@@ -1,11 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" fill="none">
<title>Dead Bug</title> <title>Dead Bug</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/>
<path id="arm_l" d="M 106.0 150.0 L 106.0 120.0 L 106.0 90.0" stroke="#a9afba" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/> <path id="arm_l" d="M 106.0 150.0 L 106.0 120.0 L 106.0 90.0" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_l" d="M 191.0 150.0 L 235.2 137.3 L 273.7 126.3" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/> <path id="leg_l" d="M 191.0 150.0 L 235.2 137.3 L 273.7 126.3" stroke="#86cfc5" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="spine" d="M 185.0 148.0 Q 141.5 148.0 100.0 148.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="spine" d="M 185.0 148.0 Q 141.5 148.0 100.0 148.0" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="arm_r" d="M 100.0 148.0 L 78.8 126.8 L 57.6 105.6" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="arm_r" d="M 100.0 148.0 L 78.8 126.8 L 57.6 105.6" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<path id="leg_r" d="M 185.0 148.0 L 205.2 106.7 L 244.6 113.6" stroke="#3a3f4b" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/> <path id="leg_r" d="M 185.0 148.0 L 205.2 106.7 L 244.6 113.6" stroke="#0d9488" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
<circle id="head" cx="80.4" cy="143.8" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/> <circle id="head" cx="80.4" cy="143.8" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>
<line id="nose" x1="80.4" y1="133.8" x2="80.4" y2="126.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/> <line id="nose" x1="80.4" y1="133.8" x2="80.4" y2="126.8" stroke="#3a3f4b" stroke-width="4" stroke-linecap="round"/>
<g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -2,16 +2,15 @@
<title>Lat Pull Down</title> <title>Lat Pull Down</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <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 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 144.0 132.0 L 144.0 150.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"/> <circle cx="272.0" cy="19.0" r="4" fill="#6b7180"/>
<rect x="170" y="112" width="40" height="7" rx="3" fill="#c5cad4"/> <path d="M 272.0 19.0 L 196.0 2.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<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 181.7 28.2 L 198.0 3.0" stroke="#86cfc5" stroke-width="5" 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="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="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="arm_r" d="M 147.7 37.1 L 174.8 24.0 L 194.0 1.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 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"/> <path d="M 172.0 2.0 L 220.0 2.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"/> <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"/> <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"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

@@ -2,16 +2,15 @@
<title>Lat Pull Down</title> <title>Lat Pull Down</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <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 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 144.0 132.0 L 144.0 150.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"/> <circle cx="272.0" cy="19.0" r="4" fill="#6b7180"/>
<rect x="170" y="112" width="40" height="7" rx="3" fill="#c5cad4"/> <path d="M 272.0 19.0 L 196.0 36.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<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 176.8 58.2 L 198.0 37.0" stroke="#86cfc5" stroke-width="5" 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="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="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="arm_r" d="M 147.7 37.1 L 171.7 55.1 L 194.0 35.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 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"/> <path d="M 172.0 36.0 L 220.0 36.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"/> <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"/> <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"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

+8 -9
View File
@@ -6,30 +6,29 @@
"props": [ "props": [
{"type": "scene", "shapes": [ {"type": "scene", "shapes": [
{"kind": "line", "pts": [[126, 130], [162, 130]], "w": 8}, {"kind": "line", "pts": [[126, 130], [162, 130]], "w": 8},
{"kind": "line", "pts": [[124, 130], [124, 56]], "w": 5}, {"kind": "line", "pts": [[144, 132], [144, 150]], "w": 5},
{"kind": "line", "pts": [[124, 56], [198, 12]], "w": 5}, {"kind": "circle", "c": [272, 19], "r": 4, "fill": true, "color": "prop"}
{"kind": "rect", "x": 170, "y": 112, "w": 40, "h": 7, "r": 3}
]}, ]},
{"type": "cable", "from": [198, 8], "to": ["hand_r", "hand_l"]}, {"type": "cable", "from": [272, 19], "to": ["hand_r", "hand_l"], "w": 4},
{"type": "bar", "at": ["hand_r", "hand_l"], "halfLen": 28} {"type": "bar", "at": ["hand_r", "hand_l"], "halfLen": 24}
], ],
"frames": [ "frames": [
{ {
"hold": 0.4, "tween": 1.0, "hold": 0.4, "tween": 1.0,
"root": [150, 122], "root": [150, 122],
"spine": [93, 90], "neck": 85, "gaze": 55, "spine": [93, 90], "neck": 85, "gaze": 55,
"arm_r": [20, 10], "arm_l": [20, 10], "arm_r": [35, 35], "arm_l": [35, 35],
"leg_r": [-12, -80], "leg_l": [-12, -80], "leg_r": [-12, -80], "leg_l": [-12, -80],
"pins": {"hand_r": [198, 24], "hand_l": [202, 26], "pins": {"hand_r": [194, 1], "hand_l": [198, 3],
"foot_r": [193, 150], "foot_l": [197, 151]} "foot_r": [193, 150], "foot_l": [197, 151]}
}, },
{ {
"hold": 0.4, "tween": 1.2, "hold": 0.4, "tween": 1.2,
"root": [150, 122], "root": [150, 122],
"spine": [93, 90], "neck": 85, "gaze": 30, "spine": [93, 90], "neck": 85, "gaze": 30,
"arm_r": [-115, -20], "arm_l": [-115, -20], "arm_r": [-38, 38], "arm_l": [-38, 38],
"leg_r": [-12, -80], "leg_l": [-12, -80], "leg_r": [-12, -80], "leg_l": [-12, -80],
"pins": {"hand_r": [165, 66], "hand_l": [169, 68], "pins": {"hand_r": [194, 35], "hand_l": [198, 37],
"foot_r": [193, 150], "foot_l": [197, 151]} "foot_r": [193, 150], "foot_l": [197, 151]}
} }
] ]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 157 KiB

+6 -7
View File
@@ -2,16 +2,15 @@
<title>Lat Pull Down</title> <title>Lat Pull Down</title>
<line x1="16" y1="156" x2="304" y2="156" stroke="#b9bec9" stroke-width="3" stroke-linecap="round"/> <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 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 144.0 132.0 L 144.0 150.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"/> <circle cx="272.0" cy="19.0" r="4" fill="#6b7180"/>
<rect x="170" y="112" width="40" height="7" rx="3" fill="#c5cad4"/> <path d="M 272.0 19.0 L 196.0 36.0" stroke="#c5cad4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<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 176.8 58.2 L 198.0 37.0" stroke="#86cfc5" stroke-width="5" 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="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="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="arm_r" d="M 147.7 37.1 L 171.7 55.1 L 194.0 35.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 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"/> <path d="M 172.0 36.0 L 220.0 36.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"/> <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"/> <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"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

+9 -2
View File
@@ -13,7 +13,10 @@ changing data, never artwork.
lengths: `headR`, `neck`, `spine1`/`spine2` (two chained segments so the lengths: `headR`, `neck`, `spine1`/`spine2` (two chained segments so the
spine can curve), `upperArm`/`foreArm`, `thigh`/`shin`, plus `leftOffset` spine can curve), `upperArm`/`foreArm`, `thigh`/`shin`, plus `leftOffset`
(the small offset that separates left-limb attachments visually). (the small offset that separates left-limb attachments visually).
`neutral` is the default; add profiles to add figures. `neutral` is the default; add profiles to add figures. `frontal` shortens
the legs for face-on seated machines (thighs point mostly at the viewer, so
they render foreshortened); a motion opts in with a top-level
`"figure": "frontal"`.
- **`<Exercise>/motion.json`** — the exercise script: key frames of - **`<Exercise>/motion.json`** — the exercise script: key frames of
**absolute joint angles** (degrees, y-up: `0`=forward/right, `90`=up, **absolute joint angles** (degrees, y-up: `0`=forward/right, `90`=up,
`180`=back/left, `-90`=down), a `root` pelvis position, and timing. `180`=back/left, `-90`=down), a `root` pelvis position, and timing.
@@ -22,6 +25,7 @@ changing data, never artwork.
{ {
"name": "Bird Dog", "name": "Bird Dog",
"primary": 2, // 1-based frame used for visual.svg "primary": 2, // 1-based frame used for visual.svg
"figure": "frontal", // optional profile override (default: neutral)
"working": ["arm_r", "leg_l"], // parts drawn in the accent color "working": ["arm_r", "leg_l"], // parts drawn in the accent color
"hide": [], // limbs fully occluded in this view "hide": [], // limbs fully occluded in this view
"frames": [ "frames": [
@@ -88,7 +92,10 @@ scale drawings of the machine.
- **`cable`** — a thin line from a fixed anchor `from` to a moving joint `to`; - **`cable`** — a thin line from a fixed anchor `from` to a moving joint `to`;
the machine's pulley line. the machine's pulley line.
- **`bar` / `dumbbell` / `pad`** — a segment centered on the joint(s) in - **`bar` / `dumbbell` / `pad`** — a segment centered on the joint(s) in
`at` (a single extremity, or the midpoint of `["hand_r", "hand_l"]`). `at` (a single joint, or the midpoint of a list). Joints are the extremities
(`hand_r`, `foot_l`, …) plus the mid joints (`elbow_r`, `knee_l`, …), so a
machine pad can ride a knee (`["knee_r", "knee_l"]`) or span a shin
(`["knee_r", "foot_r"]`).
`bar` lies at a fixed world `angle` (default 0 = horizontal — in side view a `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` two-handed bar is drawn horizontal by convention); `dumbbell` and `pad`
default to perpendicular to the lower bone (forearm/shin), or take an default to perpendicular to the lower bone (forearm/shin), or take an
@@ -5,10 +5,10 @@
<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 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 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 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="arm_l" d="M 155.6 39.6 L 174.0 63.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="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="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="arm_r" d="M 149.6 37.6 L 170.1 59.5 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 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"/> <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"/> <circle id="head" cx="153.1" cy="17.9" r="10" fill="white" stroke="#3a3f4b" stroke-width="6"/>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

+1 -1
View File
@@ -17,7 +17,7 @@
"hold": 0.4, "tween": 1.0, "hold": 0.4, "tween": 1.0,
"root": [140, 122], "root": [140, 122],
"spine": [85, 82], "neck": 80, "gaze": 5, "spine": [85, 82], "neck": 80, "gaze": 5,
"arm_r": [-10, -25], "arm_l": [-10, -25], "arm_r": [-40, -8], "arm_l": [-40, -8],
"leg_r": [-8, -75], "leg_l": [-8, -75], "leg_r": [-8, -75], "leg_l": [-8, -75],
"pins": {"hand_r": [200, 62], "hand_l": [204, 64], "pins": {"hand_r": [200, 62], "hand_l": [204, 64],
"foot_r": [188, 148], "foot_l": [192, 149]} "foot_r": [188, 148], "foot_l": [192, 149]}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 155 KiB

@@ -5,12 +5,12 @@
<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 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 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 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="arm_l" d="M 110.7 42.1 L 98.5 69.5 L 128.0 64.0" 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="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="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="arm_r" d="M 104.7 40.1 L 94.7 68.3 L 124.0 62.0" 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 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"/> <path d="M 126.0 69.0 L 126.0 57.0" 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"/> <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"/> <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"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -5,12 +5,12 @@
<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 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 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 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="arm_l" d="M 110.7 42.1 L 113.1 72.0 L 128.0 98.0" 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="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="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="arm_r" d="M 104.7 40.1 L 109.7 69.6 L 124.0 96.0" 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 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"/> <path d="M 126.0 103.0 L 126.0 91.0" 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"/> <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"/> <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"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

+6 -4
View File
@@ -17,17 +17,19 @@
"hold": 0.4, "tween": 1.1, "hold": 0.4, "tween": 1.1,
"root": [118, 124], "root": [118, 124],
"spine": [100, 98], "neck": 86, "gaze": 6, "spine": [100, 98], "neck": 86, "gaze": 6,
"arm_r": [-78, 30], "arm_l": [-78, 30], "arm_r": [-108, 12], "arm_l": [-108, 12],
"leg_r": [-24, -74], "leg_l": [-24, -74], "leg_r": [-24, -74], "leg_l": [-24, -74],
"pins": {"foot_r": [156, 151], "foot_l": [160, 152]} "pins": {"hand_r": [124, 62], "hand_l": [128, 64],
"foot_r": [156, 151], "foot_l": [160, 152]}
}, },
{ {
"hold": 0.4, "tween": 1.1, "hold": 0.4, "tween": 1.1,
"root": [118, 124], "root": [118, 124],
"spine": [100, 98], "neck": 86, "gaze": 6, "spine": [100, 98], "neck": 86, "gaze": 6,
"arm_r": [-78, -88], "arm_l": [-78, -88], "arm_r": [-81, -61], "arm_l": [-81, -61],
"leg_r": [-24, -74], "leg_l": [-24, -74], "leg_r": [-24, -74], "leg_l": [-24, -74],
"pins": {"foot_r": [156, 151], "foot_l": [160, 152]} "pins": {"hand_r": [124, 96], "hand_l": [128, 98],
"foot_r": [156, 151], "foot_l": [160, 152]}
} }
] ]
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 156 KiB

+3 -3
View File
@@ -5,12 +5,12 @@
<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 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 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 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="arm_l" d="M 110.7 42.1 L 113.1 72.0 L 128.0 98.0" 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="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="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="arm_r" d="M 104.7 40.1 L 109.7 69.6 L 124.0 96.0" 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 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"/> <path d="M 126.0 103.0 L 126.0 91.0" 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"/> <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"/> <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"> <g font-family="-apple-system, Helvetica, sans-serif" font-size="11" fill="#6b7180">

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

+11
View File
@@ -10,6 +10,17 @@
"shin": 40, "shin": 40,
"leftOffset": [6, 2] "leftOffset": [6, 2]
}, },
"frontal": {
"headR": 10,
"neck": 20,
"spine1": 43,
"spine2": 42,
"upperArm": 30,
"foreArm": 30,
"thigh": 22,
"shin": 26,
"leftOffset": [6, 2]
},
"female": { "female": {
"headR": 9, "headR": 9,
"neck": 19, "neck": 19,
Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 27 KiB

+20 -8
View File
@@ -57,7 +57,14 @@ LIMBS = { # limb -> (attach joint, [bone length keys], pin key)
ANGLE_KEYS = ["spine", "neck", "gaze", "arm_r", "arm_l", "leg_r", "leg_l"] 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"} # Prop joint refs -> (limb, chain index): extremities are index 2, mid joints
# (elbows/knees) index 1, so equipment can ride either joint.
JOINT_LIMB = {
"hand_r": ("arm_r", 2), "elbow_r": ("arm_r", 1),
"hand_l": ("arm_l", 2), "elbow_l": ("arm_l", 1),
"foot_r": ("leg_r", 2), "knee_r": ("leg_r", 1),
"foot_l": ("leg_l", 2), "knee_l": ("leg_l", 1),
}
def bodies(): def bodies():
@@ -244,17 +251,19 @@ def flip_props(props, width):
def joint_points(geo, ref): def joint_points(geo, ref):
"""Resolve a joint ref — `"hand_r"` or a `["hand_r", "hand_l"]` midpoint """Resolve a joint ref — `"hand_r"`, `"knee_l"`, or a midpoint list like
to (point, lower-bone unit direction). None when the limb isn't drawn.""" `["knee_r", "foot_r"]` — to (point, unit direction of the bone ending at
the first joint). None when the limb isn't drawn."""
names = ref if isinstance(ref, list) else [ref] names = ref if isinstance(ref, list) else [ref]
pts, direction = [], None pts, direction = [], None
for name in names: for name in names:
limb = geo.get(JOINT_LIMB[name]) limb_name, idx = JOINT_LIMB[name]
limb = geo.get(limb_name)
if not limb: if not limb:
return None, None return None, None
pts.append(limb[-1]) pts.append(limb[idx])
if direction is None: if direction is None:
a, b = limb[-2], limb[-1] a, b = limb[idx - 1], limb[idx]
d = math.hypot(b[0] - a[0], b[1] - a[1]) or 1.0 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) direction = ((b[0] - a[0]) / d, (b[1] - a[1]) / d)
return ((sum(p[0] for p in pts) / len(pts), return ((sum(p[0] for p in pts) / len(pts),
@@ -487,7 +496,9 @@ def export_app_resources(folders):
def render_exercise(folder, figure="neutral", flip=False): def render_exercise(folder, figure="neutral", flip=False):
motion = load_motion(folder) motion = load_motion(folder)
body = bodies()[figure] # A motion may pin its own profile (e.g. "frontal": foreshortened legs for
# face-on seated machines); it wins over the CLI default.
body = bodies()[motion.get("figure", figure)]
working = set(motion.get("working", [])) working = set(motion.get("working", []))
hide = set(motion.get("hide", [])) hide = set(motion.get("hide", []))
props = motion.get("props", []) props = motion.get("props", [])
@@ -521,10 +532,11 @@ def contact_sheet(folders, figure="neutral", out=None):
from PIL import Image, ImageDraw from PIL import Image, ImageDraw
font = legend_font() font = legend_font()
body = bodies()[figure] profiles = bodies()
cells = [] cells = []
for folder in folders: for folder in folders:
motion = load_motion(folder) motion = load_motion(folder)
body = profiles[motion.get("figure", figure)]
working, hide = set(motion.get("working", [])), set(motion.get("hide", [])) working, hide = set(motion.get("working", [])), set(motion.get("hide", []))
props = motion.get("props", []) props = motion.get("props", [])
for i, kf in enumerate(motion["frames"], start=1): for i, kf in enumerate(motion["frames"], start=1):
+20 -16
View File
@@ -70,29 +70,32 @@ struct SplitDocument: Codable {
// MARK: - Seed data (canonical source for Workouts/Resources/StarterSplits/*.json) // MARK: - Seed data (canonical source for Workouts/Resources/StarterSplits/*.json)
struct Ex { let name: String; var weight = 0; var sets = 4; var reps = 10; var load = 1; var dur = 0 } // `machine: true` emits `machineSettings: []` marks the exercise machine-based
// (empty = nothing recorded yet), which lights up the machine-settings UI without
// the user having to flip the editor toggle first.
struct Ex { let name: String; var weight = 0; var sets = 4; var reps = 10; var load = 1; var dur = 0; var machine = false }
struct Sp { let name: String; let color: String; let icon: String; let activity: Int; let ex: [Ex] } struct Sp { let name: String; let color: String; let icon: String; let activity: Int; let ex: [Ex] }
let seeds: [Sp] = [ let seeds: [Sp] = [
Sp(name: "Upper Body", color: "blue", icon: "figure.strengthtraining.traditional", activity: 0, ex: [ Sp(name: "Upper Body", color: "blue", icon: "figure.strengthtraining.traditional", activity: 0, ex: [
Ex(name: "Lat Pull Down", weight: 110), Ex(name: "Lat Pull Down", weight: 110, machine: true),
Ex(name: "Seated Row", weight: 90), Ex(name: "Seated Row", weight: 90, machine: true),
Ex(name: "Shoulder Press", weight: 40), Ex(name: "Shoulder Press", weight: 40, machine: true),
Ex(name: "Chest Press", weight: 40), Ex(name: "Chest Press", weight: 40, machine: true),
Ex(name: "Tricep Press", weight: 100), Ex(name: "Tricep Press", weight: 100, machine: true),
Ex(name: "Arm Curl", weight: 40), Ex(name: "Arm Curl", weight: 40, machine: true),
]), ]),
Sp(name: "Core", color: "orange", icon: "figure.core.training", activity: 3, ex: [ Sp(name: "Core", color: "orange", icon: "figure.core.training", activity: 3, ex: [
Ex(name: "Abdominal", weight: 40), Ex(name: "Abdominal", weight: 40, machine: true),
Ex(name: "Rotary", weight: 40), Ex(name: "Rotary", weight: 40, machine: true),
]), ]),
Sp(name: "Lower Body", color: "green", icon: "figure.run", activity: 0, ex: [ Sp(name: "Lower Body", color: "green", icon: "figure.run", activity: 0, ex: [
Ex(name: "Leg Press", weight: 140), Ex(name: "Leg Press", weight: 140, machine: true),
Ex(name: "Leg Curl", weight: 40), Ex(name: "Leg Curl", weight: 40, machine: true),
Ex(name: "Leg Extension", weight: 80), Ex(name: "Leg Extension", weight: 80, machine: true),
Ex(name: "Abductor", weight: 130), Ex(name: "Abductor", weight: 130, machine: true),
Ex(name: "Adductor", weight: 130), Ex(name: "Adductor", weight: 130, machine: true),
Ex(name: "Calfs", weight: 100), Ex(name: "Calfs", weight: 100, machine: true),
]), ]),
Sp(name: "Bodyweight Core", color: "teal", icon: "figure.core.training", activity: 3, ex: [ Sp(name: "Bodyweight Core", color: "teal", icon: "figure.core.training", activity: 3, ex: [
Ex(name: "Cat-Cow", sets: 1, reps: 10, load: 0), Ex(name: "Cat-Cow", sets: 1, reps: 10, load: 0),
@@ -128,7 +131,8 @@ for (order, sp) in seeds.enumerated() {
ExerciseDocument( ExerciseDocument(
id: deterministicULID(label: "starter.\(slug).ex\(idx)"), id: deterministicULID(label: "starter.\(slug).ex\(idx)"),
name: e.name, order: idx, sets: e.sets, reps: e.reps, weight: e.weight, name: e.name, order: idx, sets: e.sets, reps: e.reps, weight: e.weight,
loadType: e.load, durationSeconds: e.dur) loadType: e.load, durationSeconds: e.dur,
machineSettings: e.machine ? [] : nil)
}, },
activityType: sp.activity) activityType: sp.activity)
let data = try encoder.encode(doc) let data = try encoder.encode(doc)
@@ -140,16 +140,27 @@ struct ExerciseFigureView: View {
// MARK: Props // MARK: Props
/// The extremity point a prop follows (plus the lower-bone unit direction for /// Prop joint refs (limb, chain index): extremities are index 2, mid joints
/// perpendicular items). Nil when any referenced limb isn't drawn this frame. /// (elbows/knees) index 1, so equipment can ride either joint. Kept 1:1 with
/// the reference renderer's `JOINT_LIMB`.
private static let propJoints: [String: (limb: FigureLimb, index: Int)] = [
"hand_r": (.armR, 2), "elbow_r": (.armR, 1),
"hand_l": (.armL, 2), "elbow_l": (.armL, 1),
"foot_r": (.legR, 2), "knee_r": (.legR, 1),
"foot_l": (.legL, 2), "knee_l": (.legL, 1),
]
/// The joint point a prop follows (plus the unit direction of the bone ending
/// at the first joint, for perpendicular items). Nil when any referenced limb
/// isn't drawn this frame.
private func jointAnchor(_ geo: FigureGeometry, _ ref: PropJointRef) -> (point: CGPoint, direction: CGVector)? { private func jointAnchor(_ geo: FigureGeometry, _ ref: PropJointRef) -> (point: CGPoint, direction: CGVector)? {
var points: [CGPoint] = [] var points: [CGPoint] = []
var direction: CGVector? var direction: CGVector?
for name in ref.names { for name in ref.names {
guard let limb = FigureLimb.allCases.first(where: { $0.pinKey == name }), guard let joint = Self.propJoints[name],
let chain = geo.limbs[limb], chain.count >= 2 else { return nil } let chain = geo.limbs[joint.limb], chain.count > joint.index else { return nil }
let a = chain[chain.count - 2] let a = chain[joint.index - 1]
let b = chain[chain.count - 1] let b = chain[joint.index]
points.append(b) points.append(b)
if direction == nil { if direction == nil {
let d = max(hypot(b.x - a.x, b.y - a.y), 1) let d = max(hypot(b.x - a.x, b.y - a.y), 1)
@@ -22,6 +22,13 @@ struct ExerciseInfo {
var targets: [String] var targets: [String]
var sections: [Section] var sections: [Section]
/// Whether the authored `Type:` identifies this as a machine exercise the
/// library convention is that every machine entry's type starts "Machine-based".
/// Drives the machine-settings sections' visibility before any settings exist.
var isMachineBased: Bool {
type?.localizedCaseInsensitiveContains("machine") == true
}
struct Section { struct Section {
var title: String var title: String
var items: [Item] var items: [Item]
+7 -3
View File
@@ -35,6 +35,9 @@ struct ExerciseMotion: Codable {
let name: String let name: String
/// 1-based frame used for the static visual (unused by the animated renderer). /// 1-based frame used for the static visual (unused by the animated renderer).
let primary: Int? let primary: Int?
/// Body-profile override (e.g. `"frontal"`: foreshortened legs for face-on
/// seated machines). Nil uses the `neutral` profile.
let figure: String?
/// Parts (`arm_r`, `leg_l`, `spine`, ) drawn in the working accent color. /// Parts (`arm_r`, `leg_l`, `spine`, ) drawn in the working accent color.
let working: [String]? let working: [String]?
/// Limbs fully occluded in this view never drawn. /// Limbs fully occluded in this view never drawn.
@@ -45,8 +48,9 @@ struct ExerciseMotion: Codable {
let frames: [MotionKeyFrame] let frames: [MotionKeyFrame]
} }
/// A prop's joint reference: one extremity (`"hand_r"`) or the midpoint of two /// A prop's joint reference: one joint (`"hand_r"`, `"knee_l"`, `"elbow_r"`, )
/// (`["foot_r", "foot_l"]`). Extremity keys match the pin keys. /// or the midpoint of two (`["foot_r", "foot_l"]`, `["knee_r", "foot_r"]`).
/// Extremity keys match the pin keys; elbows/knees are the mid joints.
enum PropJointRef: Codable { enum PropJointRef: Codable {
case single(String) case single(String)
case midpoint([String]) case midpoint([String])
@@ -180,7 +184,7 @@ enum ExerciseMotionLibrary {
let bodyData = try? Data(contentsOf: bodyURL), let bodyData = try? Data(contentsOf: bodyURL),
let motion = try? JSONDecoder().decode(ExerciseMotion.self, from: motionData), let motion = try? JSONDecoder().decode(ExerciseMotion.self, from: motionData),
let profiles = try? JSONDecoder().decode([String: ExerciseBodyProfile].self, from: bodyData), let profiles = try? JSONDecoder().decode([String: ExerciseBodyProfile].self, from: bodyData),
let body = profiles["neutral"] let body = profiles[motion.figure ?? "neutral"]
else { return nil } else { return nil }
return Resources(motion: motion, body: body) return Resources(motion: motion, body: body)
} }
@@ -1,17 +1,17 @@
{ {
"name": "Abductor", "name": "Abductor",
"primary": 2, "primary": 2,
"figure": "frontal",
"working": ["leg_r", "leg_l"], "working": ["leg_r", "leg_l"],
"hide": [], "hide": [],
"props": [ "props": [
{"type": "scene", "shapes": [ {"type": "scene", "shapes": [
{"kind": "rect", "x": 152, "y": 56, "w": 16, "h": 72, "r": 5}, {"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": "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": [[160, 136], [160, 150]], "w": 6}
{"kind": "line", "pts": [[188, 78], [188, 108]], "w": 4, "color": "prop"}, ]},
{"kind": "line", "pts": [[213, 110], [213, 132]], "w": 9, "color": "prop"}, {"type": "pad", "at": ["knee_r"], "angle": 90, "halfLen": 13, "w": 6},
{"kind": "line", "pts": [[107, 110], [107, 132]], "w": 9, "color": "prop"} {"type": "pad", "at": ["knee_l"], "angle": 90, "halfLen": 13, "w": 6}
]}
], ],
"frames": [ "frames": [
{ {
@@ -19,16 +19,14 @@
"root": [160, 116], "root": [160, 116],
"spine": [90, 90], "neck": 90, "spine": [90, 90], "neck": 90,
"arm_r": [-48, -82], "arm_l": [-132, -98], "arm_r": [-48, -82], "arm_l": [-132, -98],
"leg_r": [-22, 0], "leg_l": [-158, 0], "leg_r": [-75, -90], "leg_l": [-105, -90]
"pins": {"foot_r": [180, 156], "foot_l": [140, 156]}
}, },
{ {
"hold": 0.5, "tween": 1.1, "hold": 0.5, "tween": 1.1,
"root": [160, 116], "root": [160, 116],
"spine": [90, 90], "neck": 90, "spine": [90, 90], "neck": 90,
"arm_r": [-48, -82], "arm_l": [-132, -98], "arm_r": [-48, -82], "arm_l": [-132, -98],
"leg_r": [-22, 0], "leg_l": [-158, 0], "leg_r": [-30, -90], "leg_l": [-150, -90]
"pins": {"foot_r": [216, 156], "foot_l": [104, 156]}
} }
] ]
} }
@@ -1,17 +1,17 @@
{ {
"name": "Adductor", "name": "Adductor",
"primary": 2, "primary": 2,
"figure": "frontal",
"working": ["leg_r", "leg_l"], "working": ["leg_r", "leg_l"],
"hide": [], "hide": [],
"props": [ "props": [
{"type": "scene", "shapes": [ {"type": "scene", "shapes": [
{"kind": "rect", "x": 152, "y": 56, "w": 16, "h": 72, "r": 5}, {"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": "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": [[160, 136], [160, 150]], "w": 6}
{"kind": "line", "pts": [[188, 78], [188, 108]], "w": 4, "color": "prop"}, ]},
{"kind": "line", "pts": [[197, 110], [197, 132]], "w": 9, "color": "prop"}, {"type": "pad", "at": ["knee_r"], "angle": 90, "halfLen": 13, "w": 6},
{"kind": "line", "pts": [[123, 110], [123, 132]], "w": 9, "color": "prop"} {"type": "pad", "at": ["knee_l"], "angle": 90, "halfLen": 13, "w": 6}
]}
], ],
"frames": [ "frames": [
{ {
@@ -19,16 +19,14 @@
"root": [160, 116], "root": [160, 116],
"spine": [90, 90], "neck": 90, "spine": [90, 90], "neck": 90,
"arm_r": [-48, -82], "arm_l": [-132, -98], "arm_r": [-48, -82], "arm_l": [-132, -98],
"leg_r": [-22, 0], "leg_l": [-158, 0], "leg_r": [-30, -90], "leg_l": [-150, -90]
"pins": {"foot_r": [216, 156], "foot_l": [104, 156]}
}, },
{ {
"hold": 0.5, "tween": 1.1, "hold": 0.5, "tween": 1.1,
"root": [160, 116], "root": [160, 116],
"spine": [90, 90], "neck": 90, "spine": [90, 90], "neck": 90,
"arm_r": [-48, -82], "arm_l": [-132, -98], "arm_r": [-48, -82], "arm_l": [-132, -98],
"leg_r": [-22, 0], "leg_l": [-158, 0], "leg_r": [-75, -90], "leg_l": [-105, -90]
"pins": {"foot_r": [180, 156], "foot_l": [140, 156]}
} }
] ]
} }
@@ -6,8 +6,8 @@
"props": [ "props": [
{"type": "scene", "shapes": [ {"type": "scene", "shapes": [
{"kind": "line", "pts": [[116, 134], [150, 134]], "w": 8}, {"kind": "line", "pts": [[116, 134], [150, 134]], "w": 8},
{"kind": "line", "pts": [[146, 42], [176, 68]], "w": 8}, {"kind": "line", "pts": [[136, 52], [164, 70]], "w": 8},
{"kind": "line", "pts": [[176, 68], [176, 128]], "w": 5} {"kind": "line", "pts": [[164, 70], [164, 128]], "w": 5}
]}, ]},
{"type": "bar", "at": ["hand_r", "hand_l"], "angle": 90, "halfLen": 6} {"type": "bar", "at": ["hand_r", "hand_l"], "angle": 90, "halfLen": 6}
], ],
@@ -16,7 +16,7 @@
"hold": 0.4, "tween": 1.0, "hold": 0.4, "tween": 1.0,
"root": [130, 124], "root": [130, 124],
"spine": [88, 86], "neck": 82, "gaze": -18, "spine": [88, 86], "neck": 82, "gaze": -18,
"arm_r": [-35, -52], "arm_l": [-35, -52], "arm_r": [-35, -58], "arm_l": [-35, -58],
"leg_r": [-8, -72], "leg_l": [-8, -72], "leg_r": [-8, -72], "leg_l": [-8, -72],
"pins": {"foot_r": [176, 150], "foot_l": [180, 151]} "pins": {"foot_r": [176, 150], "foot_l": [180, 151]}
}, },
@@ -24,7 +24,7 @@
"hold": 0.4, "tween": 1.2, "hold": 0.4, "tween": 1.2,
"root": [130, 124], "root": [130, 124],
"spine": [88, 86], "neck": 82, "gaze": -18, "spine": [88, 86], "neck": 82, "gaze": -18,
"arm_r": [-35, 138], "arm_l": [-35, 138], "arm_r": [-35, 50], "arm_l": [-35, 50],
"leg_r": [-8, -72], "leg_l": [-8, -72], "leg_r": [-8, -72], "leg_l": [-8, -72],
"pins": {"foot_r": [176, 150], "foot_l": [180, 151]} "pins": {"foot_r": [176, 150], "foot_l": [180, 151]}
} }
@@ -1,7 +1,7 @@
{ {
"name": "Bird Dog", "name": "Bird Dog",
"primary": 2, "primary": 2,
"working": ["arm_r", "leg_l"], "working": ["arm_r", "leg_l", "arm_l", "leg_r"],
"frames": [ "frames": [
{ {
"hold": 0.5, "tween": 0.8, "hold": 0.5, "tween": 0.8,
@@ -18,6 +18,22 @@
"arm_r": [161, 161], "arm_l": [-90, -90], "arm_r": [161, 161], "arm_l": [-90, -90],
"leg_r": [-83, 0], "leg_l": [15, 15], "leg_r": [-83, 0], "leg_l": [15, 15],
"pins": {"hand_l": [111, 154]} "pins": {"hand_l": [111, 154]}
},
{
"hold": 0.5, "tween": 0.8,
"root": [190, 106],
"spine": [171, 171], "neck": 187, "gaze": 205,
"arm_r": [-90, -90], "arm_l": [-90, -90],
"leg_r": [-83, 0], "leg_l": [-83, 0],
"pins": {"hand_r": [105, 152], "hand_l": [111, 154]}
},
{
"hold": 1.4, "tween": 0.8,
"root": [190, 106],
"spine": [171, 171], "neck": 187, "gaze": 195,
"arm_r": [-90, -90], "arm_l": [161, 161],
"leg_r": [15, 15], "leg_l": [-83, 0],
"pins": {"hand_r": [105, 152]}
} }
] ]
} }
@@ -9,10 +9,10 @@
{"kind": "line", "pts": [[138, 128], [138, 150]], "w": 5}, {"kind": "line", "pts": [[138, 128], [138, 150]], "w": 5},
{"kind": "line", "pts": [[120, 150], [156, 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": "rect", "x": 198, "y": 147, "w": 34, "h": 6, "r": 1},
{"kind": "line", "pts": [[183, 62], [183, 124]], "w": 4}, {"kind": "line", "pts": [[183, 62], [183, 122]], "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"} {"kind": "line", "pts": [[164, 76], [183, 76]], "w": 3, "color": "prop"}
]}, ]},
{"type": "pad", "at": ["knee_r", "knee_l"], "angle": 0, "halfLen": 14, "w": 7},
{"type": "pad", "at": ["foot_r", "foot_l"], "angle": 15, "halfLen": 7, "w": 5} {"type": "pad", "at": ["foot_r", "foot_l"], "angle": 15, "halfLen": 7, "w": 5}
], ],
"frames": [ "frames": [
@@ -1,7 +1,7 @@
{ {
"name": "Dead Bug", "name": "Dead Bug",
"primary": 2, "primary": 2,
"working": ["arm_r", "leg_l"], "working": ["arm_r", "leg_l", "arm_l", "leg_r"],
"frames": [ "frames": [
{ {
"hold": 0.5, "tween": 0.8, "hold": 0.5, "tween": 0.8,
@@ -16,6 +16,20 @@
"spine": [180, 180], "neck": 168, "gaze": 90, "spine": [180, 180], "neck": 168, "gaze": 90,
"arm_r": [135, 135], "arm_l": [90, 90], "arm_r": [135, 135], "arm_l": [90, 90],
"leg_r": [64, -10], "leg_l": [16, 16] "leg_r": [64, -10], "leg_l": [16, 16]
},
{
"hold": 0.5, "tween": 0.8,
"root": [185, 148],
"spine": [180, 180], "neck": 168, "gaze": 90,
"arm_r": [90, 90], "arm_l": [90, 90],
"leg_r": [64, -10], "leg_l": [64, -10]
},
{
"hold": 0.9, "tween": 0.8,
"root": [185, 148],
"spine": [180, 180], "neck": 168, "gaze": 90,
"arm_r": [90, 90], "arm_l": [135, 135],
"leg_r": [16, 16], "leg_l": [64, -10]
} }
] ]
} }
@@ -6,30 +6,29 @@
"props": [ "props": [
{"type": "scene", "shapes": [ {"type": "scene", "shapes": [
{"kind": "line", "pts": [[126, 130], [162, 130]], "w": 8}, {"kind": "line", "pts": [[126, 130], [162, 130]], "w": 8},
{"kind": "line", "pts": [[124, 130], [124, 56]], "w": 5}, {"kind": "line", "pts": [[144, 132], [144, 150]], "w": 5},
{"kind": "line", "pts": [[124, 56], [198, 12]], "w": 5}, {"kind": "circle", "c": [272, 19], "r": 4, "fill": true, "color": "prop"}
{"kind": "rect", "x": 170, "y": 112, "w": 40, "h": 7, "r": 3}
]}, ]},
{"type": "cable", "from": [198, 8], "to": ["hand_r", "hand_l"]}, {"type": "cable", "from": [272, 19], "to": ["hand_r", "hand_l"], "w": 4},
{"type": "bar", "at": ["hand_r", "hand_l"], "halfLen": 28} {"type": "bar", "at": ["hand_r", "hand_l"], "halfLen": 24}
], ],
"frames": [ "frames": [
{ {
"hold": 0.4, "tween": 1.0, "hold": 0.4, "tween": 1.0,
"root": [150, 122], "root": [150, 122],
"spine": [93, 90], "neck": 85, "gaze": 55, "spine": [93, 90], "neck": 85, "gaze": 55,
"arm_r": [20, 10], "arm_l": [20, 10], "arm_r": [35, 35], "arm_l": [35, 35],
"leg_r": [-12, -80], "leg_l": [-12, -80], "leg_r": [-12, -80], "leg_l": [-12, -80],
"pins": {"hand_r": [198, 24], "hand_l": [202, 26], "pins": {"hand_r": [194, 1], "hand_l": [198, 3],
"foot_r": [193, 150], "foot_l": [197, 151]} "foot_r": [193, 150], "foot_l": [197, 151]}
}, },
{ {
"hold": 0.4, "tween": 1.2, "hold": 0.4, "tween": 1.2,
"root": [150, 122], "root": [150, 122],
"spine": [93, 90], "neck": 85, "gaze": 30, "spine": [93, 90], "neck": 85, "gaze": 30,
"arm_r": [-115, -20], "arm_l": [-115, -20], "arm_r": [-38, 38], "arm_l": [-38, 38],
"leg_r": [-12, -80], "leg_l": [-12, -80], "leg_r": [-12, -80], "leg_l": [-12, -80],
"pins": {"hand_r": [165, 66], "hand_l": [169, 68], "pins": {"hand_r": [194, 35], "hand_l": [198, 37],
"foot_r": [193, 150], "foot_l": [197, 151]} "foot_r": [193, 150], "foot_l": [197, 151]}
} }
] ]
@@ -17,7 +17,7 @@
"hold": 0.4, "tween": 1.0, "hold": 0.4, "tween": 1.0,
"root": [140, 122], "root": [140, 122],
"spine": [85, 82], "neck": 80, "gaze": 5, "spine": [85, 82], "neck": 80, "gaze": 5,
"arm_r": [-10, -25], "arm_l": [-10, -25], "arm_r": [-40, -8], "arm_l": [-40, -8],
"leg_r": [-8, -75], "leg_l": [-8, -75], "leg_r": [-8, -75], "leg_l": [-8, -75],
"pins": {"hand_r": [200, 62], "hand_l": [204, 64], "pins": {"hand_r": [200, 62], "hand_l": [204, 64],
"foot_r": [188, 148], "foot_l": [192, 149]} "foot_r": [188, 148], "foot_l": [192, 149]}
@@ -17,17 +17,19 @@
"hold": 0.4, "tween": 1.1, "hold": 0.4, "tween": 1.1,
"root": [118, 124], "root": [118, 124],
"spine": [100, 98], "neck": 86, "gaze": 6, "spine": [100, 98], "neck": 86, "gaze": 6,
"arm_r": [-78, 30], "arm_l": [-78, 30], "arm_r": [-108, 12], "arm_l": [-108, 12],
"leg_r": [-24, -74], "leg_l": [-24, -74], "leg_r": [-24, -74], "leg_l": [-24, -74],
"pins": {"foot_r": [156, 151], "foot_l": [160, 152]} "pins": {"hand_r": [124, 62], "hand_l": [128, 64],
"foot_r": [156, 151], "foot_l": [160, 152]}
}, },
{ {
"hold": 0.4, "tween": 1.1, "hold": 0.4, "tween": 1.1,
"root": [118, 124], "root": [118, 124],
"spine": [100, 98], "neck": 86, "gaze": 6, "spine": [100, 98], "neck": 86, "gaze": 6,
"arm_r": [-78, -88], "arm_l": [-78, -88], "arm_r": [-81, -61], "arm_l": [-81, -61],
"leg_r": [-24, -74], "leg_l": [-24, -74], "leg_r": [-24, -74], "leg_l": [-24, -74],
"pins": {"foot_r": [156, 151], "foot_l": [160, 152]} "pins": {"hand_r": [124, 96], "hand_l": [128, 98],
"foot_r": [156, 151], "foot_l": [160, 152]}
} }
] ]
} }
@@ -10,6 +10,17 @@
"shin": 40, "shin": 40,
"leftOffset": [6, 2] "leftOffset": [6, 2]
}, },
"frontal": {
"headR": 10,
"neck": 20,
"spine1": 43,
"spine2": 42,
"upperArm": 30,
"foreArm": 30,
"thigh": 22,
"shin": 26,
"leftOffset": [6, 2]
},
"female": { "female": {
"headR": 9, "headR": 9,
"neck": 19, "neck": 19,
@@ -7,6 +7,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT00C4K0NY1NRCFPB3XY", "id" : "01DXF6DT00C4K0NY1NRCFPB3XY",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Abdominal", "name" : "Abdominal",
"order" : 0, "order" : 0,
"reps" : 10, "reps" : 10,
@@ -17,6 +20,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT001AY3SXTEYHA94MHZ", "id" : "01DXF6DT001AY3SXTEYHA94MHZ",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Rotary", "name" : "Rotary",
"order" : 1, "order" : 1,
"reps" : 10, "reps" : 10,
@@ -7,6 +7,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT00GV3336R9C25W4X2A", "id" : "01DXF6DT00GV3336R9C25W4X2A",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Leg Press", "name" : "Leg Press",
"order" : 0, "order" : 0,
"reps" : 10, "reps" : 10,
@@ -17,6 +20,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT00Z28DJ7PSP7Q11CJH", "id" : "01DXF6DT00Z28DJ7PSP7Q11CJH",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Leg Curl", "name" : "Leg Curl",
"order" : 1, "order" : 1,
"reps" : 10, "reps" : 10,
@@ -27,6 +33,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT00D53Q4QMWAE1BHXR6", "id" : "01DXF6DT00D53Q4QMWAE1BHXR6",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Leg Extension", "name" : "Leg Extension",
"order" : 2, "order" : 2,
"reps" : 10, "reps" : 10,
@@ -37,6 +46,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT006HW2KWNA5BCCDCJE", "id" : "01DXF6DT006HW2KWNA5BCCDCJE",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Abductor", "name" : "Abductor",
"order" : 3, "order" : 3,
"reps" : 10, "reps" : 10,
@@ -47,6 +59,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT00H5B5YD16868Y95ZQ", "id" : "01DXF6DT00H5B5YD16868Y95ZQ",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Adductor", "name" : "Adductor",
"order" : 4, "order" : 4,
"reps" : 10, "reps" : 10,
@@ -57,6 +72,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT002S88DB6NKYZS4EAW", "id" : "01DXF6DT002S88DB6NKYZS4EAW",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Calfs", "name" : "Calfs",
"order" : 5, "order" : 5,
"reps" : 10, "reps" : 10,
@@ -7,6 +7,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT00N1B90PA7K5ABWSSP", "id" : "01DXF6DT00N1B90PA7K5ABWSSP",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Lat Pull Down", "name" : "Lat Pull Down",
"order" : 0, "order" : 0,
"reps" : 10, "reps" : 10,
@@ -17,6 +20,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT00R81QRWGCCQG933FZ", "id" : "01DXF6DT00R81QRWGCCQG933FZ",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Seated Row", "name" : "Seated Row",
"order" : 1, "order" : 1,
"reps" : 10, "reps" : 10,
@@ -27,6 +33,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT000FX4241G5MPG4WG2", "id" : "01DXF6DT000FX4241G5MPG4WG2",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Shoulder Press", "name" : "Shoulder Press",
"order" : 2, "order" : 2,
"reps" : 10, "reps" : 10,
@@ -37,6 +46,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT00AD5TSVJPZZVA2S41", "id" : "01DXF6DT00AD5TSVJPZZVA2S41",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Chest Press", "name" : "Chest Press",
"order" : 3, "order" : 3,
"reps" : 10, "reps" : 10,
@@ -47,6 +59,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT006QZ6XT95301HKJT8", "id" : "01DXF6DT006QZ6XT95301HKJT8",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Tricep Press", "name" : "Tricep Press",
"order" : 4, "order" : 4,
"reps" : 10, "reps" : 10,
@@ -57,6 +72,9 @@
"durationSeconds" : 0, "durationSeconds" : 0,
"id" : "01DXF6DT009J5H4Z0XPHBT1H0K", "id" : "01DXF6DT009J5H4Z0XPHBT1H0K",
"loadType" : 1, "loadType" : 1,
"machineSettings" : [
],
"name" : "Arm Curl", "name" : "Arm Curl",
"order" : 5, "order" : 5,
"reps" : 10, "reps" : 10,
+18
View File
@@ -311,6 +311,24 @@ final class SyncEngine {
do { try context.save() } catch { report("Cache save failed", error) } do { try context.save() } catch { report("Cache save failed", error) }
} }
/// Push edited machine settings onto the originating split's exercise (matched
/// by name logs reference exercises by name only), following the seed
/// clone-on-edit redirect so the live clone is updated. Skips silently when the
/// split is gone or no exercise matches, and when nothing changed (so a pristine
/// seed isn't needlessly forked). Never caches the split's id across the save,
/// since saving a seed mints a new one.
func writeBackMachineSettings(_ settings: [MachineSetting], exerciseName: String, splitID: String?) async {
guard let splitID else { return }
let liveID = currentSplitID(for: splitID)
guard let split = CacheMapper.fetchSplit(id: liveID, in: context) else { return }
var splitDoc = SplitDocument(from: split)
guard let idx = splitDoc.exercises.firstIndex(where: { $0.name == exerciseName }) else { return }
guard splitDoc.exercises[idx].machineSettings != settings else { return }
splitDoc.exercises[idx].machineSettings = settings
splitDoc.updatedAt = Date()
await save(split: splitDoc)
}
func save(workout doc: WorkoutDocument) async { func save(workout doc: WorkoutDocument) async {
guard let store else { return } guard let store else { return }
do { do {
@@ -6,6 +6,7 @@
// //
import SwiftUI import SwiftUI
import SwiftData
/// The Exercises library screen, pushed from Settings Library: every exercise with /// The Exercises library screen, pushed from Settings Library: every exercise with
/// a bundled motion rig (the same catalog the picker offers), each opening its /// a bundled motion rig (the same catalog the picker offers), each opening its
@@ -21,22 +22,73 @@ struct ExerciseLibraryView: View {
} }
} }
/// One library exercise, in the standard half-and-half exercise layout: the authored /// One library exercise, in the standard half-and-half exercise layout: the top half
/// reference content (summary, targets, setup/execution/cues) scrolls in the top /// scrolls the user's machine settings (their setup cheat-sheet), the authored
/// half, the looping form-guide figure holds the bottom. Falls back to a full-screen /// reference content (summary, targets, setup/execution/cues), and the weight
/// figure when no `info.md` is bundled. /// progression chart; the looping form-guide figure holds the bottom.
struct ExerciseLibraryDetailView: View { struct ExerciseLibraryDetailView: View {
let exerciseName: String let exerciseName: String
/// This exercise wherever it appears in the user's splits the source of the
/// recorded machine settings.
@Query private var exercises: [Exercise]
/// One completed weighted log is enough to justify the progression chart;
/// bodyweight and timed exercises never accrue one, so they skip the chart
/// instead of plotting a flat zero line.
@Query private var weightedLogs: [WorkoutLog]
init(exerciseName: String) {
self.exerciseName = exerciseName
let name = exerciseName
_exercises = Query(filter: #Predicate<Exercise> { $0.name == name })
let completedRaw = WorkoutStatus.completed.rawValue
_weightedLogs = Query(filter: #Predicate<WorkoutLog> {
$0.exerciseName == name && $0.statusRaw == completedRaw && $0.weight > 0
})
}
private var info: ExerciseInfo? { private var info: ExerciseInfo? {
ExerciseInfoLibrary.info(for: exerciseName) ExerciseInfoLibrary.info(for: exerciseName)
} }
/// Distinct recorded machine-settings lists for this exercise. Usually one; when
/// splits disagree, each distinct list keeps its split's name as a label.
private var settingsGroups: [(label: String?, settings: [MachineSetting])] {
var groups: [(label: String?, settings: [MachineSetting])] = []
for exercise in exercises {
guard let settings = exercise.machineSettings, !settings.isEmpty else { continue }
guard !groups.contains(where: { $0.settings == settings }) else { continue }
groups.append((exercise.split?.name, settings))
}
if groups.count == 1 { groups[0].label = nil }
return groups
}
var body: some View { var body: some View {
VStack(spacing: 0) { VStack(spacing: 0) {
ScrollView {
VStack(alignment: .leading, spacing: 16) {
// Show the card whenever settings are recorded or, for an
// exercise the authored info identifies as machine-based, as an
// empty state, so the feature is discoverable before first use.
if !settingsGroups.isEmpty {
MachineSettingsCard(groups: settingsGroups)
} else if info?.isMachineBased == true {
MachineSettingsCard(groups: [])
}
if let info { if let info {
ExerciseInfoContent(info: info) ExerciseInfoContent(info: info)
} }
if !weightedLogs.isEmpty {
WeightProgressionChartView(exerciseName: exerciseName)
}
}
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
ExerciseFigureSlot(exerciseName: exerciseName) ExerciseFigureSlot(exerciseName: exerciseName)
} }
.navigationTitle(exerciseName) .navigationTitle(exerciseName)
@@ -44,13 +96,55 @@ struct ExerciseLibraryDetailView: View {
} }
} }
/// The user's recorded machine comfort settings, set apart from the reference text
/// as a card: namevalue rows, grouped per split when the recorded lists differ.
/// Empty `groups` renders the not-yet-recorded state (shown for machine-based
/// exercises so the feature is visible before first use).
private struct MachineSettingsCard: View {
let groups: [(label: String?, settings: [MachineSetting])]
var body: some View {
VStack(alignment: .leading, spacing: 8) {
Text("Your Machine Settings")
.font(.headline)
if groups.isEmpty {
Text("None recorded yet. Mark the exercise as machine-based in its editor, or use the settings button on the workout screen.")
.font(.callout)
.foregroundStyle(.secondary)
}
ForEach(Array(groups.enumerated()), id: \.offset) { _, group in
VStack(alignment: .leading, spacing: 4) {
if let label = group.label {
Text(label)
.font(.caption)
.foregroundStyle(.secondary)
}
ForEach(Array(group.settings.enumerated()), id: \.offset) { _, setting in
HStack(alignment: .firstTextBaseline) {
Text(setting.name)
.foregroundStyle(.secondary)
Spacer()
Text(setting.value)
.fontWeight(.semibold)
.monospacedDigit()
}
.font(.callout)
}
}
}
}
.padding(12)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(.secondarySystemBackground), in: RoundedRectangle(cornerRadius: 12))
}
}
/// Renders a parsed `ExerciseInfo`: summary, target chips, then each authored /// Renders a parsed `ExerciseInfo`: summary, target chips, then each authored
/// section with its numbered steps or bullets. /// section with its numbered steps or bullets.
private struct ExerciseInfoContent: View { private struct ExerciseInfoContent: View {
let info: ExerciseInfo let info: ExerciseInfo
var body: some View { var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 16) { VStack(alignment: .leading, spacing: 16) {
if !info.summary.isEmpty { if !info.summary.isEmpty {
Text(info.summary) Text(info.summary)
@@ -72,10 +166,6 @@ private struct ExerciseInfoContent: View {
} }
} }
} }
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
/// Steps number themselves by their position among the section's steps, so an /// Steps number themselves by their position among the section's steps, so an
+72 -1
View File
@@ -12,6 +12,7 @@ import SwiftData
import Charts import Charts
struct ExerciseView: View { struct ExerciseView: View {
@Environment(SyncEngine.self) private var sync
@Environment(AppServices.self) private var services @Environment(AppServices.self) private var services
let workout: Workout let workout: Workout
@@ -23,6 +24,7 @@ struct ExerciseView: View {
@State private var doc: WorkoutDocument @State private var doc: WorkoutDocument
@State private var showingPlanEdit = false @State private var showingPlanEdit = false
@State private var showingNotesEdit = false @State private var showingNotesEdit = false
@State private var showingMachineSettings = false
/// `seedDoc` lets the caller hand over an in-memory document (e.g. the parent's /// `seedDoc` lets the caller hand over an in-memory document (e.g. the parent's
/// working copy right after adding an exercise) so the screen doesn't wait on /// working copy right after adding an exercise) so the screen doesn't wait on
@@ -41,6 +43,9 @@ struct ExerciseView: View {
var body: some View { var body: some View {
Group { Group {
if let log { if let log {
// Deliberately NOT the half-and-half figure layout: this screen is
// dense with the plan, notes, settings, and the progression chart
// the form guide lives in the run flow and the exercise library.
content(for: log) content(for: log)
} else { } else {
// The just-added log hasn't reached the cache yet; refresh shortly. // The just-added log hasn't reached the cache yet; refresh shortly.
@@ -54,6 +59,16 @@ struct ExerciseView: View {
.sheet(isPresented: $showingNotesEdit) { .sheet(isPresented: $showingNotesEdit) {
NotesEditView(workout: workout, logID: logID) NotesEditView(workout: workout, logID: logID)
} }
.sheet(isPresented: $showingMachineSettings) {
if let log {
MachineSettingsSheet(
exerciseName: log.exerciseName,
initialSettings: log.machineSettings ?? []
) { updated in
applyMachineSettings(updated)
}
}
}
.onAppear { .onAppear {
refreshDocIfNeeded() refreshDocIfNeeded()
// Take over this run: the watch parks and locks it while we're editing here. // Take over this run: the watch parks and locks it while we're editing here.
@@ -94,6 +109,42 @@ struct ExerciseView: View {
} }
} }
// MARK: - Machine Settings shown when the log carries settings, or for
// any exercise the authored library identifies as machine-based, so the
// section is discoverable before settings are first recorded.
if log.machineSettings != nil
|| ExerciseInfoLibrary.info(for: log.exerciseName)?.isMachineBased == true {
let settings = log.machineSettings ?? []
Section {
if settings.isEmpty {
Text("No settings recorded")
.foregroundColor(.secondary)
.italic()
} else {
ForEach(Array(settings.enumerated()), id: \.offset) { _, setting in
HStack(alignment: .firstTextBaseline) {
Text(setting.name)
.foregroundStyle(.secondary)
Spacer()
Text(setting.value)
.fontWeight(.semibold)
.monospacedDigit()
}
}
}
} header: {
HStack {
Text("Machine Settings")
Spacer()
Button("Edit") {
showingMachineSettings = true
}
.font(.subheadline)
.textCase(.none)
}
}
}
// MARK: - Notes Section (Read-only with Edit button) // MARK: - Notes Section (Read-only with Edit button)
Section { Section {
if let notes = log.notes, !notes.isEmpty { if let notes = log.notes, !notes.isEmpty {
@@ -116,11 +167,14 @@ struct ExerciseView: View {
} }
} }
// MARK: - Progress Tracking Chart // MARK: - Progress Tracking Chart (weighted exercises only a weight
// chart is meaningless for bodyweight/timed logs)
if LoadType(rawValue: log.loadType) == .weight {
Section(header: Text("Progress Tracking")) { Section(header: Text("Progress Tracking")) {
WeightProgressionChartView(exerciseName: log.exerciseName) WeightProgressionChartView(exerciseName: log.exerciseName)
} }
} }
}
// Pull plan/notes edits made in the sheets back into the live doc. // Pull plan/notes edits made in the sheets back into the live doc.
.onChange(of: showingPlanEdit) { _, presenting in .onChange(of: showingPlanEdit) { _, presenting in
if !presenting { refreshDocFromCache() } if !presenting { refreshDocFromCache() }
@@ -130,6 +184,23 @@ struct ExerciseView: View {
} }
} }
/// Apply edited machine settings: update the log's plan-time snapshot (persisted
/// with the workout), then write the same settings back to the originating
/// split's exercise as the durable default same sequencing as the workout
/// list's machine sheet.
private func applyMachineSettings(_ settings: [MachineSetting]) {
guard let i = doc.logs.firstIndex(where: { $0.id == logID }) else { return }
doc.logs[i].machineSettings = settings
doc.updatedAt = Date()
let snapshot = doc
let exerciseName = doc.logs[i].exerciseName
let splitID = doc.splitID
Task {
await sync.save(workout: snapshot)
await sync.writeBackMachineSettings(settings, exerciseName: exerciseName, splitID: splitID)
}
}
/// If the requested log isn't in the working doc yet (just-added race), pull a /// If the requested log isn't in the working doc yet (just-added race), pull a
/// fresh copy from the cache entity once it catches up. /// fresh copy from the cache entity once it catches up.
private func refreshDocIfNeeded() { private func refreshDocIfNeeded() {
@@ -334,28 +334,10 @@ struct WorkoutLogListView: View {
let splitID = doc.splitID let splitID = doc.splitID
Task { Task {
await sync.save(workout: workoutSnapshot) await sync.save(workout: workoutSnapshot)
await writeBackMachineSettings(settings, exerciseName: exerciseName, splitID: splitID) await sync.writeBackMachineSettings(settings, exerciseName: exerciseName, splitID: splitID)
} }
} }
/// Push the settings onto the originating split's exercise (matched by name
/// logs reference exercises by name only), following the seed clone-on-edit
/// redirect so the live clone is updated. Skips silently when the split is gone
/// or no exercise matches, and when nothing changed (so a pristine seed isn't
/// needlessly forked). Never caches the split's id across the save, since saving
/// a seed mints a new one.
private func writeBackMachineSettings(_ settings: [MachineSetting], exerciseName: String, splitID: String?) async {
guard let splitID else { return }
let liveID = sync.currentSplitID(for: splitID)
guard let split = CacheMapper.fetchSplit(id: liveID, in: modelContext) else { return }
var splitDoc = SplitDocument(from: split)
guard let idx = splitDoc.exercises.firstIndex(where: { $0.name == exerciseName }) else { return }
guard splitDoc.exercises[idx].machineSettings != settings else { return }
splitDoc.exercises[idx].machineSettings = settings
splitDoc.updatedAt = Date()
await sync.save(split: splitDoc)
}
/// Recompute the workout's status/end from its logs, then persist. /// Recompute the workout's status/end from its logs, then persist.
private func save() { private func save() {
doc.recomputeStatusFromLogs() doc.recomputeStatusFromLogs()
@@ -549,8 +531,9 @@ struct SplitExercisePickerSheet: View {
/// machine-based log (non-nil `machineSettings`), so there's no machine toggle /// machine-based log (non-nil `machineSettings`), so there's no machine toggle
/// just the ordered rows (reusing `MachineSettingsEditor`) plus Save/Cancel. Save /// just the ordered rows (reusing `MachineSettingsEditor`) plus Save/Cancel. Save
/// hands the edited array back to the caller, which persists it to the log and /// hands the edited array back to the caller, which persists it to the log and
/// writes it back to the split's exercise as the new default. /// writes it back to the split's exercise as the new default. Shared with
private struct MachineSettingsSheet: View { /// `ExerciseView`'s Machine Settings section.
struct MachineSettingsSheet: View {
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
let exerciseName: String let exerciseName: String
+1
View File
@@ -12,6 +12,7 @@ struct ExerciseInfoTests {
#expect(info.summary.contains("machine bench press")) #expect(info.summary.contains("machine bench press"))
#expect(info.category == "Main circuit") #expect(info.category == "Main circuit")
#expect(info.type == "Machine-based horizontal press") #expect(info.type == "Machine-based horizontal press")
#expect(info.isMachineBased)
#expect(info.targets == ["Pectorals", "anterior deltoids", "triceps"]) #expect(info.targets == ["Pectorals", "anterior deltoids", "triceps"])
#expect(info.sections.map(\.title) == ["Setup", "Execution", "Cues", "Common Mistakes", "Progression"]) #expect(info.sections.map(\.title) == ["Setup", "Execution", "Cues", "Common Mistakes", "Progression"])
@@ -0,0 +1,78 @@
import Foundation
import SwiftData
import Testing
@testable import Workouts
/// Exercises the exact fetches `ExerciseLibraryDetailView` builds its machine-settings
/// card and progression-chart gate from, against an in-memory store locking the
/// predicate shapes to the cache schema.
@MainActor
struct ExerciseLibraryQueryTests {
private func makeContext() throws -> ModelContext {
let schema = Schema([Split.self, Exercise.self, Workout.self, WorkoutLog.self])
// cloudKitDatabase: .none matches WorkoutsModelContainer see SeedLibraryTests.
let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true, cloudKitDatabase: .none)
let container = try ModelContainer(for: schema, configurations: [config])
return ModelContext(container)
}
@Test func machineSettingsFetchFindsRecordedSettings() throws {
let context = try makeContext()
let split = Split(id: "S1", name: "Upper Body", color: "indigo",
systemImage: "dumbbell.fill", order: 0,
createdAt: .now, updatedAt: .now, jsonRelativePath: "Splits/S1.json")
let exercise = Exercise(id: "E1", name: "Chest Press", order: 0, sets: 3, reps: 10,
weight: 100, loadType: LoadType.weight.rawValue,
durationTotalSeconds: 0,
machineSettings: [MachineSetting(name: "Seat Height", value: "4")])
exercise.split = split
context.insert(split)
context.insert(exercise)
try context.save()
let name = "Chest Press"
let fetched = try context.fetch(FetchDescriptor<Exercise>(
predicate: #Predicate { $0.name == name }
))
#expect(fetched.count == 1)
#expect(fetched.first?.machineSettings == [MachineSetting(name: "Seat Height", value: "4")])
#expect(fetched.first?.split?.name == "Upper Body")
}
@Test func weightedLogFetchGatesChart() throws {
let context = try makeContext()
let workout = Workout(id: "W1", splitID: nil, splitName: "Upper Body",
start: .now, end: .now, statusRaw: WorkoutStatus.completed.rawValue,
createdAt: .now, updatedAt: .now,
jsonRelativePath: "Workouts/2026/07/W1.json")
let weighted = WorkoutLog(id: "L1", exerciseName: "Chest Press", order: 0, sets: 3,
reps: 10, weight: 100, loadType: LoadType.weight.rawValue,
durationTotalSeconds: 0, currentStateIndex: 3,
statusRaw: WorkoutStatus.completed.rawValue, notes: nil, date: .now)
let bodyweight = WorkoutLog(id: "L2", exerciseName: "Plank", order: 1, sets: 3,
reps: 0, weight: 0, loadType: LoadType.duration.rawValue,
durationTotalSeconds: 60, currentStateIndex: 3,
statusRaw: WorkoutStatus.completed.rawValue, notes: nil, date: .now)
weighted.workout = workout
bodyweight.workout = workout
context.insert(workout)
context.insert(weighted)
context.insert(bodyweight)
try context.save()
let completedRaw = WorkoutStatus.completed.rawValue
let chestPress = "Chest Press"
let chestLogs = try context.fetch(FetchDescriptor<WorkoutLog>(
predicate: #Predicate { $0.exerciseName == chestPress && $0.statusRaw == completedRaw && $0.weight > 0 }
))
#expect(chestLogs.count == 1)
let plank = "Plank"
let plankLogs = try context.fetch(FetchDescriptor<WorkoutLog>(
predicate: #Predicate { $0.exerciseName == plank && $0.statusRaw == completedRaw && $0.weight > 0 }
))
#expect(plankLogs.isEmpty)
}
}
+4 -2
View File
@@ -11,8 +11,10 @@ struct ExerciseMotionTests {
@Test func bundledBirdDogResourcesDecode() throws { @Test func bundledBirdDogResourcesDecode() throws {
let resources = try #require(ExerciseMotionLibrary.resources(for: "Bird Dog")) let resources = try #require(ExerciseMotionLibrary.resources(for: "Bird Dog"))
#expect(resources.motion.name == "Bird Dog") #expect(resources.motion.name == "Bird Dog")
#expect(resources.motion.frames.count == 2) // Bird Dog alternates sides, so all four limbs are in the working set and
#expect(resources.motion.working == ["arm_r", "leg_l"]) // the loop is four key frames (lift right/left pair, then the opposite pair).
#expect(resources.motion.frames.count == 4)
#expect(resources.motion.working == ["arm_r", "leg_l", "arm_l", "leg_r"])
#expect(resources.body.upperArm == 30) #expect(resources.body.upperArm == 30)
#expect(MotionTimeline(motion: resources.motion, body: resources.body) != nil) #expect(MotionTimeline(motion: resources.motion, body: resources.body) != nil)
} }