@bitefoundry/retrieviewer 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/ASSET-PROVENANCE.md +6 -0
  2. package/ASSETS-LICENSE.md +2 -1
  3. package/ATTRIBUTION.md +6 -1
  4. package/COMFORT-ART.md +65 -0
  5. package/DESKTOP-PLATFORMS.md +75 -0
  6. package/INSTALLING.md +8 -5
  7. package/PLUGIN.md +13 -10
  8. package/PREREQUISITES.md +95 -0
  9. package/PUPPY-MEMORY.md +102 -1
  10. package/README.ko.md +110 -0
  11. package/README.md +119 -58
  12. package/RELEASING.md +27 -14
  13. package/THIRD-PARTY-NOTICES.md +5 -3
  14. package/braille.mjs +35 -9
  15. package/examples/live.mjs +2 -2
  16. package/integrations/desktop/platform.mjs +27 -0
  17. package/integrations/linux-overlay/README.md +83 -0
  18. package/integrations/linux-overlay/overlay.py +1094 -0
  19. package/integrations/macos-overlay/README.md +83 -0
  20. package/integrations/macos-overlay/overlay.jxa +639 -0
  21. package/integrations/opencode/runtime.mjs +4 -4
  22. package/integrations/opencode/tui.tsx +1 -1
  23. package/integrations/windows-overlay/Overlay.cs +4 -4
  24. package/integrations/windows-overlay/desktop.mjs +40 -8
  25. package/integrations/windows-overlay/protocol.mjs +11 -7
  26. package/integrations/windows-overlay/worker.mjs +13 -7
  27. package/package.json +41 -14
  28. package/puppy-comfort-sprites.mjs +25 -0
  29. package/puppy-companion-comfort-q5.bin.gz +0 -0
  30. package/puppy-companion-comfort.json +77 -0
  31. package/puppy-companion-life.mjs +49 -16
  32. package/puppy-companion-objects.mjs +12 -0
  33. package/puppy-frame-predictive.mjs +15 -9
  34. package/puppy-frame-store.mjs +2 -2
  35. package/puppy-paper-world.mjs +14 -0
  36. package/puppy-paper.mjs +65 -14
  37. package/retrieviewer-cli.mjs +10 -3
  38. package/retrieviewer-plugin.d.mts +1 -1
  39. package/retrieviewer-plugin.mjs +1 -1
  40. package/retrieviewer.d.mts +10 -4
  41. package/retrieviewer.mjs +20 -14
  42. package/locomotion-core.mjs +0 -21
  43. package/locomotion-puppy.animal +0 -0
  44. package/vendor/procedural-animals/package.json +0 -40
  45. package/vendor/procedural-animals/src/animal.js +0 -146
  46. package/vendor/procedural-animals/src/bake.js +0 -51
  47. package/vendor/procedural-animals/src/build.js +0 -81
  48. package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
  49. package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
  50. package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
  51. package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
  52. package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
  53. package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
  54. package/vendor/procedural-animals/src/core/build/seams.js +0 -183
  55. package/vendor/procedural-animals/src/core/build/warp.js +0 -112
  56. package/vendor/procedural-animals/src/core/build/weights.js +0 -393
  57. package/vendor/procedural-animals/src/core/math/vec.js +0 -81
  58. package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
  59. package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
  60. package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
  61. package/vendor/procedural-animals/src/core/motion/common.js +0 -158
  62. package/vendor/procedural-animals/src/core/motion/index.js +0 -22
  63. package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
  64. package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
  65. package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
  66. package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
  67. package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
  68. package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
  69. package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
  70. package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
  71. package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
  72. package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
  73. package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
  74. package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
  75. package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
  76. package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
  77. package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
  78. package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
  79. package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
  80. package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
  81. package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
  82. package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
  83. package/vendor/procedural-animals/src/index.d.ts +0 -98
  84. package/vendor/procedural-animals/src/index.js +0 -29
  85. package/vendor/procedural-animals/src/registry.js +0 -48
  86. package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
  87. package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
  88. package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
  89. package/vendor/procedural-animals/src/species/bear/index.js +0 -139
  90. package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
  91. package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
  92. package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
  93. package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
  94. package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
  95. package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
  96. package/vendor/procedural-animals/src/species/boar/index.js +0 -110
  97. package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
  98. package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
  99. package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
  100. package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
  101. package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
  102. package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
  103. package/vendor/procedural-animals/src/species/cat/index.js +0 -211
  104. package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
  105. package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
  106. package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
  107. package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
  108. package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
  109. package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
  110. package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
  111. package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
  112. package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
  113. package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
  114. package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
  115. package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
  116. package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
  117. package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
  118. package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
  119. package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
  120. package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
  121. package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
  122. package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
  123. package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
  124. package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
  125. package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
  126. package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
  127. package/vendor/procedural-animals/src/species/cow/index.js +0 -118
  128. package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
  129. package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
  130. package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
  131. package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
  132. package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
  133. package/vendor/procedural-animals/src/species/crow/index.js +0 -70
  134. package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
  135. package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
  136. package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
  137. package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
  138. package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
  139. package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
  140. package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
  141. package/vendor/procedural-animals/src/species/deer/index.js +0 -106
  142. package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
  143. package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
  144. package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
  145. package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
  146. package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
  147. package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
  148. package/vendor/procedural-animals/src/species/dog/index.js +0 -144
  149. package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
  150. package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
  151. package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
  152. package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
  153. package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
  154. package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
  155. package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
  156. package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
  157. package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
  158. package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
  159. package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
  160. package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
  161. package/vendor/procedural-animals/src/species/fish/index.js +0 -88
  162. package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
  163. package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
  164. package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
  165. package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
  166. package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
  167. package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
  168. package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
  169. package/vendor/procedural-animals/src/species/fox/index.js +0 -120
  170. package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
  171. package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
  172. package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
  173. package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
  174. package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
  175. package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
  176. package/vendor/procedural-animals/src/species/frog/index.js +0 -97
  177. package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
  178. package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
  179. package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
  180. package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
  181. package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
  182. package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
  183. package/vendor/procedural-animals/src/species/goat/index.js +0 -149
  184. package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
  185. package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
  186. package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
  187. package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
  188. package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
  189. package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
  190. package/vendor/procedural-animals/src/species/horse/index.js +0 -80
  191. package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
  192. package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
  193. package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
  194. package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
  195. package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
  196. package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
  197. package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
  198. package/vendor/procedural-animals/src/species/lion/index.js +0 -111
  199. package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
  200. package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
  201. package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
  202. package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
  203. package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
  204. package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
  205. package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
  206. package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
  207. package/vendor/procedural-animals/src/species/pig/index.js +0 -161
  208. package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
  209. package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
  210. package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
  211. package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
  212. package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
  213. package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
  214. package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
  215. package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
  216. package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
  217. package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
  218. package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
  219. package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
  220. package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
  221. package/vendor/procedural-animals/src/species/rat/index.js +0 -111
  222. package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
  223. package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
  224. package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
  225. package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
  226. package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
  227. package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
  228. package/vendor/procedural-animals/src/species/shark/index.js +0 -104
  229. package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
  230. package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
  231. package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
  232. package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
  233. package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
  234. package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
  235. package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
  236. package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
  237. package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
  238. package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
  239. package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
  240. package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
  241. package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
  242. package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
  243. package/vendor/procedural-animals/src/species/snake/index.js +0 -73
  244. package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
  245. package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
  246. package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
  247. package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
  248. package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
  249. package/vendor/procedural-animals/src/species/spider/index.js +0 -78
  250. package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
  251. package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
  252. package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
  253. package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
  254. package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
  255. package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
  256. package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
  257. package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
  258. package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
  259. package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
  260. package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
  261. package/vendor/procedural-animals/src/worker.js +0 -29
@@ -1,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
- }