@bitefoundry/retrieviewer 0.0.3 → 0.0.5

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