@bitefoundry/retrieviewer 0.0.2 → 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 (261) 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 +75 -0
  6. package/INSTALLING.md +8 -5
  7. package/PLUGIN.md +13 -10
  8. package/PREREQUISITES.md +95 -0
  9. package/PUPPY-MEMORY.md +102 -1
  10. package/README.ko.md +110 -0
  11. package/README.md +119 -58
  12. package/RELEASING.md +27 -14
  13. package/THIRD-PARTY-NOTICES.md +5 -3
  14. package/braille.mjs +35 -9
  15. package/examples/live.mjs +2 -2
  16. package/integrations/desktop/platform.mjs +27 -0
  17. package/integrations/linux-overlay/README.md +83 -0
  18. package/integrations/linux-overlay/overlay.py +1094 -0
  19. package/integrations/macos-overlay/README.md +83 -0
  20. package/integrations/macos-overlay/overlay.jxa +639 -0
  21. package/integrations/opencode/runtime.mjs +4 -4
  22. package/integrations/opencode/tui.tsx +1 -1
  23. package/integrations/windows-overlay/Overlay.cs +4 -4
  24. package/integrations/windows-overlay/desktop.mjs +40 -8
  25. package/integrations/windows-overlay/protocol.mjs +11 -7
  26. package/integrations/windows-overlay/worker.mjs +13 -7
  27. package/package.json +41 -14
  28. package/puppy-comfort-sprites.mjs +25 -0
  29. package/puppy-companion-comfort-q5.bin.gz +0 -0
  30. package/puppy-companion-comfort.json +77 -0
  31. package/puppy-companion-life.mjs +49 -16
  32. package/puppy-companion-objects.mjs +12 -0
  33. package/puppy-frame-predictive.mjs +15 -9
  34. package/puppy-frame-store.mjs +2 -2
  35. package/puppy-paper-world.mjs +14 -0
  36. package/puppy-paper.mjs +65 -14
  37. package/retrieviewer-cli.mjs +10 -3
  38. package/retrieviewer-plugin.d.mts +1 -1
  39. package/retrieviewer-plugin.mjs +1 -1
  40. package/retrieviewer.d.mts +10 -4
  41. package/retrieviewer.mjs +20 -14
  42. package/locomotion-core.mjs +0 -21
  43. package/locomotion-puppy.animal +0 -0
  44. package/vendor/procedural-animals/package.json +0 -40
  45. package/vendor/procedural-animals/src/animal.js +0 -146
  46. package/vendor/procedural-animals/src/bake.js +0 -51
  47. package/vendor/procedural-animals/src/build.js +0 -81
  48. package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
  49. package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
  50. package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
  51. package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
  52. package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
  53. package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
  54. package/vendor/procedural-animals/src/core/build/seams.js +0 -183
  55. package/vendor/procedural-animals/src/core/build/warp.js +0 -112
  56. package/vendor/procedural-animals/src/core/build/weights.js +0 -393
  57. package/vendor/procedural-animals/src/core/math/vec.js +0 -81
  58. package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
  59. package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
  60. package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
  61. package/vendor/procedural-animals/src/core/motion/common.js +0 -158
  62. package/vendor/procedural-animals/src/core/motion/index.js +0 -22
  63. package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
  64. package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
  65. package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
  66. package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
  67. package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
  68. package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
  69. package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
  70. package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
  71. package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
  72. package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
  73. package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
  74. package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
  75. package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
  76. package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
  77. package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
  78. package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
  79. package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
  80. package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
  81. package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
  82. package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
  83. package/vendor/procedural-animals/src/index.d.ts +0 -98
  84. package/vendor/procedural-animals/src/index.js +0 -29
  85. package/vendor/procedural-animals/src/registry.js +0 -48
  86. package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
  87. package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
  88. package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
  89. package/vendor/procedural-animals/src/species/bear/index.js +0 -139
  90. package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
  91. package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
  92. package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
  93. package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
  94. package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
  95. package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
  96. package/vendor/procedural-animals/src/species/boar/index.js +0 -110
  97. package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
  98. package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
  99. package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
  100. package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
  101. package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
  102. package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
  103. package/vendor/procedural-animals/src/species/cat/index.js +0 -211
  104. package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
  105. package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
  106. package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
  107. package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
  108. package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
  109. package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
  110. package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
  111. package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
  112. package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
  113. package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
  114. package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
  115. package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
  116. package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
  117. package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
  118. package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
  119. package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
  120. package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
  121. package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
  122. package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
  123. package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
  124. package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
  125. package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
  126. package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
  127. package/vendor/procedural-animals/src/species/cow/index.js +0 -118
  128. package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
  129. package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
  130. package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
  131. package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
  132. package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
  133. package/vendor/procedural-animals/src/species/crow/index.js +0 -70
  134. package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
  135. package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
  136. package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
  137. package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
  138. package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
  139. package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
  140. package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
  141. package/vendor/procedural-animals/src/species/deer/index.js +0 -106
  142. package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
  143. package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
  144. package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
  145. package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
  146. package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
  147. package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
  148. package/vendor/procedural-animals/src/species/dog/index.js +0 -144
  149. package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
  150. package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
  151. package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
  152. package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
  153. package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
  154. package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
  155. package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
  156. package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
  157. package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
  158. package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
  159. package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
  160. package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
  161. package/vendor/procedural-animals/src/species/fish/index.js +0 -88
  162. package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
  163. package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
  164. package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
  165. package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
  166. package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
  167. package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
  168. package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
  169. package/vendor/procedural-animals/src/species/fox/index.js +0 -120
  170. package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
  171. package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
  172. package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
  173. package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
  174. package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
  175. package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
  176. package/vendor/procedural-animals/src/species/frog/index.js +0 -97
  177. package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
  178. package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
  179. package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
  180. package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
  181. package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
  182. package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
  183. package/vendor/procedural-animals/src/species/goat/index.js +0 -149
  184. package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
  185. package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
  186. package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
  187. package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
  188. package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
  189. package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
  190. package/vendor/procedural-animals/src/species/horse/index.js +0 -80
  191. package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
  192. package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
  193. package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
  194. package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
  195. package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
  196. package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
  197. package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
  198. package/vendor/procedural-animals/src/species/lion/index.js +0 -111
  199. package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
  200. package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
  201. package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
  202. package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
  203. package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
  204. package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
  205. package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
  206. package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
  207. package/vendor/procedural-animals/src/species/pig/index.js +0 -161
  208. package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
  209. package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
  210. package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
  211. package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
  212. package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
  213. package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
  214. package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
  215. package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
  216. package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
  217. package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
  218. package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
  219. package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
  220. package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
  221. package/vendor/procedural-animals/src/species/rat/index.js +0 -111
  222. package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
  223. package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
  224. package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
  225. package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
  226. package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
  227. package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
  228. package/vendor/procedural-animals/src/species/shark/index.js +0 -104
  229. package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
  230. package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
  231. package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
  232. package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
  233. package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
  234. package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
  235. package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
  236. package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
  237. package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
  238. package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
  239. package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
  240. package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
  241. package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
  242. package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
  243. package/vendor/procedural-animals/src/species/snake/index.js +0 -73
  244. package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
  245. package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
  246. package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
  247. package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
  248. package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
  249. package/vendor/procedural-animals/src/species/spider/index.js +0 -78
  250. package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
  251. package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
  252. package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
  253. package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
  254. package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
  255. package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
  256. package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
  257. package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
  258. package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
  259. package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
  260. package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
  261. 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
- }