@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,575 +0,0 @@
1
- // Pig behaviour layer for the quadruped engine (species.motion.hooks, see core/motion/actions.js):
2
- //
3
- // update(P, dt, layer) every frame over the action layer: the corkscrew tail (curled and wagging
4
- // when active or feeding, uncurled and hanging when resting, dead or afraid),
5
- // the waddle (the heavy trunk rolls from side to side at the walk and trot,
6
- // the head nods), piglets' springy bounce, grunting (jaw pulses, a vocalize
7
- // event), rooting while eating (the disc pushed into the soil in forward-up
8
- // nudges, the jaw working, tail wagging), idle variants (sniffing with the head
9
- // up, grunts, piglets' frolics)
10
- // pose(engine, dt) after the engine's solve: the rostral disc wiggles and twitches (sniffing)
11
- // actions lie (kneels, drops the hindquarters, then flops onto its side), sleep
12
- // (lateral, eyes shut), wallow (rocking on the side), attack (sow: a shoulder
13
- // shove with a sideways bite; boar: head low, then an upward tusk slash),
14
- // hit (a squeal, tail uncurls), grunt, sniff, root (looping eat), frolic
15
- // (piglet: two stiff-legged bounces in place with a head toss)
16
- //
17
- // Distances are pig metres at the reference size (x cfg.s); posture offsets the engine multiplies by
18
- // cfg.k (fwd, side, headRaise, neckReach) are divided by cfg.unit.
19
- import * as THREE from 'three';
20
- import { clamp, lerp, smooth, TAU, tv, tqa } from '../../core/motion/common.js';
21
- import { mx, ONESHOTS, POSTURES } from '../../core/motion/actions.js';
22
- import { earSpine, earLeaf } from './ears.js';
23
- import { HZ, HY, pigJoints } from './rig.js';
24
- import { composeWarps } from '../../core/build/warp.js';
25
-
26
- const _q = new THREE.Quaternion(), _s = new THREE.Vector3(1, 1, 1);
27
- // extra height of the occiput over the ground when the head lies on its side (m at the reference
28
- // size): the engine's value fits a slim skull, a pig's jowls are ~5 cm wider
29
- const HEAD_REST = 0.085;
30
- // lying on the side (lie, sleep, wallow, death): the forelegs only partly laid out on the ground and not
31
- // far forward (full, the upper foreleg was pulled down across the chest and its armpit skin folded over on
32
- // itself: a maroon patch, red in the holes view)
33
- const PIG_FRONT_SPREAD = 0.15, PIG_FRONT_SIDE = 0.3;
34
- // lying on the side: the spine's lateral bend (a little toward the up side; see flop)
35
- const PIG_LIE_BEND = 0.08;
36
-
37
- function B(e) {
38
- if (!e._pig) {
39
- e._pig = {
40
- curl: 1, fear: 0, wagT: 3 + e.rand() * 5, wagAge: 9, wagAmp: 0,
41
- gruntT: 2 + e.rand() * 5, grunt: null,
42
- sniff: 0, sniffPh: 0, twitchPh: 0,
43
- idleT: 6 + e.rand() * 8,
44
- rootPh: 0, wag: 0, wagPh: 0, tail: null,
45
- };
46
- }
47
- return e._pig;
48
- }
49
- const busy = (L) => L.oneshots.some((a) => !a.stopping && a.name !== 'grunt');
50
- const find = (L, n) => L.oneshots.find((a) => a.name === n && a.w > 0);
51
- // turning on the spot (0 .. 1): a pivot keeps the core's idle layer on (it looks at the speed only), and
52
- // its look-around target and the sniff variant turned the head 6-12 deg away from the turn
53
- const turning = (e) => {
54
- const err = Math.abs(Math.atan2(Math.sin((e.wantHeading ?? e.heading) - e.heading), Math.cos((e.wantHeading ?? e.heading) - e.heading)));
55
- return Math.max(smooth(0.1, 0.3, Math.abs(e.yawRate || 0)), smooth(0.15, 0.4, err));
56
- };
57
-
58
- // ------------------------------------------------------------------------------------------------
59
- function update(P, dt, L) {
60
- const e = L.engine, cfg = e.cfg, b = B(e), u = 1 / cfg.unit, s = cfg.s;
61
- const vn = e.speed / cfg.sq, g = e.gait;
62
- const piglet = e.params.age === 'juvenile';
63
- const side = e.params.tailSide ?? 1;
64
- const dead = L.postures.some((p) => p.name === 'death' && p.w > 0);
65
- const resting = L.postures.find((p) => (p.name === 'lie' || p.name === 'sleep' || p.name === 'wallow') && p.target > 0);
66
- const eat = find(L, 'eat') || find(L, 'root') || find(L, 'drink');
67
-
68
- // ---- tail: curled when active, uncurled (hanging) when resting, dead or afraid
69
- b.fear = Math.max(0, b.fear - dt);
70
- let want = 1;
71
- if (resting) want = 0;
72
- if (b.fear > 0) want = 0;
73
- if (dead) want = 0.1;
74
- if (piglet && !dead && b.fear <= 0) want = Math.max(want, 0.7);
75
- b.curl += (want - b.curl) * (1 - Math.exp(-dt * (want > b.curl ? 1.5 : 3)));
76
- const c = b.curl;
77
- void side;
78
- // wagging: bursts when feeding, excited (moving off), and now and then standing
79
- b.wagT -= dt;
80
- if (b.wagT <= 0) {
81
- b.wagT = (eat ? 1.5 : 4) + e.rand() * (eat ? 3 : 8);
82
- if (!resting && !dead) { b.wagAge = 0; b.wagAmp = (eat ? 0.8 : 0.5) + 0.3 * e.rand(); }
83
- }
84
- b.wagAge += dt;
85
- const wa = Math.sin(Math.PI * clamp(b.wagAge / 2.4, 0, 1)) * b.wagAmp;
86
- b.wag = wa * c; // (the curled tail wags in pose(); the hanging one through the engine)
87
- b.wagPh += dt * TAU * 3.2;
88
- if (wa > 0.001) P.tailWag = Math.max(P.tailWag, wa * (1 - c));
89
-
90
- // ---- waddle: the heavy trunk rolls over the stance legs, the head nods at the walk
91
- const walkW = smooth(0.1, 0.5, vn) * (1 - smooth(3.0, 4.0, vn)) * P.gaitW;
92
- if (walkW > 0.001 && g) {
93
- const trotK = smooth(1.3, 1.9, vn);
94
- const ph = TAU * (e.phase - (g.off ? g.off[2] : 0));
95
- const amp = lerp(0.045, 0.03, trotK) * (piglet ? 0.7 : 1);
96
- P.roll += amp * Math.sin(ph) * walkW;
97
- P.side += 0.006 * u * Math.sin(ph) * walkW;
98
- const nod = 0.5 + 0.5 * Math.cos(2 * ph);
99
- P.headRaise -= 0.018 * u * walkW * nod * (1 - trotK);
100
- // piglets: a springy, bouncing trot
101
- if (piglet) P.lift += 0.012 * u * Math.pow(Math.sin(2 * ph), 2) * walkW * trotK;
102
- }
103
- // ---- a piglet carries its head higher than a finisher (side1, threequarter3, front2: the snout 15-20 deg below
104
- // level against 35 deg, the ears standing up over the poll), except while it eats, rests or lies dead
105
- if (piglet) {
106
- let busyW = dead ? 1 : eat ? eat.w : 0;
107
- for (const p of L.postures) busyW = Math.max(busyW, p.w);
108
- const k = 1 - clamp(busyW, 0, 1);
109
- P.headPitch -= 0.26 * k;
110
- P.headRaise += 0.025 * u * k;
111
- }
112
-
113
- // ---- grunting: short bursts of 1-3 grunts (jaw pulses and a flank pulse)
114
- const calm = !dead && !L.postures.some((p) => p.name === 'sleep' && p.w > 0.5);
115
- b.gruntT -= dt * (eat ? 1.6 : 1);
116
- if (b.gruntT <= 0 && calm && !L.oneshots.some((a) => a.name === 'grunt')) { b.gruntT = 3 + e.rand() * 9; L.play('grunt'); }
117
-
118
- // ---- rooting: the disc pushed into the soil in forward-up nudges, the head swinging slowly
119
- const root = find(L, 'eat') || find(L, 'root');
120
- if (root) {
121
- const w = root.w * root.w * (3 - 2 * root.w);
122
- b.rootPh += dt * 1.6;
123
- const c1 = b.rootPh % 1;
124
- const push = smooth(0.0, 0.35, c1) * (1 - smooth(0.45, 0.75, c1));
125
- const flick = smooth(0.4, 0.6, c1) * (1 - smooth(0.7, 0.95, c1));
126
- const fw = e.forward(e.heading, tv());
127
- P.headPos.addScaledVector(fw, 0.04 * s * push * w);
128
- P.headPos.y += (-0.012 * push + 0.035 * flick) * s * w;
129
- P.headPitch += (0.12 * push - 0.18 * flick) * w;
130
- P.headYaw += 0.12 * Math.sin(b.rootPh * 0.37 * TAU) * w;
131
- P.fwd += 0.015 * u * push * w;
132
- mx(P, 'jaw', 0.03 + 0.05 * flick, w);
133
- b.sniff = Math.max(b.sniff, w);
134
- }
135
-
136
- // ---- a pivot: the head leads the turn (the engine's steer lead) without the idle look pulling it back
137
- // to a point picked before the turn; a new point is picked after it
138
- const turnK = e.input.follow ? 0 : turning(e);
139
- if (turnK > 0.001 && !e.input.look && L.idle.w > 0.001 && P.look && P.look === L.idle.look) {
140
- P.lookW *= 1 - turnK;
141
- if (turnK > 0.5) { L.idle.hasLook = false; L.idle.lookT = Math.max(L.idle.lookT, 1.2); }
142
- }
143
-
144
- // ---- idle variants (not while pivoting)
145
- const idle = L.idle.w > 0.9 && !L.postures.length && !busy(L) && turnK < 0.05;
146
- if (idle) {
147
- b.idleT -= dt;
148
- if (b.idleT <= 0) {
149
- b.idleT = 6 + e.rand() * 10;
150
- if (piglet && e.rand() < 0.45) L.play('frolic');
151
- else L.play('sniff');
152
- }
153
- }
154
- // sniffing between: a quick disc twitch now and then, stronger when idle
155
- b.sniff = Math.max(b.sniff * Math.exp(-dt * 1.5), idle ? 0.35 : 0.15);
156
- }
157
-
158
- // ------------------------------------------------------------------------------------------------
159
- // pose: the rostral disc wiggles (sniffing): small fast up-down and sideways twitches
160
- function pose(e, dt) {
161
- const b = B(e), P = e.P, cfg = e.cfg;
162
- poseTail(e, b);
163
- if (e.lod >= 2) return;
164
- poseEars(e, b, dt);
165
- const sn = e.bone.snout;
166
- if (!sn) return;
167
- const awake = 1 - P.eyelid;
168
- b.twitchPh += dt * TAU * (2.5 + 3.5 * b.sniff);
169
- const a = b.sniff * awake;
170
- if (a < 1e-3) return;
171
- const tw = Math.pow(Math.max(0, Math.sin(b.twitchPh)), 2) * a;
172
- const lat = Math.sin(b.twitchPh * 0.43 + 1.3) * a;
173
- const base = tv().setFromMatrixPosition(sn.matrixWorld);
174
- _q.setFromRotationMatrix(sn.matrixWorld);
175
- const ax = tv(1, 0, 0).applyQuaternion(_q), up = tv(0, 0, 1).applyQuaternion(_q);
176
- const along = tv(0, 1, 0).applyQuaternion(_q);
177
- base.addScaledVector(along, -0.003 * tw * cfg.s);
178
- sn.matrixWorld.compose(base, tqa(ax, -0.12 * tw).multiply(tqa(up, 0.06 * lat)).multiply(_q), _s);
179
- }
180
-
181
- // the corkscrew tail: the engine has written a hanging spring chain (E); the curled tail is the rest
182
- // helix carried rigidly by the root bone (C). Per joint, the relative rotation is slerped from the
183
- // engine's toward the rest helix's by the curl amount, and the chain is rebuilt from the root; the
184
- // curled tail wags about the root.
185
- const _qa = new THREE.Quaternion(), _qb = new THREE.Quaternion(), _qc = new THREE.Quaternion(), _qp = new THREE.Quaternion();
186
- const _p = new THREE.Vector3(), _d = new THREE.Vector3(), _up = new THREE.Vector3();
187
- function poseTail(e, b) {
188
- let T = b.tail;
189
- if (!T) {
190
- const bones = [];
191
- for (let i = 0; ; i++) { const bn = e.bone['tail' + i]; if (!bn) break; bones.push(bn); }
192
- const idx = bones.map((bn) => e.sk.bones.indexOf(bn));
193
- const rest = idx.map((i) => new THREE.Quaternion().setFromRotationMatrix(e.sk.bind[i]));
194
- const rel = rest.map((q, i) => (i ? rest[i - 1].clone().invert().multiply(q) : null));
195
- const len = idx.map((i, k) => (k < idx.length - 1 ? new THREE.Vector3().setFromMatrixPosition(e.sk.bind[idx[k + 1]]).distanceTo(new THREE.Vector3().setFromMatrixPosition(e.sk.bind[i])) : 0));
196
- // rigid curl (crowd tier, fully curled): bone_i = root * inv(rest_0) * rest_i
197
- const inv0 = e.sk.bind[idx[0]].clone().invert();
198
- const R = idx.map((i) => inv0.clone().multiply(e.sk.bind[i]));
199
- T = b.tail = { bones, rel, len, R, q: bones.map(() => new THREE.Quaternion()), e: bones.map(() => new THREE.Quaternion()) };
200
- }
201
- const c = b.curl, n = T.bones.length;
202
- if (c < 1e-3 && Math.abs(b.wag) < 1e-4) return;
203
- if (e.lod >= 2 || (c > 0.995 && Math.abs(b.wag) < 1e-4)) {
204
- if (c < 0.5) return;
205
- const m0 = T.bones[0].matrixWorld;
206
- for (let i = 1; i < n; i++) T.bones[i].matrixWorld.multiplyMatrices(m0, T.R[i]);
207
- return;
208
- }
209
- for (let i = 0; i < n; i++) T.e[i].setFromRotationMatrix(T.bones[i].matrixWorld);
210
- // root: the engine's, wagged about the pelvis' up axis
211
- const q0 = T.q[0].copy(T.e[0]);
212
- if (Math.abs(b.wag) > 1e-4) {
213
- _up.set(0, 0, 1).applyQuaternion(T.e[0]); // (the root's dorsal axis)
214
- q0.premultiply(_qp.setFromAxisAngle(_up.normalize(), 0.45 * b.wag * Math.sin(b.wagPh)));
215
- _p.setFromMatrixPosition(T.bones[0].matrixWorld);
216
- T.bones[0].matrixWorld.compose(_p, q0, _s);
217
- }
218
- _p.setFromMatrixPosition(T.bones[0].matrixWorld);
219
- for (let i = 1; i < n; i++) {
220
- _qa.copy(T.e[i - 1]).invert().multiply(T.e[i]); // engine relative rotation
221
- _qb.copy(_qa).slerp(T.rel[i], c);
222
- T.q[i].copy(T.q[i - 1]).multiply(_qb);
223
- _d.set(0, T.len[i - 1], 0).applyQuaternion(T.q[i - 1]);
224
- _p.add(_d);
225
- T.bones[i].matrixWorld.compose(_p, T.q[i], _s);
226
- }
227
- void _qc;
228
- }
229
-
230
- // ears, after the engine's solve:
231
- // - a head lying on its side (lie, sleep, wallow, death) folds the ground-side ear back and up into the jowl
232
- // and the neck, where it is hidden, as a lying pig's lower ear is squashed under its head (Landrace photos;
233
- // swung up out of the ground it stuck out along the ground as a rigid blade; laid level beside the
234
- // neck it still showed as one); the upper ear falls onto the head: an erect or semi-lop leaf back over the
235
- // neck, its hollow down, a lop leaf forward over the face and the eye (lr1-lr3). The target is a whole frame
236
- // (the ear's direction and its leaf's hollow side, from the bind leaf, ears.js), so the leaf lies flat rather
237
- // than edge-on;
238
- // - then any pinna still reaching into the ground (rooting) is swung up about its base, just enough (a spring
239
- // on the correction angle keeps it smooth).
240
- const _eb = new THREE.Vector3(), _ed = new THREE.Vector3(), _el = new THREE.Vector3(), _ep = new THREE.Vector3(), _ea = new THREE.Vector3();
241
- const _hx = new THREE.Vector3(), _hy = new THREE.Vector3() /* back along the neck, level */, _hz = new THREE.Vector3(), _dT = new THREE.Vector3(), _nT = new THREE.Vector3();
242
- const _hv = new THREE.Vector3(), _dC = new THREE.Vector3(), _nC = new THREE.Vector3(), _w3 = new THREE.Vector3(), _mA = new THREE.Matrix4(), _mB = new THREE.Matrix4();
243
- const _qt = new THREE.Quaternion(), _qi = new THREE.Quaternion(), _qr = new THREE.Quaternion();
244
- // rotation taking the frame (d, n) onto (d2, n2) (n, n2 made orthogonal to d, d2)
245
- function frameRot(d, n, d2, n2, out) {
246
- _w3.copy(n).addScaledVector(d, -n.dot(d)).normalize();
247
- _mA.makeBasis(d, _w3, _ea.crossVectors(d, _w3));
248
- _w3.copy(n2).addScaledVector(d2, -n2.dot(d2)).normalize();
249
- _mB.makeBasis(d2, _w3, _ea.crossVectors(d2, _w3));
250
- return out.setFromRotationMatrix(_mB.multiply(_mA.transpose()));
251
- }
252
- function poseEars(e, b, dt) {
253
- const cfg = e.cfg;
254
- if (!b.ear) {
255
- b.ear = [0, 1].map((k) => {
256
- // (the leaf in the bind pose: the ear bone's direction and the hollow side at mid-length)
257
- // (and its first third: a tucked ear is aimed by it, since a drooping leaf's chord runs well below its root)
258
- // (the bind leaf as the mesh has it: the reference leaf through the individual's warps and size, as the pipeline
259
- // warps the mesh and the joints; the head scale fades out along a long leaf and tilts its chord several degrees)
260
- const S = k ? 'R' : 'L', P0 = e.params;
261
- const W = composeWarps([...(P0.warps || []), ...(P0.size && P0.size !== 1 ? [{ type: 'scale', k: P0.size }] : [])]) || ((p) => p);
262
- // (rig.js gives the left side; the rig mirrors it)
263
- const bl = pigJoints(P0).earBaseL, rb = S === 'L' ? bl : [-bl[0], bl[1], bl[2]], wb = W(rb);
264
- const off = (p) => { const q = W(p); return new THREE.Vector3(q[0] - wb[0], q[1] - wb[1], q[2] - wb[2]); };
265
- const dirAt = (p, v) => { const a = W(p), q = W([p[0] + 0.01 * v[0], p[1] + 0.01 * v[1], p[2] + 0.01 * v[2]]); return new THREE.Vector3(q[0] - a[0], q[1] - a[1], q[2] - a[2]).normalize(); };
266
- const sp = earSpine(rb, S, P0), q3 = sp.steps / 3 | 0, mid = sp.steps >> 1;
267
- const leaf = earLeaf(rb, S, P0);
268
- // (points on the leaf: the ground check; a drooping leaf's belly hangs 4-5 cm off the bone's chord)
269
- const pts = [];
270
- for (const u of [0.3, 0.55, 0.8, 1]) for (const a of [-0.85, 0, 0.85]) pts.push(off(leaf.mid(u, a).p));
271
- return {
272
- lift: 0, tuck: 0, relax: 0, len: e.J['earBase' + S].distanceTo(e.J['earTip' + S]), pts,
273
- d: off(sp.tip).normalize(), h: dirAt(sp.pts[mid], sp.fr[mid].h),
274
- d1: off(sp.pts[q3]).normalize(), h1: dirAt(sp.pts[q3 >> 1], sp.fr[q3 >> 1].h),
275
- };
276
- });
277
- }
278
- const qH = e.headPose.quaternion;
279
- // (the head's lateral axis and its long axis toward the disc, HZ, in the world)
280
- _hx.set(1, 0, 0).applyQuaternion(qH); _hz.set(HZ[0], HZ[1], HZ[2]).applyQuaternion(qH);
281
- // back along the neck, level (the neck lies on the ground beside it)
282
- _hy.set(-_hz.x, 0, -_hz.z);
283
- if (_hy.lengthSq() < 1e-6) _hy.set(0, 0, -1);
284
- _hy.normalize();
285
- // toward the throat, level (the head's ventral side: -HY)
286
- _hv.set(HY[0], HY[1], HY[2]).applyQuaternion(qH).multiplyScalar(-1); _hv.y = 0;
287
- if (_hv.lengthSq() < 1e-6) _hv.set(0, 0, 0); else _hv.normalize();
288
- const lop = e.params.ear === 'lop', relaxK = 0.85;
289
- const ke = 1 - Math.exp(-dt * 5);
290
- for (let k = 0; k < 2; k++) {
291
- const name = k === 0 ? 'earL' : 'earR', bone = e.bone[name], E = b.ear[k], s = k === 0 ? 1 : -1;
292
- if (!bone) continue;
293
- // (how far this ear's side of the head faces the ground: the head on its side)
294
- const side = s * _hx.y;
295
- E.tuck += (smooth(0.35, 0.75, -side) - E.tuck) * ke;
296
- E.relax += (relaxK * smooth(0.35, 0.75, side) - E.relax) * ke;
297
- _eb.setFromMatrixPosition(bone.matrixWorld);
298
- const w = Math.max(E.tuck, E.relax);
299
- if (w > 1e-3 && e.bindQ?.[name]) {
300
- _q.setFromRotationMatrix(bone.matrixWorld);
301
- // current leaf: the bind leaf carried by the bone's rotation from its bind orientation
302
- _qr.copy(e.bindQ[name]).invert().premultiply(_q);
303
- const tuck = E.tuck >= E.relax;
304
- _dC.copy(tuck ? E.d1 : E.d).applyQuaternion(_qr); _nC.copy(tuck ? E.h1 : E.h).applyQuaternion(_qr);
305
- if (tuck) {
306
- // folded under: back along the neck, a little up and toward the throat, into the jowl and the neck (which
307
- // lie on the ground over it), the hollow toward the throat: a lying neck is thickest from its back to the
308
- // throat, and the drooping leaf curls that way (its hollow up, it curled out of the neck's upper side)
309
- _dT.copy(_hy).addScaledVector(tv(0, 1, 0), 0.35).addScaledVector(_hv, 0.3).normalize();
310
- _nT.copy(_hv);
311
- } else if (lop) {
312
- // a lop ear keeps lying along the head and falls across it onto the cheek and the eye, its hollow on them
313
- // (gravity across the head's long axis)
314
- _w3.set(0, -1, 0).addScaledVector(_hz, _hz.y);
315
- _dT.copy(_dC).addScaledVector(_w3, 0.45).normalize();
316
- _nT.set(0, -1, 0);
317
- } else {
318
- // fallen back over the neck and draped down its side, the hollow on it
319
- _dT.copy(_hy).addScaledVector(tv(0, 1, 0), -0.45).normalize();
320
- _nT.copy(_hv).multiplyScalar(0.5).addScaledVector(tv(0, 1, 0), -1).normalize();
321
- }
322
- frameRot(_dC, _nC, _dT, _nT, _qt);
323
- // (the part w of that rotation, continuous in time: of q and -q the one nearer last frame's, then its
324
- // axis-angle scaled; a shortest-arc slerp switched sides where the rotation passed 180 deg and the ear
325
- // flipped through the ground in one frame)
326
- if (E.qs ? _qt.dot(E.qs) < 0 : _qt.w < 0) _qt.set(-_qt.x, -_qt.y, -_qt.z, -_qt.w);
327
- (E.qs || (E.qs = new THREE.Quaternion())).copy(_qt);
328
- const th = 2 * Math.acos(clamp(_qt.w, -1, 1)), sn = Math.sqrt(Math.max(0, 1 - _qt.w * _qt.w));
329
- if (sn > 1e-6) { _ea.set(_qt.x / sn, _qt.y / sn, _qt.z / sn); _qi.setFromAxisAngle(_ea, th * w); _q.premultiply(_qi); }
330
- bone.matrixWorld.compose(_eb, _q, _s);
331
- } else if (E.qs) E.qs = null;
332
- // the ground: a pinna reaching into it is swung up about its base, just enough: the swing about the horizontal
333
- // axis across the bone that lifts each point of the leaf above the floor (its height gain per radian is
334
- // (axis x offset).y), the largest of them; fast to rise (the head falls fast in a collapse: a spring lagged and
335
- // the leaf's belly went 29 mm into the ground), slow to let go
336
- const near = _eb.y - e.terrainH(_eb.x, _eb.z) < E.len * 1.2 + 0.03 * cfg.s;
337
- let need = 0;
338
- _q.setFromRotationMatrix(bone.matrixWorld);
339
- _ed.set(0, 1, 0).applyQuaternion(_q);
340
- _ea.crossVectors(_ed, tv(0, 1, 0));
341
- const axOk = _ea.lengthSq() > 1e-8;
342
- if (near && axOk && e.bindQ?.[name]) {
343
- _ea.normalize();
344
- _qr.copy(e.bindQ[name]).invert().premultiply(_q);
345
- for (const pt of E.pts) {
346
- _ep.copy(pt).applyQuaternion(_qr);
347
- const floor = e.terrainH(_eb.x + _ep.x, _eb.z + _ep.z) + 0.012 * cfg.s;
348
- const lack = floor - (_eb.y + _ep.y);
349
- if (lack <= 0) continue;
350
- const gain = _ea.z * _ep.x - _ea.x * _ep.z;
351
- need = Math.max(need, gain > 0.02 * E.len ? lack / gain : 1.2);
352
- }
353
- need = Math.min(1.2, need * 1.1);
354
- }
355
- E.lift = need > E.lift ? Math.min(need, E.lift + 25 * dt) : E.lift + (need - E.lift) * (1 - Math.exp(-dt * 10));
356
- if (E.lift < 1e-4 || !axOk) continue;
357
- _q.premultiply(tqa(_ea, E.lift));
358
- bone.matrixWorld.compose(_eb, _q, _s);
359
- }
360
- }
361
-
362
- // ------------------------------------------------------------------------------------------------
363
- // actions
364
-
365
- // grunt: 1-3 short jaw pulses with a flank pulse; emits vocalize { kind: 'grunt' }
366
- const grunt = {
367
- kind: 'oneshot', fade: 0.08, overlay: true, // a vocalisation: it neither cuts nor is cut by a commanded one-shot (eat, root, attack...)
368
- start(inst, L) { const b = B(L.engine); inst.n = 1 + Math.floor(L.engine.rand() * 3); inst.dur = 0.32 * inst.n + 0.1; b.grunt = inst; inst.said = 0; },
369
- update(inst, dt, L) {
370
- const k = Math.floor(inst.t / 0.32);
371
- if (k >= inst.said && k < inst.n) { inst.said = k + 1; L.engine.emit('vocalize', { kind: 'grunt', position: L.engine.headPose.position.clone() }); }
372
- if (inst.t >= inst.dur) { B(L.engine).grunt = null; return true; }
373
- return false;
374
- },
375
- apply(P, w, inst) {
376
- const x = (inst.t % 0.32) / 0.32, on = inst.t < 0.32 * inst.n ? 1 : 0;
377
- const pulse = Math.sin(Math.PI * clamp(x / 0.6, 0, 1)) * on;
378
- P.jaw = Math.max(P.jaw, 0.07 * pulse * w);
379
- P.jawOmega = Math.max(P.jawOmega, 30);
380
- P.breathAmp += 1.2 * pulse * w;
381
- },
382
- };
383
-
384
- // sniff: head up, the disc twitching fast, a look around
385
- const sniff = {
386
- kind: 'oneshot', fade: 0.35,
387
- start(inst, L) { inst.dur = 2.2 + L.engine.rand() * 1.5; inst.dir = L.engine.rand() < 0.5 ? -1 : 1; },
388
- update(inst) { return inst.t >= inst.dur; },
389
- apply(P, w, inst, L) {
390
- const u = 1 / L.engine.cfg.unit, t = inst.t;
391
- const k = smooth(0, 0.5, t) * (1 - smooth(inst.dur - 0.5, inst.dur, t)) * w;
392
- mx(P, 'headRaise', 0.06 * u, k); mx(P, 'headPitch', -0.3, k); mx(P, 'neckReach', 0.02 * u, k);
393
- // (no look to the side while the pig turns on the spot)
394
- inst.turnK = Math.max((inst.turnK ?? 0) * Math.exp(-L.engine.frameDt * 2), turning(L.engine));
395
- P.headYaw += 0.25 * inst.dir * Math.sin(t * 1.3) * k * (1 - inst.turnK);
396
- mx(P, 'lookW', 0.2, k);
397
- B(L.engine).sniff = Math.max(B(L.engine).sniff, k);
398
- },
399
- };
400
-
401
- // root: rooting in the ground (the built-in eat, looped; behaviour adds the nudges)
402
- const root = {
403
- ...ONESHOTS.eat, kind: 'oneshot',
404
- start(inst, L) { inst.tune = L.tuning.eat || {}; inst.dur = inst.opts.duration ?? Infinity; inst.fade = 0.8; },
405
- update(inst, dt, L) { return inst.t >= inst.dur || L.engine.wantSpeed > 0.05 || !!L.engine.input.follow; },
406
- apply(P, w, inst, L) { ONESHOTS.eat.apply(P, w, inst, L); B(L.engine).sniff = Math.max(B(L.engine).sniff, w); },
407
- };
408
-
409
- // lie: kneels on the carpi, drops the hindquarters, then flops onto its side (lateral), head flat,
410
- // awake (eyes open, ears and look alive)
411
- const flop = (P, w, inst, L, sleep) => {
412
- POSTURES.sleep.apply(P, w, inst, L);
413
- const c = smooth(1.0, 3.0, inst.t) * w;
414
- // (the spine a little rounded toward the up side instead of the core's lateral curl: lying on its side, the
415
- // curl sagged the middle toward the ground and the back read as a saddle between shoulder and ham;
416
- // with the wider barrel the outline over shoulder, ribs and ham varies by 2 cm, was 6.5)
417
- mx(P, 'bend', -inst.side * PIG_LIE_BEND, c);
418
- // the broad head (jowls and cheek) rests on its side higher than the engine's slim skull
419
- P.headPos.y += HEAD_REST * L.engine.cfg.s * c;
420
- // (the chin out: the deep double chin under the jaw otherwise ploughs into the ground; while the
421
- // forequarters go down the head is held up until it is laid on its side)
422
- mx(P, 'headPitch', -0.1, c);
423
- if (inst.target > 0) {
424
- const hold = smooth(0.3, 1.0, inst.t) * (1 - smooth(1.9, 2.9, inst.t)) * w;
425
- P.headRaise += 0.08 / L.engine.cfg.unit * hold; P.headPitch -= 0.3 * hold;
426
- }
427
- // the short legs stretched out from the body (the lower claws otherwise rest in the ground); the
428
- // forelegs less (PIG_FRONT_*)
429
- for (let i = 0; i < 4; i++) { P.legs[i].spread = Math.max(P.legs[i].spread, (i < 2 ? PIG_FRONT_SPREAD : 0.55) * c); }
430
- for (let i = 0; i < 2; i++) P.legs[i].side = lerp(P.legs[i].side, PIG_FRONT_SIDE, c);
431
- P.lift += 0.03 / L.engine.cfg.unit * c;
432
- if (!sleep) {
433
- // awake: eyes open, breathing normal, the head a little raised off the ground now and then
434
- mx(P, 'eyelid', 0.1, c); mx(P, 'breathRate', 0.8, c); mx(P, 'earTwitch', 0.8, c); mx(P, 'tailIdle', 0.5, c);
435
- mx(P, 'headLimp', 0.1, c);
436
- }
437
- };
438
- const lie = { kind: 'posture', fadeIn: 1.6, fadeOut: 1.4, apply(P, w, inst, L) { flop(P, w, inst, L, false); } };
439
- const sleep = { kind: 'posture', fadeIn: 1.6, fadeOut: 1.5, apply(P, w, inst, L) { flop(P, w, inst, L, true); } };
440
-
441
- // wallow: lying on the side and rocking back and forth (rubbing the flank and back in the mud),
442
- // the legs paddling in the air as it rolls toward its back
443
- const wallow = {
444
- kind: 'posture', fadeIn: 1.6, fadeOut: 1.5,
445
- apply(P, w, inst, L) {
446
- flop(P, w, inst, L, false);
447
- // (the rocking starts as soon as the pig is down on its side, ~1.8 s)
448
- const c = smooth(1.8, 3.0, inst.t) * w;
449
- const r = 0.5 - 0.5 * Math.cos(TAU * 0.22 * Math.max(0, inst.t - 1.8));
450
- P.roll += inst.side * 0.35 * r * c;
451
- for (let i = 0; i < 4; i++) { P.legs[i].spread += 0.25 * r * c; P.legs[i].fold += 0.3 * Math.max(0, Math.sin(TAU * 0.44 * inst.t + i)) * r * c; }
452
- P.headRoll += inst.side * 0.2 * r * c;
453
- },
454
- };
455
-
456
- // attack. Sow: a shoulder shove with a sideways bite (the head swipes across, mouth open). Boar (or
457
- // { style: 'slash' }): head low and turned, then an upward sideways swipe of the tusks.
458
- const attack = {
459
- kind: 'oneshot', fade: 0.15, needsStand: true,
460
- start(inst, L) {
461
- const e = L.engine;
462
- inst.style = inst.opts.style || ((e.params.boar || 0) >= 0.5 ? 'slash' : 'shove');
463
- inst.target = inst.opts.target ? inst.opts.target.clone() : null;
464
- inst.dir = e.rand() < 0.5 ? -1 : 1;
465
- if (inst.target) {
466
- const lx = (inst.target.x - e.pos.x) * Math.cos(e.heading) - (inst.target.z - e.pos.z) * Math.sin(e.heading);
467
- inst.dir = lx > 0 ? 1 : -1;
468
- }
469
- inst.dur = inst.style === 'slash' ? 1.25 : 1.1;
470
- inst.hitAt = inst.style === 'slash' ? 0.62 : 0.55;
471
- inst.hit = false;
472
- B(e).fear = 0;
473
- },
474
- update(inst, dt, L) {
475
- if (!inst.hit && inst.t >= inst.hitAt) {
476
- inst.hit = true;
477
- const e = L.engine;
478
- const p = new THREE.Vector3().copy(e.cfg.mouthLocal).applyQuaternion(e.headPose.quaternion).add(e.headPose.position);
479
- const dir = e.forward(e.heading, new THREE.Vector3()).addScaledVector(e.left(e.heading, new THREE.Vector3()), inst.dir * 0.6).normalize();
480
- if (inst.style === 'slash') dir.y = 0.5;
481
- e.emit('attackHit', { position: p, direction: dir.normalize(), style: inst.style === 'slash' ? 'tusk' : 'bite' });
482
- }
483
- return inst.t >= inst.dur;
484
- },
485
- apply(P, w, inst, L) {
486
- const e = L.engine, u = 1 / e.cfg.unit, t = inst.t, d = inst.dir;
487
- if (inst.target) { P.look = inst.target; mx(P, 'lookW', 1, w); }
488
- mx(P, 'earFlat', 0.7, w * smooth(0, 0.2, t)); mx(P, 'earTwitch', 0, w);
489
- const wind = smooth(0, 0.4, t) * (1 - smooth(inst.hitAt - 0.05, inst.hitAt + 0.1, t));
490
- const strike = smooth(inst.hitAt - 0.18, inst.hitAt, t) * (1 - smooth(inst.hitAt + 0.15, inst.dur - 0.05, t));
491
- if (inst.style === 'slash') {
492
- // head low and turned away, then swung up and across: the tusk rips upward
493
- mx(P, 'headRaise', -0.07 * u, wind * w); mx(P, 'headPitch', 0.45, wind * w); mx(P, 'headYaw', -d * 0.3, wind * w);
494
- mx(P, 'dropF', 0.15, wind * w); mx(P, 'fwd', -0.03 * u, wind * w);
495
- mx(P, 'headRaise', 0.06 * u, strike * w); mx(P, 'headPitch', -0.45, strike * w); mx(P, 'headYaw', d * 0.35, strike * w);
496
- mx(P, 'headRoll', d * 0.35, strike * w); mx(P, 'fwd', 0.06 * u, strike * w); mx(P, 'jaw', 0.25, strike * w);
497
- } else {
498
- // shoulder shove: the body lunges forward and into the target, the head swipes across, bites
499
- mx(P, 'fwd', -0.03 * u, wind * w); mx(P, 'headYaw', -d * 0.25, wind * w); mx(P, 'jaw', 0.3, wind * w);
500
- mx(P, 'fwd', 0.08 * u, strike * w); mx(P, 'side', d * 0.04 * u, strike * w); mx(P, 'roll', -d * 0.08, strike * w);
501
- mx(P, 'headYaw', d * 0.35, strike * w); mx(P, 'neckReach', 0.03 * u, strike * w);
502
- mx(P, 'jaw', 0.4 * (1 - smooth(inst.hitAt - 0.03, inst.hitAt + 0.05, t)) + 0.05, strike * w); mx(P, 'jawOmega', 30, w);
503
- }
504
- mx(P, 'gaitW', 0.4, (wind + strike > 0 ? 1 : 0) * w);
505
- },
506
- };
507
-
508
- // hit: the engine's stagger with a squeal (mouth wide), then the tail stays uncurled for a while
509
- const hit = {
510
- ...ONESHOTS.hit, kind: 'oneshot',
511
- start(inst, L) { ONESHOTS.hit.start(inst, L); B(L.engine).fear = 5; L.engine.emit('vocalize', { kind: 'squeal', position: L.engine.headPose.position.clone() }); },
512
- apply(P, w, inst, L) {
513
- ONESHOTS.hit.apply(P, w, inst, L);
514
- const k = smooth(0.02, 0.12, inst.t) * (1 - smooth(0.45, 0.7, inst.t)) * w;
515
- mx(P, 'jaw', 0.35, k); mx(P, 'jawOmega', 30, w); mx(P, 'headPitch', -0.2, k);
516
- },
517
- };
518
-
519
- // frolic (piglets): two quick stiff-legged bounces in place with a head toss and a twist of the
520
- // body (the legs stay planted: a crouch, then the body springs up on extended legs)
521
- const frolic = {
522
- kind: 'oneshot', fade: 0.1,
523
- start(inst, L) { inst.dur = 1.0; inst.toss = L.engine.rand() < 0.5 ? -1 : 1; },
524
- update(inst) { return inst.t >= inst.dur; },
525
- apply(P, w, inst) {
526
- const t = inst.t, T = 0.42;
527
- const ph = clamp(t / T, 0, 2.2);
528
- const cyc = ph < 2 ? ph % 1 : 1;
529
- // per bounce: crouch (0 - 0.35), spring up (0.35 - 0.6), settle (0.6 - 1)
530
- const crouch = smooth(0, 0.3, cyc) * (1 - smooth(0.3, 0.5, cyc));
531
- const up = smooth(0.32, 0.55, cyc) * (1 - smooth(0.6, 0.95, cyc));
532
- const env = (1 - smooth(0.85, 1.0, t / inst.dur)) * w;
533
- P.dropF += (0.14 * crouch - 0.08 * up) * env; P.dropH += (0.16 * crouch - 0.09 * up) * env;
534
- P.pitch += 0.05 * (up - crouch) * env;
535
- const k = Math.sin(Math.PI * clamp(t / inst.dur, 0, 1));
536
- P.headYaw += inst.toss * 0.35 * Math.sin(TAU * t / (2 * T)) * k * w; P.headRoll += inst.toss * 0.2 * up * env;
537
- P.roll -= inst.toss * 0.06 * up * env; P.headPitch -= 0.15 * up * env;
538
- mx(P, 'earFlat', 0.2, up * env);
539
- },
540
- };
541
-
542
- // jump: the built-in, with the forelegs tucking up more gradually after take-off (the short legs'
543
- // elbows flipped when they folded within a few frames of leaving the ground)
544
- const JUMP_TUCK = 0.4; // s (the built-in: 0.12)
545
- const jump = {
546
- ...ONESHOTS.jump, kind: 'oneshot',
547
- apply(P, w, inst, L) {
548
- ONESHOTS.jump.apply(P, w, inst, L);
549
- if (inst.phase === 'air') {
550
- const x = smooth(0, JUMP_TUCK * L.engine.cfg.sk, inst.t - inst.tAir);
551
- for (let i = 0; i < 2; i++) P.legs[i].tuck = Math.min(P.legs[i].tuck, x);
552
- }
553
- },
554
- };
555
-
556
- // death: the engine's collapse onto the side, the broad head resting on its cheek, the tail hanging
557
- const death = {
558
- ...POSTURES.death, kind: 'posture',
559
- apply(P, w, inst, L) {
560
- POSTURES.death.apply(P, w, inst, L);
561
- P.headPos.y += HEAD_REST * L.engine.cfg.s * smooth(0.35, 1.0, inst.t) * w;
562
- // the hind legs only partly in the side-lying pose (legs laid out on the ground), slightly flexed:
563
- // laid out full, the lower leg's foot target pressed the lower thigh's lateral bulge (the stifle)
564
- // 8-11 mm into bumps on a slope (death-uneven, between the torso sections the rest solver checks)
565
- const k = smooth(0.8, 1.6, inst.t) * w;
566
- for (let i = 2; i < 4; i++) P.legs[i].side = lerp(P.legs[i].side, 0.3, k);
567
- for (let i = 0; i < 2; i++) { P.legs[i].spread = lerp(P.legs[i].spread, PIG_FRONT_SPREAD, k); P.legs[i].side = lerp(P.legs[i].side, PIG_FRONT_SIDE, k); }
568
- },
569
- };
570
-
571
- export const behaviour = {
572
- update,
573
- pose,
574
- actions: { jump, lie, sleep, wallow, death, attack, hit, grunt, sniff, root, frolic },
575
- };