@franzenzenhofer/asanakit 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/README.md +78 -46
  2. package/dist/anatomy/muscles.d.ts +10 -7
  3. package/dist/anatomy/muscles.d.ts.map +1 -1
  4. package/dist/anatomy/muscles.js +21 -17
  5. package/dist/anatomy/muscles.js.map +1 -1
  6. package/dist/anatomy/validate.d.ts.map +1 -1
  7. package/dist/anatomy/validate.js +16 -10
  8. package/dist/anatomy/validate.js.map +1 -1
  9. package/dist/cli/commands/export.d.ts.map +1 -1
  10. package/dist/cli/commands/export.js +24 -2
  11. package/dist/cli/commands/export.js.map +1 -1
  12. package/dist/cli/commands/info.d.ts.map +1 -1
  13. package/dist/cli/commands/info.js +3 -1
  14. package/dist/cli/commands/info.js.map +1 -1
  15. package/dist/cli/commands/render.d.ts.map +1 -1
  16. package/dist/cli/commands/render.js +12 -3
  17. package/dist/cli/commands/render.js.map +1 -1
  18. package/dist/cli/commands/view.d.ts +3 -0
  19. package/dist/cli/commands/view.d.ts.map +1 -0
  20. package/dist/cli/commands/view.js +40 -0
  21. package/dist/cli/commands/view.js.map +1 -0
  22. package/dist/cli/index.js +7 -2
  23. package/dist/cli/index.js.map +1 -1
  24. package/dist/cli/resolve.d.ts +6 -0
  25. package/dist/cli/resolve.d.ts.map +1 -1
  26. package/dist/cli/resolve.js +40 -0
  27. package/dist/cli/resolve.js.map +1 -1
  28. package/dist/core/camera.d.ts +56 -0
  29. package/dist/core/camera.d.ts.map +1 -0
  30. package/dist/core/camera.js +20 -0
  31. package/dist/core/camera.js.map +1 -0
  32. package/dist/core/joints.d.ts +18 -0
  33. package/dist/core/joints.d.ts.map +1 -0
  34. package/dist/core/joints.js +27 -0
  35. package/dist/core/joints.js.map +1 -0
  36. package/dist/core/quat.d.ts +18 -0
  37. package/dist/core/quat.d.ts.map +1 -0
  38. package/dist/core/quat.js +25 -0
  39. package/dist/core/quat.js.map +1 -0
  40. package/dist/core/rig.d.ts +1 -6
  41. package/dist/core/rig.d.ts.map +1 -1
  42. package/dist/core/rig.js +45 -74
  43. package/dist/core/rig.js.map +1 -1
  44. package/dist/core/skeleton.d.ts +4 -13
  45. package/dist/core/skeleton.d.ts.map +1 -1
  46. package/dist/core/skeleton.js +39 -69
  47. package/dist/core/skeleton.js.map +1 -1
  48. package/dist/core/types.d.ts +62 -55
  49. package/dist/core/types.d.ts.map +1 -1
  50. package/dist/core/types.js.map +1 -1
  51. package/dist/core/vec3.d.ts +13 -0
  52. package/dist/core/vec3.d.ts.map +1 -0
  53. package/dist/core/vec3.js +26 -0
  54. package/dist/core/vec3.js.map +1 -0
  55. package/dist/export3d/gltf.d.ts +11 -0
  56. package/dist/export3d/gltf.d.ts.map +1 -0
  57. package/dist/export3d/gltf.js +28 -0
  58. package/dist/export3d/gltf.js.map +1 -0
  59. package/dist/export3d/index.d.ts +3 -0
  60. package/dist/export3d/index.d.ts.map +1 -0
  61. package/dist/export3d/index.js +3 -0
  62. package/dist/export3d/index.js.map +1 -0
  63. package/dist/export3d/shims.d.ts +7 -0
  64. package/dist/export3d/shims.d.ts.map +1 -0
  65. package/dist/export3d/shims.js +27 -0
  66. package/dist/export3d/shims.js.map +1 -0
  67. package/dist/index.d.ts +9 -0
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +9 -0
  70. package/dist/index.js.map +1 -1
  71. package/dist/library/index.js +4 -4
  72. package/dist/library/index.js.map +1 -1
  73. package/dist/model/pose.d.ts +11 -5
  74. package/dist/model/pose.d.ts.map +1 -1
  75. package/dist/model/pose.js +30 -16
  76. package/dist/model/pose.js.map +1 -1
  77. package/dist/model/schema.d.ts +69 -28
  78. package/dist/model/schema.d.ts.map +1 -1
  79. package/dist/model/schema.js +57 -17
  80. package/dist/model/schema.js.map +1 -1
  81. package/dist/physics/index.d.ts +3 -0
  82. package/dist/physics/index.d.ts.map +1 -0
  83. package/dist/physics/index.js +3 -0
  84. package/dist/physics/index.js.map +1 -0
  85. package/dist/physics/rapier-types.d.ts +60 -0
  86. package/dist/physics/rapier-types.d.ts.map +1 -0
  87. package/dist/physics/rapier-types.js +12 -0
  88. package/dist/physics/rapier-types.js.map +1 -0
  89. package/dist/physics/settle.d.ts +3 -0
  90. package/dist/physics/settle.d.ts.map +1 -0
  91. package/dist/physics/settle.js +108 -0
  92. package/dist/physics/settle.js.map +1 -0
  93. package/dist/physics/world.d.ts +4 -0
  94. package/dist/physics/world.d.ts.map +1 -0
  95. package/dist/physics/world.js +18 -0
  96. package/dist/physics/world.js.map +1 -0
  97. package/dist/render/anatomy.js +1 -1
  98. package/dist/render/anatomy.js.map +1 -1
  99. package/dist/render/annotations.d.ts +3 -2
  100. package/dist/render/annotations.d.ts.map +1 -1
  101. package/dist/render/annotations.js.map +1 -1
  102. package/dist/render/camera.d.ts +43 -0
  103. package/dist/render/camera.d.ts.map +1 -0
  104. package/dist/render/camera.js +57 -0
  105. package/dist/render/camera.js.map +1 -0
  106. package/dist/render/context.d.ts +5 -3
  107. package/dist/render/context.d.ts.map +1 -1
  108. package/dist/render/figure.d.ts +4 -2
  109. package/dist/render/figure.d.ts.map +1 -1
  110. package/dist/render/figure.js +29 -43
  111. package/dist/render/figure.js.map +1 -1
  112. package/dist/render/index.d.ts +1 -0
  113. package/dist/render/index.d.ts.map +1 -1
  114. package/dist/render/index.js +1 -0
  115. package/dist/render/index.js.map +1 -1
  116. package/dist/render/props.d.ts +4 -3
  117. package/dist/render/props.d.ts.map +1 -1
  118. package/dist/render/props.js.map +1 -1
  119. package/dist/render/scene.d.ts +7 -1
  120. package/dist/render/scene.d.ts.map +1 -1
  121. package/dist/render/scene.js +8 -1
  122. package/dist/render/scene.js.map +1 -1
  123. package/dist/render/sheet.d.ts +3 -0
  124. package/dist/render/sheet.d.ts.map +1 -1
  125. package/dist/render/sheet.js +2 -0
  126. package/dist/render/sheet.js.map +1 -1
  127. package/dist/solve.d.ts +14 -0
  128. package/dist/solve.d.ts.map +1 -0
  129. package/dist/solve.js +17 -0
  130. package/dist/solve.js.map +1 -0
  131. package/dist/standards/keypoints.d.ts +2 -10
  132. package/dist/standards/keypoints.d.ts.map +1 -1
  133. package/dist/standards/keypoints.js +33 -14
  134. package/dist/standards/keypoints.js.map +1 -1
  135. package/dist/three/index.d.ts +2 -0
  136. package/dist/three/index.d.ts.map +1 -0
  137. package/dist/three/index.js +2 -0
  138. package/dist/three/index.js.map +1 -0
  139. package/dist/three/scene.d.ts +22 -0
  140. package/dist/three/scene.d.ts.map +1 -0
  141. package/dist/three/scene.js +90 -0
  142. package/dist/three/scene.js.map +1 -0
  143. package/dist/viewer/html.d.ts +16 -0
  144. package/dist/viewer/html.d.ts.map +1 -0
  145. package/dist/viewer/html.js +59 -0
  146. package/dist/viewer/html.js.map +1 -0
  147. package/dist/viewer/index.d.ts +2 -0
  148. package/dist/viewer/index.d.ts.map +1 -0
  149. package/dist/viewer/index.js +2 -0
  150. package/dist/viewer/index.js.map +1 -0
  151. package/dist/viewer/viewer.bundle.js +4119 -0
  152. package/docs/AUTHORING.md +119 -58
  153. package/package.json +20 -5
  154. package/poses/surf/bottom-turn.pose.yaml +24 -24
  155. package/poses/surf/cutback.pose.yaml +24 -24
  156. package/poses/surf/duck-dive.pose.yaml +23 -23
  157. package/poses/surf/noseride.pose.yaml +23 -25
  158. package/poses/surf/paddling.pose.yaml +24 -24
  159. package/poses/surf/pop-up.pose.yaml +24 -24
  160. package/poses/surf/takeoff.pose.yaml +24 -24
  161. package/poses/surf/tube-stance.pose.yaml +24 -24
  162. package/poses/yoga/ashtanga/adho-mukha-svanasana.pose.yaml +22 -22
  163. package/poses/yoga/ashtanga/ardha-uttanasana.pose.yaml +22 -22
  164. package/poses/yoga/ashtanga/baddha-konasana.pose.yaml +21 -23
  165. package/poses/yoga/ashtanga/balasana.pose.yaml +23 -23
  166. package/poses/yoga/ashtanga/chaturanga-dandasana.pose.yaml +21 -21
  167. package/poses/yoga/ashtanga/dandasana.pose.yaml +21 -23
  168. package/poses/yoga/ashtanga/halasana.pose.yaml +23 -23
  169. package/poses/yoga/ashtanga/janu-sirsasana-a.pose.yaml +22 -22
  170. package/poses/yoga/ashtanga/karnapidasana.pose.yaml +23 -23
  171. package/poses/yoga/ashtanga/marichyasana-a.pose.yaml +22 -22
  172. package/poses/yoga/ashtanga/marichyasana-c.pose.yaml +21 -23
  173. package/poses/yoga/ashtanga/matsyasana.pose.yaml +23 -23
  174. package/poses/yoga/ashtanga/navasana.pose.yaml +22 -22
  175. package/poses/yoga/ashtanga/padahastasana.pose.yaml +22 -22
  176. package/poses/yoga/ashtanga/padangusthasana.pose.yaml +22 -22
  177. package/poses/yoga/ashtanga/padmasana.pose.yaml +22 -24
  178. package/poses/yoga/ashtanga/parsvottanasana.pose.yaml +22 -22
  179. package/poses/yoga/ashtanga/paschimottanasana.pose.yaml +22 -22
  180. package/poses/yoga/ashtanga/prasarita-padottanasana-a.pose.yaml +26 -26
  181. package/poses/yoga/ashtanga/prasarita-padottanasana-c.pose.yaml +26 -26
  182. package/poses/yoga/ashtanga/primary.seq.yaml +2 -4
  183. package/poses/yoga/ashtanga/purvottanasana.pose.yaml +22 -22
  184. package/poses/yoga/ashtanga/salamba-sarvangasana.pose.yaml +23 -23
  185. package/poses/yoga/ashtanga/samasthiti.pose.yaml +10 -10
  186. package/poses/yoga/ashtanga/savasana.pose.yaml +21 -21
  187. package/poses/yoga/ashtanga/setu-bandhasana.pose.yaml +22 -22
  188. package/poses/yoga/ashtanga/sirsasana.pose.yaml +23 -23
  189. package/poses/yoga/ashtanga/supta-padangusthasana.pose.yaml +22 -22
  190. package/poses/yoga/ashtanga/upavistha-konasana.pose.yaml +22 -22
  191. package/poses/yoga/ashtanga/urdhva-dhanurasana.pose.yaml +23 -23
  192. package/poses/yoga/ashtanga/urdhva-hastasana.pose.yaml +22 -22
  193. package/poses/yoga/ashtanga/urdhva-mukha-svanasana.pose.yaml +22 -22
  194. package/poses/yoga/ashtanga/utkatasana.pose.yaml +22 -22
  195. package/poses/yoga/ashtanga/uttanasana.pose.yaml +22 -22
  196. package/poses/yoga/ashtanga/utthita-parsvakonasana.pose.yaml +24 -24
  197. package/poses/yoga/ashtanga/utthita-trikonasana.pose.yaml +24 -24
  198. package/poses/yoga/ashtanga/virabhadrasana-a.pose.yaml +22 -22
  199. package/poses/yoga/ashtanga/virabhadrasana-b.pose.yaml +21 -23
package/docs/AUTHORING.md CHANGED
@@ -1,39 +1,84 @@
1
1
  # Authoring poses
2
2
 
3
- A pose is a YAML file. Nothing is drawn imperatively: you describe a body, and asanakit
4
- solves and renders it. This guide is written to be followed by a person or by a model.
3
+ A pose is a YAML file. Nothing is drawn imperatively: you describe a body in 3D, and
4
+ asanakit solves and renders it - as an SVG/PNG from any camera, as an interactive 3D
5
+ viewer, or as a GLB model. This guide is written to be followed by a person or by a model.
5
6
 
6
7
  ## The coordinate system
7
8
 
8
- Angles are **degrees**, measured **counter-clockwise from the +x axis**:
9
+ The figure stands at the origin in anatomical neutral, **facing +z**, with **+x its own
10
+ left** and **+y up**. It is one unit tall (sole to crown). The ground is the plane `y = 0`.
9
11
 
10
- ```
11
- 90 (up)
12
- |
13
- 180 -------+------- 0 (right, and the way a side-view figure faces)
14
- |
15
- -90 (down)
16
- ```
17
-
18
- The figure is one unit tall (sole to crown). The ground is `y = 0`.
12
+ All rotations are **degrees**.
19
13
 
20
14
  ## The two ways to angle a bone
21
15
 
22
16
  | Block | Meaning | Use it for |
23
17
  |---|---|---|
24
- | `joints:` | rotation **relative to the parent bone**, from anatomical neutral (standing, arms down) | small deviations from standing |
25
- | `world:` | the bone's **absolute direction** on the page | everything else |
18
+ | `joints:` | rotation **relative to the parent bone**, about the joint's own anatomical axes | small deviations from standing; twists |
19
+ | `world:` | the bone's **absolute direction** in space | everything else |
20
+
21
+ ### `world`: absolute directions
22
+
23
+ ```yaml
24
+ world:
25
+ thighL: { azimuth: 0, elevation: -55 } # down and forward
26
+ spine: { azimuth: 0, elevation: 40 } # leaning forward, 40° above horizontal
27
+ upperArmR: { azimuth: -90, elevation: 0 } # straight out to the figure's right
28
+ ```
29
+
30
+ - `azimuth` - which way the bone points on the compass of the body: `0` = the figure's
31
+ facing direction (+z), `90` = the figure's **left**, `-90` its right, `180` backward.
32
+ - `elevation` - how far it rises: `90` = straight up, `0` = horizontal, `-90` = straight down.
33
+ - `twist` (optional) - rotation about the aimed bone.
34
+
35
+ "The front thigh points forward and 55° down" is something you can reason about and check
36
+ by eye. Chaining five relative rotations is not. **`world` is what you want almost always.**
26
37
 
27
- `world` is what you want almost always. "The front thigh points down and back at -125°"
28
- is something you can reason about and check by eye. Chaining five relative rotations is not.
38
+ A bone listed in `world` ignores its parent's rotation. Its **children still hang off
39
+ it**, so pinning the thigh and then flexing the knee with `joints: {shinL: 40}` works
40
+ exactly as you would expect.
29
41
 
30
- A bone listed in `world` ignores its rest angle and its parent's rotation. Its **children
31
- still hang off it**, so pinning the thigh and then flexing the knee with `joints: {shinL: 40}`
32
- works exactly as you would expect.
42
+ > **The single most common mistake:** you tip the figure with `root.pitch` and forget
43
+ > that every unpinned limb rotates with it. Tip the root to fold forward, and the legs
44
+ > swing up into the air. **If you set root angles, pin the legs in `world`.**
33
45
 
34
- > **The single most common mistake:** you tilt the pelvis with `root.rotation` and forget
35
- > that every unpinned limb rotates with it. Tilt the pelvis to fold forward, and the legs
36
- > swing up into the air. **If you set `root.rotation`, pin the legs in `world`.**
46
+ ### `joints`: anatomical rotations
47
+
48
+ A bare number is pure **flexion** - the joint bending the way anatomy names it:
49
+
50
+ ```yaml
51
+ joints:
52
+ forearmL: 90 # elbow bends 90° (forward - the only way an elbow goes)
53
+ shinR: 60 # knee bends 60° (backward - the only way a knee goes)
54
+ ```
55
+
56
+ The object form adds the other two anatomical axes:
57
+
58
+ ```yaml
59
+ joints:
60
+ upperArmL: { abduct: 90 } # arm straight out to the side
61
+ thighR: { flex: 45, abduct: 30, twist: 20 }
62
+ ```
63
+
64
+ - `flex` - forward bend for hips/arms/spine, backward for knees, toes-up for ankles.
65
+ - `abduct` - away from the midline, on either side. Center bones lean toward the figure's left.
66
+ - `twist` - about the bone: positive is **external rotation** (toes/palms turn outward);
67
+ for center bones, turning toward the figure's left.
68
+
69
+ The signs are per-side anatomical, so a mirrored pose is literally the same numbers with
70
+ L and R swapped - which is what `mirror: true` does.
71
+
72
+ ### The root
73
+
74
+ ```yaml
75
+ root:
76
+ yaw: 90 # turn the whole figure toward its left
77
+ pitch: 40 # tip it forward (90 = horizontal, face down)
78
+ roll: -65 # cartwheel it sideways (negative drops the LEFT side)
79
+ position: [0, 0, 0]
80
+ scale: 1
81
+ ```
37
82
 
38
83
  ## Bones you can angle
39
84
 
@@ -43,10 +88,9 @@ clavicleL/R upperArmL/R forearmL/R handL/R
43
88
  hipL/R thighL/R shinL/R footL/R
44
89
  ```
45
90
 
46
- `root.rotation` aims the pelvis (90 = upright). Rotating a bone rotates everything below it.
47
-
48
- Positive `shinL` **flexes the knee** (heel toward the buttock). Positive `forearmL` flexes
49
- the elbow. Neither joint bends the other way, and the validator will tell you so.
91
+ Rotating a bone rotates everything below it. Feet rest pointing forward, dropped 20°
92
+ toward the floor; a **flat standing foot wants `world: { azimuth: …, elevation: 0 }`**
93
+ or a matching dorsiflexion.
50
94
 
51
95
  ## Landmarks you can point at
52
96
 
@@ -58,17 +102,33 @@ shoulderL/R elbowL/R wristL/R handTipL/R
58
102
  hipJointL/R kneeL/R ankleL/R toeL/R
59
103
  ```
60
104
 
61
- ## Views
105
+ ## The camera
106
+
107
+ The pose is 3D; a picture of it needs a viewpoint:
108
+
109
+ ```yaml
110
+ camera: side # or front | back | left | right | three-quarter | top
111
+ camera: { azimuth: 30, elevation: 15 } # or any orbit angle
112
+ ```
113
+
114
+ This is only the pose's **default**. `--camera` on the CLI overrides it, and every camera
115
+ shows the same body: `asanakit render pose --camera back` needs nothing re-authored.
116
+ Camera azimuth 0 looks at the figure's front; positive azimuth walks toward the figure's
117
+ left; `side` is the classic profile with the figure facing picture-right.
62
118
 
63
- | view | what it means |
64
- |---|---|
65
- | `front` | the figure faces you. Left and right limbs **mirror**: `upperArmL: 90` and `upperArmR: 90` raise both arms outward. |
66
- | `side` | profile, facing **+x** (to the right). Limbs **do not mirror** - both arms swing the same way, because you see both from the same side. The left/right offset becomes depth and nearly vanishes. |
67
- | `back` | like `front`. |
68
- | `three-quarter` | between the two. |
119
+ `mirror: true` swaps which limb does what (the other side of an asymmetric asana).
120
+ Sequences use it to render the "second side".
121
+
122
+ ## Physics, when necessary
123
+
124
+ ```yaml
125
+ physics: settle
126
+ ```
69
127
 
70
- Set `flip: true` to face the other way. Set `mirror: true` to swap which limb does what
71
- (the other side of an asymmetric asana). Sequences apply both to render "second side".
128
+ drops the solved figure onto the ground plane with a real physics engine (Rapier) and
129
+ lets it rest on its true support instead of the naive lowest-point shift. Opt-in per pose,
130
+ or ad hoc with `--settle`. The authored pose is preserved exactly; only the figure's
131
+ position and orientation change.
72
132
 
73
133
  ## Contact points: the thing that keeps you honest
74
134
 
@@ -83,17 +143,18 @@ is hovering 9 cm above it. **Every pose must declare its contact points.**
83
143
  ## The loop
84
144
 
85
145
  ```bash
86
- npx tsx src/cli/index.ts lint my-pose # anatomy + contact check
87
- npx tsx src/cli/index.ts render my-pose -o out/p.png -w 500 -h 500 --scale 500
146
+ asanakit lint my-pose # anatomy + contact check
147
+ asanakit render my-pose -o out/p.png -w 500 -h 500
148
+ asanakit view my-pose --open # orbit it in 3D
88
149
  ```
89
150
 
90
- Then **look at the PNG**. Lint proves the pose is physically possible; only your eye proves
91
- it is the right posture. Iterate until both agree.
151
+ Then **look at it - from more than one angle**. Lint proves the pose is physically
152
+ possible; only your eye proves it is the right posture. Iterate until both agree.
92
153
 
93
154
  ## A complete example
94
155
 
95
156
  ```yaml
96
- asanakit: 1
157
+ asanakit: 2
97
158
  id: adho-mukha-svanasana
98
159
  name: Downward-Facing Dog
99
160
  sanskrit: Adho Mukha Śvānāsana
@@ -107,27 +168,27 @@ drishti: nabi-chakra
107
168
  cues:
108
169
  - Lift the sit bones, lengthen the spine
109
170
  contact: [toeL, toeR, handTipL, handTipR]
171
+ camera: side
110
172
  figure:
111
- view: side
112
173
  grounded: true
113
174
  root:
114
- rotation: -48 # pelvis aims down-and-forward: the torso ramps to the hands
175
+ pitch: 138 # pelvis aims down-and-forward: the torso ramps to the hands
115
176
  world:
116
- thighL: -125 # legs ramp down-and-back to the feet
117
- thighR: -125
118
- shinL: -125 # straight leg: shin collinear with thigh
119
- shinR: -125
120
- footL: -20
121
- footR: -20
122
- spine: -48
123
- neck: -48
124
- head: -48 # head hangs between the arms, in line with the spine
125
- upperArmL: -50 # arms continue the line of the spine to the floor
126
- upperArmR: -50
127
- forearmL: -50
128
- forearmR: -50
129
- handL: -8 # palm flat
130
- handR: -8
177
+ thighL: { azimuth: 180, elevation: -55 } # legs ramp down-and-back to the feet
178
+ thighR: { azimuth: 180, elevation: -55 }
179
+ shinL: { azimuth: 180, elevation: -55 } # straight leg: shin collinear with thigh
180
+ shinR: { azimuth: 180, elevation: -55 }
181
+ footL: { azimuth: 0, elevation: -20 }
182
+ footR: { azimuth: 0, elevation: -20 }
183
+ spine: { azimuth: 0, elevation: -48 }
184
+ neck: { azimuth: 0, elevation: -48 }
185
+ head: { azimuth: 0, elevation: -48 } # head hangs between the arms, in line with the spine
186
+ upperArmL: { azimuth: 0, elevation: -50 } # arms continue the line of the spine to the floor
187
+ upperArmR: { azimuth: 0, elevation: -50 }
188
+ forearmL: { azimuth: 0, elevation: -50 }
189
+ forearmR: { azimuth: 0, elevation: -50 }
190
+ handL: { azimuth: 0, elevation: -8 } # palm flat
191
+ handR: { azimuth: 0, elevation: -8 }
131
192
  props:
132
193
  - type: mat
133
194
  muscles:
@@ -137,7 +198,7 @@ muscles:
137
198
 
138
199
  ## Reference
139
200
 
140
- - `asanakit vocab` prints every joint, landmark, muscle, style and view name.
201
+ - `asanakit vocab` prints every joint, landmark, muscle, style and camera name.
141
202
  - `asanakit schema` prints the JSON Schema for the format.
142
203
  - Props: `mat`, `ground`, `block`, `strap`, `wall`, `surfboard`, `wave`.
143
204
  - Annotations: `angle`, `line`, `plumb`, `arrow`, `label`, `point`.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@franzenzenhofer/asanakit",
3
- "version": "0.1.0",
4
- "description": "Programmatic stick-figure and anatomical infographic engine for yoga and surf postures. Declarative pose format, deterministic SVG/PNG output, CLI-first, AI-driveable.",
3
+ "version": "0.2.0",
4
+ "description": "Programmatic stick-figure and body-posture visualization engine for yoga and surf. Declarative 3D pose format, deterministic any-angle SVG/PNG, interactive three.js viewer, GLB export, Rapier physics settling. CLI-first, AI-driveable.",
5
5
  "keywords": [
6
6
  "yoga",
7
7
  "surf",
@@ -15,7 +15,14 @@
15
15
  "skeleton",
16
16
  "kinematics",
17
17
  "cli",
18
- "typescript"
18
+ "typescript",
19
+ "3d",
20
+ "three.js",
21
+ "gltf",
22
+ "glb",
23
+ "physics",
24
+ "rapier",
25
+ "camera"
19
26
  ],
20
27
  "license": "MIT",
21
28
  "author": "Franz Enzenhofer",
@@ -40,6 +47,10 @@
40
47
  ".": {
41
48
  "types": "./dist/index.d.ts",
42
49
  "default": "./dist/index.js"
50
+ },
51
+ "./physics": {
52
+ "types": "./dist/physics/index.d.ts",
53
+ "default": "./dist/physics/index.js"
43
54
  }
44
55
  },
45
56
  "files": [
@@ -50,9 +61,9 @@
50
61
  "LICENSE"
51
62
  ],
52
63
  "scripts": {
53
- "build": "tsc -p tsconfig.build.json && chmod +x dist/cli/index.js",
64
+ "build": "tsc -p tsconfig.build.json && chmod +x dist/cli/index.js && tsx scripts/build-viewer.ts",
54
65
  "dev": "tsx src/cli/index.ts",
55
- "typecheck": "tsc --noEmit",
66
+ "typecheck": "tsc --noEmit && tsc -p viewer-src/tsconfig.json",
56
67
  "lint": "eslint .",
57
68
  "lint:fix": "eslint . --fix",
58
69
  "test": "vitest run",
@@ -63,6 +74,7 @@
63
74
  "prepublishOnly": "npm run verify"
64
75
  },
65
76
  "dependencies": {
77
+ "@dimforge/rapier3d-compat": "^0.19.3",
66
78
  "@resvg/resvg-js": "^2.6.2",
67
79
  "commander": "^14.0.1",
68
80
  "culori": "^4.0.2",
@@ -70,6 +82,7 @@
70
82
  "d3-shape": "^3.2.0",
71
83
  "gl-matrix": "^3.4.4",
72
84
  "svgo": "^4.0.2",
85
+ "three": "0.185.1",
73
86
  "xmlbuilder2": "^4.0.3",
74
87
  "yaml": "^2.8.1",
75
88
  "zod": "^4.1.12"
@@ -79,7 +92,9 @@
79
92
  "@types/d3-path": "^3.1.1",
80
93
  "@types/d3-shape": "^3.1.8",
81
94
  "@types/node": "^24.9.2",
95
+ "@types/three": "^0.185.1",
82
96
  "@vitest/coverage-v8": "^3.2.4",
97
+ "esbuild": "^0.28.1",
83
98
  "eslint": "^9.38.0",
84
99
  "tsx": "^4.20.6",
85
100
  "typescript": "^5.9.3",
@@ -1,4 +1,4 @@
1
- asanakit: 1
1
+ asanakit: 2
2
2
  id: bottom-turn
3
3
  name: Bottom Turn
4
4
  english: Bottom Turn
@@ -6,42 +6,42 @@ discipline: surf
6
6
  family: turning
7
7
  difficulty: 4
8
8
  description: The turn at the base of the wave that sets up everything after it. The surfer compresses deep, drives the weight through the heels and the rail, and reaches the inside arm toward the wave face while the eyes go back up to the lip.
9
- tags: [surf, turning, rail, power]
9
+ tags: [ surf, turning, rail, power ]
10
10
  cues:
11
11
  - Compress low and drive from the heels
12
12
  - Look where you want to go - back up at the lip
13
- contact: [toeL, toeR]
13
+ contact: [ toeL, toeR ]
14
14
  figure:
15
- view: side
16
15
  grounded: true
17
16
  root:
18
- rotation: 55
17
+ pitch: 35
19
18
  world:
20
- spine: 45
21
- neck: 68
22
- head: 82
23
- thighL: -25
24
- shinL: -100
25
- footL: -15
26
- thighR: -60
27
- shinR: -145
28
- footR: -10
29
- upperArmL: -5
30
- forearmL: 15
31
- handL: 20
32
- upperArmR: -150
33
- forearmR: -140
34
- handR: -135
19
+ spine: { azimuth: 0, elevation: 45 }
20
+ neck: { azimuth: 0, elevation: 68 }
21
+ head: { azimuth: 0, elevation: 82 }
22
+ thighL: { azimuth: 0, elevation: -25 }
23
+ shinL: { azimuth: 180, elevation: -80 }
24
+ footL: { azimuth: 0, elevation: -15 }
25
+ thighR: { azimuth: 0, elevation: -60 }
26
+ shinR: { azimuth: 180, elevation: -35 }
27
+ footR: { azimuth: 0, elevation: -10 }
28
+ upperArmL: { azimuth: 0, elevation: -5 }
29
+ forearmL: { azimuth: 0, elevation: 15 }
30
+ handL: { azimuth: 0, elevation: 20 }
31
+ upperArmR: { azimuth: 180, elevation: -30 }
32
+ forearmR: { azimuth: 180, elevation: -40 }
33
+ handR: { azimuth: 180, elevation: -45 }
35
34
  props:
36
35
  - type: wave
37
36
  amplitude: 0.45
38
37
  length: 3.4
39
38
  y: -0.2
40
39
  - type: surfboard
41
- under: [ankleL, ankleR]
40
+ under: [ ankleL, ankleR ]
42
41
  rotation: 10
43
42
  length: 1.15
44
- offset: [0, -0.1]
43
+ offset: [ 0, -0.1 ]
45
44
  muscles:
46
- engaged: [quadriceps, gluteus, obliques, erectorSpinae, adductors]
47
- stretched: [hipFlexors, latissimus]
45
+ engaged: [ quadriceps, gluteus, obliques, erectorSpinae, adductors ]
46
+ stretched: [ hipFlexors, latissimus ]
47
+ camera: side
@@ -1,4 +1,4 @@
1
- asanakit: 1
1
+ asanakit: 2
2
2
  id: cutback
3
3
  name: Cutback
4
4
  english: Cutback
@@ -6,42 +6,42 @@ discipline: surf
6
6
  family: turning
7
7
  difficulty: 4
8
8
  description: The turn that takes the surfer back to the power source. Out on the shoulder the board is swung around by the torso - the chest and both arms lead the rotation back toward the breaking part of the wave, the weight settles over the tail and the front leg extends.
9
- tags: [surf, turning, rotation, flow]
9
+ tags: [ surf, turning, rotation, flow ]
10
10
  cues:
11
11
  - Turn your chest and arms first, the board follows
12
12
  - Weight back over the tail to pivot, not the nose
13
- contact: [toeL, toeR]
13
+ contact: [ toeL, toeR ]
14
14
  figure:
15
- view: side
16
15
  grounded: true
17
16
  root:
18
- rotation: 82
17
+ pitch: 8
19
18
  world:
20
- spine: 100
21
- neck: 118
22
- head: 145
23
- thighL: -45
24
- shinL: -105
25
- footL: -20
26
- thighR: -85
27
- shinR: -135
28
- footR: -15
29
- upperArmL: -178
30
- forearmL: -172
31
- handL: -170
32
- upperArmR: 132
33
- forearmR: 158
34
- handR: 162
19
+ spine: { azimuth: 180, elevation: 80 }
20
+ neck: { azimuth: 180, elevation: 62 }
21
+ head: { azimuth: 180, elevation: 35 }
22
+ thighL: { azimuth: 0, elevation: -45 }
23
+ shinL: { azimuth: 180, elevation: -75 }
24
+ footL: { azimuth: 0, elevation: -20 }
25
+ thighR: { azimuth: 0, elevation: -85 }
26
+ shinR: { azimuth: 180, elevation: -45 }
27
+ footR: { azimuth: 0, elevation: -15 }
28
+ upperArmL: { azimuth: 180, elevation: -2 }
29
+ forearmL: { azimuth: 180, elevation: -8 }
30
+ handL: { azimuth: 180, elevation: -10 }
31
+ upperArmR: { azimuth: 180, elevation: 48 }
32
+ forearmR: { azimuth: 180, elevation: 22 }
33
+ handR: { azimuth: 180, elevation: 18 }
35
34
  props:
36
35
  - type: wave
37
36
  amplitude: 0.42
38
37
  length: 3.4
39
38
  y: -0.22
40
39
  - type: surfboard
41
- under: [ankleL, ankleR]
40
+ under: [ ankleL, ankleR ]
42
41
  rotation: 4
43
42
  length: 1.15
44
- offset: [0, -0.1]
43
+ offset: [ 0, -0.1 ]
45
44
  muscles:
46
- engaged: [obliques, erectorSpinae, gluteus, quadriceps, deltoid]
47
- stretched: [pectoralis, hamstrings]
45
+ engaged: [ obliques, erectorSpinae, gluteus, quadriceps, deltoid ]
46
+ stretched: [ pectoralis, hamstrings ]
47
+ camera: side
@@ -1,4 +1,4 @@
1
- asanakit: 1
1
+ asanakit: 2
2
2
  id: duck-dive
3
3
  name: Duck Dive
4
4
  english: Duck Dive
@@ -6,32 +6,31 @@ discipline: surf
6
6
  family: prone
7
7
  difficulty: 3
8
8
  description: How a shortboarder gets under a broken wave. Both arms straighten and drive the nose deep under the water, the head follows it down, and one knee then punches into the tail to sink the whole board while the wave passes overhead.
9
- tags: [surf, prone, paddling, defensive, shortboard]
9
+ tags: [ surf, prone, paddling, defensive, shortboard ]
10
10
  cues:
11
11
  - Straight arms - push the nose down, do not pull it toward you
12
12
  - Knee into the tail only once the nose is already under
13
- contact: [handTipL, handTipR]
13
+ contact: [ handTipL, handTipR ]
14
14
  figure:
15
- view: side
16
15
  grounded: true
17
16
  root:
18
- rotation: -30
17
+ pitch: 120
19
18
  world:
20
- spine: -38
21
- neck: -34
22
- head: -30
23
- upperArmL: -56
24
- forearmL: -56
25
- handL: -56
26
- upperArmR: -50
27
- forearmR: -50
28
- handR: -50
29
- thighL: 168
30
- shinL: 142
31
- footL: 150
32
- thighR: -175
33
- shinR: 95
34
- footR: 70
19
+ spine: { azimuth: 0, elevation: -38 }
20
+ neck: { azimuth: 0, elevation: -34 }
21
+ head: { azimuth: 0, elevation: -30 }
22
+ upperArmL: { azimuth: 0, elevation: -56 }
23
+ forearmL: { azimuth: 0, elevation: -56 }
24
+ handL: { azimuth: 0, elevation: -56 }
25
+ upperArmR: { azimuth: 0, elevation: -50 }
26
+ forearmR: { azimuth: 0, elevation: -50 }
27
+ handR: { azimuth: 0, elevation: -50 }
28
+ thighL: { azimuth: 180, elevation: 12 }
29
+ shinL: { azimuth: 180, elevation: 38 }
30
+ footL: { azimuth: 180, elevation: 30 }
31
+ thighR: { azimuth: 180, elevation: -5 }
32
+ shinR: { azimuth: 180, elevation: 85 }
33
+ footR: { azimuth: 0, elevation: 70 }
35
34
  props:
36
35
  - type: wave
37
36
  amplitude: 0.5
@@ -39,9 +38,10 @@ props:
39
38
  y: 0.55
40
39
  facing: left
41
40
  - type: surfboard
42
- at: [0.023, 0.108]
41
+ at: [ 0.023, 0.108 ]
43
42
  rotation: -32
44
43
  length: 1.35
45
44
  muscles:
46
- engaged: [triceps, deltoid, latissimus, rectusAbdominis, hipFlexors]
47
- stretched: [pectoralis, quadriceps]
45
+ engaged: [ triceps, deltoid, latissimus, rectusAbdominis, hipFlexors ]
46
+ stretched: [ pectoralis, quadriceps ]
47
+ camera: side
@@ -1,4 +1,4 @@
1
- asanakit: 1
1
+ asanakit: 2
2
2
  id: noseride
3
3
  name: Noseride
4
4
  english: Noseride
@@ -6,32 +6,29 @@ discipline: surf
6
6
  family: trim
7
7
  difficulty: 4
8
8
  description: The longboard reward. With the tail held in the wave the surfer walks to the front of the board and stands tall and still on the nose, legs long, arms loose, doing as little as possible while the board trims along the face.
9
- tags: [surf, longboard, trim, nose, style]
9
+ tags: [ surf, longboard, trim, nose, style ]
10
10
  cues:
11
11
  - Stand tall and quiet - do nothing and let the board trim
12
12
  - Stay behind the tail's hold, never lunge at the nose
13
- contact: [toeL, toeR]
13
+ contact: [ toeL, toeR ]
14
14
  figure:
15
- view: side
16
15
  grounded: true
17
- root:
18
- rotation: 90
19
16
  world:
20
- spine: 95
21
- neck: 90
22
- head: 88
23
- thighL: -80
24
- shinL: -95
25
- footL: -15
26
- thighR: -100
27
- shinR: -112
28
- footR: -12
29
- upperArmL: -60
30
- forearmL: -50
31
- handL: -45
32
- upperArmR: -112
33
- forearmR: -102
34
- handR: -100
17
+ spine: { azimuth: 180, elevation: 85 }
18
+ neck: { azimuth: 0, elevation: 90 }
19
+ head: { azimuth: 0, elevation: 88 }
20
+ thighL: { azimuth: 0, elevation: -80 }
21
+ shinL: { azimuth: 180, elevation: -85 }
22
+ footL: { azimuth: 0, elevation: -15 }
23
+ thighR: { azimuth: 180, elevation: -80 }
24
+ shinR: { azimuth: 180, elevation: -68 }
25
+ footR: { azimuth: 0, elevation: -12 }
26
+ upperArmL: { azimuth: 0, elevation: -60 }
27
+ forearmL: { azimuth: 0, elevation: -50 }
28
+ handL: { azimuth: 0, elevation: -45 }
29
+ upperArmR: { azimuth: 180, elevation: -68 }
30
+ forearmR: { azimuth: 180, elevation: -78 }
31
+ handR: { azimuth: 180, elevation: -80 }
35
32
  props:
36
33
  - type: wave
37
34
  amplitude: 0.3
@@ -39,10 +36,11 @@ props:
39
36
  y: -0.18
40
37
  breaking: false
41
38
  - type: surfboard
42
- under: [ankleL, ankleR]
39
+ under: [ ankleL, ankleR ]
43
40
  rotation: -2
44
41
  length: 1.7
45
- offset: [-0.5, -0.1]
42
+ offset: [ -0.5, -0.1 ]
46
43
  muscles:
47
- engaged: [gastrocnemius, tibialisAnterior, quadriceps, erectorSpinae]
48
- stretched: [hamstrings, pectoralis]
44
+ engaged: [ gastrocnemius, tibialisAnterior, quadriceps, erectorSpinae ]
45
+ stretched: [ hamstrings, pectoralis ]
46
+ camera: side