@bitefoundry/retrieviewer 0.0.3 → 0.0.4

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 (254) hide show
  1. package/ASSET-PROVENANCE.md +6 -0
  2. package/ASSETS-LICENSE.md +2 -1
  3. package/ATTRIBUTION.md +6 -1
  4. package/COMFORT-ART.md +65 -0
  5. package/DESKTOP-PLATFORMS.md +6 -1
  6. package/PLUGIN.md +13 -10
  7. package/PREREQUISITES.md +95 -0
  8. package/PUPPY-MEMORY.md +102 -1
  9. package/README.ko.md +110 -0
  10. package/README.md +117 -59
  11. package/RELEASING.md +23 -12
  12. package/THIRD-PARTY-NOTICES.md +5 -3
  13. package/braille.mjs +35 -9
  14. package/examples/live.mjs +2 -2
  15. package/integrations/linux-overlay/overlay.py +2 -2
  16. package/integrations/macos-overlay/overlay.jxa +8 -6
  17. package/integrations/opencode/runtime.mjs +4 -4
  18. package/integrations/opencode/tui.tsx +1 -1
  19. package/integrations/windows-overlay/Overlay.cs +4 -4
  20. package/integrations/windows-overlay/protocol.mjs +11 -7
  21. package/package.json +34 -13
  22. package/puppy-comfort-sprites.mjs +25 -0
  23. package/puppy-companion-comfort-q5.bin.gz +0 -0
  24. package/puppy-companion-comfort.json +77 -0
  25. package/puppy-companion-life.mjs +49 -16
  26. package/puppy-companion-objects.mjs +12 -0
  27. package/puppy-frame-predictive.mjs +15 -9
  28. package/puppy-frame-store.mjs +2 -2
  29. package/puppy-paper-world.mjs +14 -0
  30. package/puppy-paper.mjs +65 -14
  31. package/retrieviewer-plugin.d.mts +1 -1
  32. package/retrieviewer-plugin.mjs +1 -1
  33. package/retrieviewer.d.mts +10 -4
  34. package/retrieviewer.mjs +20 -14
  35. package/locomotion-core.mjs +0 -21
  36. package/locomotion-puppy.animal +0 -0
  37. package/vendor/procedural-animals/package.json +0 -40
  38. package/vendor/procedural-animals/src/animal.js +0 -146
  39. package/vendor/procedural-animals/src/bake.js +0 -51
  40. package/vendor/procedural-animals/src/build.js +0 -81
  41. package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
  42. package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
  43. package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
  44. package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
  45. package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
  46. package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
  47. package/vendor/procedural-animals/src/core/build/seams.js +0 -183
  48. package/vendor/procedural-animals/src/core/build/warp.js +0 -112
  49. package/vendor/procedural-animals/src/core/build/weights.js +0 -393
  50. package/vendor/procedural-animals/src/core/math/vec.js +0 -81
  51. package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
  52. package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
  53. package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
  54. package/vendor/procedural-animals/src/core/motion/common.js +0 -158
  55. package/vendor/procedural-animals/src/core/motion/index.js +0 -22
  56. package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
  57. package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
  58. package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
  59. package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
  60. package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
  61. package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
  62. package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
  63. package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
  64. package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
  65. package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
  66. package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
  67. package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
  68. package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
  69. package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
  70. package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
  71. package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
  72. package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
  73. package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
  74. package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
  75. package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
  76. package/vendor/procedural-animals/src/index.d.ts +0 -98
  77. package/vendor/procedural-animals/src/index.js +0 -29
  78. package/vendor/procedural-animals/src/registry.js +0 -48
  79. package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
  80. package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
  81. package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
  82. package/vendor/procedural-animals/src/species/bear/index.js +0 -139
  83. package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
  84. package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
  85. package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
  86. package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
  87. package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
  88. package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
  89. package/vendor/procedural-animals/src/species/boar/index.js +0 -110
  90. package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
  91. package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
  92. package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
  93. package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
  94. package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
  95. package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
  96. package/vendor/procedural-animals/src/species/cat/index.js +0 -211
  97. package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
  98. package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
  99. package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
  100. package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
  101. package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
  102. package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
  103. package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
  104. package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
  105. package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
  106. package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
  107. package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
  108. package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
  109. package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
  110. package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
  111. package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
  112. package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
  113. package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
  114. package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
  115. package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
  116. package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
  117. package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
  118. package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
  119. package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
  120. package/vendor/procedural-animals/src/species/cow/index.js +0 -118
  121. package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
  122. package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
  123. package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
  124. package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
  125. package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
  126. package/vendor/procedural-animals/src/species/crow/index.js +0 -70
  127. package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
  128. package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
  129. package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
  130. package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
  131. package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
  132. package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
  133. package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
  134. package/vendor/procedural-animals/src/species/deer/index.js +0 -106
  135. package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
  136. package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
  137. package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
  138. package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
  139. package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
  140. package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
  141. package/vendor/procedural-animals/src/species/dog/index.js +0 -144
  142. package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
  143. package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
  144. package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
  145. package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
  146. package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
  147. package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
  148. package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
  149. package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
  150. package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
  151. package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
  152. package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
  153. package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
  154. package/vendor/procedural-animals/src/species/fish/index.js +0 -88
  155. package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
  156. package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
  157. package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
  158. package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
  159. package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
  160. package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
  161. package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
  162. package/vendor/procedural-animals/src/species/fox/index.js +0 -120
  163. package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
  164. package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
  165. package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
  166. package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
  167. package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
  168. package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
  169. package/vendor/procedural-animals/src/species/frog/index.js +0 -97
  170. package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
  171. package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
  172. package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
  173. package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
  174. package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
  175. package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
  176. package/vendor/procedural-animals/src/species/goat/index.js +0 -149
  177. package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
  178. package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
  179. package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
  180. package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
  181. package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
  182. package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
  183. package/vendor/procedural-animals/src/species/horse/index.js +0 -80
  184. package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
  185. package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
  186. package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
  187. package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
  188. package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
  189. package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
  190. package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
  191. package/vendor/procedural-animals/src/species/lion/index.js +0 -111
  192. package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
  193. package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
  194. package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
  195. package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
  196. package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
  197. package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
  198. package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
  199. package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
  200. package/vendor/procedural-animals/src/species/pig/index.js +0 -161
  201. package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
  202. package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
  203. package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
  204. package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
  205. package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
  206. package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
  207. package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
  208. package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
  209. package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
  210. package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
  211. package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
  212. package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
  213. package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
  214. package/vendor/procedural-animals/src/species/rat/index.js +0 -111
  215. package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
  216. package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
  217. package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
  218. package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
  219. package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
  220. package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
  221. package/vendor/procedural-animals/src/species/shark/index.js +0 -104
  222. package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
  223. package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
  224. package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
  225. package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
  226. package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
  227. package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
  228. package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
  229. package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
  230. package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
  231. package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
  232. package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
  233. package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
  234. package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
  235. package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
  236. package/vendor/procedural-animals/src/species/snake/index.js +0 -73
  237. package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
  238. package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
  239. package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
  240. package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
  241. package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
  242. package/vendor/procedural-animals/src/species/spider/index.js +0 -78
  243. package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
  244. package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
  245. package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
  246. package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
  247. package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
  248. package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
  249. package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
  250. package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
  251. package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
  252. package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
  253. package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
  254. package/vendor/procedural-animals/src/worker.js +0 -29
@@ -1,156 +0,0 @@
1
- // True frog (Ranidae) skeleton in bind pose (metres). Forward = +Z, up = +Y, the animal's left = +X.
2
- //
3
- // Reference individual: adult female American bullfrog (Lithobates catesbeianus), snout-vent length
4
- // (SVL) 140 mm. The bind pose IS the classic sitting frog (the resting stance of the
5
- // quadruped engine): forelegs upright on flat hands, hind legs folded in a Z beside the body (femur
6
- // forward and out, tibiofibula back alongside it, tarsus and the long webbed foot flat on the ground
7
- // pointing forward and out), the trunk rising from the vent to the sacral hump and on to the flat
8
- // head. No neck: the neck joints sit packed behind the skull. No tail (the urostyle is the pelvis
9
- // bone, lumbosacral -> tailBase).
10
- //
11
- // Frog bones mapped onto the standard quadruped set (core/rig/quadruped.js):
12
- // pelvis (lumbosacral -> tailBase) ilia + urostyle: the ilio-sacral hinge is the sacral hump
13
- // femur / tibia femur / tibiofibula
14
- // metatarsus (hock -> mtp) the elongated tarsus (astragalus + calcaneum)
15
- // hpaw (mtp -> htoe) metatarsals + toes (toe IV), webbed
16
- // humerus / radius humerus / radio-ulna
17
- // metacarpus / fpaw palm / fingers (4)
18
- // Extra bones: eyeL / eyeR (the eyes retract into the head to blink and swallow), throat (buccal
19
- // floor and vocal sac: pumping and croaking), tongue (attached at the front of the lower jaw, flips
20
- // out forward).
21
- import { buildRig } from '../../core/rig/rig.js';
22
- import { quadrupedBones, quadrupedLimbs } from '../../core/rig/quadruped.js';
23
- import { sub, add, mul, norm, cross, dot, len } from '../../core/math/vec.js';
24
-
25
- // head-local origin: on the midline, level with the eye centres
26
- export const HEAD_O = [0, 0.06, 0.049];
27
- export const hl = (v) => [v[0] + HEAD_O[0], v[1] + HEAD_O[1], v[2] + HEAD_O[2]];
28
-
29
- // limb segment lengths at SVL 140 mm (ranid ratios)
30
- export const SEG = { hum: 0.026, rad: 0.022, fem: 0.064, tib: 0.071 };
31
- // stance.sprawl of motion.js: the engine places the feet sprawl x leg length x 0.35 further out than
32
- // the bind, and bends knees / elbows toward poles turned out by sprawl x 1.6; the bind is built with
33
- // the same poles and its feet that much further in, so the resting stance reproduces it
34
- export const SPRAWL = 0.25;
35
-
36
- // Knee / elbow of a two-bone chain a -> c (lengths l1, l2) bent toward the pole direction (the
37
- // engine's IK solve, so the bind limb lies in the plane the engine bends it in)
38
- export function solve2(a, c, l1, l2, pole) {
39
- const d = sub(c, a), D = len(d), e1 = norm(d);
40
- let e2 = sub(pole, mul(e1, dot(pole, e1)));
41
- e2 = norm(e2);
42
- const cosA = Math.max(-1, Math.min(1, (l1 * l1 + D * D - l2 * l2) / (2 * l1 * D)));
43
- return add(a, add(mul(e1, cosA * l1), mul(e2, Math.sqrt(1 - cosA * cosA) * l1)));
44
- }
45
-
46
- // the sitting foot (left): heel beside the vent, tarsus and foot forward (tarsus pitched ~4.4 deg)
47
- const FOOT = { x: 0.035, hockBack: 0.0175, tilt: 4.4 };
48
-
49
- // the eye centre (the eye bone's head) of the left eye, see sculpt.js EYE
50
- export const EYE_C = [0.0152, 0.0012, -0.0002];
51
-
52
- export function frogJoints(params = {}) {
53
- const J = {
54
- // axial: vent -> sacral hump -> back -> skull
55
- tailBase: [0, 0.021, -0.052],
56
- lumbosacral: [0, 0.037, -0.03],
57
- lumbarMid: [0, 0.042, -0.017],
58
- thoraxRear: [0, 0.045, -0.004],
59
- chestMid: [0, 0.047, 0.009],
60
- neckBase: [0, 0.049, 0.018],
61
- neckMid: [0, 0.0505, 0.023],
62
- occiput: [0, 0.052, 0.028],
63
- nose: [0, 0.0505, 0.088],
64
- jawHinge: [0, 0.0395, 0.03],
65
- jawTip: [0, 0.0405, 0.086],
66
- // forelimb: shoulder behind the jaw angle, humerus back and down along the flank, radio-ulna
67
- // nearly upright, palm flat, fingers pointing forward and in
68
- scapTopL: [0.013, 0.054, 0.012],
69
- shoulderL: [0.0175, 0.034, 0.016],
70
- wristL: [0.025, 0.0055, 0.011],
71
- mcpL: [0.025, 0.0036, 0.0225],
72
- ftoeL: [0.025, 0.0011, 0.0395],
73
- // hind limb: the Z-fold of the sit: femur forward and out, tibiofibula back alongside it, the heel
74
- // beside the vent, tarsus and the long foot forward on the ground
75
- hipL: [0.0105, 0.028, -0.044],
76
- };
77
- // (the engine keeps a foot in the plane of its forward axis and places it by its joints' y / z only:
78
- // the bind hands and feet run straight ahead, the fingers and toes fan out from them in the sculpt:
79
- // fingers turned in, the long toes turned out)
80
- const tt = (FOOT.tilt * Math.PI) / 180;
81
- J.hockL = [FOOT.x, 0.0056 + 0.0377 * Math.sin(tt), J.hipL[2] - FOOT.hockBack];
82
- J.mtpL = [FOOT.x, 0.0056, J.hockL[2] + 0.0377 * Math.cos(tt)];
83
- J.htoeL = [FOOT.x, 0.0012, J.mtpL[2] + 0.0606];
84
- // knee and elbow from the engine's poles (sprawl)
85
- J.kneeL = solve2(J.hipL, J.hockL, SEG.fem, SEG.tib, [0.12 + SPRAWL * 1.6, 0, 1]);
86
- J.elbowL = solve2(J.shoulderL, J.wristL, SEG.hum, SEG.rad, [0.08 + SPRAWL * 1.6, 0, -1]);
87
- // extra bones
88
- const ec = hl(EYE_C);
89
- J.eyeBaseL = ec;
90
- J.eyeTopL = [ec[0], ec[1] + 0.008, ec[2]];
91
- J.throatBase = [0, 0.044, 0.036];
92
- J.throatTip = [0, 0.03, 0.046];
93
- J.tongueBase = [0, 0.0425, 0.079];
94
- J.tongueTip = [0, 0.0435, 0.046];
95
- void params;
96
- return J;
97
- }
98
-
99
- // rig.unit: the frog is short at the shoulder (0.054 m / 0.76 m = 0.07 of the cheetah) but its limbs are
100
- // long (hind limb 0.17 m, ~0.3 of the cheetah's). The core scales its skin-blend widths by the unit, and
101
- // the knee and ankle of the Z-folded hind leg swing ~150 deg between the sit and a leap: they need
102
- // blends as wide as the limb's scale, so the limb scale is used. The species' own blend distances
103
- // below are given in metres (u()).
104
- export const UNIT = 0.3;
105
- const u = (m) => m / UNIT;
106
-
107
- export function frogRig(params = {}) {
108
- const J = frogJoints(params);
109
- const rig = buildRig({
110
- joints: J,
111
- // characteristic length relative to the cheetah: shoulder (scapula top) height 0.054 m / 0.76 m
112
- unit: UNIT,
113
- headOrigin: HEAD_O,
114
- bones: quadrupedBones({
115
- tailSegs: 0, ears: false, jaw: true,
116
- extra: [
117
- ['eye{S}', 'eyeBase{S}', 'eyeTop{S}', 'head', { region: 'head', group: 'eye{S}' }],
118
- ['throat', 'throatBase', 'throatTip', 'head', { region: 'head', group: 'throat' }],
119
- ['tongue', 'tongueBase', 'tongueTip', 'jaw', { region: 'jaw', group: 'tongue' }],
120
- ],
121
- }),
122
- axial: {
123
- points: ['nose', 'occiput', 'neckMid', 'neckBase', 'chestMid', 'thoraxRear', 'lumbarMid', 'lumbosacral', 'tailBase'],
124
- bones: ['head', 'neck2', 'neck1', 'chest', 'spine3', 'spine2', 'spine1', 'pelvis'],
125
- // no neck: the skull's skin blends into the shoulders over a wide band
126
- blend: { 1: [u(-0.0084), u(0.0084), 0.5], 2: [u(-0.0042), u(0.0042)], 3: [u(-0.0042), u(0.0042)] },
127
- },
128
- limbs: frogLimbs(params),
129
- appendages: [
130
- { group: 'eyeL', bone: 'eyeL', blend: [u(-0.0014), u(0.0021)] },
131
- { group: 'eyeR', bone: 'eyeR', blend: [u(-0.0014), u(0.0021)] },
132
- { group: 'throat', bone: 'throat', blend: [u(-0.00105), u(0.0021)] },
133
- ],
134
- webTags: ['groin', 'thighweb', 'armpit'],
135
- });
136
- return rig;
137
- }
138
-
139
- // Skin-weight limbs: the standard ones; in the hind limb only the rigid webbed foot is 'distal' (the
140
- // ankle of the frog's Z-folded leg swings as far as its knee and blends as widely).
141
- export function frogLimbs(params = {}) {
142
- const L = quadrupedLimbs({ front: { tCore: 0.75, aCore: u(0.0035), aBody: u(0.0021), midX: u(0.00028) }, hind: {} });
143
- const hf = params.hindField || { tCore: 0.15, aCore: u(0.0035), aBody: u(0.0007), midX: u(0.00028) };
144
- const seg = params.segField || { tCore: 0, aCore: u(0.003), aBody: u(0.0005), midX: u(0.00028) };
145
- for (const S of ['L', 'R']) {
146
- const side = S === 'L' ? 1 : -1;
147
- if (params.splitHind !== true) {
148
- L['H' + S] = { side, S, front: false, bones: ['femur' + S, 'tibia' + S, 'metatarsus' + S, 'hpaw' + S], proximal: ['femur' + S], distal: ['hpaw' + S], field: { a: 'hip' + S, b: 'knee' + S, top: 'femur' + S, ...hf } };
149
- continue;
150
- }
151
- L['H' + S] = { side, S, front: false, bones: ['femur' + S], proximal: ['femur' + S], distal: [], field: { a: 'hip' + S, b: 'knee' + S, top: 'femur' + S, ...hf } };
152
- L['H' + S + 's'] = { side, S, front: false, bones: ['tibia' + S], proximal: ['tibia' + S], distal: [], field: { a: 'knee' + S, b: 'hock' + S, top: 'tibia' + S, ...seg } };
153
- L['H' + S + 'f'] = { side, S, front: false, bones: ['metatarsus' + S, 'hpaw' + S], proximal: ['metatarsus' + S], distal: ['hpaw' + S], field: { a: 'hock' + S, b: 'mtp' + S, top: 'metatarsus' + S, ...seg } };
154
- }
155
- return L;
156
- }
@@ -1,240 +0,0 @@
1
- // The frog, sculpted as a signed distance field around the sitting bind pose (rig.js).
2
- // Every primitive is attached to a bone (skinning) and a group (axial / limb / eye / throat / jaw /
3
- // tongue). Head primitives are placed in head-local coordinates (HEAD_O: midline, level with the eye
4
- // centres), measured from the profile, front and dorsal reference photos.
5
- //
6
- // Anatomy: no neck; a broad flat head wider than long with a huge mouth line running back to below
7
- // the tympanum; large bulging eyes on top of the head; a big round tympanum behind each eye (larger
8
- // than the eye in males) under the supratympanic fold; a plump trunk rising from the vent to the
9
- // sacral hump; short forelimbs with four slender fingers; very long hind limbs (heavy thigh,
10
- // tibiofibula, elongated tarsus, long foot with five webbed toes). Common frog variant: dorsolateral
11
- // folds along the back.
12
- import { HEAD_O, hl, EYE_C } from './rig.js';
13
- import { add, sub, mul, lerp, norm, cross, dot } from '../../core/math/vec.js';
14
- import { sculptEyeSocket } from '../../core/sdf/eyeSocket.js';
15
- import { SDFModel } from '../../core/sdf/sdf.js';
16
-
17
- // Large bulging eye: globe radius 7.2 mm (visible eye ~14-15 mm at SVL 140 mm), looking out ~57 deg
18
- // and up ~24 deg; a wide, nearly round aperture (no sclera), thick upper lid.
19
- export const EYE = {
20
- c: EYE_C, r: 0.0079, back: 0, yaw: 1.0, pitch: 0.42, lid: 0.0013,
21
- R: 0.0081, d: 0.0009, off: 0.0006, tilt: (6 * Math.PI) / 180, irisZ: 0.0052, irisR: 0.0071,
22
- };
23
-
24
- const X = [1, 0, 0];
25
-
26
- // A carved slot in the fold of a joint J between the segments toward A and toward B: a thin slab in
27
- // the plane of the joint's hinge axis and the bisector of the two segments, from `start` (m from the
28
- // joint) out to `len`.
29
- function foldSlot(m, Jt, A, Bp, start, len, tag, bone, group) {
30
- const a = norm(sub(A, Jt)), b = norm(sub(Bp, Jt));
31
- const bis = norm(add(a, b)), axis = norm(cross(a, b));
32
- m.fin({ tag, bone, group, o: add(Jt, mul(bis, start)), u: bis, v: axis, poly: [[0, -0.02], [len, -0.02], [len, 0.02], [0, 0.02]], t: 0.0026, round: 0.0012, k: 0.0006, carve: true });
33
- }
34
-
35
- // point where the ray p + t dir (t in -2..2 cm) crosses the body surface sculpted so far
36
- function surfaceAlong(m, p, dir) {
37
- const prims = m.prims.filter((q) => q.part === 'body');
38
- const f = (t) => SDFModel.evalList(prims, p[0] + dir[0] * t, p[1] + dir[1] * t, p[2] + dir[2] * t);
39
- let lo = -0.02, hi = 0.02;
40
- for (let i = 0; i < 40; i++) { const mid = 0.5 * (lo + hi); if (f(mid) < 0) lo = mid; else hi = mid; }
41
- return add(p, mul(dir, 0.5 * (lo + hi)));
42
- }
43
-
44
- // tympanum (head-local, left): centre, outward normal, radius by sex
45
- export function tympanum(params = {}) {
46
- const male = params.sex === 'male';
47
- const r = (params.tympanum || (male ? 0.0105 : 0.0074)) * (params.variant === 'common-frog' ? 0.78 : 1);
48
- return { c: [0.0262, -0.0085, -0.0235], n: norm([1, 0.12, -0.25]), r };
49
- }
50
-
51
- export function sculptFrog(m, rig, params = {}) {
52
- const J = rig.J;
53
- const male = params.sex === 'male';
54
- const temporaria = params.variant === 'common-frog';
55
- const plump = params.plump || 1;
56
-
57
- // Ellipsoid whose local Y follows `ydir`; radii = [lateral, along ydir, third axis]
58
- const ellY = (o) => {
59
- const y = norm(o.ydir);
60
- const lat = o.lateral || X;
61
- const z = norm(cross(lat, y));
62
- return m.ell({ ...o, axis: z, up: y, r: [o.r[0], o.r[1], o.r[2]] });
63
- };
64
-
65
- // ---------------------------------------------------------------- TRUNK (vent low, sacral hump, plump belly)
66
- const bodyAx = norm([0, 0.22, 1]);
67
- m.ell({ tag: 'trunk', bone: 'spine2', c: ([0, 0.0375, -0.012]), r: [0.032 * plump, 0.0205, 0.037], axis: bodyAx, k: 0 });
68
- m.ell({ tag: 'chest', bone: 'chest', c: [0, 0.041, 0.012], r: [0.026 * plump, 0.0185, 0.02], axis: bodyAx, k: 0.012 });
69
- m.ell({ tag: 'shoulders', bone: 'chest', c: [0, 0.049, 0.015], r: [0.024, 0.012, 0.016], k: 0.012 });
70
- m.ell({ tag: 'belly', bone: 'spine2', c: ([0, 0.027, -0.016]), r: [0.031 * plump, 0.0135, 0.03], axis: norm([0, 0.3, 1]), k: 0.014 });
71
- m.ell({ tag: 'hump', bone: 'pelvis', c: ([0, 0.041, -0.033]), r: [0.022, 0.0165, 0.017], k: 0.012 });
72
- m.ell({ tag: 'rump', bone: 'pelvis', c: ([0, 0.027, -0.046]), r: [0.0175, 0.0155, 0.0135], axis: norm([0, 0.5, 1]), k: 0.012 });
73
- // the vent: a slight crease at the back of the rump
74
- m.ell({ tag: 'vent', bone: 'pelvis', c: ([0, 0.016, -0.059]), r: [0.004, 0.0022, 0.004], k: 0.002, carve: true });
75
-
76
- // ---------------------------------------------------------------- HEAD (head-local, see HEAD_O)
77
- const H = { bone: 'head' };
78
- const hw = params.headWidth || 1;
79
- m.ell({ ...H, tag: 'cranium', c: hl([0, -0.01, -0.008]), r: [0.0268 * hw, 0.0105, 0.03], k: 0.012 });
80
- m.ell({ ...H, tag: 'snout', c: hl([0, -0.0115, 0.013]), r: [0.019 * hw, 0.0088, 0.027], k: 0.01 });
81
- // the canthus: a soft ridge from the eye to the nostril, the flat loreal region below it
82
- for (const s of [1, -1]) {
83
- m.cone({ ...H, tag: 'canthus', a: hl([0.0105 * s, -0.0028, 0.006]), b: hl([0.0052 * s, -0.0045, 0.0305]), ra: 0.0028, rb: 0.0018, k: 0.005 });
84
- // cheeks and the corners of the jaw (the head is widest here)
85
- m.ell({ ...H, tag: 'cheek', c: hl([0.0205 * s * hw, -0.0145, -0.017]), r: [0.0095, 0.0092, 0.0145], k: 0.009 });
86
- m.ell({ ...H, tag: 'lipwall', c: hl([0.0165 * s * hw, -0.0142, 0.002]), r: [0.0075, 0.0048, 0.028], axis: norm([-0.32 * s, 0, 1]), k: 0.008 });
87
- m.ell({ ...H, tag: 'temple', c: hl([0.02 * s * hw, -0.0065, -0.028]), r: [0.009, 0.008, 0.011], k: 0.008 });
88
- // nostrils: small raised rims with the opening carved
89
- m.sphere({ ...H, tag: 'naris', c: hl([0.0056 * s, -0.0048, 0.0318]), rad: 0.0019, k: 0.0025 });
90
- m.sphere({ ...H, tag: 'nostril', c: hl([0.0058 * s, -0.0035, 0.0322]), rad: 0.0009, k: 0.0006, carve: true });
91
- // tympanum: a flat disc set a little into the side of the head, with a low rim
92
- const T = tympanum(params);
93
- const tc = [T.c[0] * s, T.c[1], T.c[2]], tn = [T.n[0] * s, T.n[1], T.n[2]];
94
- // (placed on the surface sculpted so far: a flat disc 0.35 mm below it at its centre)
95
- const ts = surfaceAlong(m, hl(tc), tn);
96
- m.ell({ ...H, tag: 'tympanum', c: add(ts, mul(tn, 0.0019 - 0.00035)), r: [T.r, T.r, 0.0019], axis: tn, k: 0.0012, carve: true });
97
- // supratympanic fold: from behind the eye over the tympanum and down behind it to the shoulder
98
- const f0 = hl([0.0142 * s, 0.0012, -0.0095]), f1 = hl([0.0228 * s, -0.001, -0.0245]);
99
- const f2 = hl([0.0268 * s, -0.0075, -0.037]), f3 = [0.024 * s, 0.037, 0.018];
100
- m.cone({ ...H, tag: 'stfold', a: f0, b: f1, ra: 0.0017, rb: 0.0021, k: 0.004 });
101
- m.cone({ ...H, tag: 'stfold', a: f1, b: f2, ra: 0.0021, rb: 0.002, k: 0.004 });
102
- m.cone({ tag: 'stfold', bone: 'chest', a: f2, b: f3, ra: 0.002, rb: 0.0015, k: 0.005 });
103
- // eyes: bulging lids on their own bone (they retract into the head to blink)
104
- const n0 = m.prims.length;
105
- sculptEyeSocket(m, EYE, HEAD_O, s, { bone: 'eye' + (s > 0 ? 'L' : 'R'), orbit: { r: [0.0085, 0.006, 0.004], at: [0, -0.001, 0.007], k: 0.003 } });
106
- for (const p of m.prims.slice(n0)) p.group = 'eye' + (s > 0 ? 'L' : 'R');
107
- // the fleshy base of the eye bulge (a turret the globe sits in), on the eye bone
108
- const ec = hl([EYE_C[0] * s, EYE_C[1], EYE_C[2]]);
109
- m.ell({ tag: 'eyebase', bone: 'eye' + (s > 0 ? 'L' : 'R'), group: 'eye' + (s > 0 ? 'L' : 'R'), c: add(ec, [0.0005 * s, -0.004, -0.0005]), r: [0.0075, 0.005, 0.0082], k: 0.006 });
110
- }
111
- // the mouth: the upper jaw's underside is cut flat along the lip line (the lower jaw is its own part)
112
- m.ell({ ...H, tag: 'palate', c: hl([0, -0.028, 0.005]), r: [0.05, 0.0115, 0.06], axis: norm([0, 0.04, 1]), k: 0.0008, carve: true });
113
-
114
- // ---------------------------------------------------------------- LOWER JAW (rigid, meshed separately)
115
- const JW = { bone: 'jaw', group: 'jaw', part: 'jaw' };
116
- m.ell({ ...JW, tag: 'mandible', c: hl([0, -0.0185, 0.004]), r: [0.0232 * hw, 0.0066, 0.028], k: 0 });
117
- m.ell({ ...JW, tag: 'chin', c: hl([0, -0.0188, 0.0255]), r: [0.0105, 0.0055, 0.0068], k: 0.006 });
118
- for (const s of [1, -1]) m.ell({ ...JW, tag: 'jawcorner', c: hl([0.0195 * s * hw, -0.0188, -0.017]), r: [0.0062, 0.0062, 0.0105], k: 0.006 });
119
-
120
- // ---------------------------------------------------------------- THROAT (buccal floor and vocal sac: the throat bone)
121
- const TH = { bone: 'throat', group: 'throat' };
122
- m.ell({ ...TH, tag: 'throat', c: [0, 0.0355, 0.036], r: [0.0205, 0.0082, 0.019], k: 0.012 });
123
- m.ell({ ...TH, tag: 'gular', c: [0, 0.0335, 0.022], r: [0.0195, 0.0095, 0.012], k: 0.012 });
124
-
125
- // ---------------------------------------------------------------- TONGUE (rigid, attached at the front of the jaw)
126
- m.cone({ bone: 'tongue', group: 'tongue', part: 'tongue', tag: 'tongue', a: J.tongueBase, b: lerp(J.tongueBase, J.tongueTip, 0.82), ra: 0.0028, rb: 0.0048, k: 0 });
127
- m.ell({ bone: 'tongue', group: 'tongue', part: 'tongue', tag: 'tonguetip', c: lerp(J.tongueBase, J.tongueTip, 0.88), r: [0.0068, 0.0032, 0.0055], k: 0.003 });
128
-
129
- // ---------------------------------------------------------------- DORSOLATERAL FOLDS (common frog)
130
- if (temporaria) {
131
- for (const s of [1, -1]) {
132
- const pts = [hl([0.0125 * s, 0.0005, -0.012]), [0.0165 * s, 0.059, 0.013], [0.0175 * s, 0.0565, -0.008], [0.0165 * s, 0.054, -0.026], [0.0135 * s, 0.047, -0.042]];
133
- const bones = ['head', 'chest', 'spine3', 'spine2'];
134
- for (let i = 0; i < 4; i++) m.cone({ tag: 'dlfold', bone: bones[i], a: pts[i], b: pts[i + 1], ra: 0.0016, rb: 0.0016, k: 0.004 });
135
- }
136
- }
137
-
138
- // ---------------------------------------------------------------- LEGS
139
- const arm = (male ? 1.18 : 1) * (params.armK || 1);
140
- for (const S of ['L', 'R']) {
141
- const s = S === 'L' ? 1 : -1;
142
- const lat = [s, 0, 0];
143
- const sx = (v) => [v[0] * s, v[1], v[2]];
144
- // ---- front: short, upright, four slender fingers
145
- const g = 'F' + S;
146
- const Sh = J['shoulder' + S], E = J['elbow' + S], W = J['wrist' + S], M = J['mcp' + S], T = J['ftoe' + S];
147
- ellY({ tag: 'armpit', bone: 'humerus' + S, group: g, c: add(lerp(Sh, E, 0.3), sx([-0.003, 0.002, 0.002])), ydir: sub(E, Sh), lateral: lat, r: [0.0075, 0.012, 0.0075], k: 0.01 });
148
- m.cone({ tag: 'upperarm', bone: 'humerus' + S, group: g, a: Sh, b: E, ra: 0.0062 * arm, rb: 0.0048 * arm, k: 0.008 });
149
- m.cone({ tag: 'forearm', bone: 'radius' + S, group: g, a: E, b: W, ra: 0.0048 * arm, rb: 0.0031, k: 0.003 });
150
- ellY({ tag: 'forearmmuscle', bone: 'radius' + S, group: g, c: lerp(E, W, 0.3), ydir: sub(W, E), lateral: lat, r: [0.0046 * arm, 0.0085, 0.0048 * arm], k: 0.003 });
151
- const dp = norm(sub(M, W)), up = [0, 1, 0];
152
- ellY({ tag: 'palm', bone: 'metacarpus' + S, group: g, c: lerp(W, M, 0.55), ydir: dp, lateral: norm(cross(dp, up)), r: [0.0045, 0.0068, 0.0022], k: 0.003 });
153
- // fingers fan out from the palm: III longest, pointing forward and in; I (thumb) inside
154
- const fdir = norm(sub(T, M));
155
- // [angle from straight ahead (rad, + outward), length]
156
- const FING = [[-0.95, 0.0105, 1], [-0.62, 0.0135, 1], [-0.3, 0.0184, 1], [0.08, 0.0128, 1]];
157
- for (let i = 0; i < 4; i++) {
158
- const [a, L] = FING[i];
159
- const d = norm([s * Math.sin(a), fdir[1], Math.cos(a)]);
160
- const base = add(M, mul(d, -0.001));
161
- const tip = add(base, mul(d, L));
162
- tip[1] = 0.0014;
163
- m.cone({ tag: 'finger', bone: 'fpaw' + S, group: g, a: base, b: tip, ra: 0.0017, rb: 0.0011, k: 0.0015 });
164
- m.sphere({ tag: 'fingertip', bone: 'fpaw' + S, group: g, c: tip, rad: 0.00135, k: 0.001 });
165
- // male: dark nuptial pad on the thumb
166
- if (i === 0 && male) m.ell({ tag: 'nuptial', bone: 'fpaw' + S, group: g, c: lerp(base, tip, 0.3), r: [0.0022, 0.0022, 0.003], axis: d, k: 0.002 });
167
- }
168
-
169
- // ---- hind: heavy thigh, tibiofibula, long tarsus, long webbed foot
170
- const h = 'H' + S;
171
- const hs = params.splitHind !== true ? h : h + 's', hf = params.splitHind !== true ? h : h + 'f';
172
- const Hp = J['hip' + S], K = J['knee' + S], Hk = J['hock' + S], Mt = J['mtp' + S], Tt = J['htoe' + S];
173
- // web between thigh and body (spans limb and body)
174
- ellY({ tag: 'groin', bone: 'femur' + S, group: h, c: add(lerp(Hp, K, 0.22), sx([-0.002, 0.004, 0])), ydir: sub(K, Hp), lateral: lat, r: [0.0095, 0.016, 0.0095], k: 0.012, bias: 0.001 });
175
- // thigh: a thick muscle mass (the widest part of the hind limb), tapering to the knee
176
- m.cone({ tag: 'thigh', bone: 'femur' + S, group: h, a: Hp, b: K, ra: 0.0105, rb: 0.0058, k: 0.004 });
177
- ellY({ tag: 'thighmuscle', bone: 'femur' + S, group: h, c: add(lerp(Hp, K, 0.42), sx([0.0015, 0.0022, 0.0])), ydir: sub(K, Hp), lateral: lat, r: [0.0128, 0.026, 0.0118], k: 0.0025 });
178
- // shank: the calf bulges near the knee, slim toward the ankle (small blend with the thigh so the
179
- // two stay separate when the leg extends)
180
- m.sphere({ tag: 'kneecap', bone: 'tibia' + S, group: hs, c: K, rad: 0.0046, k: 0.005 });
181
- m.cone({ tag: 'shank', bone: 'tibia' + S, group: hs, a: K, b: Hk, ra: 0.0056, rb: 0.0036, k: 0.006 });
182
- ellY({ tag: 'calf', bone: 'tibia' + S, group: hs, c: add(lerp(K, Hk, 0.36), sx([0.0012, 0.0006, 0])), ydir: sub(Hk, K), lateral: lat, r: [0.0066, 0.0185, 0.0064], k: 0.006 });
183
- // the folds between thigh and shank and between shank and tarsus: in the Z-folded sit the segments
184
- // lie pressed together; a narrow slot down to near each joint keeps their skins apart (each wall
185
- // rides its own bone), so the legs straighten in a leap without stretching a web of skin across
186
- // the fold
187
- if (params.foldSlots !== false) foldSlot(m, K, Hp, Hk, 0.0045, 0.038, 'kneefold', 'tibia' + S, h);
188
- if (params.foldSlots !== false) foldSlot(m, Hk, K, Mt, 0.0035, 0.024, 'anklefold', 'metatarsus' + S, h);
189
- // tarsus (the frog's extra long segment) and the heel
190
- m.sphere({ tag: 'heel', bone: 'metatarsus' + S, group: hf, c: Hk, rad: 0.0038, k: 0.004 });
191
- m.cone({ tag: 'tarsus', bone: 'metatarsus' + S, group: hf, a: Hk, b: Mt, ra: 0.0036, rb: 0.0031, k: 0.004 });
192
- // foot: five long toes fanning out, IV longest; webbing to near the tips (not IV's last phalanges)
193
- const fd = norm(sub(Tt, Mt));
194
- const fl = norm(cross(fd, [0, 1, 0])); // toward the midline for the left foot? (fd x up)
195
- const inward = mul(fl, dot(fl, [s, 0, 0]) > 0 ? -1 : 1); // unit vector toward the midline
196
- // [angle from straight ahead (rad, + outward), length from the tarsus (m)]: I-V, IV longest
197
- const TOES = [[-0.08, 0.021], [0.1, 0.031], [0.28, 0.043], [0.52, 0.07], [0.74, 0.042]];
198
- const rot = (a) => { // rotate fd about y, + turns outward
199
- const c = Math.cos(a), sn = Math.sin(a);
200
- return norm(add(mul(fd, c), mul(inward, -sn)));
201
- };
202
- const base0 = add(Mt, mul(fd, 0.004));
203
- const tips = [];
204
- m.ell({ tag: 'sole', bone: 'hpaw' + S, group: hf, c: add(Mt, mul(fd, 0.009)), r: [0.0052, 0.0028, 0.0105], axis: fd, k: 0.003 });
205
- for (let i = 0; i < 5; i++) {
206
- const [a, lk] = TOES[i];
207
- const d = rot(a);
208
- const b = add(base0, mul(d, 0.004));
209
- const tip = add(b, mul(d, lk - 0.008));
210
- tip[1] = 0.0017;
211
- tips.push({ b, tip, d });
212
- m.cone({ tag: 'toe', bone: 'hpaw' + S, group: hf, a: add(Mt, mul(d, 0.002)), b: tip, ra: 0.0024, rb: 0.0013, k: 0.002 });
213
- m.sphere({ tag: 'toetip', bone: 'hpaw' + S, group: hf, c: tip, rad: 0.0015, k: 0.0008 });
214
- }
215
- // web: a thin membrane in the plane of the foot, its free margin notched between the toes
216
- {
217
- const o = [Mt[0], Mt[1] - 0.0024, Mt[2]];
218
- const un = norm(sub([Tt[0], 0.0019, Tt[2]], o));
219
- const v = norm(cross([0, 1, 0], un)); // lateral in-plane axis (points to the animal's left for fd forward)
220
- const to2 = (p) => { const q = sub(p, o); return [dot(q, un), dot(q, v)]; };
221
- const poly = [to2(add(Mt, mul(fd, -0.002)))];
222
- const webTo = [0.92, 0.9, 0.86, 0.7, 0.92];
223
- const P2 = tips.map((t, i) => to2(lerp(t.b, t.tip, webTo[i])));
224
- // order the toes by their in-plane angle so the outline does not cross itself
225
- const order = [0, 1, 2, 3, 4].sort((a, b) => Math.atan2(P2[a][1], P2[a][0]) - Math.atan2(P2[b][1], P2[b][0]));
226
- for (let k = 0; k < order.length; k++) {
227
- const i = order[k];
228
- poly.push(P2[i]);
229
- if (k < order.length - 1) {
230
- // concave margin between two toes: back toward the base
231
- const j = order[k + 1];
232
- const mid = [(P2[i][0] + P2[j][0]) * 0.5, (P2[i][1] + P2[j][1]) * 0.5];
233
- poly.push([mid[0] * 0.8, mid[1] * 0.8]);
234
- }
235
- }
236
- m.fin({ tag: 'web', bone: 'hpaw' + S, group: hf, o, u: un, v, poly, t: 0.0014, k: 0.0018, thin: true });
237
- }
238
- }
239
- return m;
240
- }