@bitefoundry/retrieviewer 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/ASSET-PROVENANCE.md +6 -0
  2. package/ASSETS-LICENSE.md +2 -1
  3. package/ATTRIBUTION.md +6 -1
  4. package/COMFORT-ART.md +65 -0
  5. package/DESKTOP-PLATFORMS.md +75 -0
  6. package/INSTALLING.md +8 -5
  7. package/PLUGIN.md +13 -10
  8. package/PREREQUISITES.md +95 -0
  9. package/PUPPY-MEMORY.md +102 -1
  10. package/README.ko.md +110 -0
  11. package/README.md +119 -58
  12. package/RELEASING.md +27 -14
  13. package/THIRD-PARTY-NOTICES.md +5 -3
  14. package/braille.mjs +35 -9
  15. package/examples/live.mjs +2 -2
  16. package/integrations/desktop/platform.mjs +27 -0
  17. package/integrations/linux-overlay/README.md +83 -0
  18. package/integrations/linux-overlay/overlay.py +1094 -0
  19. package/integrations/macos-overlay/README.md +83 -0
  20. package/integrations/macos-overlay/overlay.jxa +639 -0
  21. package/integrations/opencode/runtime.mjs +4 -4
  22. package/integrations/opencode/tui.tsx +1 -1
  23. package/integrations/windows-overlay/Overlay.cs +4 -4
  24. package/integrations/windows-overlay/desktop.mjs +40 -8
  25. package/integrations/windows-overlay/protocol.mjs +11 -7
  26. package/integrations/windows-overlay/worker.mjs +13 -7
  27. package/package.json +41 -14
  28. package/puppy-comfort-sprites.mjs +25 -0
  29. package/puppy-companion-comfort-q5.bin.gz +0 -0
  30. package/puppy-companion-comfort.json +77 -0
  31. package/puppy-companion-life.mjs +49 -16
  32. package/puppy-companion-objects.mjs +12 -0
  33. package/puppy-frame-predictive.mjs +15 -9
  34. package/puppy-frame-store.mjs +2 -2
  35. package/puppy-paper-world.mjs +14 -0
  36. package/puppy-paper.mjs +65 -14
  37. package/retrieviewer-cli.mjs +10 -3
  38. package/retrieviewer-plugin.d.mts +1 -1
  39. package/retrieviewer-plugin.mjs +1 -1
  40. package/retrieviewer.d.mts +10 -4
  41. package/retrieviewer.mjs +20 -14
  42. package/locomotion-core.mjs +0 -21
  43. package/locomotion-puppy.animal +0 -0
  44. package/vendor/procedural-animals/package.json +0 -40
  45. package/vendor/procedural-animals/src/animal.js +0 -146
  46. package/vendor/procedural-animals/src/bake.js +0 -51
  47. package/vendor/procedural-animals/src/build.js +0 -81
  48. package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
  49. package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
  50. package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
  51. package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
  52. package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
  53. package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
  54. package/vendor/procedural-animals/src/core/build/seams.js +0 -183
  55. package/vendor/procedural-animals/src/core/build/warp.js +0 -112
  56. package/vendor/procedural-animals/src/core/build/weights.js +0 -393
  57. package/vendor/procedural-animals/src/core/math/vec.js +0 -81
  58. package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
  59. package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
  60. package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
  61. package/vendor/procedural-animals/src/core/motion/common.js +0 -158
  62. package/vendor/procedural-animals/src/core/motion/index.js +0 -22
  63. package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
  64. package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
  65. package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
  66. package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
  67. package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
  68. package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
  69. package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
  70. package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
  71. package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
  72. package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
  73. package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
  74. package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
  75. package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
  76. package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
  77. package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
  78. package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
  79. package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
  80. package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
  81. package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
  82. package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
  83. package/vendor/procedural-animals/src/index.d.ts +0 -98
  84. package/vendor/procedural-animals/src/index.js +0 -29
  85. package/vendor/procedural-animals/src/registry.js +0 -48
  86. package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
  87. package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
  88. package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
  89. package/vendor/procedural-animals/src/species/bear/index.js +0 -139
  90. package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
  91. package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
  92. package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
  93. package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
  94. package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
  95. package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
  96. package/vendor/procedural-animals/src/species/boar/index.js +0 -110
  97. package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
  98. package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
  99. package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
  100. package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
  101. package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
  102. package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
  103. package/vendor/procedural-animals/src/species/cat/index.js +0 -211
  104. package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
  105. package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
  106. package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
  107. package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
  108. package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
  109. package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
  110. package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
  111. package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
  112. package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
  113. package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
  114. package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
  115. package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
  116. package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
  117. package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
  118. package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
  119. package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
  120. package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
  121. package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
  122. package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
  123. package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
  124. package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
  125. package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
  126. package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
  127. package/vendor/procedural-animals/src/species/cow/index.js +0 -118
  128. package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
  129. package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
  130. package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
  131. package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
  132. package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
  133. package/vendor/procedural-animals/src/species/crow/index.js +0 -70
  134. package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
  135. package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
  136. package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
  137. package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
  138. package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
  139. package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
  140. package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
  141. package/vendor/procedural-animals/src/species/deer/index.js +0 -106
  142. package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
  143. package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
  144. package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
  145. package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
  146. package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
  147. package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
  148. package/vendor/procedural-animals/src/species/dog/index.js +0 -144
  149. package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
  150. package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
  151. package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
  152. package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
  153. package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
  154. package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
  155. package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
  156. package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
  157. package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
  158. package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
  159. package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
  160. package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
  161. package/vendor/procedural-animals/src/species/fish/index.js +0 -88
  162. package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
  163. package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
  164. package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
  165. package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
  166. package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
  167. package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
  168. package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
  169. package/vendor/procedural-animals/src/species/fox/index.js +0 -120
  170. package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
  171. package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
  172. package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
  173. package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
  174. package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
  175. package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
  176. package/vendor/procedural-animals/src/species/frog/index.js +0 -97
  177. package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
  178. package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
  179. package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
  180. package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
  181. package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
  182. package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
  183. package/vendor/procedural-animals/src/species/goat/index.js +0 -149
  184. package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
  185. package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
  186. package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
  187. package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
  188. package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
  189. package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
  190. package/vendor/procedural-animals/src/species/horse/index.js +0 -80
  191. package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
  192. package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
  193. package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
  194. package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
  195. package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
  196. package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
  197. package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
  198. package/vendor/procedural-animals/src/species/lion/index.js +0 -111
  199. package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
  200. package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
  201. package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
  202. package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
  203. package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
  204. package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
  205. package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
  206. package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
  207. package/vendor/procedural-animals/src/species/pig/index.js +0 -161
  208. package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
  209. package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
  210. package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
  211. package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
  212. package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
  213. package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
  214. package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
  215. package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
  216. package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
  217. package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
  218. package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
  219. package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
  220. package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
  221. package/vendor/procedural-animals/src/species/rat/index.js +0 -111
  222. package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
  223. package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
  224. package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
  225. package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
  226. package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
  227. package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
  228. package/vendor/procedural-animals/src/species/shark/index.js +0 -104
  229. package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
  230. package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
  231. package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
  232. package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
  233. package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
  234. package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
  235. package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
  236. package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
  237. package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
  238. package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
  239. package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
  240. package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
  241. package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
  242. package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
  243. package/vendor/procedural-animals/src/species/snake/index.js +0 -73
  244. package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
  245. package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
  246. package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
  247. package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
  248. package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
  249. package/vendor/procedural-animals/src/species/spider/index.js +0 -78
  250. package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
  251. package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
  252. package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
  253. package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
  254. package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
  255. package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
  256. package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
  257. package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
  258. package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
  259. package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
  260. package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
  261. package/vendor/procedural-animals/src/worker.js +0 -29
@@ -1,513 +0,0 @@
1
- // White-tailed deer behaviour layer for the quadruped engine (species.motion.hooks, see
2
- // core/motion/actions.js):
3
- //
4
- // pose(engine, dt) after the engine's solve: the ears swivel on their own, constantly (each
5
- // pinna turns toward a new "sound" every 0.6-3 s, faster when alarmed); the
6
- // tail flag (raised vertically, white underside showing, waving a little from
7
- // side to side) blended over the engine's tail chain
8
- // update(P, dt, layer) every frame over the action layer: alarm level (fleeing, hit, stomping,
9
- // jumping) -> tail flag; the walk's head nod; grazing with frequent head-up
10
- // alert checks (chewing, ears pricked, looking round); zig-zag escape
11
- // steering; idle variants (the suspicious foot stomp with head bob, the alert
12
- // stare, tail swishes); sternal sleep with the head laid back
13
- // actions stomp, alert, flee, attack (buck: antler thrust; doe / fawn: rears and
14
- // flails with the forefeet), hit (engine stagger + tail flag), jump (slower
15
- // tuck, forelegs reaching for the landing; opts.height / distance), death
16
- // (hooves planted while the legs buckle), lie / sleep (staged kneel, rise hind
17
- // first), sit (sternal bedding, head up and alert)
18
- //
19
- // Distances are deer metres at the reference size (x cfg.s); posture offsets the engine multiplies
20
- // by cfg.k (fwd, side, headRaise, neckReach) are divided by cfg.unit.
21
- import * as THREE from 'three';
22
- import { clamp, lerp, smooth, TAU, tv, tqa } from '../../core/motion/common.js';
23
- import { mx, mxLeg, ONESHOTS, POSTURES } from '../../core/motion/actions.js';
24
- import { antlerCurves } from './sculpt.js';
25
- import { deerJoints } from './rig.js';
26
-
27
- const _q = new THREE.Quaternion(), _s = new THREE.Vector3(1, 1, 1);
28
- const sm = (w) => w * w * (3 - 2 * w);
29
-
30
- // per-engine behaviour state
31
- function B(e) {
32
- if (!e._deer) {
33
- e._deer = {
34
- ear: [{ sw: 0, v: 0, target: 0, tNext: 0.4 }, { sw: 0, v: 0, target: 0, tNext: 1.1 }],
35
- alarm: 0, flag: 0, flagV: 0, flagT: 0,
36
- idleT: 6 + e.rand() * 6, graze: { checkIn: 2 + e.rand() * 3, t: -1, dur: 2, look: new THREE.Vector3() },
37
- flee: null, dirs: null,
38
- };
39
- }
40
- return e._deer;
41
- }
42
- const busy = (L) => L.postures.length > 0 || L.oneshots.some((a) => !a.stopping);
43
-
44
- // antler sample points (beam and tine tips) relative to the occiput, bind pose, reference size
45
- const _AJ = deerJoints();
46
- function antlerSamples(A) {
47
- const o = _AJ.occiput, out = [];
48
- for (const side of antlerCurves(A)) {
49
- for (let i = 2; i < side.beam.length; i += 2) out.push(side.beam[i]);
50
- out.push(side.beam[side.beam.length - 1]);
51
- for (const t of side.tines) out.push(t.pts[t.pts.length - 1], t.pts[Math.floor(t.pts.length / 2)]);
52
- }
53
- return out.map((p) => new THREE.Vector3(p[0] - o[0], p[1] - o[1], p[2] - o[2]));
54
- }
55
- const _qa = new THREE.Quaternion(), _qb = new THREE.Quaternion(), _m = new THREE.Matrix4();
56
-
57
- // antlers never enter the ground (a buck lying dead, sleeping, grazing on a bank): the skull (with
58
- // the jaw and ears) turns about the occiput just enough to lift the lowest antler point, smoothly
59
- function antlerClear(e, b, dt) {
60
- const A = e.params.antlers;
61
- if (!A) return;
62
- const cfg = e.cfg, head = e.bone.head;
63
- if (!head || !e.bindQ || !e.bindQ.head) return;
64
- if (e.lod >= 2 && e.P.groundW < 0.01 && !(b.aLift > 0)) return; // (crowd: only resting on the ground)
65
- if (!b.aPts) { b.aPts = antlerSamples(A); b.aLift = 0; b.aReach = Math.max(...b.aPts.map((v) => v.length())); }
66
- const occ = tv().setFromMatrixPosition(head.matrixWorld);
67
- const s = cfg.s;
68
- if (occ.y - e.terrainH(occ.x, occ.z) > b.aReach * s + 0.05 && b.aLift < 1e-4) return;
69
- _qa.setFromRotationMatrix(head.matrixWorld).multiply(_qb.copy(e.bindQ.head).invert());
70
- let need = 0, ax = null, deep = 0;
71
- const clr = (A.base * 0.8 + 0.01) * s;
72
- for (const v of b.aPts) {
73
- const r = tv().copy(v).multiplyScalar(s).applyQuaternion(_qa);
74
- const p = tv().copy(occ).add(r);
75
- const depth = e.terrainH(p.x, p.z) + clr - p.y;
76
- if (depth <= deep) continue;
77
- const hor = Math.hypot(r.x, r.z);
78
- if (hor < 1e-3) continue;
79
- deep = depth; ax = tv().crossVectors(r, tv(0, 1, 0)).normalize();
80
- need = Math.asin(clamp(depth / Math.max(hor, depth + 1e-3), 0, 1)) * 1.05;
81
- }
82
- // (rises at once when needed, relaxes slowly)
83
- b.aLift = need > b.aLift ? need : Math.max(need, b.aLift - dt * 1.2);
84
- if (!ax) { if (b.aLift < 1e-4) return; ax = b.aAx || tv(1, 0, 0); } else { b.aAx = (b.aAx || new THREE.Vector3()).copy(ax); }
85
- if (b.aLift < 1e-4) return;
86
- const R = tqa(b.aAx, b.aLift);
87
- for (const name of ['head', 'jaw', 'earL', 'earR']) {
88
- const bn = e.bone[name];
89
- if (!bn) continue;
90
- const p = tv().setFromMatrixPosition(bn.matrixWorld).sub(occ).applyQuaternion(R).add(occ);
91
- _q.setFromRotationMatrix(bn.matrixWorld).premultiply(R);
92
- bn.matrixWorld.compose(p, _q, _s);
93
- }
94
- void _m;
95
- }
96
-
97
- // ------------------------------------------------------------------------------------------------
98
- // pose: antler ground clearance, ear swivels and the tail flag
99
- function pose(e, dt) {
100
- const b = B(e), P = e.P, cfg = e.cfg;
101
- antlerClear(e, b, dt);
102
- const awake = 1 - P.eyelid;
103
- // ---- ears
104
- if (cfg.hasEars && e.lod < 2) {
105
- const alert = clamp(b.alarm + (P.lookW > 0 && P.look ? 0.3 : 0), 0, 1);
106
- for (let k = 0; k < 2; k++) {
107
- const E = b.ear[k], s = k === 0 ? 1 : -1;
108
- const bone = k === 0 ? e.bone.earL : e.bone.earR;
109
- if (!bone) continue;
110
- E.tNext -= dt * (1 + 1.5 * alert);
111
- if (E.tNext <= 0) {
112
- E.tNext = 0.6 + e.rand() * 2.4;
113
- // mostly out to the side and back (sounds behind), sometimes forward; independent per ear
114
- const r = e.rand();
115
- E.target = r < 0.25 ? -0.25 * s : r < 0.5 ? 0 : (0.3 + 0.9 * e.rand()) * s;
116
- }
117
- const want = E.target * awake * (1 - clamp(P.earFlat, 0, 1));
118
- const om = 14; // quick, critically damped swivel
119
- E.v += (om * om * (want - E.sw) - 2 * om * E.v) * dt;
120
- E.sw += E.v * dt;
121
- if (Math.abs(E.sw) < 1e-4) continue;
122
- const base = tv().setFromMatrixPosition(bone.matrixWorld);
123
- _q.setFromRotationMatrix(bone.matrixWorld);
124
- const ax = tv(0, 1, 0).applyQuaternion(_q);
125
- _q.premultiply(tqa(ax, E.sw));
126
- bone.matrixWorld.compose(base, _q, _s);
127
- }
128
- }
129
- // ---- tail flag: each segment turned toward vertical (a little back at the root, the tip
130
- // leaning forward over the rump), with a slow side-to-side wave
131
- const f = b.flag;
132
- if (f < 1e-3) return;
133
- const tl = e.tail, n = tl.n, fr = e.fr;
134
- const up = tv(0, 1, 0).applyQuaternion(fr.qPel), back = tv(0, 0, -1).applyQuaternion(fr.qPel), latP = tv(1, 0, 0).applyQuaternion(fr.qPel);
135
- // (the bone roll is parallel-transported along the chain exactly as the engine does it, so the
136
- // flag blends in without a twist)
137
- const latRef = tv().copy(latP);
138
- const p = tv().copy(tl.p[0]);
139
- const wave = e.lod >= 2 ? 0 : Math.sin(e.time * TAU * 1.3) * 0.35;
140
- for (let i = 0; i < n; i++) {
141
- const r = i / Math.max(1, n - 1);
142
- const a = lerp(0.95, 1.75, Math.pow(r, 0.8)); // target angle from "back" toward "up" (rad)
143
- // the segment swings up through the horizontal behind the rump (an angle blend in the
144
- // back / up plane: the hanging tail and the flag point in nearly opposite directions)
145
- const cur = tv().subVectors(tl.p[i + 1], tl.p[i]).normalize();
146
- const cb = cur.dot(back), cu = cur.dot(up), cl = cur.dot(latP);
147
- const th0 = Math.atan2(cu, cb), th = th0 + (a - th0) * f;
148
- const lt = cl * (1 - f) + wave * r * 0.5 * f;
149
- const h = Math.sqrt(Math.max(0, 1 - lt * lt));
150
- const d = tv().copy(back).multiplyScalar(Math.cos(th) * h).addScaledVector(up, Math.sin(th) * h).addScaledVector(latP, lt).normalize();
151
- const q0 = tv().copy(p);
152
- p.addScaledVector(d, tl.len[i]);
153
- latRef.addScaledVector(d, -latRef.dot(d)).normalize();
154
- e.setBoneF(e.tailNames[i], q0, d, latRef);
155
- }
156
- }
157
-
158
- // ------------------------------------------------------------------------------------------------
159
- // update: alarm / flag, walk nod, grazing alert checks, idle variants, escape steering
160
- function update(P, dt, L) {
161
- const e = L.engine, b = B(e), cfg = e.cfg, u = 1 / cfg.unit;
162
- const vn = e.speed / cfg.sq;
163
- // ---- alarm: fleeing at a gallop, hit, stomping, jumping, an attack
164
- let alarmT = smooth(4.2, 6.5, vn) * P.gaitW;
165
- for (const a of L.oneshots) {
166
- if (a.stopping && a.w < 0.3) continue;
167
- if (a.name === 'hit' || a.name === 'flee' || a.name === 'jump') alarmT = 1;
168
- else if (a.name === 'stomp') alarmT = Math.max(alarmT, smooth(0.6, 1.2, a.t) * 0.9);
169
- else if (a.name === 'attack') alarmT = Math.max(alarmT, 0.6);
170
- }
171
- if (e.air.active) alarmT = 1;
172
- if (e.input.alarm) alarmT = 1; // (games: motion.input.alarm = true keeps the flag up)
173
- // the flag stays up for a moment after the danger (the tail comes down while slowing)
174
- b.alarm = alarmT > b.alarm ? alarmT : Math.max(alarmT, b.alarm - dt * 0.5);
175
- // lying / dead: tail down
176
- const down = L.postures.reduce((m, p) => Math.max(m, p.w), 0);
177
- const flagT = clamp(b.alarm, 0, 1) * (1 - down);
178
- // critically damped spring (fast up, slower down)
179
- const om = flagT > b.flag ? 9 : 5;
180
- b.flagV += (om * om * (flagT - b.flag) - 2 * om * b.flagV) * dt;
181
- b.flag = clamp(b.flag + b.flagV * dt, 0, 1);
182
- if (b.flag > 0.3) { mx(P, 'earFlat', 0.25, smooth(5, 9, vn) * b.flag); mx(P, 'tailIdle', 0, b.flag); }
183
-
184
- // ---- walk: the head and neck nod once per forelimb stance
185
- const g = e.gait;
186
- const walkW = smooth(0.12, 0.6, vn) * (1 - smooth(1.4, 1.9, vn)) * P.gaitW;
187
- if (walkW > 0.001) {
188
- const ph = e.phase - g.off[0];
189
- const c = 0.5 + 0.5 * Math.cos(4 * Math.PI * (ph - 0.1));
190
- P.headRaise -= 0.03 * u * walkW * c;
191
- P.headPitch += 0.05 * walkW * (c - 0.5);
192
- }
193
-
194
- // ---- grazing: frequent head-up alert checks (chewing, ears pricked, looking round)
195
- const eat = L.oneshots.find((a) => a.name === 'eat' || a.name === 'drink');
196
- const gz = b.graze;
197
- if (eat && !eat.stopping && eat.w > 0.9) {
198
- if (gz.t < 0) {
199
- gz.checkIn -= dt;
200
- if (gz.checkIn <= 0) {
201
- gz.t = 0; gz.dur = 1.4 + e.rand() * 1.8;
202
- const a = e.heading + (e.rand() - 0.5) * 2.6, d = 10 * cfg.k;
203
- gz.look.set(e.pos.x + Math.sin(a) * d, e.pos.y + 0.8 * cfg.s, e.pos.z + Math.cos(a) * d);
204
- }
205
- }
206
- } else if (!eat) { gz.t = -1; gz.checkIn = 1.5 + e.rand() * 2; }
207
- if (gz.t >= 0) {
208
- // (a check under way runs to its end, also while the grazing fades out)
209
- gz.t += dt;
210
- if (gz.t > gz.dur) { gz.t = -1; gz.checkIn = (eat && eat.name === 'drink' ? 3 : 2.2) + e.rand() * 4; }
211
- }
212
- if (gz.t >= 0 && eat) {
213
- const c = sm(smooth(0, 0.35, gz.t) * (1 - smooth(gz.dur - 0.45, gz.dur, gz.t))) * sm(eat.w);
214
- mx(P, 'headW', 0, c); mx(P, 'headReach', 0, c); mx(P, 'headPitch', -0.05, c); mx(P, 'headYaw', 0, c);
215
- mx(P, 'headOmega', 1.4, c);
216
- mx(P, 'headRaise', 0.02 * u, c);
217
- P.look = gz.look; mx(P, 'lookW', 1, c);
218
- mx(P, 'earFlat', -0.12, c); mx(P, 'earTwitch', 0.3, c);
219
- if (eat.name === 'eat') { mx(P, 'jaw', 0.05 + 0.05 * Math.max(0, Math.sin(gz.t * 7.5)), c); }
220
- else mx(P, 'jaw', 0.02, c);
221
- }
222
-
223
- // ---- escape steering (flee): zig-zags at speed
224
- const f = b.flee;
225
- if (f) {
226
- f.t += dt;
227
- if (f.t >= f.dur) b.flee = null;
228
- else {
229
- f.next -= dt;
230
- if (f.next <= 0) { f.side = -f.side; f.next = 0.9 + e.rand() * 0.7; }
231
- e.wantSpeed = Math.max(e.wantSpeed, f.speed * cfg.sq * smooth(0, 0.4, f.t));
232
- e.wantHeading = f.h0 + f.side * f.amp * smooth(0.5, 1.2, f.t);
233
- }
234
- }
235
-
236
- // ---- sleep (sternal, curled): the body stays upright, the head is laid back along the flank
237
- for (const p of L.postures) {
238
- if (p.name !== 'sleep') continue;
239
- const c = sm(clamp(p.w, 0, 1)) * smooth(1.0, 3.0, p.t);
240
- mx(P, 'roll', p.side * 0.1, c); mx(P, 'bend', p.side * 0.45, c);
241
- mx(P, 'tailCurl', 0, c); mx(P, 'tailSide', p.side * 0.3, c);
242
- mx(P, 'earFlat', 0.6, c);
243
- }
244
- // dying / dead: ears laid back; a buck's head stays upright on its chin, the antlers clear of
245
- // the ground (a head on its cheek would drive the lower beam into the ground)
246
- for (const p of L.postures) {
247
- if (p.name !== 'death') continue;
248
- const w = sm(clamp(p.w, 0, 1)) * smooth(0.3, 1.0, p.t);
249
- mx(P, 'earFlat', 1, w); mx(P, 'earTwitch', 0, w);
250
- if (!e.params.antlers) P.headPos.y += 0.018 * cfg.s * w; // (the broad pinnae lie on the ground, not in it)
251
- else {
252
- mx(P, 'headRoll', 0, w); mx(P, 'headPitch', 0.05, w);
253
- P.headPos.y += 0.09 * cfg.s * w;
254
- }
255
- }
256
-
257
- // any other action interrupts grazing / drinking
258
- if (L.oneshots.some((a) => !a.stopping && a.name !== 'eat' && a.name !== 'drink' && a.name !== 'hit')) for (const a of L.oneshots) if (a.name === 'eat' || a.name === 'drink') a.stopping = true;
259
-
260
- // ---- idle variants (standing still, nothing else running, nobody steering the gaze)
261
- if (e.idleVariants !== false && L.idle.w > 0.98 && !busy(L) && !e.input.look && !e.input.follow) {
262
- b.idleT -= dt;
263
- if (b.idleT <= 0) {
264
- b.idleT = 7 + e.rand() * 9;
265
- const r = e.rand();
266
- if (r < 0.35) L.play('stomp');
267
- else if (r < 0.7) L.play('alert');
268
- }
269
- } else if (busy(L)) b.idleT = Math.max(b.idleT, 4);
270
- }
271
-
272
- // ------------------------------------------------------------------------------------------------
273
- // stomp: suspicious. Head up and ears forward, a head bob (a feint: the head dips as if to feed
274
- // and snaps back up), then 2-3 hard stomps with one forefoot; tail half raised.
275
- const stomp = {
276
- kind: 'oneshot', fade: 0.25,
277
- start(inst, L) {
278
- const e = L.engine;
279
- inst.leg = inst.opts.leg ?? (e.rand() < 0.5 ? 0 : 1);
280
- const n = inst.opts.count ?? (e.rand() < 0.5 ? 2 : 3);
281
- inst.hits = Array.from({ length: n }, (_, i) => 1.15 + i * 0.42);
282
- inst.done = inst.hits.map(() => false);
283
- inst.dur = inst.hits[n - 1] + 0.75;
284
- const a = e.heading + (e.rand() - 0.5) * 1.2, d = 8 * e.cfg.k;
285
- inst.look = inst.opts.target ? inst.opts.target.clone() : new THREE.Vector3(e.pos.x + Math.sin(a) * d, e.pos.y + 0.6 * e.cfg.s, e.pos.z + Math.cos(a) * d);
286
- },
287
- update(inst, dt, L) {
288
- const e = L.engine;
289
- inst.hits.forEach((tt, j) => {
290
- if (!inst.done[j] && inst.t >= tt) {
291
- inst.done[j] = true;
292
- const leg = e.legs[inst.leg];
293
- e.emit('footstep', { foot: leg.def.key, position: leg.plant.clone(), speed: 0, strength: 1, stomp: true });
294
- }
295
- });
296
- return inst.t >= inst.dur;
297
- },
298
- apply(P, w, inst, L) {
299
- const e = L.engine, s = e.cfg.s, u = 1 / e.cfg.unit, t = inst.t;
300
- mx(P, 'gaitW', 0, w); mx(P, 'legGait', 0, w);
301
- P.look = inst.look; mx(P, 'lookW', 1, w);
302
- mx(P, 'earFlat', -0.15, w); mx(P, 'earTwitch', 0.2, w);
303
- mx(P, 'headRaise', 0.035 * u, w);
304
- // head bob: dips toward the ground and snaps back up
305
- const bob = Math.sin(Math.PI * clamp((t - 0.25) / 0.6, 0, 1));
306
- mx(P, 'headRaise', -0.22 * u, w * bob * bob); mx(P, 'headPitch', 0.35, w * bob);
307
- mx(P, 'lookW', 0, w * bob);
308
- // stomps: the foot is lifted (knee flexed) and slammed down on its own spot
309
- let lift = 0;
310
- for (const tt of inst.hits) lift = Math.max(lift, smooth(tt - 0.3, tt - 0.1, t) * (1 - smooth(tt - 0.07, tt, t)));
311
- const leg = e.legs[inst.leg];
312
- const k = w * smooth(0.8, 0.95, t) * (1 - smooth(inst.hits[inst.hits.length - 1], inst.hits[inst.hits.length - 1] + 0.3, t));
313
- const tp = tv().copy(leg.plant);
314
- tp.y += 0.13 * s * lift;
315
- tp.addScaledVector(e.forward(e.heading, tv()), 0.02 * s * lift);
316
- P.legs[inst.leg].target.copy(tp);
317
- mxLeg(P, inst.leg, 'reach', 1, k);
318
- // the body leans back a little onto the other legs, the forehand drops at each strike
319
- mx(P, 'dropF', 0.04 + 0.05 * (1 - lift), k);
320
- },
321
- };
322
-
323
- // alert: stands tall and stares, ears forward, neck stretched up, tail twitching half-raised
324
- const alert = {
325
- kind: 'oneshot', fade: 0.35,
326
- start(inst, L) {
327
- const e = L.engine;
328
- inst.dur = inst.opts.duration ?? 2.5 + e.rand() * 2;
329
- const a = e.heading + (e.rand() - 0.5) * 2.0, d = 12 * e.cfg.k;
330
- inst.look = inst.opts.target ? inst.opts.target.clone() : new THREE.Vector3(e.pos.x + Math.sin(a) * d, e.pos.y + 0.5 * e.cfg.s, e.pos.z + Math.cos(a) * d);
331
- },
332
- update(inst) { return inst.t >= inst.dur; },
333
- apply(P, w, inst, L) {
334
- const u = 1 / L.engine.cfg.unit;
335
- const k = w * smooth(0, 0.3, inst.t);
336
- mx(P, 'headRaise', 0.07 * u, k); mx(P, 'neckReach', -0.02 * u, k); mx(P, 'headPitch', -0.12, k);
337
- P.look = inst.look; mx(P, 'lookW', 1, k);
338
- mx(P, 'earFlat', -0.2, k); mx(P, 'earTwitch', 0.2, k);
339
- mx(P, 'tailLift', 0.35, k); mx(P, 'breathRate', 1.4, k);
340
- },
341
- };
342
-
343
- // flee: bounds away with long zig-zags, tail flagged, ears back
344
- const flee = {
345
- kind: 'oneshot', fade: 0.25,
346
- start(inst, L) {
347
- const e = L.engine, b = B(e);
348
- inst.dur = inst.opts.duration ?? 4;
349
- let h0 = e.heading;
350
- if (inst.opts.from) h0 = Math.atan2(e.pos.x - inst.opts.from.x, e.pos.z - inst.opts.from.z);
351
- if (inst.opts.heading !== undefined) h0 = inst.opts.heading;
352
- b.flee = { t: 0, dur: inst.dur, h0, side: e.rand() < 0.5 ? -1 : 1, next: 1.0, amp: 0.35, speed: inst.opts.speed ?? (e.cfg.gears.bound || 11 * e.cfg.sq) / e.cfg.sq };
353
- },
354
- update(inst, dt, L) { if (inst.t >= inst.dur) { B(L.engine).flee = null; return true; } return false; },
355
- apply(P, w) { mx(P, 'earFlat', 0.5, w); },
356
- };
357
-
358
- // attack: bucks lower the head and thrust the antlers (with a twist); does and fawns rear up on the
359
- // hind legs and flail with the forefeet, striking down alternately, then come down on their own
360
- // hoofprints (running, they butt with the head instead). play('attack', { style: 'strike' |
361
- // 'antler' }) picks one.
362
- const STRIKES = [0.5, 0.66, 0.82, 0.98];
363
- const attack = {
364
- ...ONESHOTS.attack,
365
- kind: 'oneshot', needsStand: true,
366
- start(inst, L) {
367
- const e = L.engine;
368
- const run = smooth(1.5, 4, e.speed / e.cfg.sk);
369
- const want = inst.opts.style || (e.params.antlers ? 'antler' : 'strike');
370
- inst.strikeMode = want !== 'antler' && run < 0.3;
371
- if (inst.strikeMode) {
372
- inst.style = 'strike'; inst.dur = 1.72; inst.run = run; inst.hits = STRIKES.map(() => false);
373
- inst.target = inst.opts.target ? inst.opts.target.clone() : null;
374
- return;
375
- }
376
- inst.tune = { ...inst.tune, style: 'headbutt' };
377
- ONESHOTS.attack.start.call(this, inst, L);
378
- },
379
- update(inst, dt, L) {
380
- if (!inst.strikeMode) return ONESHOTS.attack.update.call(this, inst, dt, L);
381
- const e = L.engine;
382
- STRIKES.forEach((t0, j) => {
383
- if (!inst.hits[j] && inst.t >= t0 + 0.08) {
384
- inst.hits[j] = true;
385
- const leg = e.legs[j & 1];
386
- const p = new THREE.Vector3().setFromMatrixPosition(e.bone['fhoof' + leg.def.S].matrixWorld);
387
- const dir = inst.target ? inst.target.clone().sub(e.pos).setY(0).normalize() : e.forward(e.heading, new THREE.Vector3());
388
- e.emit('attackHit', { position: p, direction: dir, style: 'strike' });
389
- }
390
- });
391
- return inst.t >= inst.dur;
392
- },
393
- apply(P, w, inst, L) {
394
- const t = inst.t;
395
- if (!inst.strikeMode) {
396
- ONESHOTS.attack.apply.call(this, P, w, inst, L);
397
- // antler thrust: the head goes low, antlers forward; a twisting shove at contact
398
- const low = smooth(0, 0.35, t) * (1 - smooth(0.75, 1.1, t));
399
- const thrust = smooth(0.35, 0.55, t) * (1 - smooth(0.65, 1.0, t));
400
- mx(P, 'headPitch', 0.95, low * w);
401
- mx(P, 'headRoll', 0.2 * Math.sin((t - 0.4) * 8), thrust * w);
402
- mx(P, 'earFlat', 1, w);
403
- // (a shorter lunge than the engine's charge: the planted hooves stay within reach)
404
- P.fwd *= 1 - 0.65 * w;
405
- return;
406
- }
407
- const e = L.engine, cfg = e.cfg;
408
- if (inst.target) { P.look = inst.target; mx(P, 'lookW', 1, w); }
409
- mx(P, 'earFlat', 1, w * smooth(0, 0.15, t)); mx(P, 'earTwitch', 0, w);
410
- // up on the hind legs, forehand raised; the gait is held until the forefeet are down again
411
- const up = smooth(0.05, 0.42, t) * (1 - smooth(1.05, 1.42, t));
412
- const hold = Math.min(1, smooth(0.0, 0.2, t) * (1 - smooth(1.5, 1.7, t)));
413
- mx(P, 'gaitW', 0, hold * w); mx(P, 'legGait', 0, hold * w);
414
- mx(P, 'dropF', -1.0, up * w); mx(P, 'dropH', 0.22, up * w); mx(P, 'headRaise', 0.03 / cfg.unit, up * w);
415
- const fwd = e.forward(e.heading, tv()), lat = e.left(e.heading, tv());
416
- for (let i = 0; i < 2; i++) {
417
- const leg = e.legs[i], Ld = leg.def;
418
- // between strikes the forelegs are folded; each strike reaches forward and down
419
- let k = 0;
420
- for (let j = i; j < STRIKES.length; j += 2) k = Math.max(k, Math.pow(Math.sin(Math.PI * clamp((t - STRIKES[j] + 0.06) / 0.22, 0, 1)), 2));
421
- mxLeg(P, i, 'tuck', 1, up * (1 - k) * w); P.legs[i].extend = 0.2;
422
- const tp = tv().copy(e.fr.shC).addScaledVector(fwd, 0.42 * Ld.len).addScaledVector(lat, Ld.s * Ld.cx);
423
- tp.y -= 0.55 * Ld.len;
424
- const ks = k * up * w;
425
- // coming down: each forefoot is set back on the hoofprint it rose from
426
- const down = (1 - up) * hold * w;
427
- P.legs[i].target.copy(leg.plant).lerp(tp, ks / Math.max(1e-3, ks + down));
428
- mxLeg(P, i, 'reach', 1, Math.max(ks, down));
429
- }
430
- },
431
- };
432
-
433
- // jump: the engine's leap (the species' everyday obstacle jump; play('jump', { height, distance })
434
- // picks another one: { height: 2 } is the record escape leap). The legs fold up a little more slowly
435
- // after take-off (the long slender forelegs tucked in 0.12 s snapped at the elbow), and the forelegs
436
- // unfold and reach for the ground over the last part of the flight (they were still folded under the
437
- // chest at touchdown)
438
- const jump = {
439
- ...ONESHOTS.jump, kind: 'oneshot', airborne: true,
440
- start(inst, L) {
441
- const o = inst.opts, t = inst.tune || {};
442
- if (o.height || o.distance) {
443
- const h = o.height ?? t.height, k = t.height ? h / t.height : 1;
444
- inst.tune = { ...t, height: h, distance: o.distance ?? (t.distance ?? 3.8) * Math.sqrt(k) * (k > 1 ? 1.3 : 1) };
445
- }
446
- ONESHOTS.jump.start.call(this, inst, L);
447
- },
448
- apply(P, w, inst, L) {
449
- ONESHOTS.jump.apply.call(this, P, w, inst, L);
450
- if (inst.phase === 'air') {
451
- const k = smooth(0, 0.26, inst.t - inst.tAir);
452
- const T = (2 * inst.vy) / 9.81, x = clamp((inst.t - inst.tAir) / T, 0, 1);
453
- const reach = smooth(0.62, 0.92, x);
454
- P.legs.forEach((l, i) => { l.tuck = Math.min(l.tuck, k) * (1 - (i < 2 ? 0.75 : 0.35) * reach); });
455
- }
456
- },
457
- };
458
-
459
- // hit: the engine's stagger, the tail flags
460
- const hit = { ...ONESHOTS.hit, kind: 'oneshot' };
461
-
462
- // lie / sleep: the engine's kneeling sequence (down forelegs first, up hind end first). Getting up,
463
- // the sequence runs on a weight that reaches zero a little before the posture ends, so the springs
464
- // that stagger the two ends have settled when the posture is removed (no snap of the forelegs).
465
- function staged(def) {
466
- return {
467
- ...def, kind: 'posture',
468
- apply(P, w, inst, L) {
469
- const dt = clamp(inst.t - (inst.ts ?? inst.t), 0, 0.1);
470
- inst.ts = inst.t;
471
- inst.shift = inst.target > 0 ? 0 : Math.min(0.3, (inst.shift || 0) + dt * 0.8);
472
- const we = clamp((w - inst.shift) / (1 - inst.shift), 0, 1);
473
- def.apply(P, we, inst, L);
474
- },
475
- };
476
- }
477
-
478
- // death: the engine's collapse, at its own pace. The legs buckle under the load: the hooves stay
479
- // planted while the carpi and hocks give and the body sinks, and fold up only as the body goes over
480
- // onto its side (the engine folds them from the start: on the deer's long legs all four hooves hung
481
- // 6-8 cm in the air while the body was still near standing height, as if it floated)
482
- const death = {
483
- ...POSTURES.death, kind: 'posture',
484
- apply(P, w, inst, L) {
485
- POSTURES.death.apply(P, w, inst, L);
486
- // (the legs swing out to the side only once the body is well down: moving the feet to the side
487
- // pose lifts them in a small step)
488
- const t = inst.t, fall = clamp((t - 0.3) / 0.55, 0, 1), fallE = fall * fall;
489
- for (let i = 0; i < 4; i++) { mxLeg(P, i, 'fold', 0, w * (1 - fallE)); P.legs[i].side *= smooth(0.6, 1.15, t); }
490
- },
491
- };
492
-
493
- // sit: a deer beds down sternally with the head up, ears forward and alert (a dog-like sit reads as
494
- // an injured deer); lie is the same bed, relaxed, the head lower
495
- function alertBed(def) {
496
- const base = staged(def);
497
- return {
498
- ...base,
499
- apply(P, w, inst, L) {
500
- base.apply(P, w, inst, L);
501
- const u = 1 / L.engine.cfg.unit;
502
- const k = sm(clamp(w, 0, 1)) * smooth(0.6, 1.6, inst.t);
503
- mx(P, 'headRaise', 0.06 * u, k); mx(P, 'headPitch', -0.1, k);
504
- mx(P, 'earFlat', -0.15, k); mx(P, 'earTwitch', 0.6, k); mx(P, 'tailIdle', 0.4, k);
505
- },
506
- };
507
- }
508
-
509
- export const hooks = {
510
- pose,
511
- update,
512
- actions: { stomp, alert, flee, attack, hit, jump, death, lie: staged(POSTURES.lie), sit: alertBed(POSTURES.lie), sleep: staged(POSTURES.sleep) },
513
- };