@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,152 +0,0 @@
1
- // Pig skeleton in bind pose (metres). Forward = +Z, up = +Y, the animal's left = +X.
2
- // Reference individual: a Large White finisher / young gilt, 0.72 m at the withers, ~120 kg.
3
- // Landmarks from side1.jpg / side2.jpg (normalised to the withers height) and the
4
- // porcine limb table: point of shoulder 0.48 m, elbow 0.31, carpus 0.15, fore fetlock
5
- // 0.065, stifle 0.36, hock 0.17 (point of hock 0.21), hind fetlock 0.065; snout tip -> buttock
6
- // 1.35 m (1.87 x withers), belly 0.30 m above the ground.
7
- //
8
- // Hooves: like the cow, a hoof bone per leg below the pastern (fpaw / hpaw = pastern: fetlock ->
9
- // coffin joint; fhoof / hhoof = the two main claws: coffin joint -> toe), the dew claws ride on the
10
- // pastern. A snout bone carries the rostral disc (twitches and wiggles while sniffing).
11
- //
12
- // The tail is a corkscrew (pigTail below): the rest chain is the curled tail, which the behaviour
13
- // hook holds rigidly on the root bone at runtime (no stretch); uncurling (resting, fear) blends to
14
- // the engine's hanging tail.
15
- import { buildRig } from '../../core/rig/rig.js';
16
- import { quadrupedBones, quadrupedLimbs } from '../../core/rig/quadruped.js';
17
- import { EAR_BASE, earSpine } from './ears.js';
18
-
19
- export const TAIL_SEGS = 10;
20
- export const TAIL_LENS = [0.052, 0.03, 0.025, 0.023, 0.022, 0.021, 0.02, 0.019, 0.018, 0.017];
21
- // Head frame: modelled along its own axis (poll -> snout disc), pitched 35 degrees nose-down in the
22
- // bind pose (relaxed standing carriage, research 3: snout 30-45 deg below horizontal). Head-local
23
- // coordinates: x lateral, y dorsal (forehead side), z along the head toward the disc; origin on the
24
- // axis level with the eyes.
25
- export const HEAD_PITCH = (35 * Math.PI) / 180;
26
- export const HZ = [0, -Math.sin(HEAD_PITCH), Math.cos(HEAD_PITCH)];
27
- export const HY = [0, Math.cos(HEAD_PITCH), Math.sin(HEAD_PITCH)];
28
- export const HEAD_O = [0, 0.585, 0.59];
29
- export const SNOUT_K = 1.15; // (the sculpt's snout length factor at params.snoutLen = 1)
30
- export const hl = (v) => [HEAD_O[0] + v[0], HEAD_O[1] + v[1] * HY[1] + v[2] * HZ[1], HEAD_O[2] + v[1] * HY[2] + v[2] * HZ[2]];
31
- export const hdir = (v) => [v[0], v[1] * HY[1] + v[2] * HZ[1], v[1] * HY[2] + v[2] * HZ[2]];
32
-
33
- // ears: the root on the head and the leaf geometry are in ears.js (the ear bone runs from the root to the
34
- // leaf's tip, wherever the leaf's bend puts it)
35
- export function pigJoints(params = {}) {
36
- const K = (params.snoutLen ?? 1) * SNOUT_K;
37
- const sz = (z) => (z > 0.06 ? 0.06 + (z - 0.06) * K : z);
38
- const eb = hl(EAR_BASE);
39
- const J = {
40
- nose: hl([0, -0.012, sz(0.198)]),
41
- snoutBase: hl([0, 0.0, sz(0.12)]),
42
- occiput: hl([0, -0.015, -0.115]),
43
- neckMid: [0, 0.59, 0.415],
44
- neckBase: [0, 0.56, 0.33],
45
- chestMid: [0, 0.625, 0.16],
46
- thoraxRear: [0, 0.645, -0.02],
47
- lumbarMid: [0, 0.655, -0.19],
48
- lumbosacral: [0, 0.66, -0.36],
49
- tailBase: [0, 0.69, -0.59],
50
- // fore: scapula sloping ~65 deg, the humerus down and back, radius and cannon near vertical,
51
- // an upright pastern (pigs stand on the tips of the claws)
52
- scapTopL: [0.065, 0.66, 0.255],
53
- shoulderL: [0.105, 0.48, 0.395],
54
- elbowL: [0.1, 0.31, 0.29],
55
- wristL: [0.088, 0.15, 0.305],
56
- mcpL: [0.083, 0.064, 0.322],
57
- fcoffinL: [0.083, 0.028, 0.345],
58
- ftoeL: [0.083, 0.002, 0.388],
59
- // hind: hip joint, stifle, hock, fetlock, coffin joint, toe
60
- hipL: [0.09, 0.55, -0.4],
61
- kneeL: [0.11, 0.36, -0.27],
62
- hockL: [0.086, 0.17, -0.395],
63
- mtpL: [0.082, 0.064, -0.362],
64
- hcoffinL: [0.082, 0.028, -0.338],
65
- htoeL: [0.082, 0.002, -0.296],
66
- jawHinge: hl([0, -0.052, -0.06]),
67
- jawTip: hl([0, -0.085, sz(0.15)]),
68
- earBaseL: eb,
69
- earTipL: earSpine(eb, 'L', params).tip,
70
- };
71
- pigTail(J, params);
72
- return J;
73
- }
74
-
75
- // the bind tail: a corkscrew. The root runs back from the tail head, then every joint turns by the
76
- // same relative rotation (TAIL_BETA about the local axis cos(TAU) lateral + sin(TAU) along), which
77
- // makes a helix: the loops roll down behind the buttocks and progress to one side (params.tailSide).
78
- // The behaviour hook keeps this shape rigid on the root bone when the tail is curled, and blends
79
- // toward the engine's hanging chain when it uncurls.
80
- export const TAIL_ROOT_PITCH = 4; // deg above horizontal
81
- export const TAIL_BETA = 58; // deg per joint (curling up)
82
- export const TAIL_TAU = 0.45; // rad (helix lead)
83
- const rot = (v, a, ang) => {
84
- const c = Math.cos(ang), s = Math.sin(ang), d = a[0] * v[0] + a[1] * v[1] + a[2] * v[2];
85
- const cr = [a[1] * v[2] - a[2] * v[1], a[2] * v[0] - a[0] * v[2], a[0] * v[1] - a[1] * v[0]];
86
- return [0, 1, 2].map((i) => v[i] * c + cr[i] * s + a[i] * d * (1 - c));
87
- };
88
- const norm3 = (v) => { const l = Math.hypot(v[0], v[1], v[2]) || 1; return [v[0] / l, v[1] / l, v[2] / l]; };
89
- export function pigTail(J, params = {}) {
90
- const n = TAIL_SEGS, side = params.tailSide ?? 1;
91
- const docked = params.docked ? 0.35 : 1;
92
- const r0 = (TAIL_ROOT_PITCH * Math.PI) / 180;
93
- let y = [0, Math.sin(r0), -Math.cos(r0)], x = [1, 0, 0];
94
- const beta = (TAIL_BETA * Math.PI) / 180, tau = TAIL_TAU * side;
95
- let p = J.tailBase.slice();
96
- J.tail0 = p.slice();
97
- for (let i = 0; i < n; i++) {
98
- const l = TAIL_LENS[i] * (i < 2 ? 1 : docked);
99
- p = [p[0] + y[0] * l, p[1] + y[1] * l, p[2] + y[2] * l];
100
- J['tail' + (i + 1)] = p;
101
- const ax = norm3([x[0] * Math.cos(tau) + y[0] * Math.sin(tau), x[1] * Math.cos(tau) + y[1] * Math.sin(tau), x[2] * Math.cos(tau) + y[2] * Math.sin(tau)]);
102
- // (the root bends less into the first loop)
103
- const b = beta * (i === 0 ? 0.6 : 1);
104
- y = rot(y, ax, b); x = rot(x, ax, b);
105
- }
106
- return J;
107
- }
108
-
109
- export function pigBones() {
110
- const b = quadrupedBones({ tailSegs: TAIL_SEGS, ears: true, jaw: true, extra: [['snout', 'snoutBase', 'nose', 'head', { region: 'head', group: 'snout' }]] });
111
- for (const d of b) {
112
- if (d[0] === 'fpaw{S}') { d[2] = 'fcoffin{S}'; d[4] = { region: 'limb', group: 'F{S}' }; }
113
- if (d[0] === 'hpaw{S}') { d[2] = 'hcoffin{S}'; d[4] = { region: 'limb', group: 'H{S}' }; }
114
- }
115
- b.push(
116
- ['fhoof{S}', 'fcoffin{S}', 'ftoe{S}', 'fpaw{S}', { region: 'foot', group: 'F{S}' }],
117
- ['hhoof{S}', 'hcoffin{S}', 'htoe{S}', 'hpaw{S}', { region: 'foot', group: 'H{S}' }],
118
- );
119
- return b;
120
- }
121
-
122
- export function pigRig(params = {}, J = pigJoints(params)) {
123
- const limbs = quadrupedLimbs({
124
- // (the short legs are sunk deep in the fat body: the limb cores stop well below the girdles)
125
- front: { tCore: 0.62, aCore: 0.05, aBody: -0.09, midX: 0.05 },
126
- hind: { tCore: 0.55, aCore: 0.022, aBody: -0.08, midX: 0.02 },
127
- });
128
- for (const L of Object.values(limbs)) { L.bones.push((L.front ? 'fhoof' : 'hhoof') + L.S); L.distal.push((L.front ? 'fhoof' : 'hhoof') + L.S); }
129
- return buildRig({
130
- joints: J,
131
- unit: 0.72 / 0.76,
132
- headOrigin: HEAD_O,
133
- bones: pigBones(),
134
- axial: {
135
- points: ['nose', 'occiput', 'neckMid', 'neckBase', 'chestMid', 'thoraxRear', 'lumbarMid', 'lumbosacral', 'tailBase', ...Array.from({ length: TAIL_SEGS }, (_, i) => 'tail' + (i + 1))],
136
- bones: ['head', 'neck2', 'neck1', 'chest', 'spine3', 'spine2', 'spine1', 'pelvis', ...Array.from({ length: TAIL_SEGS }, (_, i) => 'tail' + i)],
137
- // the heavy jowl hangs far below the axis: the skull's influence runs back into the throat;
138
- // the short thick neck blends broadly into the shoulders
139
- blend: { 1: [-0.05, 0.1, 2], 2: [-0.05, 0.05, 1], 3: [-0.08, 0.08, 1] },
140
- bodyTail: 0, // the thin tail is set on the rump: body skin blends into it only at the root
141
- },
142
- limbs,
143
- appendages: [
144
- { group: 'earL', bone: 'earL', blend: [-0.002, 0.005] },
145
- { group: 'earR', bone: 'earR', blend: [-0.002, 0.005] },
146
- { group: 'snout', bone: 'snout', blend: [-0.01, 0.02] },
147
- // the skin under the chin rides on the jaw and blends into the throat (sculpt.js 'jawskin')
148
- { group: 'jawskin', bone: 'jaw', blend: [-0.004, 0.012] },
149
- ],
150
- webTags: ['flankfold', 'thighfront', 'scapmuscle', 'pectoral', 'forearmweb', 'ham'],
151
- });
152
- }
@@ -1,382 +0,0 @@
1
- // The pig, sculpted as a signed distance field.
2
- // Every primitive is attached to a bone (skinning) and a group (axial / limb / ear / snout / jaw).
3
- // The head is modelled in its own frame (rig.js: hl()), measured from the profile and frontal
4
- // references (face1, front1, face2); the body relative to the joints so the sculpt follows the
5
- // skeleton.
6
- //
7
- // A pig is a barrel on four short legs sunk into it: the shoulders, the back and the hams are one
8
- // smooth fat-covered mass (no visible withers, no waist), the neck is hidden in the jowls, and the
9
- // wedge-shaped head ends in the flat rostral disc with its two nostrils.
10
- //
11
- // Individual knobs (params, see index.js): boar (0 sow .. 1 boar: shoulder shield, crest over the
12
- // neck, bigger jowls, tusks, sheath and testes instead of the teat row), belly (0 lean .. 1 a sow's
13
- // sagging belly), teats (pairs), ear ('erect' | 'semi' | 'lop'), earSize, dish (dished face,
14
- // Berkshire), snoutLen, ham (fullness of the hams), piglet.
15
- import { HEAD_O, HZ, HY, hl, hdir, TAIL_SEGS, SNOUT_K } from './rig.js';
16
- import { add, sub, mul, lerp, norm, cross } from '../../core/math/vec.js';
17
- import { eyeFrameOf, apertureTiltAlong } from '../../core/sdf/eyeSocket.js';
18
- import { earLeaf } from './ears.js';
19
-
20
- // Eye (head-local centre -> offset from HEAD_O): globe ~23 mm, visible opening ~20 x 11 mm, under
21
- // a fat-padded brow, at the side of a face that narrows in front of it (face2, front1: both eyes
22
- // show from straight in front). EYE_OUT moves the ball out along its axis so its front sits at the
23
- // skin (the lids are the surface, not a tunnel through the brow and jowl: AUTHORING section 7).
24
- const EYE_LOCAL = [0.058, 0.026, 0.006];
25
- const EYE_FWD = 40; // deg forward of lateral (along the head)
26
- const EYE_OUT = 0.016;
27
- const eyeDir = (() => {
28
- const a = (EYE_FWD * Math.PI) / 180;
29
- return norm(add(add([Math.cos(a), 0, 0], mul(HZ, Math.sin(a))), mul(HY, 0.1)));
30
- })();
31
- // (the aperture: 20 x 14 mm, a rounder opening than the 22 x 12 mm almond, which read as a narrow slit: front1,
32
- // face2 show round dark eyes with level lids)
33
- // (the 20 x 14 mm opening showed the whole round iris, a doll's eye; the photos (eye_lwshow_R,
34
- // eye_mochyn, eye_gifu) show a small almond, ~19 x 10.5 mm, with pointed corners, the upper lid hooding the top of
35
- // the iris: R 11.2 / d 6.0 mm)
36
- const EYE_BASE = {
37
- c: add(sub(hl(EYE_LOCAL), HEAD_O), mul(eyeDir, EYE_OUT)), r: 0.0128, back: 0.003, yaw: Math.atan2(eyeDir[0], eyeDir[2]), pitch: Math.asin(eyeDir[1]),
38
- lid: 0.0028, R: 0.0112, d: 0.006, off: 0.0006, tilt: 0, irisZ: 0.0074, irisR: 0.0088,
39
- };
40
- // the lid line level in the standing carriage (laid along the head axis, which is carried 35 deg
41
- // nose-down, and rolled 0.12 further, the almond sloped 24 deg down toward the snout: a sly, angry look; the
42
- // untilted frame is level, apertureTiltAlong(EYE_BASE, HEAD_O, HZ) - 0.12 was 0.44)
43
- // (a slight roll, the inner corner a little lower: eye_lwshow_R, eye_mochyn)
44
- EYE_BASE.tilt = 0.1;
45
- void apertureTiltAlong; void HZ;
46
- export const EYE = EYE_BASE;
47
-
48
- const X = [1, 0, 0];
49
- const UP = [0, 1, 0];
50
-
51
- // tusk centre line (head-local, left): the lower canine grows out of the jaw beside the snout and
52
- // curves up and back outside the upper lip
53
- // (rooted in the jaw a third of the way from the disc to the eye, out through the mouth line at the
54
- // side, then up and back clear of the lip)
55
- export function tuskPath(params, s) {
56
- const L = params.tusks || 0;
57
- const a = [0.03 * s, -0.078, 0.128];
58
- const b = [0.066 * s, -0.066, 0.132];
59
- const m = [0.077 * s, -0.052 + 0.014 * L, 0.13 - 0.008 * L];
60
- const c = [0.082 * s, -0.05 + 0.04 * L, 0.127 - 0.04 * L];
61
- return [a, b, m, c];
62
- }
63
- // the tusk as a smooth arched cone (reference space, the bind pose): a chain of round cones along a cubic Bezier
64
- // from just inside the lower lip (a little way from the root toward b) over b and m to the tip c, tapering from
65
- // 4.5-7 mm to a 1.2 mm point. Its own part, meshed finely (regions.js): in the jaw's 3 mm cells the 2-6 mm cone
66
- // meshed as a crumpled, faceted blade, and the lip crease painted round it.
67
- export const TUSK_N = 8;
68
- export function tuskCones(params, s) {
69
- const T = tuskPath(params, s).map(hl), L = params.tusks || 0;
70
- const P0 = lerp(T[0], T[1], 0.55), P1 = T[1], P2 = T[2], P3 = T[3];
71
- const at = (t) => { const u = 1 - t; return add(add(mul(P0, u * u * u), mul(P1, 3 * u * u * t)), add(mul(P2, 3 * u * t * t), mul(P3, t * t * t))); };
72
- const r0 = 0.0045 + 0.0025 * L, r1 = 0.0012;
73
- const rad = (t) => r1 + (r0 - r1) * (1 - Math.pow(t, 1.3));
74
- const out = [];
75
- for (let i = 0; i < TUSK_N; i++) { const t0 = i / TUSK_N, t1 = (i + 1) / TUSK_N; out.push({ a: at(t0), b: at(t1), ra: rad(t0), rb: rad(t1) }); }
76
- return out;
77
- }
78
-
79
- // Ear leaves (ears.js): the tiles of one smooth curved sheet, thick at the root and thinning to a round rim.
80
- // (Exported under the old name for the meshing plan and the tools.)
81
- export function earShape(J, params, S) {
82
- return earLeaf(J['earBase' + S], S, params);
83
- }
84
-
85
- // The eye in its socket (core sculptEyeSocket, plus the lids): an orbit hollow, the lid shell over the ball, a soft
86
- // roll of the upper lid along the top of the opening and a thinner lower lid, then the almond cut through them, so
87
- // the lid margins stand as rounded rims round the eye instead of a hole cut in a smooth shell (which read as a
88
- // ragged dark speck; eye_lwshow_R, eye_mochyn, eye_gifu: a thick, rounded upper lid with a fold above it, a
89
- // slim lower lid). The rolls are straight along the opening, so they sink into the ball toward the corners.
90
- function pigEye(m, s) {
91
- const E = EYE, ef = eyeFrameOf(E, HEAD_O, s), bone = 'head';
92
- const at = (u, v, w) => add(add(add(ef.c, mul(ef.x, u)), mul(ef.y, v)), mul(ef.z, w));
93
- m.ell({ bone, tag: 'orbit', c: at(0, 0.0015, 0.014), axis: ef.z, up: ef.y, r: [0.016, 0.0115, 0.008], k: 0.011, carve: true });
94
- m.sphere({ bone, tag: 'eyelid', c: ef.c, rad: E.r + E.lid, k: E.r * 0.4 });
95
- const h = E.R - E.d, rl = E.r + E.lid;
96
- const onShell = (y) => Math.sqrt(Math.max(0, rl * rl - y * y));
97
- // upper lid: a roll ~2 mm proud of the shell over the top of the opening
98
- const yu = E.off + h + 0.0016;
99
- m.ell({ bone, tag: 'lidroll', c: at(0, yu, onShell(yu) - 0.0012), axis: ef.z, up: ef.y, r: [0.0105, 0.0032, 0.0028], k: 0.003 });
100
- // lower lid: slimmer, ~1 mm proud
101
- const yl = E.off - h - 0.0012;
102
- // (soft and broad: a thinner roll meshed a droplet-shaped knot under the lid at medium's 2.1 mm eyelid cells)
103
- m.ell({ bone, tag: 'lidroll', c: at(0, yl, onShell(yl) - 0.0017), axis: ef.z, up: ef.y, r: [0.0088, 0.0028, 0.0026], k: 0.0035 });
104
- m.lens({ bone, tag: 'eyesocket', c: add(ef.c, mul(ef.y, E.off)), x: ef.x, y: ef.y, z: ef.z, R: E.R, d: E.d, zMin: -E.r * 0.16, zMax: E.r * 2, k: E.r * 0.18, carve: true });
105
- return ef;
106
- }
107
-
108
- export function sculptPig(m, rig, params = {}) {
109
- const J = rig.J;
110
- const piglet = params.age === 'juvenile';
111
- const boar = params.boar ?? 0;
112
- const belly = params.belly ?? 0.3;
113
- const hamK = params.ham ?? 1;
114
- const fat = params.fat ?? 1;
115
- const snoutK = (params.snoutLen ?? 1) * SNOUT_K;
116
- const dish = params.dish ?? 0.2;
117
-
118
- const ellY = (o) => {
119
- const y = norm(o.ydir);
120
- const lat = o.lateral || X;
121
- const z = norm(cross(lat, y));
122
- return m.ell({ ...o, axis: z, up: y, r: [o.r[0], o.r[1], o.r[2]] });
123
- };
124
- // ellipsoid in head-local coordinates: r = [lateral, dorsal, along the head]
125
- const H = { bone: 'head' };
126
- const hell = (o) => m.ell({ ...H, ...o, c: hl(o.c), axis: o.axisL ? norm(hdir(o.axisL)) : HZ, up: o.upL ? norm(hdir(o.upL)) : HY });
127
- const SN = { bone: 'snout', group: 'snout' };
128
- // snout-local along coordinate: the snout is longer or shorter per breed / individual (the
129
- // rostral end moves, the eyes stay)
130
- const sz = (z) => (z > 0.06 ? 0.06 + (z - 0.06) * snoutK : z);
131
-
132
- // ---------------------------------------------------------------- TORSO
133
- // one long barrel: shoulders, back and hams blend into a single fat-covered mass; a level (or
134
- // slightly arched) top line 0.72-0.74 m, belly 0.30 m above the ground, half width ~0.18 m
135
- const wB = (1 + 0.05 * boar) * fat;
136
- // (a piglet's underline tucked up: side1 / research 2, a young gilt's chest 0.53 withers heights deep and its
137
- // belly 0.47 above the ground, against 0.58-0.60 and 0.38 on a finisher; the top line stays)
138
- const tuck = piglet ? 0.03 : 0;
139
- // (side2: the chest 0.58 withers heights deep behind the elbow, the belly 0.39 above the ground; the
140
- // barrel as wide in the middle as over the shoulders and hams from above, front2)
141
- m.ell({ tag: 'barrel', bone: 'spine2', c: [0, 0.525 + tuck / 2, -0.08], r: [0.186 * wB, 0.2 - tuck / 2, 0.5], k: 0 });
142
- // (the ribs and the fat over them: as wide over the middle as over the shoulder and thigh muscles, a finisher is
143
- // straight-sided from above; the barrel alone was 5-6 cm narrower a side than the hams there, which showed as a
144
- // saddle in the back when the pig lay on its side. Only over the middle: a wider barrel
145
- // also pushed the flank by the thigh out, and a dead pig's lower thigh into a slope)
146
- m.ell({ tag: 'ribs', bone: 'spine2', c: [0, 0.535 + tuck / 2, -0.055], r: [0.21 * wB, 0.15, 0.295], k: 0.07 });
147
- // (the chest floor behind the elbows level with the belly line: side2, chest depth ~0.58 withers heights)
148
- m.ell({ tag: 'shoulder', bone: 'spine3', c: [0, 0.535 + tuck / 2, 0.21], r: [0.166 * wB + 0.012 * boar, 0.178 + 0.01 * boar - tuck / 2, 0.2], k: 0.08 });
149
- m.ell({ tag: 'hamball', bone: 'pelvis', c: [0, 0.53 + tuck / 3, -0.43], r: [0.172 * wB * (0.94 + 0.06 * hamK), 0.195 - tuck / 3, 0.2 * (0.95 + 0.05 * hamK)], k: 0.08 });
150
- m.ell({ tag: 'back', bone: 'spine2', c: [0, 0.665, -0.08], r: [0.132 * wB, 0.07, 0.44], k: 0.1 });
151
- m.ell({ tag: 'rump', bone: 'pelvis', c: [0, 0.665, -0.4], r: [0.13 * wB, 0.07, 0.18], axis: norm([0, -0.1, 1]), k: 0.08 });
152
- // belly: a flat underline, sagging in older sows
153
- m.ell({ tag: 'belly', bone: 'spine2', c: [0, 0.398 - 0.04 * belly + tuck, -0.1], r: [0.148 * wB, 0.08 + 0.022 * belly, 0.33], k: 0.1 });
154
- m.ell({ tag: 'brisket', bone: 'chest', c: [0, 0.445 + tuck * 0.8, 0.3], r: [0.105, 0.095, 0.11], k: 0.06 });
155
- // hind end: the rounded buttocks over the hams; the tail is set on high between them
156
- m.ell({ tag: 'buttock', bone: 'pelvis', c: [0, 0.6, -0.54], r: [0.12 * wB, 0.11, 0.08], k: 0.08 });
157
- m.ell({ tag: 'tailroot', bone: 'pelvis', c: [0, 0.675, -0.575], r: [0.04, 0.035, 0.035], k: 0.05 });
158
- if (boar >= 0.5 && !piglet) {
159
- // testes: two large rounded bulges under the tail, between the hams
160
- for (const s of [1, -1]) m.ell({ tag: 'scrotum', bone: 'pelvis', c: [0.038 * s, 0.5, -0.585], r: [0.045, 0.06, 0.045], k: 0.04 });
161
- // sheath: the preputial pouch in front of the navel
162
- m.ell({ tag: 'sheath', bone: 'spine2', c: [0, 0.305, -0.02], r: [0.028, 0.03, 0.07], axis: norm([0, 0.25, 1]), k: 0.05 });
163
- }
164
-
165
- // ---------------------------------------------------------------- NECK (short, thick, hidden in the jowls)
166
- const nk = 1 + 0.25 * boar;
167
- m.ell({ tag: 'neck', bone: 'neck1', c: [0, 0.54, 0.38], r: [0.14 * nk * fat, 0.16, 0.13], axis: norm([0, 0.3, 1]), k: 0.1 });
168
- m.ell({ tag: 'neck', bone: 'neck2', c: [0, 0.56, 0.45], r: [0.12 * nk * fat, 0.13, 0.1], axis: norm([0, 0.4, 1]), k: 0.08 });
169
- // the top line runs almost straight from the withers to the poll (a crest / shield in boars)
170
- m.ell({ tag: 'nape', bone: 'neck1', c: [0, 0.655 + 0.012 * boar, 0.39], r: [0.1 * nk, 0.065 + 0.012 * boar, 0.14], axis: norm([0, -0.12, 1]), k: 0.09 });
171
- // throat / double chin: from under the jaw into the brisket
172
- m.cone({ tag: 'throat', bone: 'neck1', a: [0, 0.43, 0.36], b: [0, 0.46, 0.44], ra: 0.085 * fat, rb: 0.08, k: 0.09 });
173
- m.cone({ tag: 'throat', bone: 'neck2', a: [0, 0.46, 0.44], b: hl([0, -0.115, -0.03]), ra: 0.075, rb: 0.06, k: 0.08 });
174
-
175
- // ---------------------------------------------------------------- HEAD (head-local, see rig.js)
176
- // landmarks (face1 / side1): skull top y 0.085 at z -0.1, forehead 0.075 at z 0, a slightly dished
177
- // nasal bridge, the disc (centre y -0.012, z 0.19) 7 cm wide and 5.5 cm high, mouth corner below
178
- // the front of the eye, heavy jowls down to y -0.15 behind the jaw angle
179
- const hb = 1 + 0.08 * boar;
180
- hell({ tag: 'cranium', c: [0, 0.008, -0.06], r: [0.088 * hb, 0.064, 0.085], k: 0.05 });
181
- hell({ tag: 'poll', c: [0, 0.042, -0.08], r: [0.075 * hb, 0.04, 0.05], k: 0.04 });
182
- // (the boar's broader skull stays behind and below the eyes: a wider forehead and cheek would bury them)
183
- hell({ tag: 'forehead', c: [0, 0.036, 0.01], r: [0.074, 0.03, 0.08], k: 0.04 });
184
- // snout: a tapering cylinder from the face to the disc
185
- // (tapering a little more toward the disc, so the disc's rim stands a touch proud of the snout behind it: lw_show,
186
- // head_hausschwein5, side1)
187
- m.cone({ ...H, tag: 'snout', a: hl([0, -0.004, 0.05]), b: hl([0, -0.007, sz(0.16)]), ra: 0.057, rb: 0.05, k: 0.04 });
188
- hell({ tag: 'nasal', c: [0, 0.018, sz(0.1)], r: [0.05, 0.022, 0.07 * snoutK], k: 0.03 });
189
- // the dished profile (params.dish: Berkshire ~0.9, Large White ~0.35, Landrace 0 straight): the bridge sags in front
190
- // of the eyes between the forehead and the disc (side1, lw_show, bk_sow; an earlier sculpt ignored the knob and
191
- // every breed had the same straight, slightly Roman line)
192
- // (broad across the bridge, 0.11 half width: at 0.075 the carve's side walls ran from the inner eye corners
193
- // down to the snout as two ridges, a V that read as a frown from the front; face2, head_mochyn: a broad, flat bridge)
194
- if (dish > 0.01) hell({ tag: 'dish', c: [0, 0.089 - 0.02 * dish, sz(0.11)], r: [0.11, 0.04, 0.075 * snoutK], k: 0.03, carve: true });
195
- // the full face under and in front of the eyes (the maxilla under the cheek fat): no waist between the snout
196
- // and the jowls (face2, front1, threequarter2)
197
- hell({ tag: 'muzzle', c: [0, -0.03, 0.05], r: [0.064 * hb, 0.05, 0.09], k: 0.04 });
198
- for (const s of [1, -1]) {
199
- // jowls / cheeks: the big fat pads behind and below the eyes
200
- hell({ tag: 'jowl', c: [0.066 * s * hb, -0.075, -0.035], r: [0.06 * hb * fat, 0.08, 0.085], k: 0.05 });
201
- // cheek: the zygomatic arch and the masseter under their fat, behind and below the eye: the face's
202
- // outline beside the eyes (face2, front1, face3: the eyes set in from it by a third of their spacing)
203
- hell({ tag: 'cheek', c: [0.07 * s, -0.01, -0.05], r: [0.05 * fat, 0.055, 0.07], k: 0.03 });
204
- // upper lip along the side of the snout (the flews), rising to the disc; the mouth corner lies a
205
- // third of the way from the disc to the eye (face1, side1)
206
- m.cone({ ...H, tag: 'lip', a: hl([0.058 * s, -0.058, 0.045]), b: hl([0.042 * s, -0.042, sz(0.155)]), ra: 0.03, rb: 0.02, k: 0.03 });
207
- // heavy fat-padded brow over the small eye
208
- hell({ tag: 'brow', c: [0.058 * s, 0.05, 0.0], r: [0.022, 0.012, 0.03], k: 0.025 });
209
- // eye: orbit hollow, lids, almond aperture
210
- pigEye(m, s);
211
- // ear base muscles on the side of the poll
212
- // (a soft swelling, not a knob: a lying pig's lop ear swings off it)
213
- m.sphere({ ...H, tag: 'earbase', c: add(J['earBase' + (s > 0 ? 'L' : 'R')], [-0.014 * s, -0.006, 0]), rad: 0.02, k: 0.045 });
214
- }
215
- if (boar > 0) {
216
- // boar: the heavy cheeks and the ridge over the snout where the tusks' sockets bulge
217
- for (const s of [1, -1]) hell({ tag: 'jowl', c: [0.06 * s, -0.09, -0.06], r: [0.04 * boar, 0.05 * boar, 0.06], k: 0.05 });
218
- for (const s of [1, -1]) hell({ tag: 'lip', c: [0.036 * s, -0.04, sz(0.105)], r: [0.014, 0.018, 0.026], k: 0.025 });
219
- }
220
- // the soft floor between the mandibles: the chin's underside runs back into the throat (face1: a heavy rounded
221
- // chin tucked under the upper lip, no step behind it). The skin over the back half of the chin is the head's
222
- // surface, riding on the jaw (rig appendage 'jawskin') and blending into the throat, so it follows the mouth
223
- // as it opens; it meets the jaw part's underside almost tangentially a third of the way from the disc to the
224
- // eye, and only the chin's front and the lower lip are the jaw part (a jaw part exposed from the throat to
225
- // the lip read as a separate plate from below, outlined by the crease where it met the head)
226
- hell({ tag: 'underjaw', c: [0, -0.083, 0.0], r: [0.05, 0.028, 0.06], k: 0.04 });
227
- {
228
- // (a flat sheet under the chin: it ends 2.5 cm past the crossing at the mouth corner, sz(0.105), where it
229
- // runs into the chin's underside at a shallow angle; its top stays ~1.5 cm below the snout's underside and
230
- // its blend is tighter than the head's, so that in front of the corner it barely joins the upper lip: a
231
- // thicker sheet with a 4 cm blend fused with the snout there, and that skin from the upper lip to the jaw
232
- // stretched 3x when the mouth opened wide)
233
- const zx = sz(0.105), zc = 0.02, rz = zx + 0.025 - zc, u = (zx - zc) / rz, ry = 0.018;
234
- hell({ tag: 'underjaw', bone: 'jaw', group: 'jawskin', c: [0, -0.1045 + ry * Math.sqrt(1 - u * u), zc], r: [0.054, ry, rz], k: 0.03 });
235
- }
236
- // mouth line: the lower lip is tucked inside the upper lip (no slit: where the two surfaces overlap the coat
237
- // paints the mouth, which shows when the jaw drops; a carved slit's sharp lip margin meshed as a sawtooth)
238
-
239
- // snout disc (rostral plate on its own bone): a flat oval plate with a raised rim
240
- const dz = sz(0.178);
241
- // (the plate is cut close to its widest section: its flat face spans almost the whole snout end,
242
- // with a rounded rim standing a little proud of the snout behind it)
243
- m.ell({ ...SN, tag: 'disc', c: hl([0, -0.006, dz]), r: [0.058, 0.045, 0.026], axis: HZ, up: HY, k: 0.012 });
244
- m.cone({ ...SN, tag: 'snoutend', a: hl([0, -0.006, sz(0.13)]), b: hl([0, -0.006, dz - 0.008]), ra: 0.049, rb: 0.048, k: 0.02 });
245
- // flat face of the disc: a big carving sphere in front of it
246
- m.sphere({ ...SN, tag: 'discface', c: hl([0, -0.006, dz + 0.012 + 0.4]), rad: 0.4, k: 0.004, carve: true });
247
- for (const s of [1, -1]) {
248
- // nostrils: two large vertical ovals in the lower middle of the disc (each about a quarter of its
249
- // width), a septum between them (face2, front1, front2)
250
- // (smaller, flatter ovals tilted outer end down (front1, face2: two tilted ovals about a sixth
251
- // of the disc's width each, deepest at their inner upper end); the 2.6 x 3.6 cm round pits read as two black
252
- // buttons with a lit floor)
253
- const a = 0.4 * s, up = [-Math.sin(a), Math.cos(a) * HY[1], Math.cos(a) * HY[2]];
254
- m.ell({ ...SN, tag: 'nostril', c: hl([0.025 * s, -0.009, dz + 0.012]), r: [0.0135, 0.0088, 0.017], axis: HZ, up, k: 0.005, carve: true });
255
- }
256
-
257
- // ---------------------------------------------------------------- JAW (lower lip and chin: the mouth opens)
258
- const JW = { bone: 'jaw', group: 'jaw', part: 'jaw' };
259
- // (the chin's front 1 cm further back and a little higher, and the lower lip tucked further under the upper lip:
260
- // from the side and below they read as a thin pale ledge under the snout)
261
- m.ell({ ...JW, tag: 'chin', c: hl([0, -0.077, sz(0.09)]), r: [0.04, 0.027, 0.064 * snoutK], axis: HZ, up: HY, k: 0 });
262
- m.ell({ ...JW, tag: 'lowerlip', c: hl([0, -0.067, sz(0.122)]), r: [0.026, 0.015, 0.02], axis: HZ, up: HY, k: 0.015 });
263
- // the tongue on the floor of the mouth, inside the closed mouth (shows when the jaw drops: squeal, bite)
264
- m.ell({ ...JW, tag: 'tongue', c: hl([0, -0.053, sz(0.085)]), r: [0.024, 0.011, 0.05 * snoutK], axis: HZ, up: HY, k: 0.012 });
265
- for (const s of [1, -1]) {
266
- m.cone({ ...JW, tag: 'mandible', a: hl([0.032 * s, -0.08, 0.02]), b: hl([0.026 * s, -0.076, sz(0.13)]), ra: 0.02, rb: 0.016, k: 0.02 });
267
- }
268
- if ((params.tusks || 0) > 0.05) {
269
- // tusks: the lower canines, ivory, riding rigidly on the jaw (coat paints them keratin): their own part and
270
- // surface, meshed at ~1 mm (tuskCones above, regions.js)
271
- for (const s of [1, -1]) for (const c of tuskCones(params, s)) m.cone({ bone: 'jaw', group: 'jaw', part: 'tusk', tag: 'tusk', ...c, k: 0 });
272
- }
273
-
274
- // ---------------------------------------------------------------- EARS (leaves)
275
- // Each pinna is a curved sheet tiled with exact slabs (m.fin), thick at the root and thinning to a round rim
276
- // (ears.js): an erect ear curls its tip forward, a semi-lop tips its outer half forward and down, a lop ear
277
- // rises from the poll and droops forward over the eyes like a hood. (Exact slab distances keep the ears'
278
- // skin weights off the neck. The leaf's base rolls into the funnel of the ear canal inside the head's
279
- // 'earbase' swelling; no root cone in the ear part: a lying pig's ear turns on its bone about the base,
280
- // and a cone reaching into the skull stood out of it as a peg.)
281
- for (const S of ['L', 'R']) {
282
- const E = earShape(J, params, S);
283
- const ear = { bone: 'ear' + S, group: 'ear' + S, part: 'ear' + S, tag: 'ear' };
284
- // (the thickness at the coarse tiers is the leaf's own business, ears.js: tiles are not marked thin)
285
- for (const g of E.segs) m.fin({ ...ear, o: g.o, u: g.u, v: g.v, poly: g.poly, t: g.t, round: g.t / 2, grad: g.grad, curve: g.curve, k: 0 });
286
- }
287
-
288
- // ---------------------------------------------------------------- LEGS (short, sunk in the body)
289
- // (a piglet's legs as thick for its size as a finisher's, a touch thicker: threequarter3, side1)
290
- const legK = (1 + 0.1 * boar) * (piglet ? 1.05 : 1);
291
- for (const S of ['L', 'R']) {
292
- const s = S === 'L' ? 1 : -1;
293
- const lat = [s, 0, 0];
294
- const sx = (v) => [v[0] * s, v[1], v[2]];
295
- // front
296
- const g = 'F' + S;
297
- const Sc = J['scapTop' + S], Sh = J['shoulder' + S], E = J['elbow' + S], W = J['wrist' + S], M = J['mcp' + S], C = J['fcoffin' + S], T = J['ftoe' + S];
298
- ellY({ tag: 'scapmuscle', bone: 'scapula' + S, group: g, c: add(lerp(Sc, Sh, 0.5), sx([0.055, 0, -0.01])), ydir: sub(Sh, Sc), lateral: lat, r: [0.06 + 0.02 * boar, 0.15, 0.11], k: 0.1, bias: 0.006 });
299
- m.sphere({ tag: 'shoulderpoint', bone: 'humerus' + S, group: g, c: add(Sh, sx([0.02, 0.0, 0.01])), rad: 0.06 * legK, k: 0.08 });
300
- m.cone({ tag: 'upperarm', bone: 'humerus' + S, group: g, a: Sh, b: E, ra: 0.072 * legK, rb: 0.058 * legK, k: 0.08 });
301
- ellY({ tag: 'triceps', bone: 'humerus' + S, group: g, c: add(lerp(Sh, E, 0.55), sx([0.012, 0.0, -0.055])), ydir: sub(E, Sh), lateral: lat, r: [0.062 * legK, 0.1, 0.075], k: 0.08 });
302
- m.sphere({ tag: 'olecranon', bone: 'radius' + S, group: g, c: add(E, [0, 0.015, -0.04]), rad: 0.035, k: 0.04 });
303
- m.cone({ tag: 'forearm', bone: 'radius' + S, group: g, a: add(E, [0, 0, -0.005]), b: W, ra: 0.05 * legK, rb: 0.029 * legK, k: 0.04 });
304
- ellY({ tag: 'forearmmuscle', bone: 'radius' + S, group: g, c: add(lerp(E, W, 0.25), sx([0.006, 0, 0.008])), ydir: sub(W, E), lateral: lat, r: [0.045 * legK, 0.075, 0.048 * legK], k: 0.04 });
305
- // (the web from the chest wall onto the forearm, 0.3 of its length: at 0.2 the raised upper foreleg of a pig
306
- // lying on its side pulled a long thin sheet of skin to the chest with folded back faces in its crease,
307
- // red back faces in the armpit 560 -> 278 px over three views; at 0.4, 946)
308
- m.cone({ tag: 'forearmweb', bone: 'radius' + S, group: g, a: add(E, sx([-0.03, 0.05, -0.01])), b: add(lerp(E, W, 0.3), sx([-0.012, 0, 0])), ra: 0.045, rb: 0.03, k: 0.05 });
309
- // knee (carpus), cannon, fetlock
310
- ellY({ tag: 'knee', bone: 'metacarpus' + S, group: g, c: add(W, [0, 0.0, 0.002]), ydir: UP, lateral: lat, r: [0.03 * legK, 0.033, 0.029 * legK], k: 0.02 });
311
- m.cone({ tag: 'cannon', bone: 'metacarpus' + S, group: g, a: add(W, [0, -0.012, 0.0]), b: add(M, [0, 0.01, -0.002]), ra: 0.024 * legK, rb: 0.022 * legK, k: 0.015 });
312
- ellY({ tag: 'fetlock', bone: 'metacarpus' + S, group: g, c: add(M, [0, 0.0, -0.006]), ydir: [0, 1, 0.3], lateral: lat, r: [0.026 * legK, 0.026, 0.028], k: 0.015 });
313
- sculptDigits(m, 'fpaw' + S, 'fhoof' + S, g, M, C, T, s, legK);
314
-
315
- // hind: the ham (the biggest muscle mass of the pig) sweeps down to the stifle and the hock
316
- const h = 'H' + S;
317
- const Hp = J['hip' + S], K = J['knee' + S], Hk = J['hock' + S], Mt = J['mtp' + S], Ch = J['hcoffin' + S], Tt = J['htoe' + S];
318
- ellY({ tag: 'thigh', bone: 'femur' + S, group: h, c: add(lerp(Hp, K, 0.45), sx([0.035, 0, -0.045])), ydir: sub(K, Hp), lateral: lat, r: [0.075 * hamK, 0.18, 0.15 * hamK], k: 0.1, bias: 0.006 });
319
- m.cone({ tag: 'thighfront', bone: 'femur' + S, group: h, a: sx([0.13, 0.6, -0.3]), b: add(K, sx([0.0, 0.04, 0.03])), ra: 0.08, rb: 0.055, k: 0.08 });
320
- m.cone({ tag: 'ham', bone: 'femur' + S, group: h, a: sx([0.08, 0.6, -0.56]), b: add(lerp(K, Hk, 0.35), [0, 0, -0.045]), ra: 0.1 * hamK, rb: 0.048, k: 0.08 });
321
- ellY({ tag: 'flankfold', bone: 'femur' + S, group: h, c: sx([0.13, 0.4, -0.2]), ydir: [-0.1, 0.3, 0.12], lateral: lat, r: [0.04, 0.09, 0.06], k: 0.08 });
322
- m.sphere({ tag: 'stifle', bone: 'tibia' + S, group: h, c: add(K, sx([0.008, 0.01, 0.02])), rad: 0.045, k: 0.06 });
323
- ellY({ tag: 'gaskin', bone: 'tibia' + S, group: h, c: add(lerp(K, Hk, 0.35), sx([0.004, 0, -0.03])), ydir: sub(Hk, K), lateral: lat, r: [0.048 * legK, 0.095, 0.06 * legK], k: 0.05 });
324
- m.cone({ tag: 'shin', bone: 'tibia' + S, group: h, a: lerp(K, Hk, 0.1), b: Hk, ra: 0.042 * legK, rb: 0.029 * legK, k: 0.04 });
325
- m.cone({ tag: 'achilles', bone: 'tibia' + S, group: h, a: add(lerp(K, Hk, 0.45), [0, 0, -0.045]), b: add(Hk, [0, 0.04, -0.04]), ra: 0.02, rb: 0.016, k: 0.025 });
326
- m.sphere({ tag: 'calcaneus', bone: 'metatarsus' + S, group: h, c: add(Hk, [0, 0.04, -0.038]), rad: 0.021, k: 0.02 });
327
- ellY({ tag: 'hock', bone: 'metatarsus' + S, group: h, c: add(Hk, [0, 0.006, -0.004]), ydir: [0, 1, 0.25], lateral: lat, r: [0.031 * legK, 0.042, 0.033], k: 0.02 });
328
- m.cone({ tag: 'cannon', bone: 'metatarsus' + S, group: h, a: add(Hk, [0, -0.022, 0.003]), b: add(Mt, [0, 0.01, 0.0]), ra: 0.024 * legK, rb: 0.022 * legK, k: 0.015 });
329
- ellY({ tag: 'fetlock', bone: 'metatarsus' + S, group: h, c: add(Mt, [0, 0.0, -0.006]), ydir: [0, 1, 0.3], lateral: lat, r: [0.026 * legK, 0.026, 0.028], k: 0.015 });
330
- sculptDigits(m, 'hpaw' + S, 'hhoof' + S, h, Mt, Ch, Tt, s, legK * 0.98);
331
- }
332
-
333
- // ---------------------------------------------------------------- TEATS (two rows along the belly)
334
- const pairs = params.teats ?? 7;
335
- const teatK = boar >= 0.5 ? 0.45 : piglet ? 0.5 : 0.8 + 0.6 * belly;
336
- for (let i = 0; i < pairs; i++) {
337
- const z = lerp([0, 0, 0.2], [0, 0, -0.34], i / Math.max(1, pairs - 1))[2];
338
- const yb = 0.3 - 0.03 * belly + 0.008 * Math.abs(z + 0.08) * 4 * 0.3 + tuck;
339
- const x = 0.052 + 0.01 * Math.cos(((i / (pairs - 1)) - 0.5) * 2);
340
- for (const s of [1, -1]) {
341
- const a = [x * s, yb + 0.02, z], b = [x * s * 1.02, yb - 0.012 * teatK, z];
342
- m.cone({ tag: 'teat', bone: z > 0.05 ? 'spine3' : z < -0.2 ? 'spine1' : 'spine2', a, b, ra: 0.0085 * Math.max(0.6, teatK), rb: 0.006 * Math.max(0.6, teatK), k: 0.008 });
343
- }
344
- }
345
-
346
- // ---------------------------------------------------------------- TAIL (thin, corkscrew, a small tuft)
347
- const n = TAIL_SEGS;
348
- for (let i = 0; i < n; i++) {
349
- const t0 = i / n, t1 = (i + 1) / n;
350
- const r = (t) => 0.0115 - 0.0065 * Math.pow(t, 0.8);
351
- m.cone({ tag: i >= n - 1 ? 'tailtip' : 'tail', part: 'tail', bone: 'tail' + i, a: J['tail' + i], b: J['tail' + (i + 1)], ra: r(t0), rb: r(t1), k: i === 0 ? 0.03 : 0.004, thin: i > n / 2 });
352
- }
353
- return m;
354
- }
355
-
356
- // Cloven hoof: pastern with two dew claws behind the fetlock, then two claws (digits III and IV),
357
- // each a hoof-wall half-cone, flat on the ground (carved at y = 0), the interdigital cleft between
358
- // them, heel bulbs behind. Pigs walk on the tips of the claws with fairly upright pasterns.
359
- function sculptDigits(m, paw, hoof, group, M, C, T, s, w) {
360
- m.cone({ tag: 'pastern', bone: paw, group, a: M, b: C, ra: 0.022 * w, rb: 0.024 * w, k: 0.012 });
361
- // dew claws (digits II and V): small pointed claws behind, 3-5 cm above the ground
362
- for (const d of [1, -1]) {
363
- const base = add(M, [0.017 * d * w, -0.012, -0.022]);
364
- m.cone({ tag: 'dewclaw', bone: paw, group, a: base, b: add(base, [0.004 * d, -0.016, -0.012]), ra: 0.0075 * w, rb: 0.004 * w, k: 0.006 });
365
- }
366
- const zMid = (C[2] + T[2]) * 0.5;
367
- const dir = Math.sign(T[2] - C[2]);
368
- for (const d of [1, -1]) {
369
- const off = 0.0145 * d * w;
370
- const top = add(C, [off, 0.012, -0.008 * dir]);
371
- const base = [C[0] + off * 1.1, 0.0, zMid - 0.003 * dir];
372
- m.cone({ tag: 'hoof', bone: hoof, group, a: top, b: base, ra: 0.0145 * w, rb: 0.02 * w, k: 0.007 });
373
- // the toe: a pointed front of each claw
374
- m.ell({ tag: 'hoof', bone: hoof, group, c: [C[0] + off * 0.9, 0.013, T[2] - 0.016 * dir], r: [0.0135 * w, 0.0125, 0.02], axis: norm([0, -0.3, dir]), k: 0.007 });
375
- m.sphere({ tag: 'heelbulb', bone: hoof, group, c: add(C, [off * 0.9, -0.015, -0.024 * dir]), rad: 0.0145 * w, k: 0.011 });
376
- }
377
- m.cone({ tag: 'coronet', bone: hoof, group, a: add(C, [0, 0.014, -0.011 * dir]), b: add(C, [0, 0.007, 0.011 * dir]), ra: 0.024 * w, rb: 0.024 * w, k: 0.009 });
378
- // interdigital cleft: a V opening toward the front and the ground
379
- m.ell({ tag: 'cleft', bone: hoof, group, c: [C[0], 0.0, T[2] - 0.002 * dir], r: [0.003, 0.026, 0.043], k: 0.0025, carve: true });
380
- m.ell({ tag: 'cleft', bone: hoof, group, c: [C[0], -0.003, zMid], r: [0.0025, 0.017, 0.046], k: 0.002, carve: true });
381
- m.ell({ tag: 'sole', bone: hoof, group, c: [C[0], -0.2 + 0.0015, zMid], r: [0.2, 0.2, 0.2], k: 0.003, carve: true });
382
- }