@bitefoundry/retrieviewer 0.0.3 → 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 (254) 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 +6 -1
  6. package/PLUGIN.md +13 -10
  7. package/PREREQUISITES.md +95 -0
  8. package/PUPPY-MEMORY.md +102 -1
  9. package/README.ko.md +110 -0
  10. package/README.md +117 -59
  11. package/RELEASING.md +23 -12
  12. package/THIRD-PARTY-NOTICES.md +5 -3
  13. package/braille.mjs +35 -9
  14. package/examples/live.mjs +2 -2
  15. package/integrations/linux-overlay/overlay.py +2 -2
  16. package/integrations/macos-overlay/overlay.jxa +8 -6
  17. package/integrations/opencode/runtime.mjs +4 -4
  18. package/integrations/opencode/tui.tsx +1 -1
  19. package/integrations/windows-overlay/Overlay.cs +4 -4
  20. package/integrations/windows-overlay/protocol.mjs +11 -7
  21. package/package.json +34 -13
  22. package/puppy-comfort-sprites.mjs +25 -0
  23. package/puppy-companion-comfort-q5.bin.gz +0 -0
  24. package/puppy-companion-comfort.json +77 -0
  25. package/puppy-companion-life.mjs +49 -16
  26. package/puppy-companion-objects.mjs +12 -0
  27. package/puppy-frame-predictive.mjs +15 -9
  28. package/puppy-frame-store.mjs +2 -2
  29. package/puppy-paper-world.mjs +14 -0
  30. package/puppy-paper.mjs +65 -14
  31. package/retrieviewer-plugin.d.mts +1 -1
  32. package/retrieviewer-plugin.mjs +1 -1
  33. package/retrieviewer.d.mts +10 -4
  34. package/retrieviewer.mjs +20 -14
  35. package/locomotion-core.mjs +0 -21
  36. package/locomotion-puppy.animal +0 -0
  37. package/vendor/procedural-animals/package.json +0 -40
  38. package/vendor/procedural-animals/src/animal.js +0 -146
  39. package/vendor/procedural-animals/src/bake.js +0 -51
  40. package/vendor/procedural-animals/src/build.js +0 -81
  41. package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
  42. package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
  43. package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
  44. package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
  45. package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
  46. package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
  47. package/vendor/procedural-animals/src/core/build/seams.js +0 -183
  48. package/vendor/procedural-animals/src/core/build/warp.js +0 -112
  49. package/vendor/procedural-animals/src/core/build/weights.js +0 -393
  50. package/vendor/procedural-animals/src/core/math/vec.js +0 -81
  51. package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
  52. package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
  53. package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
  54. package/vendor/procedural-animals/src/core/motion/common.js +0 -158
  55. package/vendor/procedural-animals/src/core/motion/index.js +0 -22
  56. package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
  57. package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
  58. package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
  59. package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
  60. package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
  61. package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
  62. package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
  63. package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
  64. package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
  65. package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
  66. package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
  67. package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
  68. package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
  69. package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
  70. package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
  71. package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
  72. package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
  73. package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
  74. package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
  75. package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
  76. package/vendor/procedural-animals/src/index.d.ts +0 -98
  77. package/vendor/procedural-animals/src/index.js +0 -29
  78. package/vendor/procedural-animals/src/registry.js +0 -48
  79. package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
  80. package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
  81. package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
  82. package/vendor/procedural-animals/src/species/bear/index.js +0 -139
  83. package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
  84. package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
  85. package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
  86. package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
  87. package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
  88. package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
  89. package/vendor/procedural-animals/src/species/boar/index.js +0 -110
  90. package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
  91. package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
  92. package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
  93. package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
  94. package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
  95. package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
  96. package/vendor/procedural-animals/src/species/cat/index.js +0 -211
  97. package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
  98. package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
  99. package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
  100. package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
  101. package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
  102. package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
  103. package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
  104. package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
  105. package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
  106. package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
  107. package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
  108. package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
  109. package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
  110. package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
  111. package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
  112. package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
  113. package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
  114. package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
  115. package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
  116. package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
  117. package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
  118. package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
  119. package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
  120. package/vendor/procedural-animals/src/species/cow/index.js +0 -118
  121. package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
  122. package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
  123. package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
  124. package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
  125. package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
  126. package/vendor/procedural-animals/src/species/crow/index.js +0 -70
  127. package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
  128. package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
  129. package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
  130. package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
  131. package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
  132. package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
  133. package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
  134. package/vendor/procedural-animals/src/species/deer/index.js +0 -106
  135. package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
  136. package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
  137. package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
  138. package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
  139. package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
  140. package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
  141. package/vendor/procedural-animals/src/species/dog/index.js +0 -144
  142. package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
  143. package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
  144. package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
  145. package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
  146. package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
  147. package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
  148. package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
  149. package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
  150. package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
  151. package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
  152. package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
  153. package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
  154. package/vendor/procedural-animals/src/species/fish/index.js +0 -88
  155. package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
  156. package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
  157. package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
  158. package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
  159. package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
  160. package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
  161. package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
  162. package/vendor/procedural-animals/src/species/fox/index.js +0 -120
  163. package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
  164. package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
  165. package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
  166. package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
  167. package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
  168. package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
  169. package/vendor/procedural-animals/src/species/frog/index.js +0 -97
  170. package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
  171. package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
  172. package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
  173. package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
  174. package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
  175. package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
  176. package/vendor/procedural-animals/src/species/goat/index.js +0 -149
  177. package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
  178. package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
  179. package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
  180. package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
  181. package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
  182. package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
  183. package/vendor/procedural-animals/src/species/horse/index.js +0 -80
  184. package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
  185. package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
  186. package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
  187. package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
  188. package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
  189. package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
  190. package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
  191. package/vendor/procedural-animals/src/species/lion/index.js +0 -111
  192. package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
  193. package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
  194. package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
  195. package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
  196. package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
  197. package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
  198. package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
  199. package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
  200. package/vendor/procedural-animals/src/species/pig/index.js +0 -161
  201. package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
  202. package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
  203. package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
  204. package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
  205. package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
  206. package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
  207. package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
  208. package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
  209. package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
  210. package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
  211. package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
  212. package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
  213. package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
  214. package/vendor/procedural-animals/src/species/rat/index.js +0 -111
  215. package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
  216. package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
  217. package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
  218. package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
  219. package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
  220. package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
  221. package/vendor/procedural-animals/src/species/shark/index.js +0 -104
  222. package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
  223. package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
  224. package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
  225. package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
  226. package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
  227. package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
  228. package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
  229. package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
  230. package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
  231. package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
  232. package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
  233. package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
  234. package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
  235. package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
  236. package/vendor/procedural-animals/src/species/snake/index.js +0 -73
  237. package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
  238. package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
  239. package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
  240. package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
  241. package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
  242. package/vendor/procedural-animals/src/species/spider/index.js +0 -78
  243. package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
  244. package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
  245. package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
  246. package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
  247. package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
  248. package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
  249. package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
  250. package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
  251. package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
  252. package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
  253. package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
  254. package/vendor/procedural-animals/src/worker.js +0 -29
@@ -1,149 +0,0 @@
1
- // Domestic goat (Capra hircus). Cloven-hoofed browser: the horse's hoof rig (pastern + hoof bone)
2
- // with two claws per foot, scimitar horns (a rigid keratin surface on the skull), beard and wattles,
3
- // horizontal bar pupils in pale amber irises, the short tail carried up, cud chewing, browsing on the
4
- // hind legs and the rearing head clash.
5
- import { goatRig, goatJoints, HEAD_O } from './rig.js';
6
- import { add, sub, mul } from '../../core/math/vec.js';
7
- import { sculptGoat, EYE } from './sculpt.js';
8
- import { goatRegions } from './regions.js';
9
- import { goatCoat } from './coat.js';
10
- import { srgb } from '../../core/build/coatKit.js';
11
- import { rng } from '../../core/math/vec.js';
12
- import { motion } from './motion.js';
13
- import { QUALITY } from '../../core/build/pipeline.js';
14
-
15
- // a kid's short neck: the head and the upper neck move down the neck by 20 % of its length (12 % for lop ears: further,
16
- // the hanging ear's tip ran into the throat), shortening the neck above its lowest 15 % (from the neck base the shift
17
- // reached the scapulae, and the Nubian kid's sprint jittered at the wrist, p99 0.084 % S)
18
- const J0 = goatJoints();
19
- const NECK_BASE = add(J0.neckBase, mul(sub(J0.occiput, J0.neckBase), 0.15));
20
- const kidNeck = (lop) => mul(sub(J0.occiput, J0.neckBase), lop ? -0.12 : -0.2);
21
-
22
- const pick = (R, table) => {
23
- let x = R() * table.reduce((s, [, w]) => s + w, 0);
24
- for (const [k, w] of table) { x -= w; if (x <= 0) return k; }
25
- return table[table.length - 1][0];
26
- };
27
-
28
- // Breeds (variants) and their coats (coat.js COATS). salt: the breed's own seed stream, so a seed gives
29
- // a different animal in every breed (with one stream, seed N was the same individual in five coats and
30
- // seeds 1-2 were kids in every breed); picked so that seed 1 is a horned adult doe (the reference
31
- // individual, the tools' default) and seeds 2-4 hold a horned buck, a kid and a doe
32
- const BREEDS = {
33
- saanen: { salt: 158, coats: [['saanen', 1]], polled: 0.4, ear: 'erect', roman: 0, legs: 1, girth: 1, horn: 0xb4a07c },
34
- alpine: { salt: 746, coats: [['chamoisee', 40], ['coublanc', 25], ['toggenburg', 20], ['britishalpine', 15]], polled: 0.35, ear: 'erect', roman: 0, legs: 1.0, girth: 0.98, horn: 0x8a7050 },
35
- pied: { salt: 208, coats: [['pied', 60], ['piedbrown', 40]], polled: 0.3, ear: 'erect', roman: 0.15, legs: 0.98, girth: 1.02, horn: 0x9e8058 },
36
- nubian: { salt: 398, coats: [['nubianred', 40], ['nubiantan', 35], ['nubianblack', 25]], polled: 0.5, ear: 'lop', roman: 1, legs: 1.06, girth: 0.97, horn: 0x7a6248 },
37
- boer: { salt: 165, coats: [['boer', 1]], polled: 0.05, ear: 'lop', roman: 0.7, legs: 0.9, girth: 1.1, horn: 0x5e4c3a },
38
- };
39
-
40
- export default {
41
- id: 'goat',
42
- name: 'Goat',
43
- latin: 'Capra hircus',
44
- group: 'hooves',
45
- plan: 'quadruped',
46
- covering: 'fur',
47
- variants: Object.keys(BREEDS),
48
-
49
- // Seeded individual. Breed (o.variant: saanen, alpine, pied, nubian, boer) sets coat colours, ears,
50
- // Roman nose and build; sex: doe (udder) or buck (heavier, broader, a mane and "pants", big horns,
51
- // long beard); age: adult or kid (juvenile: long legs, short body, big head, horn buds, fluffy
52
- // coat). Horns (scimitar, larger in bucks) or polled; beard (bucks, many does); wattles (some).
53
- variation(R0, o) {
54
- // (a re-mixed stream: the early draws of neighbouring seeds were correlated, e.g. 16 of seeds 1-20
55
- // came out polled)
56
- const salt = BREEDS[o.variant] ? BREEDS[o.variant].salt : 0;
57
- const R = rng(Math.floor(R0() * 4294967296) ^ Math.imul(o.seed ?? 1, 0x9e3779b1) ^ 0x2545f491 ^ Math.imul(salt, 0x85ebca6b));
58
- const variant = BREEDS[o.variant] ? o.variant : pick(R, [['saanen', 30], ['alpine', 30], ['pied', 20], ['nubian', 15], ['boer', 5]]);
59
- const Bd = BREEDS[variant];
60
- const sex = o.sex || (R() < 0.45 ? 'male' : 'female');
61
- const age = o.age || (R() < 0.15 ? 'juvenile' : 'adult');
62
- const kid = age === 'juvenile';
63
- const buck = sex === 'male' && !kid;
64
- const g = () => (R() + R() + R() - 1.5) / 1.5; // ~[-1, 1], peaked
65
- const coat = pick(R, Bd.coats);
66
- const polled = R() < Bd.polled;
67
- let horns = null;
68
- if (!polled) {
69
- if (kid) horns = { len: 0.02 + 0.01 * R(), base: 0.008, curve: 0.2, spread: 0.12, upright: 0.3 };
70
- else if (buck) horns = { len: 0.3 + 0.18 * R(), base: 0.024 + 0.006 * R(), curve: 1.6 + 0.5 * R(), spread: 0.18 + 0.16 * R(), upright: 0.1 * R() };
71
- else horns = { len: 0.14 + 0.1 * R(), base: 0.0125 + 0.0035 * R(), curve: 0.9 + 0.45 * R(), spread: 0.08 + 0.1 * R(), upright: 0.2 * R() };
72
- }
73
- const beardP = variant === 'nubian' || variant === 'boer' ? 0.3 : 0.65;
74
- const beard = kid ? 0 : buck ? 0.12 + 0.1 * R() : R() < beardP ? 0.05 + 0.07 * R() : 0;
75
- const size = (buck ? 1.12 : 1) * (1 + 0.045 * g()) * (variant === 'nubian' ? 1.04 : 1) * (kid ? 0.58 : 1);
76
- return {
77
- sex, age, size, variant, coat,
78
- horns, beard,
79
- wattles: R() < 0.3,
80
- earLift: R(),
81
- ear: Bd.ear,
82
- // (a kid's face is straight: the Roman arch grows in with age, and on a kid's short face it swelled)
83
- roman: Bd.roman * (0.75 + 0.25 * R()) * (kid ? 0.35 : 1),
84
- udder: sex === 'female' && !kid ? 0.2 + 0.8 * R() : 0,
85
- heavy: buck ? 0.7 + 0.3 * R() : 0,
86
- mane: buck ? 0.4 + 0.6 * R() : 0,
87
- // (the long-haired landrace roll only: every buck had a 0.25 share of its skirt, which made every buck's barrel
88
- // a sheep's fleece; a dairy buck's body coat is as short and sleek as a doe's)
89
- shaggy: (variant === 'alpine' && R() < 0.25 ? 0.4 : 0),
90
- hornColor: Bd.horn,
91
- coatShade: g(), coatLightness: 0.05 * g(),
92
- coatSeed: Math.floor(R() * 1e6),
93
- // (the quality tier's mesh scale: the horns' cells, their least thickness and their sculpted growth ridges follow it)
94
- tierRes: (QUALITY[o.quality] || QUALITY.high).res,
95
- minThick: 0.005, // (thin parts at the coarse tiers: at 8 mm the erect ear's floor under its cup showed pinholes at medium)
96
- warps: [
97
- // a kid's neck is short (kid_side, front2: the head carried forward at about the height of the withers; with
98
- // the adult's neck its upright neck and high head read as a llama)
99
- ...(kid ? [{ type: 'shift', a: NECK_BASE, b: J0.occiput, d: kidNeck(Bd.ear === 'lop') }] : []),
100
- // (the head scale next: its centre is the head origin, where the shift has moved it)
101
- { type: 'scaleAbout', c: kid ? add(HEAD_O, kidNeck(Bd.ear === 'lop')) : HEAD_O, k: (1 + 0.035 * g()) * (kid ? 1.18 : 1) * (buck ? 1.06 : 1), r0: 0.1, r1: 0.2 },
102
- { type: 'legs', k: (1 + 0.035 * g()) * Bd.legs * (kid ? 1.18 : 1), top: 0.46 },
103
- { type: 'length', k: (1 + 0.035 * g()) * (kid ? 0.84 : 1), z0: -0.32, z1: 0.32 },
104
- { type: 'girth', k: (1 + 0.04 * g()) * Bd.girth * (buck ? 1.06 : 1) * (kid ? 0.92 : 1), cy: 0.56, z0: -0.4, z1: 0.38 },
105
- ],
106
- };
107
- },
108
- rig: (params) => goatRig(params),
109
- sculpt: (m, rig, params) => sculptGoat(m, rig, params),
110
- regions: goatRegions,
111
- coat: goatCoat,
112
- eyeSpecs: (params) => [1, -1].map((side) => ({ side, spec: EYE, headOrigin: HEAD_O, bone: 'head', look: eyeLook(params) })),
113
- motion,
114
- // (marks are the lash lines: soft brown-grey on pink-skinned white coats, dark otherwise)
115
- // (clumpDensity is the density of the tufts, not the clumping strength: lower means bigger tufts. At 0.6
116
- // the 9-11 mm coat broke into 6-14 mm tufts that read as astrakhan curls, and a buck's back at 0.45 as a
117
- // pebbled rug; side2 / side3 / walk1 show a sleek coat of fine lengthwise hair. finWidth 0.4 gave the
118
- // outline a regular zipper hem at hero)
119
- // (a buck's sleek body takes the does' fine tufts, 1.5: his long mane clumps through its length anyway; 1.1 on every
120
- // buck read as a fleece)
121
- render: (params) => ({ markColor: srgb(pinkSkinned(params) ? 0x4a3934 : 0x241f1d), strandDensity: 1400, clumpDensity: longHair(params) ? 1.1 : params.sex === 'male' && params.age !== 'juvenile' ? 1.5 : 1.6, shellScale: 0.9, finWidth: 0.3, matBorders: true }),
122
- };
123
-
124
- // The goat's signature eye: a strongly elongated horizontal bar pupil in a pale golden / amber iris
125
- //, sclera hidden, dark lids. Some lines have blue-grey irises.
126
- // (mid / hi lightened ~15 %: under the cornea they rendered darker than their hex, a dark bead)
127
- const IRISES = [
128
- { inner: 0xb88f30, mid: 0xdcb24a, hi: 0xf0d284, outer: 0x6a4a18 }, // golden
129
- { inner: 0xa87f3c, mid: 0xe8d28a, hi: 0xf6e8b0, outer: 0x7a6030 }, // pale yellow
130
- { inner: 0x74501e, mid: 0xb08238, hi: 0xd49e52, outer: 0x3e2810 }, // brown-amber
131
- { inner: 0x5e7280, mid: 0xa2bccb, hi: 0xc8dae2, outer: 0x3a4650 }, // blue
132
- ];
133
- // shaggy (long-haired landrace) goats: long coarse hair lies in bigger locks (small tight tufts read as a lamb's wool)
134
- const longHair = (params) => (params.shaggy || 0) > 0.3;
135
- // white-coated goats (and the white areas of pied / Boer coats) have pink skin: nose, lips, lids
136
- const pinkSkinned = (params) => ['saanen', 'pied', 'piedbrown'].includes(params.coat);
137
- function eyeLook(params) {
138
- const s = ((params.coatSeed || 0) % 100) / 100;
139
- const ir = IRISES[s < 0.45 ? 0 : s < 0.75 ? 1 : s < 0.96 ? 2 : 3];
140
- return {
141
- pupil: 'bar',
142
- lids: 'mammal',
143
- iris: { inner: srgb(ir.inner), mid: srgb(ir.mid), hi: srgb(ir.hi), outer: srgb(ir.outer) },
144
- sclera: { color: [0.55, 0.5, 0.45], visible: false },
145
- // (pink-grey lids on white goats: side2, face3; dark on the others)
146
- lidColor: pinkSkinned(params) ? srgb(0x8a6a62) : [0.03, 0.025, 0.022],
147
- pupilSize: [0.09, 0.32],
148
- };
149
- }
@@ -1,95 +0,0 @@
1
- // Goat motion data for the quadruped engine (schema: src/core/motion/quadruped.js).
2
- // Numbers are for the reference individual (params.size = 1, a 0.78 m Saanen doe); the engine
3
- // scales them by dynamic similarity for kids, pygmies and big bucks.
4
- //
5
- // Gaits: lateral-sequence 4-beat walk (duty 0.72 -> 0.62), 2-beat
6
- // diagonal trot (hind lands ~2 % before its diagonal fore, duty 0.45 -> 0.36) and the transverse
7
- // gallop (LH, RH, LF, RF). Crossovers sit at the predicted transitions: walk -> trot at Froude
8
- // ~0.45 (1.85 m/s for a 0.78 m goat), trot -> gallop 4.2 m/s at ~2.5 Hz (Heglund et al. 1974:
9
- // v = 1.535 M^0.24, f = 4.48 M^-0.14 for 65 kg).
10
- import { hooks } from './behaviour.js';
11
-
12
- const G = (name, v, f, D, off, o) => ({ name, v, f, D, off, ...o });
13
-
14
- export const motion = {
15
- maxSpeed: 8.5,
16
- accel: [3.5, 7],
17
- decel: 7,
18
- turnRate: 1.7, // agile: pivots on the hind legs
19
- latAccelMax: 4.5,
20
- gears: { walk: 1.0, trot: 2.7, gallop: 5.6 },
21
- gallopBlend: [3.8, 6.5],
22
- // name v f D [FL, FR, HL, HR]
23
- gaits: [
24
- G('walk', 0.0, 0.85, 0.72, [0.25, 0.75, 0.0, 0.5], { liftF: 0.045, liftH: 0.04, bobF: 0.012, bobH: 0.012, flex: 0, lat: 0.02, fold: 0.7, heel: 30, tail: 0, drop: 0 }),
25
- G('walk', 1.5, 1.35, 0.62, [0.25, 0.75, 0.0, 0.5], { liftF: 0.055, liftH: 0.048, bobF: 0.025, bobH: 0.025, flex: 0, lat: 0.025, fold: 0.85, heel: 40, tail: 0.1, drop: 0 }),
26
- G('trot', 2.2, 2.05, 0.45, [0.52, 0.02, 0.0, 0.5], { liftF: 0.08, liftH: 0.065, bobF: 0.028, bobH: 0.028, flex: 0.01, lat: 0.0, fold: 1.05, heel: 50, tail: 0.3, drop: 0.006 }),
27
- G('trot', 3.4, 2.4, 0.37, [0.52, 0.02, 0.0, 0.5], { liftF: 0.095, liftH: 0.08, bobF: 0.032, bobH: 0.032, flex: 0.015, lat: 0.0, fold: 1.15, heel: 55, tail: 0.4, drop: 0.01 }),
28
- G('gallop', 4.8, 2.7, 0.3, [0.55, 0.65, 0.0, 0.1], { liftF: 0.11, liftH: 0.1, bobF: 0.022, bobH: 0.03, flex: 0.1, lat: 0, fold: 1.15, heel: 45, tail: 0.7, drop: 0.02 }),
29
- G('gallop', 8.5, 3.0, 0.23, [0.56, 0.66, 0.0, 0.1], { liftF: 0.13, liftH: 0.12, bobF: 0.024, bobH: 0.034, flex: 0.14, lat: 0, fold: 1.4, heel: 40, tail: 1.0, drop: 0.035 }),
30
- ],
31
- feet: {
32
- // cloven hooves: the fetlock sinks a little under load, the digit flips in swing, breakover
33
- // about the claw tips; pointed hard claws plant precisely (contact near the toe)
34
- front: { type: 'unguligrade', contact: 0.9, curl: 70, flex: 4, sink: 14, hoofFlex: 20, swingBack: 0.07 },
35
- hind: { type: 'unguligrade', contact: 0.9, curl: 70, flex: 4, sink: 12, hoofFlex: 20, swingBack: 0.02 },
36
- },
37
- stance: { width: 1, gallopWidth: 0.8, sprawl: 0, crouch: 0, scuff: [10, 20, 0] },
38
- // torso cross-sections (bind pose, reference size): centre height, half height, half width
39
- // (half heights include the legs folded under the chest and thighs when lying down)
40
- body: {
41
- // (0.28 with the pelvis's 0.36: the body lies level on its folded legs; the chest at 0.25 under the higher rump
42
- // pitched forward onto the folded forelegs, a Boer buck's forearm 5 cm in the ground asleep)
43
- chest: { y: 0.56, hh: 0.28, hw: 0.15 },
44
- mid: { y: 0.55, hh: 0.23, hw: 0.17 },
45
- // (the hindquarters rest on the folded hind legs: lying at 0.3 the stifles folded in against the belly and the skin
46
- // between the thigh and the flank crumpled into a pocket in front of the stifle, a light torn knob from the side)
47
- pelvis: { y: 0.63, hh: 0.36, hw: 0.16 },
48
- back: 0.06,
49
- },
50
- head: {
51
- // [speed, raise (m), reach (m), pitch (rad, + = nose down)]: head high and alert at rest, a
52
- // little lower and forward at the walk, stretched forward in the gallop
53
- carriage: [[0, 0.03, -0.015, -0.05], [1.0, 0.0, 0.01, 0.02], [2.7, -0.01, 0.03, 0.02], [5, -0.06, 0.06, 0.1], [8, -0.1, 0.09, 0.14]],
54
- stab: [[0, 0], [1.0, 0.15], [2.7, 0.45], [5, 0.35], [8, 0.4]],
55
- neckBend: 34, neckPivot: 0.55, yaw: 0.9, pitchUp: 0.7, pitchDown: 0.9, mouth: 'jawTip',
56
- },
57
- tail: {
58
- // [speed, pitch per segment from horizontal (deg), base -> tip]: carried up, higher when running
59
- carriage: [
60
- [0.0, [28, 42, 55, 62, 66]],
61
- [1.5, [30, 45, 58, 64, 68]],
62
- [3.5, [36, 52, 64, 70, 72]],
63
- [7, [42, 58, 70, 74, 76]],
64
- ],
65
- stiffness: 1.2, sway: 4, flick: 1, wag: 0, swish: 0, curl: 0, balance: 0,
66
- radius: [0.03, 0.02],
67
- },
68
- ears: { rest: [0, 0], mobility: 1.3, speedFlatten: 0.3, twitch: 1.6, prick: 0.5 },
69
- breath: { rate: 0.32, amp: 0.006, pant: false, pantRate: 2, pantAmp: 0.015, heatSpeed: 6 },
70
- actions: {
71
- // grazing: the long face already hangs 60 deg nose-down in the bind pose
72
- // (the face nearly vertical, 77 deg nose-down: at 1.1 rad the head was cocked back against the lowered neck, the
73
- // poll extended 120 deg from its standing angle and the nape's skin folded to 0.65 of its length, its hair standing
74
- // apart in a frayed band; the throat stretched more too: > 3x 1.37 -> 0.98 % of the kid's mesh in eat and drink)
75
- eat: { style: 'graze', dropF: 0.1, dropH: 0, pitch: 1.35, ahead: 0.5 },
76
- drink: { dropF: 0.1, dropH: 0, pitch: 1.3, ahead: 0.5 },
77
- // sure-footed: a high standing jump, landing on four feet close together (opts.target lands
78
- // exactly there)
79
- jump: { height: 0.75, distance: 1.3, land: [0.16, 0.14] },
80
- sit: { dropH: 0.8 },
81
- // kneels on the carpi first, then drops the hindquarters; rises hind end first
82
- lie: { down: 'front', up: 'hind' },
83
- sleep: { down: 'front', up: 'hind' },
84
- // lying sternal: forelegs folded under the chest (carpus flexed, cannons back along the ground)
85
- fold: { front: { z: -0.2, k: 1.45, beta: 0.9 } },
86
- },
87
- hooks,
88
- // the long lop ears of Nubians and Boers hang and swing with the head; they barely prick or twist
89
- // (the engine swivels a pinna about its own long axis toward what the goat looks at: a hanging ear
90
- // twisted 25 deg about its root)
91
- variants: {
92
- nubian: { ears: { mobility: 0.5, speedFlatten: 0.15, twitch: 0.4, prick: 0.06 } },
93
- boer: { ears: { mobility: 0.5, speedFlatten: 0.15, twitch: 0.4, prick: 0.06 } },
94
- },
95
- };
@@ -1,98 +0,0 @@
1
- // Meshing plan: body at 5.4 mm (0.7 % of the withers height, like the cheetah), head at 2.6 mm
2
- // overlapping the body across the upper neck and cross-faded, eyelid patches at 0.9 mm, the lower
3
- // lip / chin / beard as its own rigid surface (the mouth opens) and the horns as a rigid keratin
4
- // surface on the skull.
5
- import { EYE, hornPath, hornCell, hornSplit, hornTipCell } from './sculpt.js';
6
- import { HEAD_O, hqOf, goatJoints } from './rig.js';
7
- import { eyeFrameOf } from '../../core/sdf/eyeSocket.js';
8
- import { norm, smoothstep, clamp } from '../../core/math/vec.js';
9
-
10
- const J = goatJoints();
11
- // The head mesh takes over across a plane through the upper neck, 30 % of the way from the mid neck
12
- // to the occiput, its normal the upper neck axis turned 45 deg forward (toward the head): it crosses
13
- // the nape ~6 cm behind the poll and the throat ~9 cm below the jaw angle, both where the neck is a
14
- // smooth tube and the fine and coarse meshes agree. (The first cut ran behind the poll and into the
15
- // concave jaw angle / throat junction, where they did not: a crack from the poll to the throat. A
16
- // plane square to the upright neck cut through the lower face, which hangs forward below the throat.)
17
- const NECK_U = norm([0, J.occiput[1] - J.neckMid[1], J.occiput[2] - J.neckMid[2]]);
18
- const NECK_A = Math.atan2(NECK_U[1], NECK_U[2]) - Math.PI / 4;
19
- export const NECK_CUT = {
20
- c: [0, J.neckMid[1] + 0.3 * (J.occiput[1] - J.neckMid[1]), J.neckMid[2] + 0.3 * (J.occiput[2] - J.neckMid[2])],
21
- d: [0, Math.sin(NECK_A), Math.cos(NECK_A)], band: 0.014,
22
- };
23
- export const neckS = (x, y, z) => (x - NECK_CUT.c[0]) * NECK_CUT.d[0] + (y - NECK_CUT.c[1]) * NECK_CUT.d[1] + (z - NECK_CUT.c[2]) * NECK_CUT.d[2];
24
-
25
- export const EYE_PATCH = { R: 0.024, B: 0.004, h: 0.0011, centres: [1, -1].map((s) => eyeFrameOf(EYE, HEAD_O, s).c) };
26
- export function eyePatchWeight(x, y, z) {
27
- let dmin = 1e9;
28
- for (const c of EYE_PATCH.centres) dmin = Math.min(dmin, Math.hypot(x - c[0], y - c[1], z - c[2]));
29
- return 1 - smoothstep(EYE_PATCH.R - EYE_PATCH.B, EYE_PATCH.R + EYE_PATCH.B, dmin);
30
- }
31
-
32
- export function goatRegions(rig, params, Q) {
33
- // (the band: wider than a body cell, so the body's cut edge, which lies up to a cell into the band,
34
- // stays in its hidden half: at the crowd tier a 25 mm cell left it on the visible side of a 14 mm band,
35
- // at the low tier 0.95 of a cell left one edge of a buck's neck uncovered)
36
- const r = Q.res, B = Math.max(NECK_CUT.band, 0.0059 * r * 1.2);
37
- const Ho = HEAD_O;
38
- // eyelid patches at hero, high and medium (what Safari and phones show): without them the 24 x 16 mm aperture's lid
39
- // margin fell on the medium tier's 5.6 mm face cells and tore into pale and dark flakes round every eye
40
- // (the full 24 mm patch: the face mesh stops a cell inside it, and at 21.5 mm that cut reached the lid margin, 19-22
41
- // exposed edges round the eyes at medium)
42
- const patches = (Q.eyePatches || r <= 2) ? EYE_PATCH.centres.map((c) => ({ c, R: EYE_PATCH.R, B: EYE_PATCH.B, h: EYE_PATCH.h * Math.max(1, r) })) : [];
43
- const head = [
44
- // (the long, broad lop ears of Nubians and Boers are meshed with the head: its cells 6 % coarser keep a
45
- // lop-eared buck inside the hero budget, 133k -> 128k vertices)
46
- { name: 'head', part: 'body', bmin: [-0.3, 0.6, 0.33], bmax: [0.3, Ho[1] + 0.14, Ho[2] + 0.24], h: 0.0028 * r * (params.ear === 'lop' ? (params.sex === 'male' && params.age !== 'juvenile' ? (r === 2 ? 1.13 : 1.12) : 1.06) : 1), F: 6, clip: (x, y, z) => neckS(x, y, z) > -B, patches },
47
- { name: 'jaw', part: 'jaw', bmin: [-0.06, Ho[1] - 0.27, Ho[2] - 0.09], bmax: [0.06, Ho[1] - 0.03, Ho[2] + 0.22], h: 0.0028 * r, F: 6, rigidBone: 'jaw' },
48
- ];
49
- // (the beard's locks are 7-12 mm thick: at the medium tier's 6.8 mm cells their tips folded over, back faces showing;
50
- // 5.4 mm there)
51
- if ((params.beard || 0) > 0.01) head.push({ name: 'beard', part: 'beard', bmin: [-0.07, Ho[1] - 0.46, Ho[2] - 0.16], bmax: [0.07, Ho[1] - 0.06, Ho[2] + 0.18], h: 0.0034 * (r === 2 ? 1.6 : r), F: 6, rigidBone: 'beard' });
52
- if (params.wattles) head.push({ name: 'wattle', part: 'wattle', bmin: [-0.06, Ho[1] - 0.2, Ho[2] - 0.18], bmax: [0.06, Ho[1] + 0.03, Ho[2] + 0.02], h: 0.0022 * r, F: 6, rigidBone: 'neck2' });
53
- // the udder / a buck's scrotum: its own closed surface, rigid on the udder bone (sculpt.js) (the scrotum
54
- // coarser: a horned, bearded lop-eared buck was 200 vertices over the hero budget)
55
- const adult = params.age !== 'juvenile', male = params.sex === 'male', HQ = hqOf(params);
56
- if (adult && (male || (params.udder ?? 0.5) > 0.05)) head.push({ name: 'udder', part: 'udder', bmin: [-0.11, 0.17, -0.44 + HQ], bmax: [0.11, male ? 0.62 : 0.56, -0.2 + HQ], h: (male ? 0.005 : 0.0042) * r, F: 6, rigidBone: 'udder' });
57
- if (params.horns && params.horns.len > 0) {
58
- // the box from the horn centre lines (both sides) plus the horn radius and two cells: a fixed box
59
- // cut the horn bases off (they start at the poll, z 0.65, and a doe's horns reach z 0.68)
60
- // (cells with the horn's girth: a buck's longest, thickest horns took 18k vertices at 3.2 mm, and a
61
- // lop-eared buck with them and a long beard came to 137k at hero, over the 130k budget)
62
- // (at most the low tier's cells at the crowd tier too: 16 mm cells left a buck's horn a chain of ragged lumps;
63
- // the horn is also kept ~0.45 of a cell thick there, sculpt.js hornPath)
64
- // (at the low and crowd tiers the tapering outer part is its own solid at the medium tier's cells, sculpt.js hornSplit)
65
- const h = hornCell(params, r), hT = hornTipCell(params);
66
- const box = (part, hh, from, to) => {
67
- const bmin = [1e9, 1e9, 1e9], bmax = [-1e9, -1e9, -1e9];
68
- for (const s of [1, -1]) {
69
- const pth = hornPath(params, s), J = hornSplit(params, pth);
70
- pth.forEach((q, i) => {
71
- if (J >= 0 && (i < from(J) || i > to(J, pth.length))) return;
72
- const m = q.r * 1.25 + 2 * hh + 0.004;
73
- for (let k = 0; k < 3; k++) { bmin[k] = Math.min(bmin[k], q.p[k] - m); bmax[k] = Math.max(bmax[k], q.p[k] + m); }
74
- });
75
- }
76
- head.push({ name: part, part, bmin, bmax, h: hh, F: 6, rigidBone: 'head' });
77
- };
78
- const split = hornSplit(params, hornPath(params, 1)) >= 0;
79
- box('horn', h, () => 0, (J, n) => (split ? J : n));
80
- if (split) box('horntip', hT, (J) => J - 2, (J, n) => n);
81
- }
82
- return {
83
- jobs: [
84
- [{ name: 'body', part: 'body', bmin: [-0.26, -0.01, -0.66], bmax: [0.26, 1.0, 0.7], h: 0.0059 * r, F: 4, clip: (x, y, z) => neckS(x, y, z) < B }],
85
- head,
86
- ],
87
- fade(x, y, z, name, patch) {
88
- const sN = neckS(x, y, z);
89
- if (name === 'body') return 1 - smoothstep(-B, B, sN);
90
- if (name === 'head') {
91
- let f = smoothstep(-B, B, sN);
92
- if (patches.length) { const ew = eyePatchWeight(x, y, z); f *= patch ? ew : 1 - ew; }
93
- return f;
94
- }
95
- return 1;
96
- },
97
- };
98
- }
@@ -1,181 +0,0 @@
1
- // Goat skeleton in bind pose (metres). Forward = +Z, up = +Y, the animal's left = +X.
2
- // Reference individual: a Saanen-type dairy doe, 0.78 m at the withers, ~65 kg (ADGA standard). Landmarks measured on side3.jpg (4x grid, 1 px = 1.39 mm) and side2.jpg
3
- // (1 px = 1.84 mm), limb segments from published goat osteometry.
4
- //
5
- // Hooves: the standard quadruped bones plus a hoof bone per leg, exactly like the horse:
6
- // fpaw / hpaw = pastern (fetlock -> coffin joint), fhoof / hhoof = the cloven hoof (coffin joint ->
7
- // toe), so the engine keeps the claws flat while the fetlock sinks under load.
8
- //
9
- // The rig depends on the individual only through the ears (erect / lateral in Swiss breeds, long and
10
- // pendulous in the Nubian: params.ear).
11
- import { buildRig } from '../../core/rig/rig.js';
12
- import { quadrupedBones, quadrupedLimbs, tailChain } from '../../core/rig/quadruped.js';
13
-
14
- export const TAIL_SEGS = 5;
15
- // a lop ear's root blend: the ear takes the skin up to 3 cm onto the head and down to 5 cm along the ear (it hangs with
16
- // gravity, turning up to 25 deg about its root against the skull: at [-0.006, 0.02] the root and the web between the
17
- // blade and the cheek stretched 3x on 1 % more of the mesh when grazing)
18
- export const LOPBL = [-0.03, 0.05];
19
-
20
- // Head frame: modelled along its own axis (poll -> muzzle), pitched 42 degrees nose-down in the
21
- // bind pose. Head-local coordinates: x lateral, y dorsal (forehead side), z along the nasal line toward
22
- // the muzzle; origin on the axis 0.07 m in front of the poll, level with the eyes.
23
- // (side2 and walk1: the eye -> nose-tip line runs 33-34 deg below the horizontal and the forehead
24
- // 51-60 deg; the poll stands ~0.3 SH above the withers, the neck rises at ~55-64 deg. The head was
25
- // carried at 54 deg with the forehead profile at 68 deg, 5-7 cm low: a grazing horse's carriage)
26
- export const HEAD_PITCH = (42 * Math.PI) / 180;
27
- export const HZ = [0, -Math.sin(HEAD_PITCH), Math.cos(HEAD_PITCH)];
28
- export const HY = [0, Math.cos(HEAD_PITCH), Math.sin(HEAD_PITCH)];
29
- const POLL = [0, 0.975, 0.59]; // top of the poll (skin), bind
30
- export const HEAD_O = [0, POLL[1] + 0.07 * HZ[1], POLL[2] + 0.07 * HZ[2]];
31
- export const hl = (v) => [HEAD_O[0] + v[0], HEAD_O[1] + v[1] * HY[1] + v[2] * HZ[1], HEAD_O[2] + v[1] * HY[2] + v[2] * HZ[2]];
32
- // a kid's face is short: in front of the eyes the head-local z (along the nasal line) is compressed by
33
- // KID_FACE (front2, kid_side: a big braincase and eyes over a short, small muzzle; the whole head scaled
34
- // up gave a kid an adult's bulbous muzzle). faceZ maps an adult head-local z to the kid's, unFaceZ back.
35
- export const KID_FACE = 0.78;
36
- export const faceZ = (z, kid) => (kid && z > 0.02 ? 0.02 + (z - 0.02) * KID_FACE : z);
37
- export const unFaceZ = (z, kid) => (kid && z > 0.02 ? 0.02 + (z - 0.02) / KID_FACE : z);
38
- // head-local point (adult coordinates) -> world, with the kid's short face
39
- export const hlk = (v, kid) => hl([v[0], v[1], faceZ(v[2], kid)]);
40
- // head-local direction -> world
41
- export const hdir = (v) => [v[0], v[1] * HY[1] + v[2] * HZ[1], v[1] * HY[2] + v[2] * HZ[2]];
42
- // world point -> head-local
43
- export const toHL = (p) => { const d = [p[0] - HEAD_O[0], p[1] - HEAD_O[1], p[2] - HEAD_O[2]]; return [d[0], d[1] * HY[1] + d[2] * HY[2], d[1] * HZ[1] + d[2] * HZ[2]]; };
44
-
45
- // ear tips (head-local, left): Swiss erect / lateral ears point out, a little up and forward;
46
- // Nubian / Boer lop ears hang straight down beside the face (their tip is placed in world space
47
- // below the base, clear of the cheek: see goatJoints)
48
- export const EAR_BASE = [0.048, 0.026, -0.06];
49
- export const EAR_TIP = {
50
- erect: [0.2, 0.015, -0.02],
51
- };
52
- // the hindquarters (hip joint, hind limb, pelvis, tail root, udder) sit this far further forward than
53
- // the first model: side1 / side2 give a body (point of shoulder -> point of buttock) of 1.06-1.09 SH,
54
- // the model had 1.24 SH, its hip points, tail head and buttock 10-18 cm behind side2's
55
- // (adults 0.07, not 0.095: the hind hooves stood 0.17 SH ahead of the rump's outline at the toe, against
56
- // 0.06-0.12 in side2 / side3; now 0.14 at the toe, 0.05 at the heel, the cannons under the pin bones. Kids keep
57
- // 0.095: their hind legs stand under the short body, kid_side, and with them further back the Nubian kid's
58
- // sprint jittered at the wrist, p99 0.086 % S)
59
- export const hqOf = (params = {}) => (params.age === 'juvenile' ? 0.095 : 0.07);
60
-
61
- export function goatJoints(params = {}) {
62
- // (erect ears: carried from level-lateral (face3) to up-and-out (face1), params.earLift 0..1)
63
- const lop = params.ear === 'lop';
64
- const kid = params.age === 'juvenile';
65
- // (kids carry their big ears up and out: front2, kid_side)
66
- const lift = kid ? Math.max(0.6, params.earLift ?? 0.5) : (params.earLift ?? 0.5);
67
- const HQ = hqOf(params);
68
- const J = {
69
- nose: hlk([0, -0.024, 0.205], kid), // (the front of the nose pad and upper lip: the engine keeps it off the ground)
70
- occiput: hl([0, -0.045, -0.1]), // (behind the poll and the horn bases: the skull top is all 'head')
71
- neckMid: [0, 0.8, 0.472],
72
- neckBase: [0, 0.64, 0.35],
73
- chestMid: [0, 0.668, 0.17],
74
- thoraxRear: [0, 0.692, 0.015],
75
- lumbarMid: [0, 0.702, -0.1],
76
- lumbosacral: [0, 0.707, -0.215],
77
- tailBase: [0, 0.71, -0.4],
78
- // fore: scapula sloping ~65 deg, humerus down and back (45 deg from vertical), radius and cannon
79
- // vertical, pastern ~50 deg (cloven hoof)
80
- // (the elbow 1.7 cm further back: with the humerus 40 deg from vertical the shoulder -> wrist span was
81
- // 93 % of humerus + radius, the engine's reach limit left the foreleg a 0.45 m stance sweep against
82
- // the hind leg's 0.75 m, and it cut the fore stances short: duty 0.53 / 0.34 / 0.20 at the walk,
83
- // trot and gallop against the table's 0.65 / 0.42 / 0.29, a high hackney flick and pacing walk)
84
- scapTopL: [0.055, 0.745, 0.265],
85
- shoulderL: [0.088, 0.53, 0.372],
86
- elbowL: [0.083, 0.405, 0.245],
87
- wristL: [0.07, 0.21, 0.252],
88
- mcpL: [0.064, 0.07, 0.256],
89
- fcoffinL: [0.064, 0.03, 0.279],
90
- ftoeL: [0.064, 0.002, 0.323],
91
- // hind: hip joint, stifle, hock, fetlock, coffin joint, toe (the cannon vertical: it stood 6 deg
92
- // forward, sickle-hocked)
93
- hipL: [0.078, 0.63, -0.36 + HQ],
94
- kneeL: [0.093, 0.45, -0.24 + HQ],
95
- hockL: [0.066, 0.25, -0.44 + HQ],
96
- mtpL: [0.06, 0.075, -0.442 + HQ],
97
- hcoffinL: [0.06, 0.031, -0.419 + HQ],
98
- htoeL: [0.06, 0.002, -0.374 + HQ],
99
- jawHinge: hl([0, -0.045, -0.02]),
100
- jawTip: hlk([0, -0.078, 0.185], kid),
101
- // (a lop ear's root sits further back on the skull: hanging from the erect ear's root, the broad blade
102
- // covered the eye)
103
- earBaseL: hl(lop ? [EAR_BASE[0], EAR_BASE[1] - 0.006, EAR_BASE[2] - 0.01] : EAR_BASE),
104
- // udder (does): its own rigid bone below the pelvis, so it can fold up out of the ground when the
105
- // doe lies down (hooks.pose)
106
- // beard: its own bone below the chin (hangs from the jaw; hooks.pose swings it out of the ground)
107
- beardTop: hlk([0, -0.094, 0.115], kid),
108
- udderTop: [0, 0.44, -0.34 + HQ],
109
- udderBot: [0, 0.3, -0.325 + HQ],
110
- };
111
- // lop ears (Nubian, Boer): long and broad, hanging down beside the face and jaw from the base, flaring out
112
- // to 9 cm from the root at the tip and a little back of vertical, so the blade stays behind the eye (side_boer,
113
- // the Nubian standard; hanging straight down with the face pitched 42 deg nose-down it covered the eye) and
114
- // clear of the throat (within the 2 cm blend of the throat skin it took neck weights and stretched)
115
- const eb = J.earBaseL;
116
- // (a kid's lop ears are shorter: its head is scaled up as a whole, and full-length ears hung below its knees)
117
- // (Nubian ears ~25 cm, reaching below the jaw; a Boer's a little shorter: at 21 cm they ended at the
118
- // mouth corner, short paddles)
119
- const le = (kid ? 0.82 : 1) * (params.variant === 'boer' ? 0.9 : 1);
120
- J.earTipL = lop ? [eb[0] + 0.1 * le, eb[1] - 0.225 * le, eb[2] - 0.05 * le]
121
- : hl([EAR_TIP.erect[0] - 0.02 * lift, EAR_TIP.erect[1] - 0.03 + 0.11 * lift, EAR_TIP.erect[2] + 0.02 * lift]);
122
- // (a kid's erect ears are long for its head: as long as its face, front2)
123
- if (kid && !lop) for (let i = 0; i < 3; i++) J.earTipL[i] = eb[i] + (J.earTipL[i] - eb[i]) * 1.15;
124
- J.beardTip = [J.beardTop[0], J.beardTop[1] - Math.max(0.03, params.beard || 0), J.beardTop[2] - 0.01];
125
- // the short flat tail is carried up (research: erect most of the time)
126
- tailChain(J, 'tailBase', [28, 42, 55, 62, 66], [0.035, 0.032, 0.03, 0.028, 0.026]);
127
- return J;
128
- }
129
-
130
- export function goatBones() {
131
- const b = quadrupedBones({ tailSegs: TAIL_SEGS, ears: true, jaw: true });
132
- for (const d of b) {
133
- if (d[0] === 'fpaw{S}') { d[2] = 'fcoffin{S}'; d[4] = { region: 'limb', group: 'F{S}' }; }
134
- if (d[0] === 'hpaw{S}') { d[2] = 'hcoffin{S}'; d[4] = { region: 'limb', group: 'H{S}' }; }
135
- }
136
- b.push(['udder', 'udderTop', 'udderBot', 'pelvis', { region: 'torso', group: 'udder' }]);
137
- b.push(['beard', 'beardTop', 'beardTip', 'jaw', { region: 'jaw', group: 'jaw' }]);
138
- b.push(
139
- ['fhoof{S}', 'fcoffin{S}', 'ftoe{S}', 'fpaw{S}', { region: 'foot', group: 'F{S}' }],
140
- ['hhoof{S}', 'hcoffin{S}', 'htoe{S}', 'hpaw{S}', { region: 'foot', group: 'H{S}' }],
141
- );
142
- return b;
143
- }
144
-
145
- export function goatRig(params = {}, J = goatJoints(params)) {
146
- const limbs = quadrupedLimbs({
147
- front: { tCore: 0.5, aCore: 0.05, aBody: -0.15, midX: 0.0 },
148
- hind: { tCore: 0.45, aCore: 0.022, aBody: -0.11, midX: 0.008 },
149
- });
150
- for (const L of Object.values(limbs)) { L.bones.push((L.front ? 'fhoof' : 'hhoof') + L.S); L.distal.push((L.front ? 'fhoof' : 'hhoof') + L.S); }
151
- return buildRig({
152
- joints: J,
153
- unit: 1.03,
154
- headOrigin: HEAD_O,
155
- bones: goatBones(),
156
- axial: {
157
- points: ['nose', 'occiput', 'neckMid', 'neckBase', 'chestMid', 'thoraxRear', 'lumbarMid', 'lumbosacral', 'tailBase', ...Array.from({ length: TAIL_SEGS }, (_, i) => 'tail' + (i + 1))],
158
- bones: ['head', 'neck2', 'neck1', 'chest', 'spine3', 'spine2', 'spine1', 'pelvis', ...Array.from({ length: TAIL_SEGS }, (_, i) => 'tail' + i)],
159
- // the skull's influence reaches back into the throat (widening with the depth below the axis)
160
- // (a narrower lever, 0.5, kept the cheek out of the blend but gathered the stretch at the jaw angle:
161
- // fewer triangles over 2x, more over 3x; the throat stretch is cured in the poses instead, the grazing
162
- // head pitch and a kid's short face, see motion.js and rig.js faceZ)
163
- // (the neck base blends over 8 cm each side: the skin over the withers stretched 3x when the head went
164
- // down or round to the flank)
165
- // (15 cm: at 8 cm the skin over the withers bent over a ridge when the neck went down to graze; the Boer
166
- // keeps 11 cm: wider, its broad chest front took neck weights, and lying dead it rested 11 mm in the
167
- // ground, and its red / white border across the lower neck stretched)
168
- blend: { 1: [-0.05, 0.14, 4.5], 3: params.variant === 'boer' ? [-0.11, 0.11, 0] : [-0.15, 0.15, 0] },
169
- bodyTail: 0, // (the rump and buttocks do not blend into the tail: they tore when the thighs folded to lie down)
170
- },
171
- limbs,
172
- appendages: [
173
- // (a long lop ear swings about its root as the head moves: its root blends over 2.6 cm, where an
174
- // erect ear's took 6 mm and tore; reaching 1 cm onto the head it dragged the skin behind the root)
175
- { group: 'earL', bone: 'earL', blend: params.ear === 'lop' ? LOPBL : [-0.002, 0.004] },
176
- { group: 'earR', bone: 'earR', blend: params.ear === 'lop' ? LOPBL : [-0.002, 0.004] },
177
- { group: 'udder', bone: 'udder', blend: [-0.004, 0.02] },
178
- ],
179
- webTags: ['flankfold', 'thighfront', 'scapmuscle', 'pectoral', 'forearmweb'],
180
- });
181
- }