@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,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
- }