@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,118 +0,0 @@
1
- // Spider skeleton in bind pose (metres; dimensions below are written in millimetres).
2
- // Forward = +Z, up = +Y, the animal's left = +X. Two variants share the rig: the wolf spider
3
- // (Lycosidae, reference female Hogna carolinensis, body 25 mm) and the tarantula (Theraphosidae,
4
- // reference female Brachypelma hamorii, body 60 mm).
5
- import { buildRig } from '../../core/rig/rig.js';
6
- import { spiderBones, spiderLimbs, planarChain, solveBindElevations, legJoints, palpJoints, AXIAL_POINTS, AXIAL_BONES } from '../../core/rig/spider.js';
7
-
8
- const D2R = Math.PI / 180;
9
- const mm = (v) => v.map((x) => x * 0.001);
10
-
11
- // Per-variant anatomy (mm, degrees). leg: [I, II, III, IV] total lengths; seg: segment fractions
12
- // coxa, trochanter, femur, patella, tibia, metatarsus, tarsus; el: bind elevations of the segments
13
- // (the metatarsus is solved so the claw rests on the ground); r: segment radii (base, end).
14
- export const VARIANTS = {
15
- wolf: {
16
- unit: 0.013,
17
- bodyLen: 25,
18
- axial: { front: [0, 7.4, 6.5], ceph: [0, 7.6, 1.6], pedA: [0, 6.3, -4.5], pedB: [0, 6.1, -5.7], abdEnd: [0, 5.4, -17.2], spinTip: [0, 4.7, -18.5] },
19
- carapace: { len: 11, wid: 8.6, top: 9.9, rearTop: 7.3, bottom: 4.5, headW: 5.2 },
20
- abdomen: { c: [0, 6.5, -11.4], r: [3.9, 3.35, 6.1] },
21
- chel: { base: [0.95, 7.0, 6.1], tip: [0.9, 3.8, 7.0], fang: [0.15, 4.25, 6.75], r: [0.95, 0.72], fangR: 0.2 },
22
- coxa: { y: 5.1, x: [2.35, 2.75, 2.75, 2.45], z: [3.3, 1.4, -0.6, -2.6], az: [30, 66, 112, 150] },
23
- leg: [35, 33, 31, 43],
24
- seg: [0.08, 0.05, 0.26, 0.12, 0.2, 0.19, 0.1],
25
- el: [-14, 4, 30, -6, -28, 0, -14],
26
- legR: [[1.05, 0.95], [0.84, 0.8], [0.8, 0.68], [0.7, 0.63], [0.63, 0.53], [0.5, 0.4], [0.39, 0.29]],
27
- hindR: 1.06,
28
- tipY: 0.32,
29
- palp: { base: [1.75, 5.2, 5.4], az: 14, len: 16, seg: [0.12, 0.08, 0.3, 0.15, 0.18, 0.17], el: [-30, -10, 15, -30, 0, -50], r: [[0.62, 0.55], [0.5, 0.48], [0.46, 0.42], [0.42, 0.4], [0.4, 0.37], [0.37, 0.28]], tipY: 0.55 },
30
- spinR: 0.45,
31
- },
32
- tarantula: {
33
- unit: 0.028,
34
- bodyLen: 60,
35
- axial: { front: [0, 13.2, 12.8], ceph: [0, 14.2, 3.5], pedA: [0, 12.0, -11.6], pedB: [0, 11.8, -13.6], abdEnd: [0, 10.8, -41.5], spinTip: [0, 9.2, -46] },
36
- carapace: { len: 25, wid: 23.5, top: 16.2, rearTop: 14.0, bottom: 7.4, headW: 13 },
37
- abdomen: { c: [0, 12.4, -27.6], r: [12.0, 9.6, 14.4] },
38
- chel: { base: [3.0, 12.6, 11.2], tip: [2.9, 9.4, 18.0], fang: [2.6, 4.9, 16.4], r: [3.1, 2.4], fangR: 0.75 },
39
- coxa: { y: 8.6, x: [5.8, 6.7, 6.7, 6.0], z: [6.2, 2.0, -2.6, -7.0], az: [26, 60, 114, 150] },
40
- leg: [65, 60, 55, 72.5],
41
- seg: [0.09, 0.06, 0.25, 0.14, 0.2, 0.16, 0.1],
42
- el: [-10, 6, 34, -4, -30, 0, -13],
43
- legR: [[3.0, 2.7], [2.4, 2.3], [2.3, 2.0], [2.05, 1.95], [1.95, 1.75], [1.65, 1.45], [1.45, 1.25]],
44
- hindR: 1.04,
45
- tipY: 1.3,
46
- palp: { base: [4.6, 8.4, 10.8], az: 16, len: 37, seg: [0.14, 0.08, 0.28, 0.16, 0.18, 0.16], el: [-30, -10, 15, -30, 0, -40], r: [[2.2, 2.0], [1.9, 1.8], [1.8, 1.65], [1.65, 1.55], [1.55, 1.45], [1.45, 1.2]], tipY: 1.3 },
47
- spinR: 1.3,
48
- },
49
- };
50
-
51
- // Anatomy of one individual: the variant's reference numbers with the seeded proportions of
52
- // params (legK: leg length factor, abdK: abdomen size, palpBulb: male palpal bulbs).
53
- export function spiderDims(params = {}) {
54
- const V = VARIANTS[params.variant] || VARIANTS.wolf;
55
- const legK = params.legK || 1, abdK = params.abdK || 1;
56
- const d = JSON.parse(JSON.stringify(V));
57
- d.variant = VARIANTS[params.variant] ? params.variant : 'wolf';
58
- d.leg = V.leg.map((l) => l * legK);
59
- d.palp.len = V.palp.len * (0.5 + 0.5 * legK);
60
- d.abdomen.r = V.abdomen.r.map((r) => r * abdK);
61
- // a bigger abdomen hangs further back from the pedicel
62
- d.abdomen.c = [0, V.abdomen.c[1] + (abdK - 1) * 0.4 * V.abdomen.r[1], V.abdomen.c[2] - (abdK - 1) * V.abdomen.r[2]];
63
- d.axial.abdEnd = [0, V.axial.abdEnd[1] - (abdK - 1) * 0.3 * V.abdomen.r[1], V.axial.abdEnd[2] - 2 * (abdK - 1) * V.abdomen.r[2]];
64
- d.axial.spinTip = [0, V.axial.spinTip[1] - (abdK - 1) * 0.3 * V.abdomen.r[1], V.axial.spinTip[2] - 2 * (abdK - 1) * V.abdomen.r[2]];
65
- d.palpBulb = params.palpBulb || 0;
66
- return d;
67
- }
68
-
69
- export function spiderJoints(params = {}) {
70
- const d = spiderDims(params);
71
- const J = {};
72
- for (const [k, v] of Object.entries(d.axial)) J[k] = mm(v);
73
- J.cheBaseL = mm(d.chel.base);
74
- J.cheTipL = mm(d.chel.tip);
75
- J.fangTipL = mm(d.chel.fang);
76
- for (let i = 1; i <= 4; i++) {
77
- const L = d.leg[i - 1];
78
- const lens = d.seg.map((f) => f * L * 0.001);
79
- const base = mm([d.coxa.x[i - 1], d.coxa.y, d.coxa.z[i - 1]]);
80
- const el = solveBindElevations(base[1], lens, d.el.map((e) => e * D2R), 5, d.tipY * 0.001);
81
- planarChain(J, legJoints(i, 'L'), base, d.coxa.az[i - 1] * D2R, el, lens, 1);
82
- }
83
- {
84
- const P = d.palp;
85
- const lens = P.seg.map((f) => f * P.len * 0.001);
86
- const base = mm(P.base);
87
- // the tibia takes up the height so the tarsus meets the ground slanting forward
88
- const el = solveBindElevations(base[1], lens, P.el.map((e) => e * D2R), 4, P.tipY * 0.001);
89
- planarChain(J, palpJoints('L'), base, P.az * D2R, el, lens, 1);
90
- }
91
- return J;
92
- }
93
-
94
- export function spiderRig(params = {}) {
95
- const d = spiderDims(params);
96
- const J = spiderJoints(params);
97
- const U = d.unit;
98
- return buildRig({
99
- joints: J,
100
- unit: U,
101
- headOrigin: J.ceph,
102
- meta: { dims: d },
103
- bones: spiderBones(),
104
- axial: {
105
- points: AXIAL_POINTS,
106
- bones: AXIAL_BONES,
107
- // the carapace is rigid: head and prosoma share it (the engine never bends them apart); the
108
- // pedicel is a short stalk, blended narrowly into the abdomen
109
- blend: { 1: [-0.1, 0.1], 2: [-0.012, 0.004], 3: [-0.004, 0.02] },
110
- },
111
- limbs: spiderLimbs({
112
- leg: { tCore: 0.5, aCore: 0.05, aBody: -0.05, midX: 0.06 },
113
- palp: { tCore: 0.45, aCore: 0.04, aBody: -0.05, midX: 0.04 },
114
- }),
115
- appendages: [],
116
- webTags: [],
117
- });
118
- }
@@ -1,182 +0,0 @@
1
- // The spider, sculpted as a signed distance field (reference space, metres).
2
- //
3
- // Parts (meshed separately, see regions.js): 'body' (prosoma, pedicel, abdomen, spinnerets, palps,
4
- // coxae and trochanters), one part per leg ('legL1' .. 'legR4': coxa -> tarsus, the coxa and
5
- // trochanter duplicated so both surfaces agree across the cut), 'chelL'/'chelR' (rigid chelicerae)
6
- // and 'fangL'/'fangR' (rigid fangs). Eyes are glossy domes (look.lids 'simple') set in shallow
7
- // sockets on the head.
8
- import { spiderDims } from './rig.js';
9
- import { legJoints, legBones, palpJoints, palpBones } from '../../core/rig/spider.js';
10
- import { add, sub, mul, lerp, norm, cross, len } from '../../core/math/vec.js';
11
- import { eyeFrameOf } from '../../core/sdf/eyeSocket.js';
12
- import { QUALITY } from '../../core/build/pipeline.js';
13
-
14
- const M = 0.001;
15
- const mm = (v) => v.map((x) => x * M);
16
-
17
- // Eyes per variant (mm, head-local: relative to the ceph joint; left side). r: radius; yaw: outward
18
- // divergence of the view axis (rad, > PI/2 looks backward); pitch: upward tilt; back: how far the
19
- // dome centre sits inside the surface point.
20
- export const EYES = {
21
- // Lycosidae 4-2-2: a straight anterior row of 4 small eyes above the chelicerae, 2 huge posterior
22
- // median eyes looking forward, 2 posterior lateral eyes on top looking up and back
23
- wolf: [
24
- // (set into the carapace surface: the domes bulge ~0.4 r; the PME sit on the front of the face)
25
- { name: 'PME', c: [1.02, 1.2, 4.57], r: 0.47, yaw: 0.14, pitch: 0.02, back: 0.2 },
26
- { name: 'PLE', c: [1.78, 1.54, 2.72], r: 0.3, yaw: 2.1, pitch: 0.75, back: 0.14 },
27
- { name: 'AME', c: [0.42, 0.3, 5.26], r: 0.22, yaw: 0.05, pitch: -0.05, back: 0.07 },
28
- { name: 'ALE', c: [1.0, 0.3, 5.05], r: 0.17, yaw: 0.55, pitch: -0.05, back: 0.05 },
29
- ],
30
- // Theraphosidae: 8 small eyes clustered on a raised ocular tubercle
31
- tarantula: [
32
- { name: 'AME', c: [0.62, 2.55, 6.1], r: 0.5, yaw: 0.08, pitch: 0.5, back: 0.2 },
33
- { name: 'ALE', c: [1.62, 2.05, 6.25], r: 0.52, yaw: 0.6, pitch: 0.25, back: 0.2 },
34
- { name: 'PME', c: [0.85, 2.6, 5.05], r: 0.3, yaw: 0.5, pitch: 1.0, back: 0.12 },
35
- { name: 'PLE', c: [1.72, 2.2, 4.75], r: 0.42, yaw: 1.7, pitch: 0.45, back: 0.16 },
36
- ],
37
- };
38
-
39
- export function eyeSpec(e) {
40
- const r = e.r * M;
41
- return { c: mm(e.c), r, back: e.back * M, yaw: e.yaw, pitch: e.pitch, tilt: 0, lid: 0, R: r * 1.1, d: r * 0.6, off: 0, irisZ: r * 0.6, irisR: r * 0.8, name: e.name };
42
- }
43
-
44
- // minimum radius of thin parts per quality tier (coarse meshes would lose the tarsi otherwise)
45
- const MIN_R = { hero: 0, high: 0, medium: 0.26, low: 0.4, crowd: 0.58 }; // ~ one cell: legs stay >= 2 voxels thick
46
-
47
- export function sculptSpider(m, rig, params) {
48
- const J = rig.J, d = spiderDims(params);
49
- const F = d.unit / 0.013; // size relative to the wolf spider
50
- const minR = (MIN_R[params.quality] ?? 0) * M * F;
51
- const R = (r) => Math.max(r * M, minR);
52
- const HO = J.ceph;
53
- const hl = (v) => add(HO, mm(v));
54
- const X = [1, 0, 0];
55
- const ellY = (o) => {
56
- const y = norm(o.ydir);
57
- const z = norm(cross(o.lateral || X, y));
58
- return m.ell({ ...o, axis: z, up: y });
59
- };
60
- const wolf = d.variant === 'wolf';
61
- const C = d.carapace;
62
- const z0 = J.pedA[2] / M, z1 = J.front[2] / M, Lc = z1 - z0;
63
- const B = { bone: 'prosoma', group: 'axial', part: 'body' };
64
- const H = { bone: 'head', group: 'axial', part: 'body' };
65
-
66
- // ------------------------------------------------------------------ PROSOMA
67
- // carapace: thoracic dome, raised cephalic region, sloping rear; sternum below
68
- const thTop = C.rearTop + (C.top - C.rearTop) * (wolf ? 0.55 : 0.75);
69
- m.ell({ ...B, tag: 'thorax', c: mm([0, (thTop + C.bottom) / 2, z0 + 0.42 * Lc]), r: mm([C.wid / 2, (thTop - C.bottom) / 2, 0.41 * Lc]), k: 0 });
70
- m.ell({ ...B, tag: 'thoraxRear', c: mm([0, (C.rearTop + C.bottom) / 2 + 0.2 * F, z0 + 0.2 * Lc]), r: mm([C.wid * 0.36, (C.rearTop - C.bottom) / 2, 0.2 * Lc]), k: 0.9 * M * F });
71
- m.ell({ ...H, tag: 'cephalic', c: mm([0, C.top - (wolf ? 2.3 : 3.2) * F, z0 + 0.78 * Lc]), r: mm([C.headW / 2, (wolf ? 2.3 : 3.2) * F, 0.26 * Lc]), axis: norm([0, wolf ? 0.18 : 0.05, 1]), k: 1.2 * M * F });
72
- // clypeus: the face between the anterior eyes and the chelicerae
73
- m.ell({ ...H, tag: 'clypeus', c: add(J.front, mm([0, -0.2 * F, -0.9 * F])), r: mm([C.headW * 0.36, 1.1 * F, 0.9 * F]), k: 0.8 * M * F });
74
- m.ell({ ...B, tag: 'sternum', c: mm([0, C.bottom + 0.45 * F, z0 + 0.5 * Lc]), r: mm([C.wid * 0.27, 0.7 * F, 0.3 * Lc]), k: 0.8 * M * F });
75
- // labium and endites (mouthparts between the palp coxae)
76
- m.ell({ ...B, tag: 'labium', c: mm([0, C.bottom + 0.6 * F, z0 + 0.86 * Lc]), r: mm([0.9 * F, 0.55 * F, 0.9 * F]), k: 0.5 * M * F });
77
- // fovea: a short median groove on the thoracic dome, and the cephalic groove
78
- m.ell({ ...B, tag: 'fovea', c: mm([0, thTop + 0.02 * F, z0 + 0.36 * Lc]), r: mm([0.16 * F, 0.3 * F, 0.9 * F]), k: 0.25 * M * F, carve: true });
79
- if (!wolf) {
80
- // tarantula: low wide carapace with a raised ocular tubercle
81
- m.ell({ ...H, tag: 'tubercle', c: hl([0, 1.7, 5.4]), r: mm([2.3, 1.3, 1.9]), k: 1.1 * M * F });
82
- }
83
-
84
- // ------------------------------------------------------------------ EYES (sockets; the domes are eye meshes)
85
- for (const e of EYES[d.variant]) {
86
- const E = eyeSpec(e);
87
- for (const s of [1, -1]) {
88
- const ef = eyeFrameOf(E, HO, s);
89
- // a raised rim around the lens, cut open by the socket the dome sits in
90
- m.sphere({ ...H, tag: 'eyerim', c: add(ef.c, mul(ef.z, -E.r * 0.25)), rad: E.r * 1.05, k: E.r * 0.6 });
91
- m.sphere({ ...H, tag: 'eyesocket', c: add(ef.c, mul(ef.z, E.r * 0.1)), rad: E.r * 0.98, k: E.r * 0.15, carve: true });
92
- }
93
- }
94
-
95
- // ------------------------------------------------------------------ PEDICEL, ABDOMEN, SPINNERETS
96
- const A = { bone: 'abdomen', group: 'axial', part: 'body' };
97
- m.cone({ bone: 'pedicel', group: 'axial', part: 'body', tag: 'pedicel', a: J.pedA, b: J.pedB, ra: (wolf ? 0.75 : 1.9) * M * F / F * (wolf ? 1 : 1), rb: (wolf ? 0.7 : 1.8) * M, k: 0.3 * M * F });
98
- const ac = mm(d.abdomen.c), ar = mm(d.abdomen.r);
99
- m.ell({ ...A, tag: 'abdomen', c: ac, r: ar, axis: norm([0, 0.06, 1]), k: 0 });
100
- m.ell({ ...A, tag: 'abdomenFront', c: add(ac, [0, -ar[1] * 0.05, ar[2] * 0.52]), r: [ar[0] * 0.7, ar[1] * 0.72, ar[2] * 0.45], k: 1.0 * M * F });
101
- m.ell({ ...A, tag: 'abdomenRear', c: add(ac, [0, -ar[1] * 0.12, -ar[2] * 0.6]), r: [ar[0] * 0.72, ar[1] * 0.72, ar[2] * 0.42], k: 1.2 * M * F });
102
- // spinnerets: wolf 3 short pairs; tarantula 2 visible pairs, the posterior pair long and finger-like
103
- const SP = { bone: 'spinnerets', group: 'axial', part: 'body', tag: 'spinneret' };
104
- const st = J.abdEnd, sd = norm(sub(J.spinTip, J.abdEnd)), sl = len(sub(J.spinTip, J.abdEnd));
105
- for (const s of [1, -1]) {
106
- if (wolf) {
107
- m.cone({ ...SP, a: add(st, mm([0.45 * s, -0.25, 0.3])), b: add(add(st, mul(sd, sl * 0.9)), mm([0.5 * s, -0.2, 0])), ra: d.spinR * M, rb: d.spinR * 0.7 * M, k: 0.25 * M });
108
- m.cone({ ...SP, a: add(st, mm([0.2 * s, -0.6, 0.3])), b: add(add(st, mul(sd, sl * 0.7)), mm([0.2 * s, -0.55, 0])), ra: d.spinR * 0.8 * M, rb: d.spinR * 0.55 * M, k: 0.25 * M });
109
- } else {
110
- m.cone({ ...SP, a: add(st, mm([1.1 * s, -0.4, 0.8])), b: add(add(st, mul(sd, sl * 1.15)), mm([1.9 * s, 0.9, 0])), ra: d.spinR * M, rb: d.spinR * 0.62 * M, k: 0.8 * M });
111
- m.cone({ ...SP, a: add(st, mm([0.55 * s, -1.2, 0.8])), b: add(add(st, mul(sd, sl * 0.45)), mm([0.6 * s, -1.4, 0])), ra: d.spinR * 0.6 * M, rb: d.spinR * 0.45 * M, k: 0.6 * M });
112
- }
113
- }
114
-
115
- // ------------------------------------------------------------------ CHELICERAE AND FANGS (rigid parts)
116
- for (const S of ['L', 'R']) {
117
- const s = S === 'L' ? 1 : -1;
118
- const b0 = J['cheBase' + S], b1 = J['cheTip' + S], ft = J['fangTip' + S];
119
- const CH = { bone: 'chelicera' + S, group: 'chel' + S, part: 'chel' + S };
120
- const cr = d.chel.r.map((r) => r * M);
121
- const dir = norm(sub(b1, b0));
122
- m.cone({ ...CH, tag: 'chelicera', a: b0, b: add(b1, mul(dir, -cr[1] * 0.4)), ra: cr[0], rb: cr[1], k: 0 });
123
- // the stout basal boss bulging forward (wolf) / the long forward-projecting paturon (tarantula)
124
- ellY({ ...CH, tag: 'chelicera', c: add(lerp(b0, b1, 0.35), mm([0.1 * s * F, 0, (wolf ? 0.35 : 0.8) * F])), ydir: dir, r: [cr[0] * 0.92, len(sub(b1, b0)) * 0.4, cr[0] * 0.95], k: 0.5 * M * F });
125
- // fang groove with its row of teeth: a shallow furrow on the inner face
126
- ellY({ ...CH, tag: 'fangGroove', c: add(lerp(b0, b1, 0.8), mm([-0.55 * s * F, 0, 0.1 * F])), ydir: dir, r: [cr[1] * 0.35, len(sub(b1, b0)) * 0.22, cr[1] * 0.4], k: 0.2 * M * F, carve: true });
127
- const FG = { bone: 'fang' + S, group: 'fang' + S, part: 'fang' + S, tag: 'fang' };
128
- const fr = d.chel.fangR * M;
129
- // a curved fang: base, then bending toward the tip
130
- const fd = norm(sub(ft, b1)), fl = len(sub(ft, b1));
131
- const bend = norm(cross(fd, [s, 0, 0]));
132
- const mid = add(lerp(b1, ft, 0.5), mul(bend, fl * 0.12));
133
- m.cone({ ...FG, a: add(b1, mul(fd, -fr * 0.5)), b: mid, ra: fr, rb: fr * 0.62, k: 0.08 * M * F });
134
- m.cone({ ...FG, a: mid, b: ft, ra: fr * 0.62, rb: fr * 0.12, k: 0.08 * M * F });
135
- }
136
-
137
- // ------------------------------------------------------------------ PALPS (body part)
138
- for (const S of ['L', 'R']) {
139
- const pj = palpJoints(S), pb = palpBones(S);
140
- const g = { group: 'P' + S, part: 'body' };
141
- for (let k = 0; k < pb.length; k++) {
142
- const [ra, rb] = d.palp.r[k];
143
- const a = J[pj[k]], b = J[pj[k + 1]];
144
- m.cone({ ...g, bone: pb[k], tag: k === 0 ? 'palpcoxa' : 'palp', a, b, ra: R(ra * F / F), rb: R(rb), k: (k === 0 ? 0.6 : 0.09) * M * F });
145
- if (k > 0 && k < pb.length - 1) m.sphere({ ...g, bone: pb[k], tag: 'knuckle', c: b, rad: R(rb * 1.08), k: 0.08 * M * F });
146
- }
147
- if (d.palpBulb > 0) {
148
- // male: the swollen cymbium / palpal bulb ("boxing gloves")
149
- const a = J[pj[5]], b = J[pj[6]];
150
- // (swollen but compact: about the width of the palp tibia plus a third)
151
- ellY({ ...g, bone: pb[5], tag: 'palpbulb', c: lerp(a, b, 0.5), ydir: sub(b, a), r: mm([0.65 * (0.62 * F * d.palpBulb + 0.3 * F), len(sub(b, a)) / M * 0.36, 0.65 * (0.7 * F * d.palpBulb + 0.3 * F)]), k: 0.2 * M * F });
152
- }
153
- }
154
-
155
- // ------------------------------------------------------------------ LEGS
156
- for (const S of ['L', 'R']) {
157
- for (let i = 1; i <= 4; i++) {
158
- const lj = legJoints(i, S), lb = legBones(i, S), key = S + i;
159
- const thick = i === 4 ? d.hindR : i === 3 ? (1 + d.hindR) / 2 : 1;
160
- for (let k = 0; k < 7; k++) {
161
- const [ra, rb] = d.legR[k];
162
- const a = J[lj[k]], b = J[lj[k + 1]];
163
- const parts = k <= 2 ? ['body', 'leg' + key] : ['leg' + key];
164
- for (const part of parts) {
165
- const g = { group: key, part, bone: lb[k] };
166
- if (k === 0) {
167
- // coxa: a stout cylinder set into the prosoma between carapace margin and sternum
168
- m.cone({ ...g, tag: 'coxa', a: add(a, mul(norm(sub(b, a)), -0.6 * M * F)), b, ra: R(ra * thick), rb: R(rb * thick), k: part === 'body' ? 0.55 * M * F : 0.1 * M * F });
169
- } else {
170
- m.cone({ ...g, tag: ['coxa', 'troch', 'femur', 'patella', 'tibia', 'meta', 'tarsus'][k], a, b, ra: R(ra * thick), rb: R(rb * thick), k: 0.07 * M * F });
171
- // swollen joint condyles: the knee (femur-patella) is the biggest
172
- if (k < 6) m.sphere({ ...g, tag: 'knuckle', c: add(b, mul(norm(sub(b, a)), -rb * 0.25 * M)), rad: R(rb * thick * (k === 2 ? 1.12 : 1.06)), k: 0.07 * M * F });
173
- }
174
- }
175
- }
176
- // claw tuft: the rounded tarsus tip
177
- const tip = J[lj[7]], ta = J[lj[6]];
178
- m.sphere({ group: key, part: 'leg' + key, bone: lb[6], tag: 'claws', c: add(tip, mul(norm(sub(ta, tip)), d.legR[6][1] * 0.3 * M)), rad: R(d.legR[6][1] * thick * 1.02), k: 0.06 * M * F });
179
- }
180
- }
181
- return m;
182
- }
@@ -1,160 +0,0 @@
1
- // Wolf body language, layered over the core actions every frame (species.motion.hooks.update, see
2
- // core/motion/actions.js).
3
- //
4
- // Tail carriage by mood (Schenkel 1947 in Mech & Boitani 2003): hangs at rest, ~level in the
5
- // travelling trot (the carriage table in motion.js), raised stiff above the back in a threat or an
6
- // attack, tucked between the hind legs when hit or afraid. Ears: pricked forward when alert (a look
7
- // target), pinned flat in an attack (core) and when howling. Hackles: the long guard hair of the
8
- // mane, cape and saddle lifts during an attack (P.furRaise -> the coat shader). Snarl: the jaw opens
9
- // on the crouch before the bite so the canines show. Howling: an idle variant every 25-60 s of
10
- // standing still (or on demand via `motion.input.howl = true`): head thrown back 50-60 deg, ears
11
- // back, jaw half open in an "O", lasting 3-6 s.
12
- import { clamp, smooth, lerp, angDiff } from '../../core/motion/common.js';
13
- import { mx, mxLegs } from '../../core/motion/actions.js';
14
- const sm = (w) => w * w * (3 - 2 * w);
15
-
16
- // moveTo: a wolf slows down to turn onto a point close beside or behind it. The engine caps the speed
17
- // only by the heading error (1.5 sk beyond 1.2 rad), so with the wolf's calm turn rate (1.8 rad/s) a
18
- // target inside its turning circle was circled without end. A point is reachable
19
- // on a turn of radius R only while it lies outside the turning circle on its side: R < d / (2 sin err)
20
- // (d distance, err bearing from the heading). The speed is capped so the radius at the engine's yaw
21
- // limit, v / w(v), keeps a margin inside that bound; near the point and well off the heading the wolf
22
- // all but pivots, then goes. (Engine-wide, the same cap belongs in quadruped.js drive().)
23
- const ARRIVE_MARGIN = 0.8;
24
- function arriveCap(e, st) {
25
- const inp = e.input, cfg = e.cfg;
26
- // arrived (drive() dropped the target and zeroed the speed): stand facing the way it went instead of
27
- // pivoting on to the last bearing of the point (a front paw dragged ~2 % S in that pivot)
28
- if (st.tgt && !inp.target && !inp.follow && !inp.speed && Math.hypot(st.tgt.x - e.pos.x, st.tgt.z - e.pos.z) < 0.5 * cfg.k + 0.03 * e.speed) {
29
- inp.heading = e.heading + 0.25 * e.yawRate;
30
- e.wantHeading = inp.heading;
31
- }
32
- st.tgt = inp.target && !inp.follow ? (st.tgt || { x: 0, z: 0 }) : null;
33
- if (!st.tgt) return;
34
- st.tgt.x = inp.target.x; st.tgt.z = inp.target.z;
35
- if (!(e.wantSpeed > 0.05) || e.air?.active) return;
36
- const dx = inp.target.x - e.pos.x, dz = inp.target.z - e.pos.z, d = Math.hypot(dx, dz);
37
- const err = Math.abs(angDiff(e.heading, Math.atan2(dx, dz))), sn = Math.sin(err);
38
- if (sn < 1e-3) return;
39
- const rMax = (ARRIVE_MARGIN * d) / (2 * sn);
40
- // the engine's yaw-rate limit at speed v (quadruped.js step: pivots are slower than turns on the move)
41
- const wAt = (v) => Math.min(cfg.turnRate * lerp(0.55, 1, smooth(0.3, 2, v / cfg.sq)), cfg.latAccelMax / Math.max(v, 0.5 * cfg.sk));
42
- if (e.wantSpeed / wAt(e.wantSpeed) <= rMax) return;
43
- // v / w(v) grows with v: bisect for the fastest speed whose turning radius fits
44
- let lo = 0, hi = e.wantSpeed;
45
- for (let i = 0; i < 12; i++) { const m = 0.5 * (lo + hi); if (m / wAt(m) <= rMax) lo = m; else hi = m; }
46
- // (a point ahead that the straight line passes within the stop radius needs no turn: the cap fades out)
47
- const stopR = 0.35 * cfg.k + 0.02 * e.speed;
48
- e.wantSpeed = lerp(e.wantSpeed, lo, err < 1.2 ? smooth(0.4 * stopR, 0.8 * stopR, d * sn) : 1);
49
- }
50
-
51
- export function wolfUpdate(P, dt, L) {
52
- const e = L.engine;
53
- const st = L._wolf || (L._wolf = { howlIn: 25 + e.rand() * 20, howlT: -1, howlDur: 4, howlW: 0 });
54
- arriveCap(e, st);
55
- // (the sleeping forepaw pull-back below overrides this animal's fold placement only while it sleeps)
56
- if (st.acts && st.acts.fold && !L.postures.some((p) => p.name === 'sleep')) st.acts.fold = undefined;
57
- let raise = 0;
58
-
59
- for (const a of L.oneshots) {
60
- const w = sm(a.w);
61
- if (w <= 0) continue;
62
- if (a.name === 'attack') {
63
- const t = a.t;
64
- // threat -> lunge: hackles up, tail raised stiff above the back, snarl before the bite
65
- raise = Math.max(raise, w * (0.5 + 0.5 * smooth(0, 0.2, t)));
66
- mx(P, 'tailLift', 0.75, w); mx(P, 'tailStiff', 1.8, w);
67
- const snarl = smooth(0.0, 0.12, t) * (1 - smooth(0.22, 0.3, t));
68
- P.jaw = Math.max(P.jaw, 0.3 * snarl * w); // (the lower fangs come clear of the upper lip)
69
- mx(P, 'headRaise', -0.035, snarl * w);
70
- } else if (a.name === 'hit') {
71
- // flinch: tail clamped between the hind legs, ears flat (core), body drops (core)
72
- const k = w * (1 - smooth(0.45, 0.75, a.t) * 0.6);
73
- mx(P, 'tailLift', -0.8, k); mx(P, 'tailStiff', 1.6, k); mx(P, 'tailIdle', 0, k);
74
- }
75
- }
76
- // dying / dead: ears folded back flat against the neck
77
- for (const p of L.postures) {
78
- if (p.name === 'death') { const w = sm(clamp(p.w, 0, 1)) * smooth(0.3, 1.0, p.t); mx(P, 'earFlat', 1.15, w); mx(P, 'earTwitch', 0, w); mx(P, 'headRoll', p.side * 0.8, w); P.headPos.y += 0.05 * e.cfg.s * w; }
79
- }
80
- // curled sleep (curled1: a ring on one hip, the nose tucked by the tail). The spine
81
- // bends into a C (2.2 rad, rolled 0.45 onto the hip, the hind legs to the inside); the head turns back
82
- // along the inside of the curl and rests on the ground by the hind feet (yaw 2.3 rad; the occiput 20 cm
83
- // inside and 5 cm ahead of the turned chest's shoulders, 10 cm up: further back, the throat's stretch
84
- // > 3x rose past 4 % of its triangles); the brush sweeps round the outside of the hind feet and forward
85
- // to the nose (tailSide 3.4 curves it progressively, tailCurl -0.5 holds the root back: the old 2.4 rad
86
- // turned it near the root and tucked it under the belly). The forelegs stay forward on the ground, as in
87
- // curled1: tucked (the core's tuck places them in the unbent body frame, ~26 cm off, and the elbow
88
- // flipped on the way out), reached (the paw stands up) or turned with the chest (the inner elbow dropped
89
- // into the ground: 7-23 mm) they failed the metrics. (roll 0.45: 0.65 pressed the lower forearm 9-14 mm
90
- // into the ground, 0.5 up to 6 mm)
91
- for (const p of L.postures) {
92
- if (p.name === 'sleep' && p.tune.style !== 'lateral') {
93
- const c = sm(clamp(p.w, 0, 1)) * smooth(1.2, 3.2, p.t), side = p.side, k = e.cfg.k, fr = e.fr;
94
- mx(P, 'roll', side * 0.45, c); mx(P, 'bend', side * 2.2, c);
95
- mxLegs(P, 'side', 0, 0.55, c); mxLegs(P, 'spread', 0, 0, c);
96
- // forelegs drawn back under the head (curled1: the paws just show at the front of the ring, not a leg's
97
- // length ahead of it like a sphinx's): the engine's fold places the forepaw at zS + actions.fold.front.z
98
- // leg lengths, flat on the ground; this animal's own copy of that tuning moves it 25 cm back once the
99
- // curl has settled, the forearm and paw kept flat and the elbows folding up beside the chest. (A 'reach'
100
- // blend stood the paw up and swung the elbow 10 mm into the ground; a 'sit' blend stood the forelegs up
101
- // like posts; the core's tuck places the paw in the unbent body frame, ~26 cm off.) Skin penetration
102
- // 0.30-0.62 % S (seeds 1-4, every morph, both sides).
103
- const cF = sm(clamp(p.w, 0, 1)) * smooth(2.6, 4.4, p.t);
104
- if (!st.acts) { st.acts = { ...e.cfg.actions }; e.cfg.actions = st.acts; }
105
- const L0 = e.legs[0].def, z0 = (0.5 * L0.Lr + L0.Lmc) / L0.len;
106
- // (k -1.45, beta 0 and z0 are the engine's own fold values: continuous as the pull-back fades)
107
- st.acts.fold = cF > 1e-3 ? { front: { z: z0 - (cF * 0.25 * k) / L0.len, k: -1.45, beta: 0 } } : undefined;
108
- mx(P, 'headYaw', side * 2.3, c);
109
- // the chest's flat forward and left (its frame is the last frame's: the posture changes slowly)
110
- const q = fr.qCh;
111
- let fx = 2 * (q.x * q.z + q.w * q.y), fz = 1 - 2 * (q.x * q.x + q.y * q.y);
112
- const fl = Math.hypot(fx, fz) || 1; fx /= fl; fz /= fl;
113
- const lat = side * 0.2 * k, fwd = 0.05 * k;
114
- const tx = fr.shC.x + fz * lat + fx * fwd, tz = fr.shC.z - fx * lat + fz * fwd;
115
- const hp = P.headPos;
116
- hp.x += (tx - hp.x) * c; hp.z += (tz - hp.z) * c; hp.y += (e.terrainH(tx, tz) + 0.1 * k - hp.y) * c;
117
- mx(P, 'tailCurl', side * -0.5, c); mx(P, 'tailSide', side * 3.4, c); mx(P, 'tailStiff', 0.7, c);
118
- }
119
- }
120
-
121
- // lying: rolled onto one hip, both hind legs to that side (lying1), not a symmetric sphinx
122
- for (const p of L.postures) {
123
- if (p.name === 'lie') {
124
- const w = sm(clamp(p.w, 0, 1)) * smooth(0.6, 1.8, p.t);
125
- mx(P, 'roll', p.side * 0.25, w);
126
- mxLegs(P, 'side', 0, 0.5, w);
127
- }
128
- }
129
-
130
- // alert: ears pricked forward while watching something
131
- const idleW = L.idle.w;
132
- if (e.input.look && raise < 0.01) mx(P, 'earFlat', -0.18, clamp(P.lookW, 0, 1));
133
-
134
- // howling (idle variant)
135
- const still = idleW > 0.95 && !L.postures.length && !L.oneshots.some((a) => !a.stopping && a.name !== 'hit');
136
- if (st.howlT < 0) {
137
- if (still) st.howlIn -= dt;
138
- if (e.input.howl && idleW > 0.3) { e.input.howl = false; st.howlIn = 0; }
139
- if (st.howlIn <= 0 && still) { st.howlT = 0; st.howlDur = 3 + e.rand() * 3; }
140
- } else {
141
- st.howlT += dt;
142
- if (!still && idleW < 0.6) st.howlT = Math.max(st.howlT, st.howlDur);
143
- if (st.howlT > st.howlDur + 1.2) { st.howlT = -1; st.howlIn = 25 + e.rand() * 35; }
144
- }
145
- const hw = st.howlT < 0 ? 0 : smooth(0, 0.9, st.howlT) * (1 - smooth(st.howlDur, st.howlDur + 1.2, st.howlT));
146
- st.howlW = hw;
147
- if (hw > 0.001) {
148
- const w = hw * idleW;
149
- mx(P, 'lookW', 0, w);
150
- mx(P, 'headRaise', 0.07, w); mx(P, 'neckReach', -0.03, w);
151
- mx(P, 'headPitch', -1.0, w);
152
- // the "O" opens after the head is up, with a slight waver
153
- const o = smooth(0.5, 1.2, st.howlT) * (1 - smooth(st.howlDur - 0.3, st.howlDur + 0.4, st.howlT));
154
- mx(P, 'jaw', 0.2 + 0.03 * Math.sin(st.howlT * 5.1), o * w); mx(P, 'jawOmega', 6, w);
155
- mx(P, 'earFlat', 0.55, w); mx(P, 'earTwitch', 0, w);
156
- mx(P, 'breathAmp', 0.4, w); mx(P, 'eyelid', 0.45, o * w);
157
- mx(P, 'dropH', 0.05, w);
158
- }
159
- P.furRaise = Math.max(P.furRaise || 0, raise);
160
- }