@bitefoundry/retrieviewer 0.0.0-stage → 0.0.1

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 (292) hide show
  1. package/ASSET-PROVENANCE.md +43 -0
  2. package/ASSETS-LICENSE.md +58 -0
  3. package/ATTRIBUTION.md +54 -0
  4. package/EMBEDDING.md +96 -0
  5. package/INSTALLING.md +107 -0
  6. package/LICENSE +16 -0
  7. package/LICENSE-CODE +21 -0
  8. package/PLUGIN.md +110 -0
  9. package/PUPPY-MEMORY.md +57 -0
  10. package/PUPPY-Q5-COMPARISON.md +73 -0
  11. package/README.md +61 -2
  12. package/RELEASING.md +61 -0
  13. package/THIRD-PARTY-NOTICES.md +17 -0
  14. package/TRADEMARKS.md +21 -0
  15. package/braille.mjs +45 -0
  16. package/examples/bridge.py +62 -0
  17. package/examples/embed.mjs +15 -0
  18. package/examples/live.mjs +40 -0
  19. package/examples/plugin.mjs +21 -0
  20. package/integrations/opencode/runtime.mjs +195 -0
  21. package/integrations/opencode/tui.tsx +59 -0
  22. package/locomotion-core.mjs +21 -0
  23. package/locomotion-puppy.animal +0 -0
  24. package/package.json +125 -4
  25. package/pet-q5-manifest.json +118 -0
  26. package/puppy-clean.mjs +51 -0
  27. package/puppy-companion-interactions-v3-q5.bin.gz +0 -0
  28. package/puppy-companion-interactions-v3.json +1 -0
  29. package/puppy-companion-life.mjs +182 -0
  30. package/puppy-companion-objects.mjs +30 -0
  31. package/puppy-companion-sprites.mjs +14 -0
  32. package/puppy-continuous.mjs +57 -0
  33. package/puppy-face.mjs +46 -0
  34. package/puppy-frame-predictive.mjs +147 -0
  35. package/puppy-frame-store.mjs +108 -0
  36. package/puppy-mouth-anchor.json +1 -0
  37. package/puppy-mouth-anchor.mjs +33 -0
  38. package/puppy-paper-actions-v9-q5.bin.gz +0 -0
  39. package/puppy-paper-actions-v9.json +1 -0
  40. package/puppy-paper-actions.mjs +48 -0
  41. package/puppy-paper-approach-q5.bin.gz +0 -0
  42. package/puppy-paper-approach.json +1 -0
  43. package/puppy-paper-area.mjs +15 -0
  44. package/puppy-paper-arrival-seat-q5.bin.gz +0 -0
  45. package/puppy-paper-arrival-seat.json +1 -0
  46. package/puppy-paper-behaviors-q5.bin.gz +0 -0
  47. package/puppy-paper-behaviors.json +1 -0
  48. package/puppy-paper-behaviors.mjs +8 -0
  49. package/puppy-paper-contact.mjs +103 -0
  50. package/puppy-paper-director.mjs +21 -0
  51. package/puppy-paper-paw-transport.mjs +76 -0
  52. package/puppy-paper-rear-gallop-q5.bin.gz +0 -0
  53. package/puppy-paper-rear-gallop.json +1 -0
  54. package/puppy-paper-seat-q5.bin.gz +0 -0
  55. package/puppy-paper-seat.json +14 -0
  56. package/puppy-paper-seat.mjs +13 -0
  57. package/puppy-paper-trick-timing.mjs +58 -0
  58. package/puppy-paper-world.mjs +108 -0
  59. package/puppy-paper.mjs +271 -0
  60. package/puppy-stable-meta.json +1606 -0
  61. package/puppy-stable.mjs +72 -0
  62. package/puppy-stride-meta.json +343 -0
  63. package/puppy-stride-tweens-q5.bin.gz +0 -0
  64. package/puppy-zoomies.mjs +27 -0
  65. package/puppy-zoomies30.mjs +12 -0
  66. package/retrieviewer-cli.mjs +81 -0
  67. package/retrieviewer-config.mjs +49 -0
  68. package/retrieviewer-install.mjs +157 -0
  69. package/retrieviewer-plugin.d.mts +44 -0
  70. package/retrieviewer-plugin.mjs +97 -0
  71. package/retrieviewer-stdio.mjs +38 -0
  72. package/retrieviewer.d.mts +85 -0
  73. package/retrieviewer.mjs +142 -0
  74. package/vendor/procedural-animals/LICENSE +21 -0
  75. package/vendor/procedural-animals/package.json +40 -0
  76. package/vendor/procedural-animals/src/animal.js +146 -0
  77. package/vendor/procedural-animals/src/bake.js +51 -0
  78. package/vendor/procedural-animals/src/build.js +81 -0
  79. package/vendor/procedural-animals/src/core/build/coatKit.js +121 -0
  80. package/vendor/procedural-animals/src/core/build/featherCards.js +189 -0
  81. package/vendor/procedural-animals/src/core/build/finEdges.js +85 -0
  82. package/vendor/procedural-animals/src/core/build/furSlope.js +115 -0
  83. package/vendor/procedural-animals/src/core/build/mesh.js +67 -0
  84. package/vendor/procedural-animals/src/core/build/pipeline.js +272 -0
  85. package/vendor/procedural-animals/src/core/build/seams.js +183 -0
  86. package/vendor/procedural-animals/src/core/build/warp.js +112 -0
  87. package/vendor/procedural-animals/src/core/build/weights.js +393 -0
  88. package/vendor/procedural-animals/src/core/math/vec.js +81 -0
  89. package/vendor/procedural-animals/src/core/motion/actions.js +800 -0
  90. package/vendor/procedural-animals/src/core/motion/bird.js +3063 -0
  91. package/vendor/procedural-animals/src/core/motion/birdActions.js +1059 -0
  92. package/vendor/procedural-animals/src/core/motion/common.js +158 -0
  93. package/vendor/procedural-animals/src/core/motion/index.js +22 -0
  94. package/vendor/procedural-animals/src/core/motion/quadruped.js +2875 -0
  95. package/vendor/procedural-animals/src/core/motion/snake.js +1594 -0
  96. package/vendor/procedural-animals/src/core/motion/spider.js +1810 -0
  97. package/vendor/procedural-animals/src/core/motion/swimmer.js +1047 -0
  98. package/vendor/procedural-animals/src/core/motion/swimmerActions.js +613 -0
  99. package/vendor/procedural-animals/src/core/render/animalObject.js +262 -0
  100. package/vendor/procedural-animals/src/core/render/coatMaterial.js +1301 -0
  101. package/vendor/procedural-animals/src/core/render/dqs.js +159 -0
  102. package/vendor/procedural-animals/src/core/render/eyes.js +676 -0
  103. package/vendor/procedural-animals/src/core/render/membranes.js +77 -0
  104. package/vendor/procedural-animals/src/core/render/skeleton.js +41 -0
  105. package/vendor/procedural-animals/src/core/rig/bird.js +327 -0
  106. package/vendor/procedural-animals/src/core/rig/quadruped.js +76 -0
  107. package/vendor/procedural-animals/src/core/rig/rig.js +79 -0
  108. package/vendor/procedural-animals/src/core/rig/snake.js +76 -0
  109. package/vendor/procedural-animals/src/core/rig/spider.js +110 -0
  110. package/vendor/procedural-animals/src/core/rig/swimmer.js +181 -0
  111. package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +53 -0
  112. package/vendor/procedural-animals/src/core/sdf/mesher.js +238 -0
  113. package/vendor/procedural-animals/src/core/sdf/sdf.js +263 -0
  114. package/vendor/procedural-animals/src/index.d.ts +98 -0
  115. package/vendor/procedural-animals/src/index.js +29 -0
  116. package/vendor/procedural-animals/src/registry.js +48 -0
  117. package/vendor/procedural-animals/src/species/bear/behaviour.js +463 -0
  118. package/vendor/procedural-animals/src/species/bear/claws.js +147 -0
  119. package/vendor/procedural-animals/src/species/bear/coat.js +726 -0
  120. package/vendor/procedural-animals/src/species/bear/index.js +139 -0
  121. package/vendor/procedural-animals/src/species/bear/motion.js +112 -0
  122. package/vendor/procedural-animals/src/species/bear/regions.js +78 -0
  123. package/vendor/procedural-animals/src/species/bear/rig.js +112 -0
  124. package/vendor/procedural-animals/src/species/bear/sculpt.js +272 -0
  125. package/vendor/procedural-animals/src/species/boar/behaviour.js +335 -0
  126. package/vendor/procedural-animals/src/species/boar/coat.js +372 -0
  127. package/vendor/procedural-animals/src/species/boar/index.js +110 -0
  128. package/vendor/procedural-animals/src/species/boar/motion.js +85 -0
  129. package/vendor/procedural-animals/src/species/boar/regions.js +88 -0
  130. package/vendor/procedural-animals/src/species/boar/rig.js +111 -0
  131. package/vendor/procedural-animals/src/species/boar/sculpt.js +285 -0
  132. package/vendor/procedural-animals/src/species/cat/behaviour.js +559 -0
  133. package/vendor/procedural-animals/src/species/cat/coat.js +841 -0
  134. package/vendor/procedural-animals/src/species/cat/index.js +211 -0
  135. package/vendor/procedural-animals/src/species/cat/motion.js +101 -0
  136. package/vendor/procedural-animals/src/species/cat/regions.js +82 -0
  137. package/vendor/procedural-animals/src/species/cat/rig.js +100 -0
  138. package/vendor/procedural-animals/src/species/cat/sculpt.js +266 -0
  139. package/vendor/procedural-animals/src/species/cat/whiskers.js +110 -0
  140. package/vendor/procedural-animals/src/species/cheetah/coat.js +427 -0
  141. package/vendor/procedural-animals/src/species/cheetah/index.js +51 -0
  142. package/vendor/procedural-animals/src/species/cheetah/joints.js +3 -0
  143. package/vendor/procedural-animals/src/species/cheetah/motion.js +77 -0
  144. package/vendor/procedural-animals/src/species/cheetah/regions.js +95 -0
  145. package/vendor/procedural-animals/src/species/cheetah/rig.js +66 -0
  146. package/vendor/procedural-animals/src/species/cheetah/sculpt.js +158 -0
  147. package/vendor/procedural-animals/src/species/chicken/coat.js +313 -0
  148. package/vendor/procedural-animals/src/species/chicken/coverts.js +320 -0
  149. package/vendor/procedural-animals/src/species/chicken/index.js +110 -0
  150. package/vendor/procedural-animals/src/species/chicken/motion.js +177 -0
  151. package/vendor/procedural-animals/src/species/chicken/regions.js +66 -0
  152. package/vendor/procedural-animals/src/species/chicken/rig.js +144 -0
  153. package/vendor/procedural-animals/src/species/chicken/sculpt.js +389 -0
  154. package/vendor/procedural-animals/src/species/chicken/wingLook.js +66 -0
  155. package/vendor/procedural-animals/src/species/chicken/wingStack.js +124 -0
  156. package/vendor/procedural-animals/src/species/cow/behaviour.js +521 -0
  157. package/vendor/procedural-animals/src/species/cow/coat.js +465 -0
  158. package/vendor/procedural-animals/src/species/cow/index.js +118 -0
  159. package/vendor/procedural-animals/src/species/cow/motion.js +81 -0
  160. package/vendor/procedural-animals/src/species/cow/regions.js +98 -0
  161. package/vendor/procedural-animals/src/species/cow/rig.js +116 -0
  162. package/vendor/procedural-animals/src/species/cow/sculpt.js +339 -0
  163. package/vendor/procedural-animals/src/species/crow/coat.js +145 -0
  164. package/vendor/procedural-animals/src/species/crow/index.js +70 -0
  165. package/vendor/procedural-animals/src/species/crow/joints.js +3 -0
  166. package/vendor/procedural-animals/src/species/crow/motion.js +101 -0
  167. package/vendor/procedural-animals/src/species/crow/regions.js +50 -0
  168. package/vendor/procedural-animals/src/species/crow/rig.js +83 -0
  169. package/vendor/procedural-animals/src/species/crow/sculpt.js +118 -0
  170. package/vendor/procedural-animals/src/species/deer/behaviour.js +513 -0
  171. package/vendor/procedural-animals/src/species/deer/coat.js +391 -0
  172. package/vendor/procedural-animals/src/species/deer/index.js +106 -0
  173. package/vendor/procedural-animals/src/species/deer/motion.js +97 -0
  174. package/vendor/procedural-animals/src/species/deer/regions.js +60 -0
  175. package/vendor/procedural-animals/src/species/deer/rig.js +124 -0
  176. package/vendor/procedural-animals/src/species/deer/sculpt.js +297 -0
  177. package/vendor/procedural-animals/src/species/dog/behaviour.js +521 -0
  178. package/vendor/procedural-animals/src/species/dog/coat.js +495 -0
  179. package/vendor/procedural-animals/src/species/dog/index.js +144 -0
  180. package/vendor/procedural-animals/src/species/dog/motion.js +118 -0
  181. package/vendor/procedural-animals/src/species/dog/regions.js +61 -0
  182. package/vendor/procedural-animals/src/species/dog/rig.js +129 -0
  183. package/vendor/procedural-animals/src/species/dog/sculpt.js +246 -0
  184. package/vendor/procedural-animals/src/species/eagle/coat.js +250 -0
  185. package/vendor/procedural-animals/src/species/eagle/index.js +76 -0
  186. package/vendor/procedural-animals/src/species/eagle/joints.js +3 -0
  187. package/vendor/procedural-animals/src/species/eagle/motion.js +137 -0
  188. package/vendor/procedural-animals/src/species/eagle/regions.js +57 -0
  189. package/vendor/procedural-animals/src/species/eagle/rig.js +107 -0
  190. package/vendor/procedural-animals/src/species/eagle/sculpt.js +137 -0
  191. package/vendor/procedural-animals/src/species/fish/coat.js +271 -0
  192. package/vendor/procedural-animals/src/species/fish/index.js +88 -0
  193. package/vendor/procedural-animals/src/species/fish/motion.js +92 -0
  194. package/vendor/procedural-animals/src/species/fish/regions.js +27 -0
  195. package/vendor/procedural-animals/src/species/fish/rig.js +143 -0
  196. package/vendor/procedural-animals/src/species/fish/sculpt.js +214 -0
  197. package/vendor/procedural-animals/src/species/fish/variants.js +126 -0
  198. package/vendor/procedural-animals/src/species/fox/behaviour.js +314 -0
  199. package/vendor/procedural-animals/src/species/fox/coat.js +444 -0
  200. package/vendor/procedural-animals/src/species/fox/index.js +120 -0
  201. package/vendor/procedural-animals/src/species/fox/motion.js +81 -0
  202. package/vendor/procedural-animals/src/species/fox/regions.js +59 -0
  203. package/vendor/procedural-animals/src/species/fox/rig.js +91 -0
  204. package/vendor/procedural-animals/src/species/fox/sculpt.js +202 -0
  205. package/vendor/procedural-animals/src/species/frog/behaviour.js +590 -0
  206. package/vendor/procedural-animals/src/species/frog/coat.js +305 -0
  207. package/vendor/procedural-animals/src/species/frog/index.js +97 -0
  208. package/vendor/procedural-animals/src/species/frog/motion.js +69 -0
  209. package/vendor/procedural-animals/src/species/frog/regions.js +46 -0
  210. package/vendor/procedural-animals/src/species/frog/rig.js +156 -0
  211. package/vendor/procedural-animals/src/species/frog/sculpt.js +240 -0
  212. package/vendor/procedural-animals/src/species/goat/behaviour.js +509 -0
  213. package/vendor/procedural-animals/src/species/goat/coat.js +590 -0
  214. package/vendor/procedural-animals/src/species/goat/index.js +149 -0
  215. package/vendor/procedural-animals/src/species/goat/motion.js +95 -0
  216. package/vendor/procedural-animals/src/species/goat/regions.js +98 -0
  217. package/vendor/procedural-animals/src/species/goat/rig.js +181 -0
  218. package/vendor/procedural-animals/src/species/goat/sculpt.js +547 -0
  219. package/vendor/procedural-animals/src/species/horse/coat.js +361 -0
  220. package/vendor/procedural-animals/src/species/horse/coatSeam.js +122 -0
  221. package/vendor/procedural-animals/src/species/horse/index.js +80 -0
  222. package/vendor/procedural-animals/src/species/horse/motion.js +245 -0
  223. package/vendor/procedural-animals/src/species/horse/regions.js +60 -0
  224. package/vendor/procedural-animals/src/species/horse/rig.js +117 -0
  225. package/vendor/procedural-animals/src/species/horse/sculpt.js +316 -0
  226. package/vendor/procedural-animals/src/species/horse/seamWeights.js +272 -0
  227. package/vendor/procedural-animals/src/species/lion/behaviour.js +509 -0
  228. package/vendor/procedural-animals/src/species/lion/coat.js +1016 -0
  229. package/vendor/procedural-animals/src/species/lion/index.js +111 -0
  230. package/vendor/procedural-animals/src/species/lion/motion.js +87 -0
  231. package/vendor/procedural-animals/src/species/lion/regions.js +106 -0
  232. package/vendor/procedural-animals/src/species/lion/rig.js +110 -0
  233. package/vendor/procedural-animals/src/species/lion/sculpt.js +384 -0
  234. package/vendor/procedural-animals/src/species/lion/whiskers.js +132 -0
  235. package/vendor/procedural-animals/src/species/pig/behaviour.js +575 -0
  236. package/vendor/procedural-animals/src/species/pig/coat.js +730 -0
  237. package/vendor/procedural-animals/src/species/pig/ears.js +242 -0
  238. package/vendor/procedural-animals/src/species/pig/index.js +161 -0
  239. package/vendor/procedural-animals/src/species/pig/motion.js +105 -0
  240. package/vendor/procedural-animals/src/species/pig/regions.js +100 -0
  241. package/vendor/procedural-animals/src/species/pig/rig.js +152 -0
  242. package/vendor/procedural-animals/src/species/pig/sculpt.js +382 -0
  243. package/vendor/procedural-animals/src/species/rabbit/behaviour.js +605 -0
  244. package/vendor/procedural-animals/src/species/rabbit/coat.js +285 -0
  245. package/vendor/procedural-animals/src/species/rabbit/index.js +85 -0
  246. package/vendor/procedural-animals/src/species/rabbit/motion.js +85 -0
  247. package/vendor/procedural-animals/src/species/rabbit/regions.js +48 -0
  248. package/vendor/procedural-animals/src/species/rabbit/rig.js +99 -0
  249. package/vendor/procedural-animals/src/species/rabbit/sculpt.js +148 -0
  250. package/vendor/procedural-animals/src/species/rat/behaviour.js +539 -0
  251. package/vendor/procedural-animals/src/species/rat/coat.js +341 -0
  252. package/vendor/procedural-animals/src/species/rat/index.js +111 -0
  253. package/vendor/procedural-animals/src/species/rat/motion.js +90 -0
  254. package/vendor/procedural-animals/src/species/rat/regions.js +92 -0
  255. package/vendor/procedural-animals/src/species/rat/rig.js +112 -0
  256. package/vendor/procedural-animals/src/species/rat/sculpt.js +163 -0
  257. package/vendor/procedural-animals/src/species/rat/whiskers.js +119 -0
  258. package/vendor/procedural-animals/src/species/shark/coat.js +383 -0
  259. package/vendor/procedural-animals/src/species/shark/index.js +104 -0
  260. package/vendor/procedural-animals/src/species/shark/motion.js +69 -0
  261. package/vendor/procedural-animals/src/species/shark/regions.js +34 -0
  262. package/vendor/procedural-animals/src/species/shark/rig.js +194 -0
  263. package/vendor/procedural-animals/src/species/shark/sculpt.js +343 -0
  264. package/vendor/procedural-animals/src/species/shark/variants.js +105 -0
  265. package/vendor/procedural-animals/src/species/sheep/behaviour.js +522 -0
  266. package/vendor/procedural-animals/src/species/sheep/coat.js +529 -0
  267. package/vendor/procedural-animals/src/species/sheep/index.js +152 -0
  268. package/vendor/procedural-animals/src/species/sheep/motion.js +86 -0
  269. package/vendor/procedural-animals/src/species/sheep/neck.js +41 -0
  270. package/vendor/procedural-animals/src/species/sheep/regions.js +62 -0
  271. package/vendor/procedural-animals/src/species/sheep/rig.js +163 -0
  272. package/vendor/procedural-animals/src/species/sheep/sculpt.js +542 -0
  273. package/vendor/procedural-animals/src/species/snake/coat.js +315 -0
  274. package/vendor/procedural-animals/src/species/snake/index.js +73 -0
  275. package/vendor/procedural-animals/src/species/snake/motion.js +51 -0
  276. package/vendor/procedural-animals/src/species/snake/regions.js +51 -0
  277. package/vendor/procedural-animals/src/species/snake/rig.js +108 -0
  278. package/vendor/procedural-animals/src/species/snake/sculpt.js +122 -0
  279. package/vendor/procedural-animals/src/species/spider/coat.js +279 -0
  280. package/vendor/procedural-animals/src/species/spider/index.js +78 -0
  281. package/vendor/procedural-animals/src/species/spider/motion.js +72 -0
  282. package/vendor/procedural-animals/src/species/spider/regions.js +87 -0
  283. package/vendor/procedural-animals/src/species/spider/rig.js +118 -0
  284. package/vendor/procedural-animals/src/species/spider/sculpt.js +182 -0
  285. package/vendor/procedural-animals/src/species/wolf/behaviour.js +160 -0
  286. package/vendor/procedural-animals/src/species/wolf/coat.js +749 -0
  287. package/vendor/procedural-animals/src/species/wolf/index.js +107 -0
  288. package/vendor/procedural-animals/src/species/wolf/motion.js +80 -0
  289. package/vendor/procedural-animals/src/species/wolf/regions.js +57 -0
  290. package/vendor/procedural-animals/src/species/wolf/rig.js +87 -0
  291. package/vendor/procedural-animals/src/species/wolf/sculpt.js +339 -0
  292. package/vendor/procedural-animals/src/worker.js +29 -0
@@ -0,0 +1,509 @@
1
+ // Goat behaviour layer for the quadruped engine (species.motion.hooks, see core/motion/actions.js):
2
+ //
3
+ // pose(engine, dt) after the engine's solve: the ruminant's sideways grinding of the lower
4
+ // jaw while chewing the cud, quick ear flicks (fly flicks, one ear at a time)
5
+ // update(P, dt, layer) every frame over the action layer: cud chewing bouts (standing or lying),
6
+ // the short tail flicking up, automatic idle variants (browsing, rearing to
7
+ // browse, bleating, head shake, pawing, ear flicks), the buck's raised mane
8
+ // in a threat
9
+ // actions browse (reach up, or rear onto the hind legs: opts.rear), bleat, headshake,
10
+ // paw (scrape the ground with a foreleg), attack (rear up, twist the head,
11
+ // drop and clash head-down), sleep (sternal, head turned back to the flank)
12
+ //
13
+ // Posture lengths (headRaise, neckReach, fwd) are engine units (x cfg.k): species metres / cfg.unit.
14
+ import * as THREE from 'three';
15
+ import { clamp, lerp, smooth, TAU, tv, tqa } from '../../core/motion/common.js';
16
+ import { mx, mxLeg, POSTURES, ONESHOTS } from '../../core/motion/actions.js';
17
+
18
+ const _q = new THREE.Quaternion(), _q2 = new THREE.Quaternion(), _qh = new THREE.Quaternion(), _qI = new THREE.Quaternion(), _s = new THREE.Vector3(1, 1, 1), _m = new THREE.Matrix4();
19
+ const PI = Math.PI;
20
+ // lop ears hang with gravity: the share of the way to the standing hang and the largest turn about the root (25 deg:
21
+ // a lop ear's root lies in the head / neck skin blend, and turned further the skin round the root stretched 3x)
22
+ export const HANG = { f: 0.8, max: 0.44 };
23
+ const sm = (w) => w * w * (3 - 2 * w);
24
+
25
+ function B(e) {
26
+ if (!e._goat) {
27
+ e._goat = {
28
+ cud: 0, cudOn: e.rand() < 0.6, cudT: 6 + e.rand() * 10, chewPh: 0, grind: 0,
29
+ ear: [{ a: 0, age: 9, next: 2 + e.rand() * 4 }, { a: 0, age: 9, next: 3 + e.rand() * 5 }],
30
+ tailT: 1 + e.rand() * 2, tailAge: 9,
31
+ idleT: 5 + e.rand() * 6,
32
+ };
33
+ }
34
+ return e._goat;
35
+ }
36
+ const busy = (L) => L.postures.length > 0 || L.oneshots.some((a) => !a.stopping);
37
+
38
+ // ------------------------------------------------------------------------------------------------
39
+ // pose: jaw grinding (lateral swing of the mandible) and ear flicks
40
+ function pose(e, dt) {
41
+ const b = B(e);
42
+ // udder / scrotum: drawn up out of the ground when the body rests on it (lying, sleeping, dead)
43
+ const ud = e.bone.udder;
44
+ if (ud) {
45
+ // (a buck's scrotum hangs 12.5 cm below the udder bone's top, its bottom 0.325 m in the bind pose; held up until the
46
+ // hindquarters have risen)
47
+ const male = e.params?.sex === 'male';
48
+ const m = ud.matrixWorld.elements, sY = e.J.udderTop.y / 0.44;
49
+ const drop = (male ? 0.125 : 0.168 + 0.065 * (e.params?.udder || 0)) * sY;
50
+ const dl = Math.hypot(m[4], m[5], m[6]) || 1;
51
+ // (lying on its side the udder's axis is level: a lift toward the sky moved it out of the flank, and the rigid bag
52
+ // stood out sideways from the belly like a ball, floating beside the rump. There it hangs toward the ground about
53
+ // its attachment and draws up into the belly along its own axis, against the belly and the lower thigh)
54
+ const side = smooth(0.2, 0.75, 1 + m[5] / dl);
55
+ b.udSide = (b.udSide || 0) + (side - (b.udSide || 0)) * (1 - Math.exp(-dt * 6));
56
+ const top = tv().setFromMatrixPosition(ud.matrixWorld);
57
+ _q.setFromRotationMatrix(ud.matrixWorld);
58
+ if (b.udSide > 1e-3) {
59
+ _qh.setFromUnitVectors(tv(0, 1, 0).applyQuaternion(_q), tv(0, -1, 0)).slerp(_qI, 1 - 0.55 * b.udSide);
60
+ _q.premultiply(_qh);
61
+ top.addScaledVector(tv(0, 1, 0).applyQuaternion(_q), -(0.05 + 0.05 * (e.params?.udder || 0)) * sY * b.udSide);
62
+ }
63
+ // (the udder is its own rigid surface: all of it must clear the ground, up to 20 cm for a doe in milk; a buck's scrotum,
64
+ // 18 cm from the groin, 8 cm: lifted 14.5 cm it vanished into the body when he sat or lay down)
65
+ let want = Math.max(e.P.groundW, e.P.dropH > 0 ? 0.6 * Math.min(1, e.P.dropH) : 0) * (male ? 0.08 : 0.1 + 0.14 * (e.params?.udder || 0)) * e.cfg.s * (1 - b.udSide);
66
+ // ... and at least as much as its lowest point (the teat tips, the scrotum) needs to clear the ground: rising
67
+ // hind end first the posture's weights fell faster than the hindquarters rose, and the udder dipped 7 mm
68
+ // into the ground
69
+ const low = top.y + tv(0, 1, 0).applyQuaternion(_q).y * drop;
70
+ want = Math.max(want, e.terrainH(top.x, top.z) + 0.02 * e.cfg.s - low);
71
+ b.udLift = (b.udLift || 0) + (want - (b.udLift || 0)) * (1 - Math.exp(-dt * 12));
72
+ if (b.udLift > 1e-5 || b.udSide > 1e-3) {
73
+ top.y += Math.max(0, b.udLift);
74
+ ud.matrixWorld.compose(top, _q, _s);
75
+ }
76
+ }
77
+ // beard: a long beard that would reach into the ground (grazing, drinking, lying) swings back
78
+ // about the chin just enough, smoothly
79
+ const bd = e.bone.beard;
80
+ if (bd && (e.params?.beard || 0) > 0.01) {
81
+ const base = tv().setFromMatrixPosition(bd.matrixWorld);
82
+ _q.setFromRotationMatrix(bd.matrixWorld);
83
+ // the beard hangs from the chin skin: it follows the skull more than the opening jaw (the long
84
+ // lock amplified every jaw movement into a whip at its tip)
85
+ if (e.bone.head) { _q2.setFromRotationMatrix(e.bone.head.matrixWorld).multiply(b.beardRel || (b.beardRel = beardRelQ(e))); _q.slerp(_q2, 0.75); }
86
+ const len = b.beardLen ?? (b.beardLen = e.J.beardTop.distanceTo(e.J.beardTip));
87
+ liftOut(e, b.beardSt || (b.beardSt = {}), base, _q, len, dt, 0.04 * e.cfg.s);
88
+ bd.matrixWorld.compose(base, _q, _s);
89
+ }
90
+ // long lop ears (Nubian, Boer) hang below the muzzle: swung forward and out of the ground when
91
+ // grazing or lying
92
+ if (e.params?.ear === 'lop' && e.lod < 2) {
93
+ // ... and they hang with gravity: turned about the root toward the ear's standing hang (turned with the head's yaw),
94
+ // most of the way, while the head is upright (a rigid ear kept its standing angle to the skull, so with the head
95
+ // down to graze or drink it stood out behind the jaw like a plate; the Nubian standard: pendulous ears fall along
96
+ // the face). A head rolled onto its side (dead, lying flat) leaves the ears to the posture.
97
+ const qRel = _q2.setFromRotationMatrix(e.bone.head.matrixWorld).multiply(b.headInv || (b.headInv = e.bindQ.head.clone().invert()));
98
+ const lat = tv(1, 0, 0).applyQuaternion(qRel);
99
+ const psi = Math.atan2(-lat.z, lat.x);
100
+ const hang = HANG.f * (1 - smooth(0.35, 0.7, Math.abs(lat.y)));
101
+ for (let k = 0; k < 2 && hang > 1e-3; k++) {
102
+ const S = k === 0 ? 'L' : 'R', bone = e.bone['ear' + S];
103
+ if (!bone) continue;
104
+ const d0 = b['hang' + S] || (b['hang' + S] = tv(0, 1, 0).applyQuaternion(e.bindQ['ear' + S]).clone());
105
+ const want = tv().copy(d0).applyAxisAngle(tv(0, 1, 0), psi);
106
+ _q.setFromRotationMatrix(bone.matrixWorld);
107
+ const now = tv(0, 1, 0).applyQuaternion(_q);
108
+ _qh.setFromUnitVectors(now, want);
109
+ const ang = 2 * Math.acos(Math.min(1, Math.abs(_qh.w)));
110
+ _qh.slerp(_qI, 1 - Math.min(hang, ang > 1e-4 ? HANG.max / ang : 1));
111
+ bone.matrixWorld.compose(tv().setFromMatrixPosition(bone.matrixWorld), _q.premultiply(_qh), _s);
112
+ }
113
+ for (let k = 0; k < 2; k++) {
114
+ const S = k === 0 ? 'L' : 'R', bone = e.bone['ear' + S];
115
+ if (!bone) continue;
116
+ const st = b['lop' + S] || (b['lop' + S] = {});
117
+ const base = tv().setFromMatrixPosition(bone.matrixWorld);
118
+ _q.setFromRotationMatrix(bone.matrixWorld);
119
+ const len = st.len ?? (st.len = e.J['earBase' + S].distanceTo(e.J['earTip' + S]));
120
+ if (liftOut(e, st, base, _q, len, dt, 0.02 * e.cfg.s)) bone.matrixWorld.compose(base, _q, _s);
121
+ }
122
+ }
123
+ if (e.lod >= 2) return;
124
+ const jaw = e.bone.jaw;
125
+ if (jaw && b.grind > 1e-3) {
126
+ const base = tv().setFromMatrixPosition(jaw.matrixWorld);
127
+ _q.setFromRotationMatrix(jaw.matrixWorld);
128
+ const ax = tv(0, 0, 1).applyQuaternion(_q); // perpendicular to the jaw and to the lateral axis
129
+ const a = 0.07 * b.grind * Math.sin(b.chewPh);
130
+ jaw.matrixWorld.compose(base, tqa(ax, a).multiply(_q), _s);
131
+ }
132
+ for (let k = 0; k < 2; k++) {
133
+ const E = b.ear[k];
134
+ if (E.age > 0.5) continue;
135
+ const bone = k === 0 ? e.bone.earL : e.bone.earR;
136
+ if (!bone) continue;
137
+ // a flick: fast twist about the ear's long axis and a flap, decaying in ~0.4 s
138
+ const f = Math.sin(Math.min(1, E.age / 0.45) * PI * 2) * Math.exp(-E.age * 5) * (k === 0 ? 1 : -1);
139
+ const base = tv().setFromMatrixPosition(bone.matrixWorld);
140
+ _q.setFromRotationMatrix(bone.matrixWorld);
141
+ const along = tv(0, 1, 0).applyQuaternion(_q), flap = tv(0, 0, 1).applyQuaternion(_q);
142
+ _q.premultiply(tqa(along, 0.5 * f * E.a)).premultiply(tqa(flap, 0.35 * f * E.a));
143
+ bone.matrixWorld.compose(base, _q, _s);
144
+ }
145
+ }
146
+
147
+ // Keeps a hanging part (beard, lop ear) out of the ground: the smallest swing up about its root that
148
+ // lifts sample points along it (fractions of its length) above the terrain, followed by a critically
149
+ // damped spring (st: { lift, v }). Returns the rotated quaternion in _q (world) for the bone at base.
150
+ function liftOut(e, st, base, q, len, dt, margin) {
151
+ const dir = tv(0, 1, 0).applyQuaternion(q);
152
+ let need = 0;
153
+ if (base.y - e.terrainH(base.x, base.z) < len + margin + 0.02 * e.cfg.s) {
154
+ for (const f of [1.12, 0.8, 0.5]) {
155
+ const pt = tv().copy(base).addScaledVector(dir, len * f);
156
+ const floor = e.terrainH(pt.x, pt.z) + margin;
157
+ if (pt.y < floor) need = Math.max(need, Math.asin(clamp((floor - pt.y) / (len * f), 0, 1)) * 1.35);
158
+ }
159
+ }
160
+ const om = 28, h = Math.min(dt, 0.05);
161
+ st.v = (st.v || 0) + (om * om * (need - (st.lift || 0)) - 2 * om * (st.v || 0)) * h;
162
+ st.lift = Math.max(0, (st.lift || 0) + st.v * h);
163
+ if (st.lift > 1e-4) {
164
+ const axis = tv().crossVectors(dir, tv(0, 1, 0));
165
+ if (axis.lengthSq() > 1e-8) q.premultiply(tqa(axis.normalize(), st.lift));
166
+ }
167
+ return st.lift > 1e-4;
168
+ }
169
+
170
+ // the beard bone's bind rotation relative to the head bone's (so the head-following beard keeps its
171
+ // bind hang)
172
+ function beardRelQ(e) {
173
+ return e.bindQ.head.clone().invert().multiply(e.bindQ.beard);
174
+ }
175
+
176
+ // ------------------------------------------------------------------------------------------------
177
+ // update: cud chewing, tail flicks, ear flicks, idle variants
178
+ function update(P, dt, L) {
179
+ const e = L.engine, b = B(e), cfg = e.cfg;
180
+ // a kid runs slower than dynamic similarity would give it (a 20 kg kid: ~5.2 m/s, not 6.5): requests
181
+ // above 0.8 of its scaled top speed are capped there (a cap on every speed also slowed the trot it jumps
182
+ // from, and the jump's crouch caught a foreleg mid-stride)
183
+ if (e.params?.age === 'juvenile' && e.wantSpeed > 0.8 * cfg.maxSpeed) P.speedScale *= 0.8 * cfg.maxSpeed / e.wantSpeed;
184
+ // a kid carries its head lower and further forward, on a less upright neck (kid_side, front2: with the
185
+ // adult's high, alert carriage its long legs and upright neck read as a llama); not in actions
186
+ if (e.params?.age === 'juvenile') {
187
+ let act = 0;
188
+ for (const a of L.oneshots) act = Math.max(act, a.w || 0);
189
+ for (const p of L.postures) act = Math.max(act, p.w || 0);
190
+ const kw = 1 - act;
191
+ P.headRaise -= (0.045 / cfg.unit) * kw;
192
+ P.neckReach += (0.025 / cfg.unit) * kw;
193
+ P.headPitch += 0.1 * kw;
194
+ }
195
+ const vn = e.speed / cfg.sq;
196
+ const still = 1 - smooth(0.1, 0.6, vn);
197
+ // --- rumination: chewing bouts of 20-40 s with pauses, standing or lying (not while asleep,
198
+ // eating, bleating or fighting)
199
+ b.cudT -= dt;
200
+ if (b.cudT <= 0) { b.cudOn = !b.cudOn; b.cudT = b.cudOn ? 18 + e.rand() * 22 : 8 + e.rand() * 14; }
201
+ const lying = L.postures.some((p) => p.name === 'lie') ? 1 : 0;
202
+ const quiet = L.oneshots.some((a) => !a.stopping && a.name !== 'hit' && a.name !== 'headshake') ? 0 : 1;
203
+ const asleep = L.postures.some((p) => p.name === 'sleep' || p.name === 'death') ? 1 : 0;
204
+ const want = b.cudOn && quiet && !asleep ? Math.max(still * L.idle.w, lying) : 0;
205
+ b.cud += (want - b.cud) * (1 - Math.exp(-dt * 3));
206
+ // chew rate ~1.3 Hz; every ~40 chews a bolus is swallowed (a short pause)
207
+ const rate = 1.3 * (1 - 0.8 * smooth(0.85, 1, (b.chewPh / TAU) % 40 / 40));
208
+ b.chewPh += dt * TAU * rate;
209
+ const chew = b.cud * (0.5 + 0.5 * Math.sin(b.chewPh));
210
+ b.grind = b.cud;
211
+ // (ruminating goats chew with the lips closed: a small drop of the jaw under the sideways grind, less
212
+ // than the lips' overlap; 0.1 rad opened the mouth 2 cm at the lips for most of an idle goat's time)
213
+ if (b.cud > 1e-3) { P.jaw = Math.max(P.jaw, 0.015 * chew); P.jawOmega = Math.max(P.jawOmega, 18); mx(P, 'eyelid', 0.25, b.cud * 0.6); }
214
+ // --- tail: held up, flicks in quick bursts (a few rapid side flicks)
215
+ b.tailT -= dt;
216
+ if (b.tailT <= 0) { b.tailT = 2 + e.rand() * 5; b.tailAge = 0; }
217
+ b.tailAge += dt;
218
+ const tw = b.tailAge < 0.8 ? Math.sin(PI * b.tailAge / 0.8) : 0;
219
+ if (tw > 0) { P.tailWag = Math.max(P.tailWag, 0.9 * tw * (1 - P.groundW)); mx(P, 'tailLift', 0.25, tw * 0.5); }
220
+ // --- ear flicks (one ear at a time, more often standing)
221
+ for (const E of b.ear) {
222
+ E.age += dt; E.next -= dt * (0.5 + 0.5 * still);
223
+ if (E.next <= 0) { E.next = 2.5 + e.rand() * 7; E.age = 0; E.a = (0.7 + 0.5 * e.rand()) * (1 - P.eyelid * 0.8) * (e.params?.ear === 'lop' ? 0.3 : 1); }
224
+ }
225
+ // --- lying on the side (dead): the ears fold back along the neck, out of the ground
226
+ const dead = L.postures.reduce((m, p) => (p.name === 'death' ? Math.max(m, p.w) : m), 0);
227
+ const flat = Math.max(smooth(0.3, 1.0, Math.abs(P.roll)), dead * smooth(0.3, 1, dead));
228
+ if (flat > 0) { mx(P, 'earFlat', 1.1, flat); mx(P, 'earTwitch', 0, flat); }
229
+ // ... and the head rests on the lower horn and ear, a little higher than a bare skull would
230
+ // (a long lop ear lies flat under the cheek: without the lift it was folded sharply about its root, out of
231
+ // the ground, and its root tore)
232
+ const lopLift = e.params?.ear === 'lop' ? 0.03 : 0;
233
+ if (dead > 0 && P.headW > 0) P.headPos.y += (0.035 + lopLift + 0.12 * (e.params?.horns?.len || 0)) * cfg.s * flat;
234
+ // (the head rolls over with the body rather than twisting on the atlas: the long throat stretched)
235
+ if (dead > 0) P.headRoll *= 1 - 0.45 * dead;
236
+ // --- lop ears hang: they hardly swivel, prick or flatten
237
+ if (e.params?.ear === 'lop') { P.earTwitch *= 0.25; P.earSwivel *= 0.3; P.earFlat *= 0.3; }
238
+ // --- lying / sleeping: the short tail lies flat, not curled round on the ground like a long tail
239
+ P.tailSide *= 0.2;
240
+ // --- grazing / drinking: the head pitches down ahead of the neck as it goes down (with both blended by
241
+ // the action's fade the neck was down before the nose had turned, and the poll opened 25 deg further than
242
+ // in the pose itself for a moment: the throat stretched)
243
+ for (const a of L.oneshots) {
244
+ if ((a.name !== 'eat' && a.name !== 'drink') || a.stopping || !(a.w > 0 && a.w < 1)) continue;
245
+ const pitch = a.tune?.pitch ?? 1.3;
246
+ const lead = Math.min(1, 3 * a.w) - a.w;
247
+ P.headPitch += lead * (pitch - P.headPitch);
248
+ }
249
+ // --- any other action interrupts grazing
250
+ if (L.oneshots.some((a) => !a.stopping && ['attack', 'jump', 'bleat', 'browse', 'paw'].includes(a.name))) for (const a of L.oneshots) if (a.name === 'eat' || a.name === 'drink') a.stopping = true;
251
+ // --- idle variants
252
+ if (e.idleVariants !== false && L.idle.w > 0.98 && !busy(L) && !e.input.look && !e.input.follow) {
253
+ b.idleT -= dt;
254
+ if (b.idleT <= 0) {
255
+ b.idleT = 7 + e.rand() * 10;
256
+ const r = e.rand();
257
+ if (r < 0.22) L.play('browse', { rear: e.rand() < 0.55 });
258
+ else if (r < 0.4) L.play('bleat');
259
+ else if (r < 0.58) L.play('headshake');
260
+ else if (r < 0.7) L.play('paw');
261
+ else if (r < 0.85) { b.ear[0].next = 0; b.ear[1].next = 0.25; }
262
+ }
263
+ } else if (busy(L)) b.idleT = Math.max(b.idleT, 3);
264
+ }
265
+
266
+ // ------------------------------------------------------------------------------------------------
267
+ // browse: stretches the neck up to strip leaves (opts.rear: rises onto the hind legs, forelegs
268
+ // raised as if resting on a trunk). Lips work, the head pulls back after each bite.
269
+ const browse = {
270
+ kind: 'oneshot', fade: 0.5, needsStand: true,
271
+ start(inst, L) {
272
+ const e = L.engine;
273
+ inst.rear = inst.opts.rear ?? true;
274
+ inst.dur = inst.opts.loop ? Infinity : (inst.opts.duration ?? (inst.rear ? 5 : 4.5));
275
+ inst.yaw = (e.rand() - 0.5) * 0.5;
276
+ },
277
+ update(inst) { return inst.t >= inst.dur; },
278
+ apply(P, w, inst, L) {
279
+ const e = L.engine, cfg = e.cfg, t = inst.t, u = 1 / cfg.unit;
280
+ const up = w * smooth(0, 0.9, t);
281
+ // reach and bite cycle (~0.9 s): stretch, bite, pull back and chew
282
+ const c = (t * 1.1) % 1;
283
+ const bite = smooth(0.2, 0.35, c) * (1 - smooth(0.4, 0.7, c));
284
+ mx(P, 'lookW', 0, up);
285
+ mx(P, 'headPitch', -0.75 - 0.12 * bite, up); mx(P, 'headRaise', (0.1 + 0.015 * bite) * u, up); mx(P, 'neckReach', 0.03 * u, up);
286
+ mx(P, 'headYaw', inst.yaw + 0.1 * Math.sin(t * 0.8), up);
287
+ mx(P, 'jaw', 0.05 + 0.18 * bite, up); mx(P, 'jawOmega', 16, up);
288
+ mx(P, 'earFlat', -0.1, up); mx(P, 'tailLift', 0.15, up);
289
+ if (inst.rear) {
290
+ // up on the hind legs: the body comes down first, then the forefeet reach the ground again
291
+ const body = w * smooth(0.2, 1.3, t) * (1 - smooth(inst.dur - 1.2, inst.dur - 0.2, t));
292
+ const legs = Math.min(w * smooth(0.2, 0.7, t), w * smooth(0.004 * cfg.k, 0.04 * cfg.k, e.shY.x) + body);
293
+ mx(P, 'gaitW', 0, w); mx(P, 'legGait', 0, w);
294
+ // (body ~55 deg up: the neck still reaches up and forward, the forelegs half folded as if
295
+ // resting on a trunk)
296
+ mx(P, 'dropF', -1.2, body); mx(P, 'dropH', 0.15, body);
297
+ for (let i = 0; i < 2; i++) { mxLeg(P, i, 'tuck', 1, legs); P.legs[i].extend = lerp(P.legs[i].extend, 0.3, legs); }
298
+ mx(P, 'headPitch', 0.1 - 0.1 * bite, body); mx(P, 'headRaise', 0.0, body); mx(P, 'neckReach', 0.045 * u, body);
299
+ }
300
+ },
301
+ };
302
+
303
+ // bleat: head up, mouth open, jaw quiver, ears back a little
304
+ const bleat = {
305
+ kind: 'oneshot', fade: 0.25,
306
+ start(inst) { inst.dur = inst.opts.duration ?? 1.7; inst.said = false; },
307
+ update(inst, dt, L) {
308
+ if (!inst.said && inst.t > 0.4) { inst.said = true; L.engine.emit('vocalize', { kind: 'bleat' }); }
309
+ return inst.t >= inst.dur;
310
+ },
311
+ apply(P, w, inst, L) {
312
+ const e = L.engine, t = inst.t, u = 1 / e.cfg.unit;
313
+ const up = w * smooth(0, 0.35, t);
314
+ const call = smooth(0.35, 0.5, t) * (1 - smooth(inst.dur - 0.45, inst.dur - 0.15, t));
315
+ mx(P, 'lookW', 0.3, up);
316
+ mx(P, 'headPitch', -0.55, up); mx(P, 'headRaise', 0.04 * u, up); mx(P, 'neckReach', 0.015 * u, up);
317
+ mx(P, 'jaw', 0.42 + 0.07 * Math.sin(t * TAU * 11), call * w); mx(P, 'jawOmega', 30, w);
318
+ mx(P, 'earFlat', 0.3, up); mx(P, 'breathAmp', 2.2, call * w); mx(P, 'tailLift', 0.2, up);
319
+ },
320
+ };
321
+
322
+ // head shake: fast rotations about the nose axis (flies, water), ears flapping
323
+ const headshake = {
324
+ kind: 'oneshot', fade: 0.12,
325
+ start(inst) { inst.dur = 1.0; },
326
+ update(inst) { return inst.t >= inst.dur; },
327
+ apply(P, w, inst) {
328
+ const t = inst.t;
329
+ const env = smooth(0, 0.12, t) * (1 - smooth(0.55, 0.95, t)) * w;
330
+ const s = Math.sin(t * TAU * 4.2);
331
+ mx(P, 'headOmega', 5, env); // (the head springs follow the fast shake)
332
+ mx(P, 'headRoll', 0.42 * s, env); mx(P, 'headYaw', 0.16 * s, env); mx(P, 'headPitch', -0.1, env);
333
+ mx(P, 'earTwitch', 2.5, env); mx(P, 'eyelid', 0.5, env); mx(P, 'lookW', 0, env);
334
+ },
335
+ };
336
+
337
+ // paw: scrapes the ground two or three times with one foreleg (before lying down, or in agitation)
338
+ // Each scrape (0.9 s): the hoof comes up and forward and is held there (~0.4 s, so the lifted foreleg reads:
339
+ // a continuous 0.55 s loop was never caught lifted in the action strip), strikes down and drags back along
340
+ // the ground.
341
+ const PAW_T0 = 0.35, PAW_CYC = 0.9, PAW_N = 2;
342
+ // hoof path per cycle phase f (0..1): [forward (x 0.07 m), height (x 0.1 m)]
343
+ function pawPath(f) {
344
+ const up = smooth(0.0, 0.16, f) * (1 - smooth(0.6, 0.7, f));
345
+ const fwd = -0.15 + 1.15 * smooth(0.0, 0.2, f) - 1.15 * smooth(0.62, 0.98, f); // (periodic: -0.15 at both ends)
346
+ return [fwd, up];
347
+ }
348
+ const paw = {
349
+ kind: 'oneshot', fade: 0.3, needsStand: true,
350
+ start(inst, L) { const e = L.engine; inst.dur = PAW_T0 + PAW_N * PAW_CYC + 0.45; inst.leg = inst.opts.side === -1 ? 1 : inst.opts.side === 1 ? 0 : (e.rand() < 0.5 ? 0 : 1); inst.hits = 0; },
351
+ update(inst, dt, L) {
352
+ const e = L.engine;
353
+ // the strike lands at 0.68 of each cycle
354
+ const n = Math.floor(clamp((inst.t - PAW_T0 - 0.68 * PAW_CYC) / PAW_CYC + 1, 0, PAW_N));
355
+ if (n > inst.hits && inst.hits < PAW_N) {
356
+ inst.hits = n;
357
+ e.emit('footstep', { foot: e.legs[inst.leg].def.key, position: e.legs[inst.leg].contact.clone(), speed: 0, strength: 0.6, paw: true });
358
+ }
359
+ return inst.t >= inst.dur;
360
+ },
361
+ apply(P, w, inst, L) {
362
+ const e = L.engine, cfg = e.cfg, s = cfg.s, t = inst.t, i = inst.leg;
363
+ const tEnd = PAW_T0 + PAW_N * PAW_CYC;
364
+ const k = w * smooth(0.15, 0.35, t) * (1 - smooth(tEnd + 0.05, tEnd + 0.35, t));
365
+ mx(P, 'gaitW', 0, w); mx(P, 'legGait', 0, w);
366
+ mx(P, 'headPitch', 0.35, k); mx(P, 'headRaise', -0.05 / cfg.unit, k); mx(P, 'lookW', 0, k);
367
+ mx(P, 'side', -0.012 * (i === 0 ? 1 : -1) / cfg.unit, k); // weight onto the other three legs
368
+ const u = clamp((t - PAW_T0) / PAW_CYC, 0, PAW_N);
369
+ const f = u >= PAW_N ? 1 : u - Math.floor(u);
370
+ const [pf, pu] = u >= PAW_N ? [-0.15, 0] : pawPath(f);
371
+ const leg = e.legs[i];
372
+ const fwd = e.forward(e.heading, tv());
373
+ // (a clear lift, the hoof raised ~10 cm and brought forward, then struck down and dragged back: a 3.5 cm
374
+ // scrape did not read)
375
+ const tp = tv().copy(leg.plant).addScaledVector(fwd, 0.07 * s * pf);
376
+ tp.y += 0.1 * s * pu + 0.004 * s;
377
+ P.legs[i].target.lerp(tp, k / Math.max(1e-3, P.legs[i].reach + k));
378
+ mxLeg(P, i, 'reach', 1, k);
379
+ },
380
+ };
381
+
382
+ // attack: the goat's clash. Rises on the hind legs with the head twisted to one side, then drops
383
+ // forward and brings the horns / forehead down onto the opponent (the impact at the forefeet's
384
+ // landing). Buck: mane raised.
385
+ const attack = {
386
+ kind: 'oneshot', fade: 0.15, needsStand: true,
387
+ start(inst, L) {
388
+ const e = L.engine;
389
+ inst.dur = 2.1; inst.hit = false;
390
+ inst.side = inst.opts.side ?? (e.rand() < 0.5 ? -1 : 1);
391
+ inst.run = smooth(0.8, 2.5, e.speed / e.cfg.sq);
392
+ inst.target = inst.opts.target ? inst.opts.target.clone() : null;
393
+ },
394
+ update(inst, dt, L) {
395
+ const e = L.engine;
396
+ if (!inst.hit && inst.t >= 1.18) {
397
+ inst.hit = true;
398
+ const p = new THREE.Vector3().copy(e.headPose.position);
399
+ const dir = inst.target ? inst.target.clone().sub(e.pos).setY(0).normalize() : e.forward(e.heading, new THREE.Vector3());
400
+ e.emit('attackHit', { position: p, direction: dir, style: 'headbutt' });
401
+ }
402
+ return inst.t >= inst.dur;
403
+ },
404
+ apply(P, w, inst, L) {
405
+ const e = L.engine, cfg = e.cfg, t = inst.t, u = 1 / cfg.unit;
406
+ if (inst.target) { P.look = inst.target; mx(P, 'lookW', 0.6, w); }
407
+ const rise = smooth(0.1, 0.8, t);
408
+ const drop = smooth(0.92, 1.2, t);
409
+ // (running: no rearing, a lowered-head charge into the clash)
410
+ const still = 1 - inst.run;
411
+ const up = rise * (1 - drop) * w * still;
412
+ const clash = smooth(0.98, 1.2, t) * (1 - smooth(1.45, 2.0, t)) * w;
413
+ const legsW = Math.max(up, w * still * smooth(0.1, 0.4, t) * (1 - smooth(1.02, 1.16, t)));
414
+ mx(P, 'gaitW', 0, w * still * (1 - smooth(1.6, 2.05, t))); mx(P, 'legGait', 0, w * still * (1 - smooth(1.5, 2.0, t)));
415
+ if (inst.run > 0) { const low = smooth(0.3, 0.9, t) * (1 - smooth(1.3, 1.9, t)) * w * inst.run; mx(P, 'headPitch', 0.8, low); mx(P, 'headRaise', -0.06 * u, low); }
416
+ // rear
417
+ mx(P, 'dropF', -1.35, up); mx(P, 'dropH', 0.2, up); mx(P, 'pitch', 0.05, up);
418
+ for (let i = 0; i < 2; i++) { mxLeg(P, i, 'tuck', 1, legsW); P.legs[i].extend = lerp(P.legs[i].extend, lerp(0.25, 0.9, smooth(0.85, 1.1, t)), legsW); }
419
+ mx(P, 'headRoll', 0.45 * inst.side, up); mx(P, 'headYaw', -0.2 * inst.side, up); mx(P, 'headPitch', 0.15, up);
420
+ mx(P, 'headRaise', 0.03 * u, up);
421
+ // drop and clash: head down, forehead first, body lunging forward, forequarters low
422
+ mx(P, 'dropF', 0.28 * still, clash); mx(P, 'fwd', 0.07 * u, clash); mx(P, 'headPitch', 0.95, clash);
423
+ mx(P, 'headRaise', -0.07 * u, clash); mx(P, 'neckReach', 0.03 * u, clash);
424
+ mx(P, 'earFlat', 0.8, w * smooth(0, 0.2, t)); mx(P, 'earTwitch', 0, w);
425
+ mx(P, 'tailLift', 0.4, w);
426
+ // (the buck's mane rises in the threat)
427
+ if (e.params?.sex === 'male' && e.params?.age !== 'juvenile') P.furRaise = Math.max(P.furRaise || 0, 0.6 * w);
428
+ },
429
+ };
430
+
431
+ // lie: the engine's kneeling lie (actions.lie: down front, up hind), with the rise finished a little
432
+ // before the posture is released: its end-first springs (kF / kH) must settle at zero before the
433
+ // posture instance is removed, or the legs jump in the last frame of standing up
434
+ function lieApply(P, w, inst, L) {
435
+ const we = inst.target > 0 ? w : smooth(0.3, 1, w);
436
+ POSTURES.lie.apply(P, we, inst, L);
437
+ }
438
+ const lie = { kind: 'posture', fadeIn: 1.4, fadeOut: 1.3, apply: lieApply };
439
+
440
+ // sleep: sternal (goats rarely sleep flat out), head turned back and resting against the flank,
441
+ // eyes closed
442
+ const sleep = {
443
+ kind: 'posture', fadeIn: 1.3, fadeOut: 1.0,
444
+ apply(P, w, inst, L) {
445
+ lieApply(P, w, inst, L);
446
+ const e = L.engine;
447
+ const c = sm(clamp(w, 0, 1)) * smooth(1.2, 3.2, inst.t);
448
+ mx(P, 'headYaw', inst.side * 0.8, c); mx(P, 'headPitch', 0.45, c); mx(P, 'headRaise', -0.07 / e.cfg.unit, c);
449
+ mx(P, 'bend', inst.side * 0.35, c);
450
+ mx(P, 'earFlat', 0.45, c); mx(P, 'earTwitch', 0.2, c);
451
+ mx(P, 'eyelid', 1, smooth(1.8, 3.2, inst.t) * w);
452
+ mx(P, 'breathRate', 0.6, c); mx(P, 'lookW', 0, c); mx(P, 'tailIdle', 0.2, c);
453
+ },
454
+ };
455
+
456
+ // death: the engine's collapse (legs buckle, topple onto the side, settle), with the body sinking level and
457
+ // leaning to its side while the legs buckle (falls onto its side): the forelegs, the
458
+ // longer pair, buckled further than the hind ones and the goat pitched onto its nose with its hindquarters
459
+ // high before it rolled over
460
+ const death = {
461
+ kind: 'posture', fadeIn: POSTURES.death.fadeIn, fadeOut: POSTURES.death.fadeOut,
462
+ apply(P, w, inst, L) {
463
+ POSTURES.death.apply(P, w, inst, L);
464
+ const e = L.engine, cfg = e.cfg, t = inst.t, side = inst.side;
465
+ const buckle = smooth(0, 0.35, t), fall = clamp((t - 0.3) / 0.55, 0, 1), fallE = fall * fall;
466
+ const settle = fall >= 1 ? Math.exp(-(t - 0.85) * 6) * Math.sin((t - 0.85) * 18) * 0.06 : 0;
467
+ const mv = e.air.active ? 0 : smooth(0.08, 0.45, e.speed / cfg.sk) * (1 - smooth(0.3, 0.7, t));
468
+ const kb = 1 - mv;
469
+ mx(P, 'dropF', lerp(0.42 * buckle * kb, 1, fallE), w);
470
+ mx(P, 'roll', side * (1.42 * (fallE + 0.22 * buckle * kb * (1 - fallE)) - settle), w);
471
+ // (the head goes down with the body as it goes over, not ahead of it: the engine drops it to the ground
472
+ // from 0.35 s, and the goat dived onto its nose before it rolled)
473
+ P.headW *= smooth(0.5, 1.05, t);
474
+ },
475
+ };
476
+
477
+ // hit: the engine's flinch (a shove away from the blow and a restep), held long enough to read on a goat: the
478
+ // body leans and bends away for ~0.4 s with the head thrown up and away, then the goat shakes it off (the
479
+ // engine's 0.12 s recoil barely showed in any frame)
480
+ const hit = {
481
+ ...ONESHOTS.hit,
482
+ kind: 'oneshot',
483
+ start(inst, L) {
484
+ ONESHOTS.hit.start(inst, L);
485
+ inst.dur = 1.4;
486
+ inst.dead = L.postures.some((p) => p.name === 'death');
487
+ },
488
+ apply(P, w, inst) {
489
+ const t = inst.t;
490
+ const k = smooth(0, 0.1, t) * (1 - 0.55 * smooth(0.3, 0.75, t)) * (1 - smooth(0.75, 1.25, t)) * w * (inst.dead ? 0.4 : 1);
491
+ mx(P, 'roll', inst.lx * 0.22, k); mx(P, 'bend', -inst.lx * 0.36, k);
492
+ mx(P, 'pitch', inst.lz * 0.1, k); mx(P, 'dropF', 0.2, k); mx(P, 'dropH', 0.13, k);
493
+ P.headLocal.set(inst.lx * 0.08, 0.03, inst.lz * 0.07 - 0.03); mx(P, 'headLocalW', 1, k);
494
+ mx(P, 'headYaw', -inst.lx * 0.5, k); mx(P, 'headPitch', -0.3, k);
495
+ mx(P, 'earFlat', 1, w * (1 - smooth(0.55, 0.95, t))); mx(P, 'eyelid', 0.7, k);
496
+ mx(P, 'jaw', 0.16, k); mx(P, 'tailLift', -0.15, k);
497
+ if (inst.dead) return;
498
+ // shaking it off
499
+ const sh = smooth(0.7, 0.85, t) * (1 - smooth(1.12, 1.32, t)) * w;
500
+ mx(P, 'headOmega', 5, sh); mx(P, 'headRoll', 0.3 * Math.sin((t - 0.7) * TAU * 4.2), sh);
501
+ mx(P, 'earTwitch', 2.5, sh);
502
+ },
503
+ };
504
+
505
+ export const hooks = {
506
+ pose,
507
+ update,
508
+ actions: { browse, bleat, headshake, paw, attack, hit, lie, sleep, death },
509
+ };