@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,242 +0,0 @@
1
- // Pig ear leaves: the geometry shared by the rig (the ear bone runs from the root to the leaf's tip), the
2
- // sculpt (tiles), the meshing plan (the region box) and the coat (the hollow side, how far out along the ear).
3
- //
4
- // A leaf is one smooth curved sheet with a mid-surface P(s, a) (s 0 root .. 1 tip, a -1 .. 1 across):
5
- // - the spine leaves the head along the root direction `root` (WORLD, standing pig, left ear), runs straight
6
- // for the first s0 of its length and then bends toward the hollow side by `bend` degrees in all (bendPow
7
- // > 1: the bend comes late, toward the tip);
8
- // - its cross-section is a circular arc that rolls both edges toward the hollow by `cup` (rad, root -> tip:
9
- // the root rolled into the funnel of the ear canal, flatter toward the tip), half width W earW(s);
10
- // - it is thick at the root and thins toward the rim (`thick`: [root, rim] full thickness, m): cartilage and
11
- // skin ~1.2-1.5 cm where the pinna leaves the head, 3-4 mm at its free edge, with a round rim.
12
- // The sheet is tiled with small exact slabs (m.fin with a thickness gradient, core sdf.js), each its quad
13
- // projected on its own plane and run one rim radius past every edge it shares with a neighbour, so the
14
- // rounded ends of neighbours make one cylinder there and the sheet runs on smoothly.
15
- //
16
- // Forms (from photos):
17
- // - erect (Large White, Hampshire, Berkshire; face1, face2, front1): a broad leaf up and forward, the hollow
18
- // facing forward and out, a rounded tip curling a little forward;
19
- // - semi (Duroc; face3): up and out from the top corners of the poll with the hollow facing forward, curving
20
- // out and down as it goes (sweep) and the outer part folding forward and down (bend), a thick, soft leaf
21
- // hanging beside the eyes;
22
- // - lop (Landrace, Gloucester Old Spot): the leaf leaves the poll corner forward along the head and a little out
23
- // and up, then droops forward and down over the eye toward the snout, a soft visor with air under it (its
24
- // convex back out and up, the hollow facing the face below it), the forehead showing between the two.
25
- const PI = Math.PI;
26
- const add = (a, b) => [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
27
- const sub = (a, b) => [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
28
- const mul = (a, k) => [a[0] * k, a[1] * k, a[2] * k];
29
- const dot = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
30
- const cross = (a, b) => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
31
- const norm = (a) => { const l = Math.hypot(a[0], a[1], a[2]) || 1; return [a[0] / l, a[1] / l, a[2] / l]; };
32
- const clamp01 = (x) => (x < 0 ? 0 : x > 1 ? 1 : x);
33
- const sstep = (a, b, x) => { const t = clamp01((x - a) / (b - a)); return t * t * (3 - 2 * t); };
34
-
35
- // ear root on the head (head-local, rig.js hl()): the top corners of the broad poll (face2 / front1: the
36
- // ear bases well out from the midline)
37
- export const EAR_BASE = [0.07, 0.056, -0.074];
38
- // the ears' meshing cell at the hero tier (regions.js: x the tier's res)
39
- export const EAR_CELL = 0.003;
40
-
41
- // leaf outlines: half width (x W) along the leaf
42
- const OUTLINE = {
43
- // (broad, the widest a third of the way up, a rounded tip: face2, front1)
44
- // (a pointed tip, lw_show, head_hausschwein5, face2; the rounded tip read as a mouse's ear)
45
- erect: [[0, 0.5], [0.08, 0.68], [0.22, 0.94], [0.4, 1.0], [0.6, 0.9], [0.78, 0.66], [0.9, 0.38], [1.0, 0.06]],
46
- // (broad and blunt: face3)
47
- semi: [[0, 0.5], [0.08, 0.7], [0.24, 0.95], [0.45, 1.0], [0.66, 0.9], [0.84, 0.64], [0.95, 0.36], [1.0, 0.12]],
48
- // (long, widest past the middle, a rounded point toward the snout)
49
- lop: [[0, 0.46], [0.08, 0.64], [0.24, 0.9], [0.46, 1.0], [0.66, 0.92], [0.84, 0.66], [0.95, 0.36], [1.0, 0.1]],
50
- };
51
- // root / facing: WORLD directions of the standing pig (left ear); rootH / facingH: the same in head-local
52
- // coordinates (x out, y dorsal, z along the head toward the disc; the head is carried HEAD_PITCH nose-down)
53
- export const EAR_FORM = {
54
- // (splayed out ~36 deg from upright and a broader leaf, as in lw_show, face2, head_hausschwein5: at 29 deg
55
- // and 0.38 wide they stood up like a rabbit's)
56
- erect: { root: [0.58, 0.8, 0.2], len: 0.2, facing: [0.45, -0.4, 0.9], bend: 12, s0: 0.1, bendPow: 2, cup: [0.95, 0.28], width: 0.41, thick: [0.012, 0.0055], wave: 0, ns: 12, na: 10 },
57
- // (up and out from the poll corner with the hollow forward, the outer part folding forward and down to hang
58
- // beside the eye, the tips about level with the eyes: face3, Duroc photos; held out flat as brims)
59
- semi: { root: [0.9, 0.0, 0.45], len: 0.235, facing: [0.1, -0.45, 1], bend: 45, s0: 0.4, bendPow: 1.2, sweep: 75, sweepS0: 0.2, sweepPow: 1.3, cup: [0.7, 0.35], width: 0.29, thick: [0.014, 0.0055], wave: 0, ns: 22, na: 10 },
60
- // (forward from the poll corners along the head and angled out, then drooping over the eyes like a soft visor
61
- // with air under it, the forehead showing between the two: Landrace photos; 0.68 as wide as long and
62
- // rolled round the head, the two leaves covered the whole upper face like a helmet)
63
- // (the root rising ~8 deg above level before the leaf droops (it left the poll 12 deg nose-down
64
- // and lay along the forehead like a decal from the front 3/4; lr_heads: forward and level from the
65
- // poll, then down over the eye))
66
- lop: { rootH: [0.3, 0.55, 0.78], len: 0.22, facingH: [-0.5, -0.85, 0.15], bend: 95, s0: 0.3, bendPow: 1.5, cup: [0.45, 0.2], width: 0.28, thick: [0.015, 0.0055], wave: 0.015, ns: 14, na: 10 },
67
- };
68
- // (rig.js HEAD_PITCH: kept here as a number, rig.js imports this module)
69
- const HP = (35 * PI) / 180;
70
- const fromHead = (v) => [v[0], v[1] * Math.cos(HP) - v[2] * Math.sin(HP), v[1] * Math.sin(HP) + v[2] * Math.cos(HP)];
71
- const rootOf = (F) => (F.rootH ? fromHead(F.rootH) : F.root);
72
- const facingOf = (F) => (F.facingH ? fromHead(F.facingH) : F.facing);
73
- export const earType = (params) => (params.ear === 'lop' || params.ear === 'semi' ? params.ear : 'erect');
74
- export const earW = (type, t) => {
75
- const W = OUTLINE[type];
76
- for (let i = 1; i < W.length; i++) if (t <= W[i][0]) { const [t0, w0] = W[i - 1], [t1, w1] = W[i]; return w0 + ((w1 - w0) * (t - t0)) / (t1 - t0); }
77
- return W[W.length - 1][1];
78
- };
79
-
80
- // the root direction of the left ear (world, standing) and the leaf length for this individual (the pinnae
81
- // carried more forward / more out, params.earFwd / earOut; params.earSize)
82
- // (params.earForm: overrides of the form's numbers, for tools)
83
- const formOf = (params) => (params.earForm ? { ...EAR_FORM[earType(params)], ...params.earForm } : EAR_FORM[earType(params)]);
84
- export function earRoot(params) {
85
- const F = formOf(params);
86
- const d = norm(rootOf(F));
87
- return { dir: norm([d[0] + 0.25 * (params.earOut || 0), d[1], d[2] + 0.35 * (params.earFwd || 0)]), len: F.len * (params.earSize ?? 1) };
88
- }
89
-
90
- // the spine of one leaf: stations 0..steps from the root; per station the point and the leaf's frame: d along
91
- // the spine, h the hollow side, l across the leaf (l = d x h). The frame folds toward the hollow (`bend`
92
- // degrees in all from s0 on, bendPow > 1: late) and sweeps within the leaf's plane toward +l (`sweep`
93
- // degrees from sweepS0 on, sweepPow): a leaf held out sideways with its hollow forward that curves down as
94
- // it goes (face3) sweeps; one that tips over toward its hollow folds. (Left ear; mirrored for the right.)
95
- export function earSpine(base, S, params, steps = 96) {
96
- const s = S === 'L' || S === 1 ? 1 : -1;
97
- const type = earType(params);
98
- const F = formOf(params);
99
- const { dir, len } = earRoot(params);
100
- const d0 = [dir[0] * s, dir[1], dir[2]];
101
- const fc = facingOf(F);
102
- const fw = [fc[0] * s, fc[1], fc[2]];
103
- const f0 = norm(sub(fw, mul(d0, dot(fw, d0))));
104
- const lat = norm(cross(d0, f0));
105
- const B = (F.bend * PI) / 180, Bs = ((F.sweep || 0) * PI) / 180 * s, Bt = ((F.twist || 0) * PI) / 180 * s;
106
- const ramp = (u, u0, p) => Math.pow(clamp01((u - u0) / (1 - u0)), p);
107
- const foldAt = (u) => B * ramp(u, F.s0, F.bendPow);
108
- const sweepAt = (u) => Bs * ramp(u, F.sweepS0 ?? F.s0, F.sweepPow ?? 1);
109
- const twistAt = (u) => Bt * ramp(u, F.twistS0 ?? F.s0, F.twistPow ?? 1);
110
- const pts = [base], fr = [{ d: d0, h: f0, l: lat }];
111
- let o = base, d = d0, h = f0, l = lat;
112
- for (let k = 1; k <= steps; k++) {
113
- const u0 = (k - 1) / steps, u1 = k / steps;
114
- const da = foldAt(u1) - foldAt(u0), db = sweepAt(u1) - sweepAt(u0), dt = twistAt(u1) - twistAt(u0);
115
- const dPrev = d;
116
- // fold: d toward h about l
117
- { const c = Math.cos(da), sn = Math.sin(da); const d2 = add(mul(d, c), mul(h, sn)); h = sub(mul(h, c), mul(d, sn)); d = d2; }
118
- // sweep: d toward l about h (the right ear sweeps the mirrored way: its l is the mirror's -l)
119
- { const c = Math.cos(db), sn = Math.sin(db); const d2 = add(mul(d, c), mul(l, sn)); l = sub(mul(l, c), mul(d, sn)); d = d2; }
120
- // twist: the leaf turns about its spine, h toward l (a lop ear's leaf turns from a visor over the eye to a
121
- // flap hanging down the side of the face)
122
- { const c = Math.cos(dt), sn = Math.sin(dt); const h2 = add(mul(h, c), mul(l, sn)); l = sub(mul(l, c), mul(h, sn)); h = h2; }
123
- d = norm(d); h = norm(sub(h, mul(d, dot(h, d)))); l = cross(d, h);
124
- o = add(o, mul(norm(add(dPrev, d)), len / steps));
125
- pts.push(o);
126
- fr.push({ d, h, l });
127
- }
128
- return { type, F, s, d0, f0, lat, pts, fr, L: len, W: F.width * len * (params.earWide ?? 1), steps, tip: o };
129
- }
130
-
131
- // the leaf: tiles for the sculpt, the mid-surface for tools, the outline points for the region box.
132
- // res: the quality tier's cell scale (params.tierRes): the leaf is at least 1.8 ear cells thick at every tier
133
- // (EAR_CELL x res, regions.js; a sheet thinner than that has both faces in one cell and meshes with rows of
134
- // pinholes: a 3.6 mm rim at the 3 mm hero cells did).
135
- // Each tile is a curved, tapered slab (core fin({ grad, curve })): its mid-surface a quadric fitted to 9
136
- // points of the leaf's mid-surface, its half thickness a plane fitted to its corners, so neighbouring tiles
137
- // meet with the same tangent plane and thickness (a smooth sheet: planar tiles showed a grid of facets).
138
- export function earLeaf(base, S, params) {
139
- const sp = earSpine(base, S, params);
140
- const { F, type, pts: spine, fr, steps: STEPS, W, L } = sp;
141
- const res = params.tierRes ?? 1;
142
- const tMin = (res >= 1.9 ? 2.3 : 1.8) * EAR_CELL * res; // (medium and below 2.3 cells: at 1.8 the round rim, thinner than a 6 mm cell, meshed scalloped like torn paper)
143
- // (fractional stations: linear between the spine's 96 steps)
144
- const at = (kf) => {
145
- const k = Math.min(STEPS - 1, Math.max(0, Math.floor(kf))), f = kf - k, A = fr[k], Bf = fr[k + 1];
146
- const h = norm(add(mul(A.h, 1 - f), mul(Bf.h, f))), l = norm(add(mul(A.l, 1 - f), mul(Bf.l, f)));
147
- return { p: add(mul(spine[k], 1 - f), mul(spine[k + 1], f)), h, l };
148
- };
149
- // (a soft, slightly uneven rim: the half width wanders by F.wave along the leaf, three to four times, face3;
150
- // the phase differs per side and individual)
151
- const wph = ((params.coatSeed || 0) % 628) / 100 + (S === 'L' || S === 1 ? 0 : 2.1);
152
- const half = (kf) => { const t = kf / STEPS; return Math.max(1e-4, earW(type, t) * W * (1 + (F.wave || 0) * Math.sin(2 * PI * 3.4 * t + wph) * sstep(0.1, 0.35, t))); };
153
- const cupAt = (kf) => F.cup[0] + (F.cup[1] - F.cup[0]) * (kf / STEPS);
154
- // mid-surface point and hollow-side normal at station kf (0..STEPS), across a (-1..1)
155
- const P = (kf, a) => {
156
- const { p, h, l } = at(kf), w = half(kf), kap = cupAt(kf) / w, x = a * w;
157
- return add(add(p, mul(l, Math.sin(kap * x) / kap)), mul(h, (1 - Math.cos(kap * x)) / kap));
158
- };
159
- const Nrm = (kf, a) => {
160
- const { h, l } = at(kf), w = half(kf), kap = cupAt(kf) / w, x = a * w;
161
- return norm(add(mul(h, Math.cos(kap * x)), mul(l, -Math.sin(kap * x))));
162
- };
163
- // thickness (full, m): thick where the pinna leaves the head, thinning toward the tip and the edges
164
- const thick = (u, a) => {
165
- const tr = F.thick[0], te = F.thick[1];
166
- const t = te + (tr - te) * (1 - sstep(0, 0.55, u)) * (1 - sstep(0.25, 1, Math.abs(a)));
167
- return Math.max(t, tMin);
168
- };
169
- const NS = F.ns, NA = F.na;
170
- const st = (i) => (i * STEPS) / NS;
171
- const segs = [], outline = [base];
172
- for (let i = 0; i < NS; i++) {
173
- for (let j = 0; j < NA; j++) {
174
- const a0 = -1 + (2 * j) / NA, a1 = -1 + (2 * (j + 1)) / NA, k0 = st(i), k1 = st(i + 1);
175
- const Q = [P(k0, a0), P(k1, a0), P(k1, a1), P(k0, a1)];
176
- const C = mul(add(add(Q[0], Q[1]), add(Q[2], Q[3])), 0.25);
177
- const v = norm(sub(add(Q[1], Q[2]), add(Q[0], Q[3])));
178
- let u = sub(add(Q[3], Q[2]), add(Q[0], Q[1]));
179
- u = norm(sub(u, mul(v, dot(u, v))));
180
- // (the fin's normal u x v points into the hollow: the coat reads the hollow side from it)
181
- if (dot(cross(u, v), Nrm((k0 + k1) / 2, (a0 + a1) / 2)) < 0) u = mul(u, -1);
182
- const n = cross(u, v);
183
- const q2 = Q.map((q) => [dot(sub(q, C), u), dot(sub(q, C), v)]);
184
- // the mid-surface over the tile: z = m0 + mu x + mv y + (muu x^2 + 2 muv x y + mvv y^2) / 2 (least squares, 9 points)
185
- const rows = [], zs = [];
186
- for (const kf of [k0, (k0 + k1) / 2, k1]) for (const a of [a0, (a0 + a1) / 2, a1]) {
187
- const d = sub(P(kf, a), C), x = dot(d, u), y = dot(d, v);
188
- rows.push([1, x, y, 0.5 * x * x, x * y, 0.5 * y * y]); zs.push(dot(d, n));
189
- }
190
- const curve = lsq(rows, zs);
191
- // half thickness at the corners, fitted by a plane h0 + gu x + gv y
192
- const hc = [thick(k0 / STEPS, a0), thick(k1 / STEPS, a0), thick(k1 / STEPS, a1), thick(k0 / STEPS, a1)].map((t) => t / 2);
193
- const [h0, gu, gv] = lsq(q2.map(([x, y]) => [1, x, y]), hc);
194
- // edges: Q0-Q1 the a0 side (the rim if j = 0), Q1-Q2 the tip side (the rim if last), Q2-Q3 the a1
195
- // side (the rim if j = NA - 1), Q3-Q0 the root side (the first row runs into the head)
196
- const hEdge = (c0, c1) => (hc[c0] + hc[c1]) / 2;
197
- const ext = [j === 0 ? 0 : hEdge(0, 1), i === NS - 1 ? 0 : hEdge(1, 2), j === NA - 1 ? 0 : hEdge(2, 3), hEdge(3, 0)];
198
- const poly = offsetPoly(q2, ext);
199
- segs.push({ o: C, u, v, poly, t: 2 * h0, grad: [gu, gv], curve });
200
- for (const [x, y] of poly) {
201
- const z = curve[0] + curve[1] * x + curve[2] * y + 0.5 * (curve[3] * x * x + 2 * curve[4] * x * y + curve[5] * y * y);
202
- outline.push(add(add(add(C, mul(u, x)), mul(v, y)), mul(n, z)));
203
- }
204
- }
205
- }
206
- // (mid-surface for tools: s 0..1, a -1..1)
207
- const mid = (s, a) => ({ p: P(clamp01(s) * STEPS, a), n: Nrm(clamp01(s) * STEPS, a) });
208
- return { base, along: norm(sub(sp.tip, base)), L, W, segs, pts: outline, mid, tip: sp.tip, type };
209
- }
210
-
211
- // least squares: argmin |A m - z| (normal equations, Gaussian elimination with partial pivoting)
212
- function lsq(A, z) {
213
- const n = A[0].length;
214
- const M = Array.from({ length: n }, () => new Array(n + 1).fill(0));
215
- for (let r = 0; r < A.length; r++) for (let i = 0; i < n; i++) { for (let j = 0; j < n; j++) M[i][j] += A[r][i] * A[r][j]; M[i][n] += A[r][i] * z[r]; }
216
- for (let c = 0; c < n; c++) {
217
- let pr = c;
218
- for (let r = c + 1; r < n; r++) if (Math.abs(M[r][c]) > Math.abs(M[pr][c])) pr = r;
219
- [M[c], M[pr]] = [M[pr], M[c]];
220
- const d = M[c][c] || 1e-30;
221
- for (let r = 0; r < n; r++) if (r !== c) { const f = M[r][c] / d; for (let j = c; j <= n; j++) M[r][j] -= f * M[c][j]; }
222
- }
223
- return M.map((row, i) => row[n] / (row[i] || 1e-30));
224
- }
225
-
226
- // a convex polygon (2D) with each edge k pushed out by ext[k]
227
- function offsetPoly(q, ext) {
228
- const n = q.length;
229
- let area = 0;
230
- for (let k = 0; k < n; k++) { const [x0, y0] = q[k], [x1, y1] = q[(k + 1) % n]; area += x0 * y1 - x1 * y0; }
231
- const sg = area > 0 ? 1 : -1;
232
- const lines = q.map((p, k) => {
233
- const p1 = q[(k + 1) % n], dx = p1[0] - p[0], dy = p1[1] - p[1], l = Math.hypot(dx, dy) || 1;
234
- return { px: p[0] + ((sg * dy) / l) * ext[k], py: p[1] - ((sg * dx) / l) * ext[k], dx: dx / l, dy: dy / l };
235
- });
236
- return q.map((_, k) => {
237
- const A = lines[(k + n - 1) % n], B = lines[k], den = A.dx * B.dy - A.dy * B.dx;
238
- if (Math.abs(den) < 1e-9) return [B.px, B.py];
239
- const t = ((B.px - A.px) * B.dy - (B.py - A.py) * B.dx) / den;
240
- return [A.px + A.dx * t, A.py + A.dy * t];
241
- });
242
- }
@@ -1,161 +0,0 @@
1
- // Domestic pig (Sus scrofa domesticus). Cloven-hoofed (two main claws and two dew claws per foot,
2
- // on the cow's hoof-bone rig), a long fat barrel on short legs, the wedge head with the flat rostral
3
- // disc on its own bone, small deep-set eyes with round pupils and pale lashes, erect / semi / lop
4
- // ears per breed, and the corkscrew tail. Bare skin (material 4, subsurface-lit) under sparse
5
- // bristles. Seeded breeds (variants): Large White / Yorkshire (default), Landrace, Duroc, Hampshire,
6
- // Berkshire, spotted (Gloucester Old Spot / Pietrain).
7
- // Behaviours: rooting, sniffing with the disc, grunting, tail curling and wagging, flopping onto the
8
- // side to lie, the waddling trot, bouncing piglets; attack: a shoulder shove and bite, the boar's
9
- // upward tusk slash.
10
- import { pigRig, HEAD_O } from './rig.js';
11
- import { sculptPig, EYE } from './sculpt.js';
12
- import { pigRegions } from './regions.js';
13
- import { pigCoat } from './coat.js';
14
- import { srgb } from '../../core/build/coatKit.js';
15
- import { QUALITY } from '../../core/build/pipeline.js';
16
- import { rng } from '../../core/math/vec.js';
17
- import { motion } from './motion.js';
18
-
19
- const pick = (R, table) => {
20
- let x = R() * table.reduce((s, [, w]) => s + w, 0);
21
- for (const [k, w] of table) { x -= w; if (x <= 0) return k; }
22
- return table[table.length - 1][0];
23
- };
24
-
25
- // Breeds: withers height of an adult sow (boars ~5-10 % taller), ears, face, build
26
- // (a finisher of 0.72 m is the reference individual)
27
- const BREED = {
28
- largewhite: { name: 'Large White / Yorkshire', h: [0.7, 0.9], ear: 'erect', dish: 0.35, snout: 1.0, length: 1.0, legs: 1.0, girth: 1.0, ham: 1.0, earSize: 1.0 },
29
- landrace: { name: 'Landrace', h: [0.68, 0.88], ear: 'lop', dish: 0.0, snout: 1.1, length: 1.08, legs: 0.98, girth: 0.97, ham: 0.95, earSize: 1.05 },
30
- duroc: { name: 'Duroc', h: [0.72, 0.92], ear: 'semi', dish: 0.25, snout: 1.0, length: 0.98, legs: 1.02, girth: 1.04, ham: 1.1, earSize: 0.95 },
31
- hampshire: { name: 'Hampshire', h: [0.7, 0.88], ear: 'erect', dish: 0.15, snout: 1.02, length: 0.98, legs: 1.0, girth: 1.02, ham: 1.08, earSize: 0.9 },
32
- berkshire: { name: 'Berkshire', h: [0.64, 0.82], ear: 'erect', dish: 0.9, snout: 0.86, length: 0.96, legs: 0.96, girth: 1.03, ham: 1.02, earSize: 0.9 },
33
- spotted: { name: 'Spotted (Gloucester Old Spot)', h: [0.7, 0.88], ear: 'lop', dish: 0.2, snout: 1.0, length: 1.0, legs: 0.98, girth: 1.05, ham: 1.0, earSize: 1.0 },
34
- };
35
- const VARIANT_KEYS = Object.keys(BREED);
36
-
37
- export default {
38
- id: 'pig',
39
- name: 'Pig',
40
- latin: 'Sus scrofa domesticus',
41
- group: 'hooves',
42
- plan: 'quadruped',
43
- covering: 'skin',
44
- variants: VARIANT_KEYS.map((id) => ({ id, name: BREED[id].name, latin: 'Sus scrofa domesticus' })),
45
-
46
- // Seeded individual. opts.variant picks the breed (default Large White); sex: sow (teat row, a
47
- // sagging belly with age) or boar (heavier shoulders and neck shield, visible small tusks, sheath
48
- // and testes); age: adult (finisher to mature breeding stock) or juvenile (a piglet: big head and
49
- // ears, short snout and body, fine hair, bouncy); size, build, ears, face, tail curl side, coat
50
- // shade, mud, spots / belt / points.
51
- variation(R0, o) {
52
- const R = rng(Math.floor(R0() * 4294967296) ^ Math.imul(o.seed ?? 1, 0x9e3779b1) ^ 0x5bd1e995);
53
- const variant = BREED[o.variant] ? o.variant : 'largewhite';
54
- const B = BREED[variant];
55
- const sex = o.sex || (R() < 0.6 ? 'female' : 'male');
56
- const age = o.age || 'adult';
57
- const piglet = age === 'juvenile';
58
- const male = sex === 'male';
59
- const g = () => (R() + R() + R() - 1.5) / 1.5; // ~[-1, 1], peaked
60
- // maturity: 0 finisher (6 months) .. 1 mature breeding sow / boar
61
- const mature = piglet ? 0 : Math.pow(R(), 1.4);
62
- const boar = male && !piglet ? 0.5 + 0.5 * mature : 0;
63
- const hRef = B.h[0] + (B.h[1] - B.h[0]) * mature;
64
- // (piglet: a weaner of 4-10 weeks, 0.30-0.45 m at the withers, built like side1 / threequarter3: a long, rounded
65
- // body with its underline tucked up, on thick straight legs, the head and ears still big; a newborn's
66
- // shape at a weaner's size, 1.42-1.49 withers heights long on thin stilts)
67
- const size = piglet ? (0.36 + 0.14 * R()) : (hRef / 0.74) * (male ? 1.06 : 1) * (1 + 0.03 * g()); // (0.74: the withers after the legs warp)
68
- const belly = male || piglet ? 0.1 : 0.2 + 0.45 * mature * (0.6 + 0.4 * R());
69
- // (a piglet's erect ears big and broad and held out to the sides, front1 / front2; its lop and semi-lop leaves
70
- // only a little bigger for its size. The head warp enlarges the ears too, at no cost in vertices: the mesh is
71
- // made in reference space, and 1.25 x 1.3 bigger leaves put a piglet over the vertex budgets)
72
- const erect = B.ear === 'erect';
73
- const earSize = B.earSize * (1 + 0.06 * g()) * (piglet ? (erect ? 1.12 : 1.02) : 1);
74
- return {
75
- variant, sex, age, size,
76
- boar, mature,
77
- belly,
78
- fat: 1 + 0.04 * g() + 0.03 * mature,
79
- ham: B.ham * (1 + 0.05 * g()) * (piglet ? 1.06 : 1),
80
- ear: B.ear, earSize, earWide: piglet && erect ? 1.18 : 1, earFwd: 0.5 * g(), earOut: 0.6 * g() + (piglet && erect ? 0.6 : 0),
81
- dish: B.dish * (0.8 + 0.4 * R()) + (piglet ? 0.1 : 0),
82
- snoutLen: B.snout * (1 + 0.04 * g()) * (piglet ? 0.85 : 1),
83
- tusks: male && !piglet ? 0.35 + 0.65 * mature * (0.7 + 0.3 * R()) : 0,
84
- teats: R() < 0.5 ? 7 : R() < 0.7 ? 6 : 8,
85
- tailSide: R() < 0.5 ? 1 : -1,
86
- docked: false,
87
- wrinkles: 0.3 + 0.5 * mature + (variant === 'berkshire' ? 0.2 : 0),
88
- bristle: (1 + 0.15 * g()) * (male ? 1.2 : 1),
89
- mud: R() < 0.35 ? 0.35 + 0.6 * R() : 0,
90
- // Hampshire belt edges: the front one across the head behind the eyes (head-local z), the back one
91
- // at mid-ribcage (bind z); coat.js says why
92
- belt: [-0.055 + 0.012 * g(), 0.02 + 0.04 * g()],
93
- blaze: 0.6 + 0.6 * R(), socks: 0.8 + 0.5 * R(),
94
- spotCount: 5 + Math.floor(R() * 7), spotSize: 0.8 + 0.5 * R(),
95
- coatShade: g(), coatLightness: 0.05 * g(),
96
- coatSeed: Math.floor(R() * 1e6),
97
- // thin parts (ears, the tail tip) at the coarse tiers: at least sqrt(3) cells thick (a slab
98
- // thinner than that slips between the samples: rows of pinholes in the ears at medium)
99
- minThick: 0.0027,
100
- // (the quality tier's cell scale: the ear leaf's tiles overlap by the rim radius the core inflates them to)
101
- tierRes: QUALITY[o.quality]?.res ?? 1,
102
- warps: [
103
- // (the head scale first: its centre is the unwarped head origin)
104
- // (piglet, with its tucked-up underline, sculpt.js: snout -> buttock 1.72-1.82 withers heights, belly 0.45-0.47
105
- // above the ground, head (disc -> ear base) 0.41-0.42, elbow 0.47, width 0.53: side1 1.73-1.76 / 0.47-0.49 /
106
- // 0.43 / 0.48, a weaner 1.8-1.9 long, research 2; an earlier piglet measured 1.42-1.49 long, 0.46 wide, elbow 0.50)
107
- { type: 'scaleAbout', c: HEAD_O, k: 1.13 * (1 + 0.03 * g()) * (piglet ? 1.24 : 1) * (male && !piglet ? 1.05 : 1), r0: 0.12, r1: 0.24 },
108
- { type: 'legs', k: 1.06 * B.legs * (1 + 0.045 * g()) * (piglet ? 1.19 : 1), top: 0.36 },
109
- { type: 'length', k: 0.95 * B.length * (1 + 0.045 * g()) * (piglet ? 1.16 : 1) * (1 + 0.03 * mature), z0: -0.42, z1: 0.3 },
110
- { type: 'girth', k: B.girth * (1 + 0.06 * g()) * (piglet ? 0.95 : 1) * (1 + 0.04 * mature), cy: 0.52, z0: -0.55, z1: 0.36 },
111
- ...(boar > 0 ? [{ type: 'girth', k: 1 + 0.07 * boar, cy: 0.55, z0: 0.12, z1: 0.5 }] : []),
112
- ],
113
- };
114
- },
115
- rig: (params) => pigRig(params),
116
- sculpt: (m, rig, params) => sculptPig(m, rig, params),
117
- regions: pigRegions,
118
- coat: pigCoat,
119
- eyeSpecs: (params) => [1, -1].map((side) => ({ side, spec: EYE, headOrigin: HEAD_O, bone: 'head', look: eyeLook(params) })),
120
- motion,
121
- // (a piglet's hair is finer and denser than a finisher's bristles: side1, threequarter3, front2 show a pale
122
- // velvet over the skin, no single hairs. On the adult grid, 1.85 mm cells, a piglet's short hairs stacked
123
- // every shell into one crisp speck: 6.6-9.5 % bright specks on a lit cheek; on a finer grid each
124
- // hair is below a pixel from half a metre on and the shells draw their expected coverage, a haze)
125
- // (and the Duroc's longer red-gold hair sparser, face3: individual hairs, not a fine speckle)
126
- render: (params) => ({ ...RENDER, strandDensity: params && params.age === 'juvenile' ? PIGLET_STRANDS : params && params.variant === 'duroc' ? 3400 : RENDER.strandDensity }),
127
- };
128
- // (strands on a 12000 /m grid (piglets 13000): the shells draw a bristle 0.3 of its cell wide, and the hair
129
- // shader lights it darker than the wrapped skin near the terminator, so the 6000 grid's 0.25 mm hairs drew a dark
130
- // hatching over the face from half a metre; on the finer grid they fall below a pixel there and blend to a faint
131
- // haze, single pale hairs showing only up close and in the silhouette fins. skinScatter less red: the wrap past the
132
- // terminator tinted the pale skin brick; it is also the colour of the light through the ears, coat.js)
133
- const RENDER = { markColor: srgb(0x3a2a28), strandDensity: 12000, skinScatter: [0.86, 0.58, 0.52, 0.42], skinTrans: [0, 1], clumpDensity: 1, shellScale: 1, finWidth: 0.35, raiseLen: [0.02, 0.04] };
134
- const PIGLET_STRANDS = 13000;
135
-
136
- // Round pupil (slightly horizontally oval), brown iris (light amber to deep chocolate; a few blue),
137
- // sclera hidden, pink or dark lids.
138
- // (the amber iris read olive-green in the showcase's daylight; the photos show warm mid to dark brown)
139
- const IRISES = [
140
- { inner: 0x3a2214, mid: 0x6a4026, hi: 0x8c5a36, outer: 0x24140c }, // brown
141
- { inner: 0x4a2c16, mid: 0x7c4c2a, hi: 0x9c6a3e, outer: 0x2e1a0c }, // light brown
142
- { inner: 0x1e120a, mid: 0x321e12, hi: 0x4c2e1c, outer: 0x120a06 }, // dark chocolate
143
- { inner: 0x4a5a66, mid: 0x7a8c98, hi: 0x9aacb6, outer: 0x2e3840 }, // blue-grey
144
- ];
145
- function eyeLook(params) {
146
- const s = ((params.coatSeed || 0) % 100) / 100;
147
- // (blue-grey only in the white breeds; a Duroc's blue-grey iris read milky in daylight)
148
- const pinkBreed = !params.variant || params.variant === 'largewhite' || params.variant === 'landrace' || params.variant === 'spotted';
149
- const ir = IRISES[s < 0.5 ? 0 : s < 0.75 ? 1 : s < 0.95 || !pinkBreed ? 2 : 3];
150
- const dark = params.variant === 'berkshire' || params.variant === 'hampshire';
151
- return {
152
- pupil: 'round',
153
- lids: 'mammal',
154
- iris: { inner: srgb(ir.inner), mid: srgb(ir.mid), hi: srgb(ir.hi), outer: srgb(ir.outer) },
155
- sclera: { color: [0.6, 0.55, 0.52], visible: false },
156
- // (the Duroc's lids its red skin, coat.js COATS.red body #8A5846 in linear: the pink of the white
157
- // breeds drew a pale lilac disc over the eye in a blink, in the shade under the ear)
158
- lidColor: dark ? [0.06, 0.05, 0.05] : params.variant === 'duroc' ? [0.25, 0.1, 0.065] : [0.42, 0.22, 0.2],
159
- pupilSize: [0.2, 0.42],
160
- };
161
- }
@@ -1,105 +0,0 @@
1
- // Pig motion data for the quadruped engine (schema: src/core/motion/quadruped.js).
2
- // Numbers are for the reference individual (params.size = 1, a 0.72 m Large White finisher); the
3
- // engine scales them by dynamic similarity for piglets and big sows / boars.
4
- //
5
- // Gaits: lateral-sequence walk (Yucatan minipig and 100-113 kg
6
- // finishers: 1.0-1.7 Hz, duty 0.65 -> 0.55, the hind -> fore interval 0.25 -> 0.3 of the stride),
7
- // a diagonal trot (duty 0.45 -> 0.40, 2.0-2.4 Hz), walk -> trot at Froude ~0.45 (~1.6 m/s), and a
8
- // short transverse gallop (LH, RH, LF, RF) from ~3.5 m/s up to the domestic top speed of ~5 m/s
9
- // (Heglund et al. 1974: trot -> gallop 4.7 m/s at 2.3 Hz for 110 kg). Heavy pigs roll their trunk
10
- // from side to side when walking and trotting (the waddle: behaviour hook).
11
- import { behaviour } from './behaviour.js';
12
-
13
- const G = (name, v, f, D, off, o) => ({ name, v, f, D, off, ...o });
14
- // torso sections for a breed's leg length (legs warp k, top 0.36 m) and width factor w
15
- const bodyFor = (legs, w) => {
16
- const dy = 0.36 * 1.06 * (legs - 1);
17
- return {
18
- chest: { y: 0.535 + dy, hh: 0.245, hw: 0.275 * w },
19
- // (mid and rump measured on the body: barrel 0.199-0.209, rump 0.225-0.24 m; the barrel
20
- // later widened to 0.21-0.22 over the ribs)
21
- mid: { y: 0.53 + dy, hh: 0.26, hw: 0.215 * w },
22
- pelvis: { y: 0.54 + dy, hh: 0.24, hw: 0.255 * w },
23
- rump: { z: -0.47, y: 0.57 + dy, hh: 0.21, hw: 0.24 * w },
24
- back: 0.05,
25
- };
26
- };
27
-
28
- export const motion = {
29
- maxSpeed: 5.2,
30
- accel: [2.5, 4.5],
31
- decel: 6,
32
- // a heavy, stiff-backed animal: a walking turn of 0.7 body lengths radius (research 4: 0.5-1), a
33
- // cornering limit of 0.3 g (2.2 / 6 were a dog's: 0.61 g, the gallop leaned 23 deg like a motorbike)
34
- turnRate: 1.6,
35
- latAccelMax: 3,
36
- gears: { walk: 1.0, trot: 2.4, gallop: 4.4 },
37
- gallopBlend: [3.4, 5.2],
38
- // name v f D [FL, FR, HL, HR]
39
- gaits: [
40
- G('walk', 0.0, 0.95, 0.66, [0.25, 0.75, 0.0, 0.5], { liftF: 0.04, liftH: 0.035, bobF: 0.01, bobH: 0.01, flex: 0, lat: 0.03, fold: 0.7, heel: 26, tail: 0, drop: 0 }),
41
- G('walk', 1.3, 1.55, 0.56, [0.3, 0.8, 0.0, 0.5], { liftF: 0.05, liftH: 0.045, bobF: 0.018, bobH: 0.018, flex: 0, lat: 0.04, fold: 0.85, heel: 36, tail: 0.1, drop: 0 }),
42
- G('trot', 1.7, 1.95, 0.46, [0.52, 0.02, 0.0, 0.5], { liftF: 0.065, liftH: 0.055, bobF: 0.022, bobH: 0.022, flex: 0.008, lat: 0.0, fold: 1.0, heel: 45, tail: 0.3, drop: 0.004 }),
43
- G('trot', 3.2, 2.35, 0.4, [0.52, 0.02, 0.0, 0.5], { liftF: 0.08, liftH: 0.07, bobF: 0.028, bobH: 0.028, flex: 0.012, lat: 0.0, fold: 1.1, heel: 50, tail: 0.4, drop: 0.008 }),
44
- G('gallop', 3.6, 2.45, 0.34, [0.55, 0.65, 0.0, 0.12], { liftF: 0.09, liftH: 0.08, bobF: 0.02, bobH: 0.028, flex: 0.06, lat: 0, fold: 1.2, heel: 45, tail: 0.6, drop: 0.012 }),
45
- G('gallop', 5.2, 2.75, 0.29, [0.56, 0.66, 0.0, 0.12], { liftF: 0.1, liftH: 0.09, bobF: 0.022, bobH: 0.032, flex: 0.08, lat: 0, fold: 1.3, heel: 40, tail: 0.8, drop: 0.02 }),
46
- ],
47
- feet: {
48
- // on the tips of the two main claws, fairly upright pasterns: the fetlock sinks a little under
49
- // load, the claws flip in swing
50
- front: { type: 'unguligrade', contact: 0.9, curl: 62, flex: 4, sink: 10, hoofFlex: 16, swingBack: 0.04 },
51
- hind: { type: 'unguligrade', contact: 0.9, curl: 62, flex: 4, sink: 9, hoofFlex: 16, swingBack: 0.015 },
52
- },
53
- stance: { width: 1, gallopWidth: 0.85, sprawl: 0, crouch: 0, scuff: [10, 20, 0] },
54
- // torso cross-sections (bind pose, reference size): centre height, half height, half width
55
- // (measured on the bind mesh at the girdles, shoulder and thigh muscles included: tools sec.mjs)
56
- body: bodyFor(1, 1),
57
-
58
-
59
- head: {
60
- // [speed, raise (m), reach (m), pitch (rad, + = nose down)]: low and forward, the snout near the
61
- // ground at the walk (side3, side4_walk, research 3), a little higher at the trot, stretched forward
62
- // when galloping
63
- carriage: [[0, 0, 0, 0], [1.0, -0.08, 0.03, 0.25], [2.4, -0.02, 0.03, 0.04], [4.4, -0.02, 0.05, 0.0]],
64
- stab: [[0, 0], [1.0, 0.15], [2.4, 0.35], [4.4, 0.3]],
65
- neckBend: 22, neckPivot: 0.5, yaw: 0.7, pitchUp: 0.5, pitchDown: 0.7, mouth: 'jawTip',
66
- },
67
- tail: {
68
- // [speed, pitch per segment from horizontal (deg), root -> tip]: the curled carriage (rig.js);
69
- // the behaviour hook adds the helix yaw and uncurls it when the pig rests or is afraid
70
- carriage: [
71
- [0.0, [14, -6, -24, -30, -32, -32, -32, -32, -32, -32]],
72
- [2.4, [18, -2, -20, -27, -30, -30, -30, -30, -30, -30]],
73
- [4.4, [24, 6, -12, -22, -26, -28, -28, -28, -28, -28]],
74
- ],
75
- stiffness: 1.6, sway: 3, flick: 0, wag: 0, swish: 0, curl: 0, balance: 0,
76
- radius: [0.012, 0.006],
77
- },
78
- ears: { rest: [0, 0], mobility: 0.8, speedFlatten: 0.15, twitch: 1.0, prick: 0.35 },
79
- breath: { rate: 0.35, amp: 0.008, pant: false, pantRate: 2.2, pantAmp: 0.015, heatSpeed: 5 },
80
- actions: {
81
- // rooting: the snout goes down to the ground in front of the forefeet (behaviour: nudges)
82
- eat: { style: 'graze', dropF: 0.06, dropH: 0, pitch: 0.95, ahead: 0.55 },
83
- drink: { dropF: 0.06, dropH: 0, pitch: 0.95, ahead: 0.55 },
84
- // poor jumpers: a low scrambling hop (research 4: they step or scramble over 0.3-0.5 m at most; the
85
- // body rises ~0.2 m, 0.4 s in the air; 0.42 m floated a 120 kg pig over its own withers height)
86
- jump: { height: 0.16, distance: 0.8, land: [0.24, 0.2] },
87
- sit: { dropH: 0.85 },
88
- // kneels on both carpi first, then drops the hindquarters, then flops onto the side
89
- lie: { style: 'lateral', down: 'front', up: 'front' },
90
- wallow: { style: 'lateral', down: 'front', up: 'front' },
91
- sleep: { style: 'lateral', down: 'front', up: 'front' },
92
- fold: { front: { z: -0.18, k: 1.45, beta: 0.9 } },
93
- idle: { shift: 0.7 },
94
- },
95
- // per breed: the torso sits lower on shorter legs (the legs warp, index.js BREED) and the
96
- // heavier-hammed breeds rest on wider sections (a body lying on its side)
97
- variants: {
98
- landrace: { body: bodyFor(0.98, 1) },
99
- duroc: { body: bodyFor(1.02, 1.07) },
100
- hampshire: { body: bodyFor(1, 1.05) },
101
- berkshire: { body: bodyFor(0.96, 1.03) },
102
- spotted: { body: bodyFor(0.98, 1.04) },
103
- },
104
- hooks: behaviour,
105
- };
@@ -1,100 +0,0 @@
1
- // Meshing plan: body at 7.8 mm (1.1 % of the withers height: the barrel's skin area is ~1.6x the
2
- // cheetah's), the face at 4.1 mm overlapping the body just behind the eyes and cross-faded, the feet
3
- // below mid-cannon at 3.5 mm (the cleft and the dew claws read), eyelid patches at 0.9 mm, and
4
- // separate surfaces: the lower jaw (lower lip, chin; rigid), the boar's tusks (1.2 mm, rigid on the jaw), the ears (rigid on the
5
- // ear bones, their thick roots buried in the head) and the corkscrew tail (its own skinned surface at
6
- // 2 mm, the root buried in the rump).
7
- //
8
- // Seams. The skinning relaxes the axial coordinate and solves the limb fields over each surface
9
- // separately, so two overlapping surfaces agree only where the weights do not depend on the
10
- // surface: the face cut lies in front of the jowls (the jowls touch the shoulders, and the body's
11
- // limb field reached into them while the head surface had no limb at all: the neck cracked open
12
- // when the head went down), the foot cut on the rigid cannon; the overlaps run on well past the
13
- // fade line (M), since the relaxation is one-sided next to a surface's open edge.
14
- import { EYE, earShape, tuskCones } from './sculpt.js';
15
- import { EAR_CELL } from './ears.js';
16
- import { HEAD_O, HZ, hl } from './rig.js';
17
- import { eyeFrameOf } from '../../core/sdf/eyeSocket.js';
18
- import { smoothstep, norm } from '../../core/math/vec.js';
19
-
20
- // The face is cut off across the head behind the eyes: below the eye line by a plane slanting forward
21
- // to the throat (in front of the jowls, see above), above it by a plane across the head axis 5 cm behind
22
- // the eyes. The upper plane keeps the switch line in front of the poll: behind it (the slanted plane
23
- // alone reached 16 cm back there, behind the occiput) both surfaces carry ~25 % neck2 weight, relaxed
24
- // differently on each, and they parted by up to 6 mm when the head lay on its side (lie, sleep, death).
25
- // Here both carry the head bone alone. (smooth minimum of the two signed distances, k 2 cm)
26
- export const NECK_CUT = { c: hl([0, 0, -0.035]), d: norm([0, 0.4, 1]), top: hl([0, 0, -0.05]), band: 0.012 };
27
- export const neckS = (x, y, z) => {
28
- const a = (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];
29
- const b = (y - NECK_CUT.top[1]) * HZ[1] + (z - NECK_CUT.top[2]) * HZ[2];
30
- const k = 0.02, h = Math.min(1, Math.max(0, 0.5 + (0.5 * (b - a)) / k));
31
- return b + (a - b) * h - k * h * (1 - h);
32
- };
33
- // feet: below mid-cannon
34
- export const FOOT_CUT = { y: 0.105, band: 0.007 };
35
-
36
- export const EYE_PATCH = { R: 0.023, B: 0.003, h: 0.0009, centres: [1, -1].map((s) => eyeFrameOf(EYE, HEAD_O, s).c) };
37
- export function eyePatchWeight(x, y, z) {
38
- let dmin = 1e9;
39
- for (const c of EYE_PATCH.centres) dmin = Math.min(dmin, Math.hypot(x - c[0], y - c[1], z - c[2]));
40
- return 1 - smoothstep(EYE_PATCH.R - EYE_PATCH.B, EYE_PATCH.R + EYE_PATCH.B, dmin);
41
- }
42
-
43
- function boxOf(pts, pad) {
44
- const mn = [1e9, 1e9, 1e9], mx = [-1e9, -1e9, -1e9];
45
- for (const p of pts) for (let i = 0; i < 3; i++) { mn[i] = Math.min(mn[i], p[i] - pad); mx[i] = Math.max(mx[i], p[i] + pad); }
46
- return [mn, mx];
47
- }
48
-
49
- export function pigRegions(rig, params, Q) {
50
- // (the cross-fade bands are wider than the coarser surface's cells at every tier)
51
- const r = Q.res, B = NECK_CUT.band * (0.6 + 0.4 * r), FB = FOOT_CUT.band * (0.3 + 0.7 * r), FY = FOOT_CUT.y;
52
- const J = rig.J;
53
- // eyelid patches at hero / high (0.9 / 1.2 mm) and, the pig's own, at medium (1.8 mm): the lids of the
54
- // 22 x 12 mm aperture meshed at the medium head cells (8.6 mm) came out as a jagged notch (Safari, phones)
55
- const patches = Q.eyePatches || r <= 2 ? EYE_PATCH.centres.map((c) => ({ c, R: EYE_PATCH.R, B: EYE_PATCH.B * Math.max(1, r), h: r > 1.5 ? 0.0021 : EYE_PATCH.h * Math.max(1, r) })) : [];
56
- const crowd = r >= 4;
57
- const hBody = 0.0078 * r, hHead = 0.0041 * r * (1 + 0.05 * (r - 1)), hFeet = 0.0035 * (crowd ? 4.2 : Math.min(r, 2.4));
58
- // overlapping surfaces sample the field on the same coarse spacing as the body (F x h ~ 4 body
59
- // cells): the primitive lists a vertex is skinned from are then culled alike on both sides
60
- const Fof = (h) => Math.max(3, Math.round((4 * hBody) / h));
61
- const M = Math.min(3.5 * hBody, 0.04);
62
- const tailPts = [J.tailBase];
63
- for (let i = 1; i <= 10; i++) if (J['tail' + i]) tailPts.push(J['tail' + i]);
64
- const [tmin, tmax] = boxOf(tailPts, 0.025);
65
- const [hmin, hmax] = boxOf([J.nose, J.jawHinge, J.jawTip, hl([0, 0.1, -0.05]), hl([0.12, -0.15, -0.05]), hl([-0.12, -0.15, -0.05])], 0.06);
66
- const ear = (S, h, F) => { const [bmin, bmax] = boxOf(earShape(J, params, S).pts, 0.05); return { name: 'ear' + S, part: 'ear' + S, bmin, bmax, h, F, rigidBone: 'ear' + S }; };
67
- // the boar's tusks: a small rigid surface each at 1.2 mm (x res), their roots buried in the lower lip (in the jaw's
68
- // 3 mm cells the 1.2-7 mm cone meshed as a crumpled blade)
69
- const tusks = (params.tusks || 0) > 0.05 ? [1, -1].map((s) => {
70
- const pts = []; for (const c of tuskCones(params, s)) pts.push(c.a, c.b);
71
- const [bmin, bmax] = boxOf(pts, 0.012);
72
- return { name: s > 0 ? 'tuskL' : 'tuskR', part: 'tusk', bmin, bmax, h: 0.0012 * r, F: 3, rigidBone: 'jaw' };
73
- }) : [];
74
- return {
75
- jobs: [
76
- [{ name: 'body', part: 'body', bmin: [-0.3, Math.max(-0.01, FY - FB - M - hBody), -0.72], bmax: [0.3, 0.84, 0.8], h: hBody, F: 4, clip: (x, y, z) => neckS(x, y, z) < B + M && y > FY - FB - M }],
77
- [
78
- { name: 'head', part: 'body', bmin: hmin, bmax: hmax, h: hHead, F: Fof(hHead), clip: (x, y, z) => neckS(x, y, z) > -B - M, patches },
79
- { name: 'jaw', part: 'jaw', bmin: [-0.1, 0.3, 0.5], bmax: [0.1, 0.62, 0.84], h: 0.003 * r * (r > 2 ? 0.8 : 1), F: 6, rigidBone: 'jaw' },
80
- // (the leaves are at least 1.8 of these cells thick at every tier, ears.js)
81
- ear('L', EAR_CELL * r, 3), ear('R', EAR_CELL * r, 3),
82
- ...tusks,
83
- ],
84
- [
85
- { name: 'feet', part: 'body', bmin: [-0.16, -0.01, -0.45], bmax: [0.16, FY + FB + M + hFeet, 0.45], h: hFeet, F: Fof(hFeet), clip: (x, y, z) => y < FY + FB + M },
86
- { name: 'tail', part: 'tail', bmin: tmin, bmax: tmax, h: 0.002 * Math.min(r, 3.6), F: 3 },
87
- ],
88
- ],
89
- fade(x, y, z, name, patch) {
90
- if (name === 'body') return (1 - smoothstep(-B, B, neckS(x, y, z))) * smoothstep(FY - FB, FY + FB, y);
91
- if (name === 'feet') return 1 - smoothstep(FY - FB, FY + FB, y);
92
- if (name === 'head') {
93
- let f = smoothstep(-B, B, neckS(x, y, z));
94
- if (patches.length) { const ew = eyePatchWeight(x, y, z); f *= patch ? ew : 1 - ew; }
95
- return f;
96
- }
97
- return 1;
98
- },
99
- };
100
- }