@bitefoundry/retrieviewer 0.0.3 → 0.0.5

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 (263) hide show
  1. package/ASSET-PROVENANCE.md +11 -0
  2. package/ASSETS-LICENSE.md +2 -1
  3. package/ATTRIBUTION.md +6 -1
  4. package/COMFORT-ART.md +95 -0
  5. package/DESKTOP-PLATFORMS.md +6 -1
  6. package/INSTALLING.md +4 -0
  7. package/PLUGIN.md +13 -10
  8. package/PREREQUISITES.md +95 -0
  9. package/PUPPY-MEMORY.md +102 -1
  10. package/README.ko.md +116 -0
  11. package/README.md +121 -59
  12. package/RELEASING.md +33 -13
  13. package/THIRD-PARTY-NOTICES.md +5 -3
  14. package/braille.mjs +35 -9
  15. package/examples/live.mjs +2 -2
  16. package/integrations/linux-overlay/overlay.py +8 -2
  17. package/integrations/macos-overlay/overlay.jxa +9 -7
  18. package/integrations/opencode/runtime.mjs +4 -4
  19. package/integrations/opencode/tui.tsx +1 -1
  20. package/integrations/windows-overlay/Overlay.cs +7 -6
  21. package/integrations/windows-overlay/desktop.mjs +2 -1
  22. package/integrations/windows-overlay/protocol.mjs +13 -7
  23. package/integrations/windows-overlay/worker.mjs +1 -1
  24. package/package.json +34 -13
  25. package/puppy-comfort-sprites.mjs +33 -0
  26. package/puppy-companion-comfort-q5.bin.gz +0 -0
  27. package/puppy-companion-comfort.json +140 -0
  28. package/puppy-companion-life.mjs +58 -18
  29. package/puppy-companion-objects.mjs +12 -0
  30. package/puppy-companion-sprites.mjs +4 -2
  31. package/puppy-frame-predictive.mjs +15 -9
  32. package/puppy-frame-store.mjs +2 -2
  33. package/puppy-paper-actions.mjs +4 -2
  34. package/puppy-paper-behaviors.mjs +1 -1
  35. package/puppy-paper-contact.mjs +4 -2
  36. package/puppy-paper-seat.mjs +4 -2
  37. package/puppy-paper-world.mjs +14 -0
  38. package/puppy-paper.mjs +79 -21
  39. package/retrieviewer-cli.mjs +8 -6
  40. package/retrieviewer-plugin.d.mts +1 -1
  41. package/retrieviewer-plugin.mjs +1 -1
  42. package/retrieviewer.d.mts +12 -4
  43. package/retrieviewer.mjs +20 -14
  44. package/locomotion-core.mjs +0 -21
  45. package/locomotion-puppy.animal +0 -0
  46. package/vendor/procedural-animals/package.json +0 -40
  47. package/vendor/procedural-animals/src/animal.js +0 -146
  48. package/vendor/procedural-animals/src/bake.js +0 -51
  49. package/vendor/procedural-animals/src/build.js +0 -81
  50. package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
  51. package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
  52. package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
  53. package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
  54. package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
  55. package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
  56. package/vendor/procedural-animals/src/core/build/seams.js +0 -183
  57. package/vendor/procedural-animals/src/core/build/warp.js +0 -112
  58. package/vendor/procedural-animals/src/core/build/weights.js +0 -393
  59. package/vendor/procedural-animals/src/core/math/vec.js +0 -81
  60. package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
  61. package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
  62. package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
  63. package/vendor/procedural-animals/src/core/motion/common.js +0 -158
  64. package/vendor/procedural-animals/src/core/motion/index.js +0 -22
  65. package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
  66. package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
  67. package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
  68. package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
  69. package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
  70. package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
  71. package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
  72. package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
  73. package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
  74. package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
  75. package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
  76. package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
  77. package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
  78. package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
  79. package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
  80. package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
  81. package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
  82. package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
  83. package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
  84. package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
  85. package/vendor/procedural-animals/src/index.d.ts +0 -98
  86. package/vendor/procedural-animals/src/index.js +0 -29
  87. package/vendor/procedural-animals/src/registry.js +0 -48
  88. package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
  89. package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
  90. package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
  91. package/vendor/procedural-animals/src/species/bear/index.js +0 -139
  92. package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
  93. package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
  94. package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
  95. package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
  96. package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
  97. package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
  98. package/vendor/procedural-animals/src/species/boar/index.js +0 -110
  99. package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
  100. package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
  101. package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
  102. package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
  103. package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
  104. package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
  105. package/vendor/procedural-animals/src/species/cat/index.js +0 -211
  106. package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
  107. package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
  108. package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
  109. package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
  110. package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
  111. package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
  112. package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
  113. package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
  114. package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
  115. package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
  116. package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
  117. package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
  118. package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
  119. package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
  120. package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
  121. package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
  122. package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
  123. package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
  124. package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
  125. package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
  126. package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
  127. package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
  128. package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
  129. package/vendor/procedural-animals/src/species/cow/index.js +0 -118
  130. package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
  131. package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
  132. package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
  133. package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
  134. package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
  135. package/vendor/procedural-animals/src/species/crow/index.js +0 -70
  136. package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
  137. package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
  138. package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
  139. package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
  140. package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
  141. package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
  142. package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
  143. package/vendor/procedural-animals/src/species/deer/index.js +0 -106
  144. package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
  145. package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
  146. package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
  147. package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
  148. package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
  149. package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
  150. package/vendor/procedural-animals/src/species/dog/index.js +0 -144
  151. package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
  152. package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
  153. package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
  154. package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
  155. package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
  156. package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
  157. package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
  158. package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
  159. package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
  160. package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
  161. package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
  162. package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
  163. package/vendor/procedural-animals/src/species/fish/index.js +0 -88
  164. package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
  165. package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
  166. package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
  167. package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
  168. package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
  169. package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
  170. package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
  171. package/vendor/procedural-animals/src/species/fox/index.js +0 -120
  172. package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
  173. package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
  174. package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
  175. package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
  176. package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
  177. package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
  178. package/vendor/procedural-animals/src/species/frog/index.js +0 -97
  179. package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
  180. package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
  181. package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
  182. package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
  183. package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
  184. package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
  185. package/vendor/procedural-animals/src/species/goat/index.js +0 -149
  186. package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
  187. package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
  188. package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
  189. package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
  190. package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
  191. package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
  192. package/vendor/procedural-animals/src/species/horse/index.js +0 -80
  193. package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
  194. package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
  195. package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
  196. package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
  197. package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
  198. package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
  199. package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
  200. package/vendor/procedural-animals/src/species/lion/index.js +0 -111
  201. package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
  202. package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
  203. package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
  204. package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
  205. package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
  206. package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
  207. package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
  208. package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
  209. package/vendor/procedural-animals/src/species/pig/index.js +0 -161
  210. package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
  211. package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
  212. package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
  213. package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
  214. package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
  215. package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
  216. package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
  217. package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
  218. package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
  219. package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
  220. package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
  221. package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
  222. package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
  223. package/vendor/procedural-animals/src/species/rat/index.js +0 -111
  224. package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
  225. package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
  226. package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
  227. package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
  228. package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
  229. package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
  230. package/vendor/procedural-animals/src/species/shark/index.js +0 -104
  231. package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
  232. package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
  233. package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
  234. package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
  235. package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
  236. package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
  237. package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
  238. package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
  239. package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
  240. package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
  241. package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
  242. package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
  243. package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
  244. package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
  245. package/vendor/procedural-animals/src/species/snake/index.js +0 -73
  246. package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
  247. package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
  248. package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
  249. package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
  250. package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
  251. package/vendor/procedural-animals/src/species/spider/index.js +0 -78
  252. package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
  253. package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
  254. package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
  255. package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
  256. package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
  257. package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
  258. package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
  259. package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
  260. package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
  261. package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
  262. package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
  263. package/vendor/procedural-animals/src/worker.js +0 -29
@@ -1,66 +0,0 @@
1
- // Cheetah skeleton in bind pose (metres). Forward = +Z, up = +Y, the animal's left = +X.
2
- // Proportions from reference photos and cheetah limb osteometry
3
- // (humerus ~0.23 m, radius ~0.22 m, femur ~0.26 m, tibia ~0.255 m, metatarsus ~0.13 m,
4
- // shoulder height ~0.76 m, head-body ~1.36 m, tail ~0.72 m).
5
- import { buildRig } from '../../core/rig/rig.js';
6
- import { quadrupedBones, quadrupedLimbs, tailChain } from '../../core/rig/quadruped.js';
7
-
8
- export const TAIL_SEGS = 10;
9
- export const HEAD_O = [0, 0.79, 0.6]; // head-local origin (between eyes and ears)
10
-
11
- export function cheetahJoints() {
12
- const J = {
13
- nose: [0, 0.772, 0.7],
14
- occiput: [0, 0.79, 0.525],
15
- neckMid: [0, 0.716, 0.45],
16
- neckBase: [0, 0.63, 0.34],
17
- chestMid: [0, 0.648, 0.16],
18
- thoraxRear: [0, 0.668, -0.03],
19
- lumbarMid: [0, 0.68, -0.225],
20
- lumbosacral: [0, 0.668, -0.41],
21
- tailBase: [0, 0.655, -0.595],
22
- scapTopL: [0.045, 0.706, 0.286],
23
- shoulderL: [0.08, 0.536, 0.386],
24
- elbowL: [0.078, 0.346, 0.256],
25
- wristL: [0.068, 0.126, 0.276],
26
- mcpL: [0.066, 0.038, 0.306],
27
- ftoeL: [0.066, 0.016, 0.353],
28
- hipL: [0.072, 0.572, -0.46],
29
- kneeL: [0.09, 0.34, -0.345],
30
- hockL: [0.078, 0.172, -0.54],
31
- mtpL: [0.074, 0.038, -0.51],
32
- htoeL: [0.074, 0.016, -0.46],
33
- jawHinge: [0, 0.755, 0.58],
34
- jawTip: [0, 0.73, 0.66],
35
- earBaseL: [0.052, 0.83, 0.552],
36
- earTipL: [0.08, 0.853, 0.548],
37
- };
38
- // relaxed tail: droops then flicks up at the tip (J-curve seen in walking references)
39
- tailChain(J, 'tailBase', [-22, -38, -52, -60, -62, -58, -48, -32, -12, 10], [0.07, 0.074, 0.075, 0.075, 0.074, 0.073, 0.071, 0.069, 0.067, 0.065]);
40
- return J;
41
- }
42
-
43
- export function cheetahRig() {
44
- const J = cheetahJoints();
45
- return buildRig({
46
- joints: J,
47
- unit: 1,
48
- headOrigin: HEAD_O,
49
- bones: quadrupedBones({ tailSegs: TAIL_SEGS, ears: true, jaw: true }),
50
- axial: {
51
- points: ['nose', 'occiput', 'neckMid', 'neckBase', 'chestMid', 'thoraxRear', 'lumbarMid', 'lumbosacral', 'tailBase', ...Array.from({ length: TAIL_SEGS }, (_, i) => 'tail' + (i + 1))],
52
- bones: ['head', 'neck2', 'neck1', 'chest', 'spine3', 'spine2', 'spine1', 'pelvis', ...Array.from({ length: TAIL_SEGS }, (_, i) => 'tail' + i)],
53
- // the skull's influence reaches well back into the nape and throat
54
- blend: { 1: [-0.035, 0.08] },
55
- },
56
- limbs: quadrupedLimbs({
57
- front: { tCore: 0.55, aCore: 0.04, aBody: -0.07, midX: 0.0 },
58
- hind: { tCore: 0.52, aCore: 0.022, aBody: -0.045, midX: 0.008 },
59
- }),
60
- appendages: [
61
- { group: 'earL', bone: 'earL', blend: [-0.003, 0.005] },
62
- { group: 'earR', bone: 'earR', blend: [-0.003, 0.005] },
63
- ],
64
- webTags: ['flankfold', 'thighfront', 'scapmuscle'],
65
- });
66
- }
@@ -1,158 +0,0 @@
1
- // The cheetah, sculpted as a signed distance field.
2
- // Every primitive is attached to a bone (for skinning) and a group (axial / limb / ear / jaw).
3
- import { HEAD_O, TAIL_SEGS } from './rig.js';
4
- import { add, sub, mul, lerp, norm, cross } from '../../core/math/vec.js';
5
- import { eyeFrameOf } from '../../core/sdf/eyeSocket.js';
6
-
7
- const hl = (v) => [v[0] + HEAD_O[0], v[1] + HEAD_O[1], v[2] + HEAD_O[2]];
8
-
9
- // Eye geometry shared by the sculpt (lids + aperture) and the eyeball shader.
10
- // c: head-local eye centre (left); r: eyeball radius; yaw: outward divergence of each eye;
11
- // lid: eyelid skin thickness; R, d: almond aperture (two circular arcs) -> 22 mm wide, 10.5 mm
12
- // tall, set 1.3 mm low (off) so the upper lid hoods the top of the iris; tilt: inner corner lower.
13
- export const EYE = { c: [0.027, 0.026, 0.024], r: 0.0122, back: 0.0025, yaw: 0.16, lid: 0.0014, R: 0.014149, d: 0.008899, off: -0.0013, tilt: (12 * Math.PI) / 180, irisZ: 0.00727, irisR: 0.0098 };
14
-
15
- const X = [1, 0, 0];
16
-
17
- export function sculptCheetah(m, rig) {
18
- const J = rig.J;
19
- const eyeFrame = (s) => eyeFrameOf(EYE, HEAD_O, s);
20
-
21
- // Ellipsoid whose local Y follows `ydir`; radii = [lateral, along ydir, third axis]
22
- const ellY = (o) => {
23
- const y = norm(o.ydir);
24
- const lat = o.lateral || X;
25
- const z = norm(cross(lat, y));
26
- return m.ell({ ...o, axis: z, up: y, r: [o.r[0], o.r[1], o.r[2]] });
27
- };
28
-
29
- // ---------------------------------------------------------------- TORSO
30
- m.ell({ tag: 'ribcage', bone: 'spine3', c: [0, 0.575, 0.13], r: [0.1, 0.18, 0.22], axis: norm([0, 0.15, -1]), k: 0 });
31
- m.ell({ tag: 'brisket', bone: 'chest', c: [0, 0.478, 0.3], r: [0.075, 0.095, 0.1], axis: norm([0, -0.35, 1]), k: 0.06 });
32
- m.ell({ tag: 'pectoral', bone: 'chest', c: [0, 0.49, 0.35], r: [0.08, 0.08, 0.075], k: 0.05 });
33
- m.ell({ tag: 'withers', bone: 'chest', c: [0, 0.705, 0.24], r: [0.055, 0.058, 0.13], axis: norm([0, -0.08, 1]), k: 0.06 });
34
- m.ell({ tag: 'back', bone: 'spine3', c: [0, 0.7, 0.0], r: [0.07, 0.05, 0.17], k: 0.06 });
35
- m.ell({ tag: 'abdomen', bone: 'spine2', c: [0, 0.628, -0.17], r: [0.076, 0.1, 0.2], axis: norm([0, 0.3, -1]), k: 0.07 });
36
- m.ell({ tag: 'loin', bone: 'spine1', c: [0, 0.695, -0.24], r: [0.064, 0.055, 0.19], k: 0.05 });
37
- m.ell({ tag: 'flank', bone: 'spine1', c: [0, 0.605, -0.31], r: [0.068, 0.07, 0.1], k: 0.05 });
38
- m.ell({ tag: 'pelvis', bone: 'pelvis', c: [0, 0.665, -0.47], r: [0.078, 0.095, 0.135], k: 0.06 });
39
- m.ell({ tag: 'croup', bone: 'pelvis', c: [0, 0.715, -0.46], r: [0.06, 0.045, 0.125], k: 0.04 });
40
- for (const s of [1, -1]) {
41
- m.ell({ tag: 'rump', bone: 'pelvis', c: [0.045 * s, 0.625, -0.575], r: [0.044, 0.075, 0.055], k: 0.04 });
42
- }
43
-
44
- // ---------------------------------------------------------------- NECK
45
- m.cone({ tag: 'neck', bone: 'neck1', a: [0, 0.61, 0.33], b: [0, 0.705, 0.455], ra: 0.088, rb: 0.064, k: 0.06 });
46
- m.cone({ tag: 'neck', bone: 'neck2', a: [0, 0.705, 0.455], b: [0, 0.772, 0.53], ra: 0.064, rb: 0.052, k: 0.04 });
47
- m.ell({ tag: 'nape', bone: 'neck1', c: [0, 0.765, 0.43], r: [0.038, 0.028, 0.12], axis: norm([0, 0.35, 1]), k: 0.04 });
48
- m.ell({ tag: 'throat', bone: 'neck1', c: [0, 0.655, 0.47], r: [0.046, 0.055, 0.09], axis: norm([0, 0.8, 0.6]), k: 0.05 });
49
- m.ell({ tag: 'throat', bone: 'neck2', c: hl([0, -0.054, -0.042]), r: [0.035, 0.028, 0.062], k: 0.03 });
50
-
51
- // ---------------------------------------------------------------- HEAD (modelled in head-local coords, see HEAD_O)
52
- // landmarks measured from profile/frontal references: nose tip (0,-0.018,0.10), eyes (+-0.029,0.026,0.021),
53
- // chin (0,-0.068,0.058), skull top 0.066, occiput -0.09
54
- const H = { bone: 'head' };
55
- m.ell({ ...H, tag: 'cranium', c: hl([0, 0.02, -0.03]), r: [0.047, 0.046, 0.062], k: 0.04 });
56
- m.ell({ ...H, tag: 'forehead', c: hl([0, 0.034, 0.018]), r: [0.021, 0.03, 0.034], axis: norm([0, -0.6, 1]), k: 0.02 });
57
- for (const s of [1, -1]) {
58
- m.ell({ ...H, tag: 'brow', c: hl([0.028 * s, 0.042, 0.022]), r: [0.014, 0.007, 0.012], k: 0.012 });
59
- m.ell({ ...H, tag: 'zygomatic', c: hl([0.047 * s, 0.006, -0.002]), r: [0.013, 0.02, 0.04], axis: norm([-0.35 * s, 0, 1]), k: 0.025 });
60
- m.ell({ ...H, tag: 'cheek', c: hl([0.035 * s, -0.027, 0.004]), r: [0.021, 0.026, 0.036], k: 0.025 });
61
- m.ell({ ...H, tag: 'lip', c: hl([0.023 * s, -0.047, 0.05]), r: [0.011, 0.009, 0.03], axis: norm([-0.45 * s, -0.15, 1]), k: 0.012 });
62
- m.ell({ ...H, tag: 'mastoid', c: hl([0.034 * s, -0.02, -0.05]), r: [0.022, 0.03, 0.03], k: 0.03 });
63
- m.ell({ ...H, tag: 'whisker', c: hl([0.0135 * s, -0.037, 0.078]), r: [0.0145, 0.0135, 0.016], k: 0.012 });
64
- }
65
- m.ell({ ...H, tag: 'muzzle', c: hl([0, -0.022, 0.058]), r: [0.024, 0.024, 0.032], axis: norm([0, -0.4, 1]), k: 0.02 });
66
- m.cone({ ...H, tag: 'nasal', a: hl([0, 0.036, 0.042]), b: hl([0, 0.002, 0.083]), ra: 0.019, rb: 0.014, k: 0.015 });
67
- m.ell({ ...H, tag: 'nose', c: hl([0, -0.012, 0.091]), r: [0.0142, 0.0086, 0.0082], axis: norm([0, 0.5, 1]), k: 0.008 });
68
- m.ell({ ...H, tag: 'philtrum', c: hl([0, -0.034, 0.088]), r: [0.01, 0.011, 0.008], k: 0.01 });
69
- for (const s of [1, -1]) {
70
- // eyelids: a thin skin shell hugging the eyeball, cut open along an almond-shaped aperture that
71
- // reaches only down to the eyeball, so the eye sits flush in its lids with no cavity around it
72
- const ef = eyeFrame(s);
73
- const at = (u, v, w) => add(add(add(ef.c, mul(ef.x, u)), mul(ef.y, v)), mul(ef.z, w));
74
- // orbit: a soft hollow around the eye so the brow, cheek and nose bridge fall away to the lids
75
- // (the inner corner opens toward the tear line instead of being buried under the bridge)
76
- ellY({ ...H, tag: 'orbit', c: at(-0.002 * s, -0.0005, 0.019), ydir: ef.y, lateral: ef.x, r: [0.018, 0.0125, 0.009], k: 0.008, carve: true });
77
- m.sphere({ ...H, tag: 'eyelid', c: ef.c, rad: EYE.r + EYE.lid, k: 0.005 });
78
- m.lens({ ...H, tag: 'eyesocket', c: add(ef.c, mul(ef.y, EYE.off)), x: ef.x, y: ef.y, z: ef.z, R: EYE.R, d: EYE.d, zMin: -0.002, zMax: 0.024, k: 0.0022, carve: true });
79
- m.sphere({ ...H, tag: 'nostril', c: hl([0.0065 * s, -0.015, 0.1]), rad: 0.003, k: 0.002, carve: true });
80
- }
81
-
82
- // ---------------------------------------------------------------- JAW (separate surface so the mouth can open)
83
- const JW = { bone: 'jaw', group: 'jaw', part: 'jaw' };
84
- m.cone({ ...JW, tag: 'mandible', a: hl([0, -0.045, -0.012]), b: hl([0, -0.052, 0.044]), ra: 0.018, rb: 0.012, k: 0 });
85
- for (const s of [1, -1]) {
86
- m.cone({ ...JW, tag: 'mandible', a: hl([0.032 * s, -0.039, -0.028]), b: hl([0.01 * s, -0.051, 0.048]), ra: 0.014, rb: 0.01, k: 0.02 });
87
- }
88
- m.ell({ ...JW, tag: 'chin', c: hl([0, -0.053, 0.05]), r: [0.015, 0.011, 0.011], k: 0.015 });
89
-
90
- // ---------------------------------------------------------------- EARS
91
- for (const S of ['L', 'R']) {
92
- const s = S === 'L' ? 1 : -1;
93
- const base = J['earBase' + S], tip = J['earTip' + S];
94
- const up = norm(sub(tip, base));
95
- const facing = norm([1.0 * s, 0.1, 1]);
96
- const c = lerp(base, tip, 0.3);
97
- const lat = norm(cross(up, facing));
98
- const ear = { bone: 'ear' + S, group: 'ear' + S };
99
- ellY({ ...ear, tag: 'ear', c, ydir: up, lateral: lat, r: [0.0165, 0.0185, 0.0062], k: 0.012 });
100
- ellY({ ...ear, tag: 'earinner', c: add(add(c, mul(facing, 0.0068)), mul(up, 0.003)), ydir: up, lateral: lat, r: [0.0112, 0.0132, 0.0044], k: 0.003, carve: true });
101
- }
102
-
103
- // ---------------------------------------------------------------- LEGS
104
- for (const S of ['L', 'R']) {
105
- const s = S === 'L' ? 1 : -1;
106
- const lat = [s, 0, 0];
107
- const sx = (v) => [v[0] * s, v[1], v[2]];
108
- // front
109
- const g = 'F' + S;
110
- const Sc = J['scapTop' + S], Sh = J['shoulder' + S], E = J['elbow' + S], W = J['wrist' + S], M = J['mcp' + S], T = J['ftoe' + S];
111
- ellY({ tag: 'scapmuscle', bone: 'scapula' + S, group: g, c: add(lerp(Sc, Sh, 0.5), sx([0.006, 0, 0])), ydir: sub(Sh, Sc), lateral: lat, r: [0.022, 0.1, 0.055], k: 0.06, bias: 0.004 });
112
- m.cone({ tag: 'upperarm', bone: 'humerus' + S, group: g, a: Sh, b: E, ra: 0.037, rb: 0.031, k: 0.06 });
113
- ellY({ tag: 'triceps', bone: 'humerus' + S, group: g, c: add(lerp(Sh, E, 0.55), [0, 0, -0.03]), ydir: sub(E, Sh), lateral: lat, r: [0.03, 0.075, 0.036], k: 0.05 });
114
- m.sphere({ tag: 'olecranon', bone: 'radius' + S, group: g, c: add(E, [0, 0.01, -0.028]), rad: 0.019, k: 0.02 });
115
- m.cone({ tag: 'forearm', bone: 'radius' + S, group: g, a: E, b: W, ra: 0.032, rb: 0.019, k: 0.025 });
116
- ellY({ tag: 'forearmmuscle', bone: 'radius' + S, group: g, c: add(lerp(E, W, 0.25), sx([0.004, 0, 0.004])), ydir: sub(W, E), lateral: lat, r: [0.03, 0.07, 0.034], k: 0.03 });
117
- m.sphere({ tag: 'wrist', bone: 'metacarpus' + S, group: g, c: add(W, [0, 0, -0.004]), rad: 0.0195, k: 0.012 });
118
- m.sphere({ tag: 'carpalpad', bone: 'metacarpus' + S, group: g, c: add(W, [0, -0.01, -0.02]), rad: 0.009, k: 0.01 });
119
- m.cone({ tag: 'pastern', bone: 'metacarpus' + S, group: g, a: W, b: M, ra: 0.018, rb: 0.017, k: 0.012 });
120
- m.sphere({ tag: 'dewclaw', bone: 'metacarpus' + S, group: g, c: add(lerp(W, M, 0.35), sx([-0.016, 0, 0.004])), rad: 0.007, k: 0.006 });
121
- const dp = norm(sub(T, M));
122
- ellY({ tag: 'paw', bone: 'fpaw' + S, group: g, c: add(add(M, mul(dp, 0.02)), [0, -0.006, 0]), ydir: dp, lateral: lat, r: [0.026, 0.036, 0.018], k: 0.014 });
123
- m.sphere({ tag: 'pad', bone: 'fpaw' + S, group: g, c: add(M, [0, -0.026, 0.012]), rad: 0.012, k: 0.01 });
124
- const toeX = [-0.019, -0.0065, 0.0065, 0.019], toeZ = [-0.009, 0, 0, -0.009];
125
- for (let i = 0; i < 4; i++) m.sphere({ tag: 'toe', bone: 'fpaw' + S, group: g, c: [T[0] + toeX[i] * s, 0.0115, T[2] - 0.008 + toeZ[i]], rad: 0.0105, k: 0.007 });
126
-
127
- // hind
128
- const h = 'H' + S;
129
- const Hp = J['hip' + S], K = J['knee' + S], Hk = J['hock' + S], Mt = J['mtp' + S], Tt = J['htoe' + S];
130
- // The thigh is a broad teardrop in side view: wide where it rises into the flank and croup,
131
- // narrowing to the stifle. Its cranial edge climbs all the way up to the iliac wing and the
132
- // flank fold webs the stifle to the belly, so there is no notch between belly and thigh.
133
- ellY({ tag: 'thigh', bone: 'femur' + S, group: h, c: add(lerp(Hp, K, 0.4), sx([0.004, 0, -0.035])), ydir: sub(K, Hp), lateral: lat, r: [0.041, 0.15, 0.1], k: 0.05, bias: 0.004 });
134
- m.cone({ tag: 'thighfront', bone: 'femur' + S, group: h, a: sx([0.04, 0.625, -0.33]), b: add(K, sx([-0.004, 0.055, 0.0])), ra: 0.04, rb: 0.025, k: 0.06 });
135
- m.cone({ tag: 'hamstring', bone: 'femur' + S, group: h, a: sx([0.046, 0.625, -0.595]), b: add(lerp(K, Hk, 0.28), [0, 0, -0.028]), ra: 0.045, rb: 0.028, k: 0.04 });
136
- ellY({ tag: 'flankfold', bone: 'femur' + S, group: h, c: sx([0.05, 0.475, -0.29]), ydir: [-0.03, 0.16, 0.1], lateral: lat, r: [0.02, 0.085, 0.04], k: 0.06 });
137
- m.sphere({ tag: 'stifle', bone: 'tibia' + S, group: h, c: add(K, sx([0.002, 0.008, 0.006])), rad: 0.0175, k: 0.04 });
138
- m.cone({ tag: 'shin', bone: 'tibia' + S, group: h, a: add(lerp(K, Hk, 0.06), sx([0.0, 0.0, 0.004])), b: Hk, ra: 0.024, rb: 0.018, k: 0.03 });
139
- ellY({ tag: 'calf', bone: 'tibia' + S, group: h, c: add(lerp(K, Hk, 0.3), sx([0.002, 0.01, -0.027])), ydir: sub(Hk, K), lateral: lat, r: [0.025, 0.065, 0.029], k: 0.035 });
140
- m.cone({ tag: 'achilles', bone: 'tibia' + S, group: h, a: add(lerp(K, Hk, 0.5), [0, 0.01, -0.035]), b: add(Hk, [0, 0.012, -0.03]), ra: 0.012, rb: 0.011, k: 0.015 });
141
- m.sphere({ tag: 'calcaneus', bone: 'metatarsus' + S, group: h, c: add(Hk, [0, 0.012, -0.026]), rad: 0.015, k: 0.012 });
142
- m.sphere({ tag: 'hock', bone: 'metatarsus' + S, group: h, c: Hk, rad: 0.021, k: 0.012 });
143
- m.cone({ tag: 'metatarsus', bone: 'metatarsus' + S, group: h, a: Hk, b: Mt, ra: 0.018, rb: 0.016, k: 0.012 });
144
- const dh = norm(sub(Tt, Mt));
145
- ellY({ tag: 'paw', bone: 'hpaw' + S, group: h, c: add(add(Mt, mul(dh, 0.02)), [0, -0.006, 0]), ydir: dh, lateral: lat, r: [0.024, 0.034, 0.017], k: 0.014 });
146
- m.sphere({ tag: 'pad', bone: 'hpaw' + S, group: h, c: add(Mt, [0, -0.026, 0.01]), rad: 0.011, k: 0.01 });
147
- for (let i = 0; i < 4; i++) m.sphere({ tag: 'toe', bone: 'hpaw' + S, group: h, c: [Tt[0] + toeX[i] * 0.95 * s, 0.011, Tt[2] - 0.008 + toeZ[i]], rad: 0.0098, k: 0.007 });
148
- }
149
-
150
- // ---------------------------------------------------------------- TAIL
151
- const tailR = (t) => (t < 0.4 ? 0.034 + (0.024 - 0.034) * (t / 0.4) : t < 0.8 ? 0.024 + (0.021 - 0.024) * ((t - 0.4) / 0.4) : 0.021 - 0.002 * ((t - 0.8) / 0.2));
152
- m.cone({ tag: 'tailroot', bone: 'tail0', a: [0, 0.672, -0.545], b: J.tail1, ra: 0.05, rb: tailR(0.1), k: 0.04 });
153
- for (let i = 0; i < TAIL_SEGS; i++) {
154
- m.cone({ tag: 'tail', bone: 'tail' + i, a: J['tail' + i], b: J['tail' + (i + 1)], ra: tailR(i / TAIL_SEGS), rb: tailR((i + 1) / TAIL_SEGS), k: 0 });
155
- }
156
-
157
- return m;
158
- }
@@ -1,313 +0,0 @@
1
- // The chicken's plumage and bare parts, baked per vertex: contour-feather shingles (material 9) coloured
2
- // by feather tract (hackle, back, wing bow, breast, fluff, saddle) with per-feather markings (shaft
3
- // streaks, bars, spangles; surf.z < 0, marking colour in patternColor), a soft down haze that is long
4
- // in the fluffy underparts and drumsticks, hair-like lanceolate hackles and saddle on roosters, bare
5
- // glossy red skin on the face, comb and wattles (material 4), red or white earlobes, a horn-yellow
6
- // keratin bill and claws, and scaled shanks and toes (material 6). Colours per breed and sex are in
7
- // palette() (sampled from the reference photos and breed standards).
8
- import { SDFModel } from '../../core/sdf/sdf.js';
9
- import { norm, sub, dot, cross, add, mul, clamp, smoothstep, mix, fbm3 } from '../../core/math/vec.js';
10
- import { srgb, mix3, MAT } from '../../core/build/coatKit.js';
11
-
12
- // feather marking modes (shader: coatMaterial.js, material 9, surf.z = -(mode + amount))
13
- export const MARK = { lace: 0, bar: 1, shaft: 2, spangle: 3 };
14
- const markZ = (mode, amt) => -(mode + clamp(amt, 0, 0.98));
15
-
16
- const C = (hex) => srgb(hex);
17
- export function palette(p = {}) {
18
- const breed = p.breed || 'red', male = p.sex === 'male', juv = p.age === 'juvenile';
19
- const skin = { comb: C(0xc41f2a), wattle: C(0xb81d24), face: C(0xcc3a42), lobe: C(0xbd2e38), lobeWhite: C(0xece6da) };
20
- const P = {
21
- red: male
22
- ? { body: C(0x7a2c12), back: C(0x9c3f16), hackle: C(0xc8741e), hackleTip: C(0xe0a040), saddle: C(0xc05a18), bow: C(0x6e2410), breast: C(0x1a1410), fluff: C(0x2a2420), tail: C(0x10171a), tailIrid: 0.7, flight: C(0x2a2018), flightEdge: C(0x8a4a22), leg: C(0xd8b04a), bill: C(0xcfae6a), lobe: 'red', marks: [] }
23
- : { body: C(0x9c5a2c), back: C(0x98562a), hackle: C(0xb67434), hackleTip: C(0xc4843e), saddle: C(0x9c5a2c), bow: C(0x8a4a24), breast: C(0xa4602e), fluff: C(0xd6bf98), tail: C(0x3e2416), tailIrid: 0.1, flight: C(0x5e3820), flightEdge: C(0xa06c3e), leg: C(0xdcb44a), bill: C(0xd8b876), lobe: 'red', marks: [{ mode: MARK.shaft, amt: 0.6, col: C(0x4e2612), where: ['hackle', 'head'] }, { mode: MARK.lace, amt: 0.4, col: C(0xc89458), where: ['back', 'wing', 'body'] }] },
24
- leghorn: { body: C(0xefede6), back: C(0xefede6), hackle: C(0xf2f0ea), hackleTip: C(0xf4f2ec), saddle: C(0xf1efe8), bow: C(0xece9e1), breast: C(0xf0eee7), fluff: C(0xf3f2ee), tail: C(0xeeece5), tailIrid: 0, flight: C(0xebe8df), flightEdge: C(0xf1efe8), leg: C(0xe6c34a), bill: C(0xe6c86a), lobe: 'white', marks: [] },
25
- australorp: { body: C(0x141619), back: C(0x131518), hackle: C(0x15171a), hackleTip: C(0x17191c), saddle: C(0x141619), bow: C(0x131518), breast: C(0x16181b), fluff: C(0x34363a), tail: C(0x101214), tailIrid: 0.8, flight: C(0x111214), flightEdge: C(0x161719), leg: C(0x2c2e32), bill: C(0x2e2e30), lobe: 'red', marks: [], irid: 0.75 },
26
- barred: { body: C(0xdcdcd4), back: C(0xd8d8d0), hackle: C(0xdedfd8), hackleTip: C(0xe2e2dc), saddle: C(0xdcdcd4), bow: C(0xd8d8d0), breast: C(0xdcdcd4), fluff: C(0xcacac2), tail: C(0xcfcfc8), tailIrid: 0, flight: C(0xb8b8b0), flightEdge: C(0xd0d0c8), leg: C(0xe2bf4c), bill: C(0xe0c262), lobe: 'red', marks: [{ mode: MARK.bar, amt: male ? 0.78 : 0.92, col: C(0x1c1c1e), where: 'all' }], barred: true },
27
- buff: { body: C(0xcf9a52), back: C(0xcb944c), hackle: C(0xd6a45c), hackleTip: C(0xdcae66), saddle: C(0xd0984e), bow: C(0xc68e48), breast: C(0xd09a54), fluff: C(0xe0c08a), tail: C(0xb67e3c), tailIrid: 0, flight: C(0xbd8743), flightEdge: C(0xd2a05a), leg: C(0xe6cfbe), bill: C(0xe0c8a2), lobe: 'red', marks: [] },
28
- speckled: { body: C(0x6a2c16), back: C(0x6a2c16), hackle: C(0x7a3518), hackleTip: C(0x8a4020), saddle: C(0x6e2e16), bow: C(0x622814), breast: C(0x6e2e16), fluff: C(0xb8a088), tail: C(0x1c1614), tailIrid: 0.4, flight: C(0x3c2014), flightEdge: C(0xe8e2d6), leg: C(0xe3cbbd), bill: C(0xd8c6a0), lobe: 'red', marks: [{ mode: MARK.spangle, amt: 0.8, col: C(0xf2eee6), where: 'all' }], spangled: true },
29
- };
30
- const out = { ...(P[breed] || P.red), ...skin, breed, male };
31
- if (!male && breed === 'red') out.tail = C(0x4a2a16);
32
- // chicks: down only (yellow, black or chipmunk-striped), pale legs and bill, no comb
33
- if (juv) {
34
- const down = {
35
- red: { body: C(0xd7b77a), back: C(0x8a6238), stripe: C(0x6b4726), fluff: C(0xeedca2) },
36
- leghorn: { body: C(0xf2e08a), back: C(0xf0dc84), fluff: C(0xf6ea9e) },
37
- buff: { body: C(0xf0d488), back: C(0xecce80), fluff: C(0xf6e4a2) },
38
- australorp: { body: C(0x1a1a1c), back: C(0x161618), fluff: C(0xd8d0b0) },
39
- barred: { body: C(0x1c1c1e), back: C(0x18181a), fluff: C(0x5a5a58), spot: C(0xf0ecd8) },
40
- speckled: { body: C(0x7a5836), back: C(0x5e3f24), stripe: C(0x4a2e1a), fluff: C(0xdcc49a) },
41
- }[breed] || { body: C(0xf2e08a), back: C(0xf0dc84), fluff: C(0xf6ea9e) };
42
- Object.assign(out, down, { hackle: down.body, hackleTip: down.body, saddle: down.back, bow: down.back, breast: down.fluff, tail: down.back, flight: mix3(down.back, down.body, 0.3), flightEdge: down.body, tailIrid: 0, marks: [], leg: C(0xe9c98a), bill: C(0xd9bc8c), juv: true });
43
- }
44
- if (p.tone) for (const k of ['body', 'back', 'hackle', 'hackleTip', 'saddle', 'bow', 'breast', 'tail', 'flight']) out[k] = out[k].map((x) => x * p.tone);
45
- return out;
46
- }
47
-
48
- export function chickenCoat(ctx) {
49
- const { model, rig, pos, nrm, regionOf, regionNames, weights, nV, params } = ctx;
50
- const { BONES, J } = rig;
51
- const form = params.form || {};
52
- const Pal = palette(params);
53
- const male = params.sex === 'male' && !Pal.juv;
54
- const comb = new Float32Array(nV * 3), tint = new Float32Array(nV * 4), surf = new Float32Array(nV * 4);
55
- const furLen = new Float32Array(nV), mark = new Float32Array(nV).fill(1), pattern = new Float32Array(nV).fill(1), patCol = new Float32Array(nV * 4);
56
- const boneName = BONES.map((b) => b.name);
57
- const tagged = (...t) => model.prims.filter((p) => t.includes(p.tag));
58
- const billP = tagged('bill'), mandP = model.forPart('jaw');
59
- const eyeP = tagged('eyesocket'), clawP = tagged('claw'), spurP = tagged('spur');
60
- const combP = tagged('comb'), wattleP = tagged('wattle'), lobeP = tagged('earlobe');
61
- const legP = tagged('tarsus', 'toe', 'pad', 'hock', 'spur', 'shank');
62
- const minD = (list, p) => { let d = 1e9; for (const q of list) d = Math.min(d, SDFModel.dist(q, p[0], p[1], p[2])); return d; };
63
- const HO = rig.headOrigin, hk = form.headK ?? 1;
64
- const axialPts = rig.AXIAL.points;
65
- const axialDir = (p) => {
66
- let best = 1e9, dir = [0, 0, -1];
67
- for (let i = 0; i < axialPts.length - 1; i++) {
68
- const a = axialPts[i], b = axialPts[i + 1], ab = sub(b, a), l2 = dot(ab, ab);
69
- const t = clamp(dot(sub(p, a), ab) / l2, 0, 1);
70
- const q = add(a, mul(ab, t)), d = Math.hypot(p[0] - q[0], p[1] - q[1], p[2] - q[2]);
71
- if (d < best) { best = d; dir = norm(ab); }
72
- }
73
- return dir;
74
- };
75
- const lobeCol = Pal.lobe === 'white' ? Pal.lobeWhite : Pal.lobe;
76
- const marks = Pal.marks || [];
77
- const irid0 = Pal.irid ?? 0.1;
78
- const neckTop = J.occiput[1], neckBot = J.neckBase[1];
79
- for (let v = 0; v < nV; v++) {
80
- const p = [pos[v * 3], pos[v * 3 + 1], pos[v * 3 + 2]], n = [nrm[v * 3], nrm[v * 3 + 1], nrm[v * 3 + 2]];
81
- const bn = boneName[weights.dominant[v]] || '';
82
- const region = regionNames[regionOf[v]];
83
- let col = Pal.body, mat = MAT.FEATHER, fl = 0.004, gloss = 0.4, size = 0.022, irid = irid0 * 0.3, mz = 0;
84
- let flow = axialDir(p), mcol = null;
85
- const h = [(p[0] - HO[0]) / hk, (p[1] - HO[1]) / hk, (p[2] - HO[2]) / hk];
86
- const up = n[1];
87
- let tract = 'body';
88
- if (region === 'jaw' || bn === 'jaw') {
89
- mat = MAT.KERATIN; col = Pal.bill; fl = 0; gloss = 0.5; size = 0; irid = 0; flow = [0, 0, 1];
90
- if (minD(billP, p) < 0.0005 && h[2] < 0.035) { mat = MAT.MOUTH; col = srgb(0xc98a86); }
91
- } else if (bn === 'head' || region === 'head') {
92
- // head: feathered crown and nape, bare red face, comb, wattles, earlobes, bill
93
- // (grading into the neck's hackles toward the nape: no seam at the head / body cut)
94
- const rn = smoothstep(0.016, 0.034, Math.hypot(h[0] * 0.6, h[1], h[2]));
95
- col = mix3(Pal.hackle, Pal.hackleTip, 0.6); size = mix(0.006, male ? 0.014 : 0.016, rn); fl = mix(0.0025, male ? 0.009 : 0.005, rn); gloss = mix(0.35, male ? 0.55 : 0.4, rn); irid = irid0 * 0.35;
96
- flow = norm([0, -0.35, -1]);
97
- if (Math.abs(h[0]) > 0.006) flow = norm([h[0] * 10, -0.5, -1]);
98
- tract = 'head';
99
- const dB = minD(billP, p), dC = combP.length ? minD(combP, p) : 1, dW = wattleP.length ? minD(wattleP, p) : 1, dL = lobeP.length ? minD(lobeP, p) : 1;
100
- const cvh = fbm3(p[0] * 700, p[1] * 700, p[2] * 700, 2) - 0.5;
101
- const bare = (col2, g2) => { mat = MAT.SKIN; col = col2; fl = 0; gloss = g2; size = 0; irid = 0; tract = 'bare'; };
102
- if (dB < 0.0012 && h[2] > 0.0195 - 0.35 * Math.min(0, h[1] + 0.004)) { mat = MAT.KERATIN; col = Pal.bill; fl = 0; gloss = 0.55; irid = 0; size = 0; flow = [0, 0, 1]; tract = 'bill'; }
103
- else if (dC < 0.0012) { bare(Pal.comb, 0.55); flow = [0, 1, 0]; }
104
- else if (dW < 0.0012) { bare(Pal.wattle, 0.6); flow = [0, -1, 0]; }
105
- else if (dL < 0.0009) { bare(lobeCol, 0.5); }
106
- else if (!Pal.juv && h[2] > -0.0095 + 0.0015 * cvh && h[2] < 0.03 && h[1] < 0.0048 - 60 * Math.max(0, h[2] - 0.006) ** 2 - 40 * Math.max(0, -0.001 - h[2]) ** 2 + 0.0008 * cvh && h[1] > -0.022 && Math.abs(h[0]) > 0.0024) {
107
- // bare facial skin with sparse bristles; feathered at its rear edge
108
- bare(Pal.face, 0.45);
109
- fl = 0.0012 * smoothstep(-0.004, -0.009, h[2]);
110
- }
111
- // the eye ring: bare skin at the lid margin
112
- for (const e of eyeP) {
113
- const de = SDFModel.dist(e, p[0], p[1], p[2]);
114
- if (Math.abs(de) < 0.0011) { mat = MAT.DARK_SKIN; col = Pal.juv ? srgb(0x3a3230) : mix3(Pal.face, srgb(0x40181a), 0.5); fl = 0; tract = 'bare'; }
115
- }
116
- if (Pal.juv && tract === 'head') { mat = MAT.FUR; fl = 0.007; size = 0.004; col = mix3(Pal.body, Pal.fluff, 0.3); gloss = 0.2; }
117
- } else if (/^(tarsus|toe)/.test(bn) || (bn.startsWith('tibia') && minD(legP, p) < 0.0009)) {
118
- // scaled shank and toes: large scutes down the front, small reticulate scales behind
119
- mat = MAT.SCALES; col = Pal.leg; fl = 0; gloss = 0.4; irid = 0; tract = 'leg';
120
- const front = bn.startsWith('tarsus') ? smoothstep(-0.2, 0.6, n[2]) : 0.5;
121
- size = mix(0.0022, 0.0042, front);
122
- flow = [0, -1, 0];
123
- if (/^toe/.test(bn)) { const b = BONES[weights.dominant[v]]; flow = norm(sub(b.tail, b.head)); size = 0.0028; }
124
- if (minD(clawP, p) < 0.0005) { mat = MAT.KERATIN; col = mix3(Pal.leg, srgb(0x6a6056), 0.5); gloss = 0.6; size = 0; }
125
- if (spurP.length && minD(spurP, p) < 0.0006) { mat = MAT.KERATIN; col = mix3(Pal.leg, srgb(0x5a5048), 0.45); gloss = 0.6; size = 0; }
126
- } else if (bn.startsWith('tibia') || bn.startsWith('femur')) {
127
- // drumstick: soft fluffy feathers pointing down the leg
128
- col = mix3(Pal.fluff, Pal.body, Pal.juv ? 0.4 : 0.55); fl = Pal.juv ? 0.009 : 0.008; size = 0.016; gloss = 0.3; irid = 0; tract = 'fluff';
129
- flow = [0, -1, -0.3];
130
- } else if (/^(humerus|ulna|hand)/.test(bn)) {
131
- // wing coverts: lie toward the trailing edge; the bow (lesser coverts) is darker on red breeds
132
- const b = BONES[weights.dominant[v]];
133
- const d = norm(sub(b.tail, b.head));
134
- const sL = b.side === 'R' ? 'R' : 'L';
135
- let wn = norm(cross(sub(J['elbow' + sL], J['shoulder' + sL]), sub(J['wrist' + sL], J['elbow' + sL])));
136
- if (wn[1] < 0) wn = mul(wn, -1);
137
- const s = b.side === 'R' ? -1 : 1;
138
- flow = mul(norm(cross(wn, d)), s);
139
- if (!Pal.juv && /^(ulna|hand)/.test(bn)) {
140
- // the forearm's coverts lie back and down along the folded flight feathers, as the greater
141
- // covert cards along the shield's rim (coverts.js), not straight across the forearm
142
- const dU = norm(sub(J['wrist' + sL], J['elbow' + sL])), tU = mul(norm(cross(wn, dU)), s);
143
- flow = norm(add(mul(dU, -0.64), mul(tU, 0.77)));
144
- }
145
- size = 0.02; fl = 0.003; tract = 'wing';
146
- const top = dot(n, wn);
147
- col = top < 0 ? mix3(Pal.fluff, Pal.body, 0.5) : Pal.bow;
148
- irid = top < 0 ? 0 : irid0 * 0.8;
149
- // a chick's wing is down in the colour of the down on its bed (the folded wing lies on the flank's
150
- // brown: its pale underside and dark bow showed as a lens and a dark knob at the wrist), the
151
- // underwing a little lighter; as long as the down around it
152
- if (Pal.juv) { const L = chickWingDownLook(params); col = top < 0 ? L.under : L.top; fl = top < 0 ? L.furUnder : L.fur; mat = MAT.FUR; size = L.size / (params.size || 1); gloss = L.gloss; irid = 0; }
153
- } else {
154
- // body tracts
155
- const dorsal = smoothstep(-0.25, 0.45, up);
156
- const ny = (p[1] - neckBot) / Math.max(1e-3, neckTop - neckBot);
157
- if (bn.startsWith('neck') || (bn === 'chest' && ny > -0.25 && p[2] > J.synsacrum[2])) {
158
- // hackles: narrow feathers flowing down the neck and over the shoulders
159
- tract = 'hackle';
160
- col = mix3(Pal.hackle, Pal.hackleTip, smoothstep(0.2, 1, ny) * 0.6);
161
- size = male ? 0.014 : 0.016; fl = male ? 0.009 : 0.005; gloss = male ? 0.55 : 0.4; irid = irid0 * 0.35;
162
- // the breast below the hackles (roosters: black breast)
163
- if (up < -0.1 && p[2] > J.neckBase[2]) { col = mix3(col, Pal.breast, smoothstep(-0.1, -0.5, up)); tract = 'breast'; }
164
- } else {
165
- col = mix3(Pal.breast, Pal.back, dorsal);
166
- size = p[2] > 0.02 ? 0.02 : 0.024;
167
- fl = mix(0.007, 0.0035, dorsal); gloss = mix(0.3, 0.45, dorsal);
168
- irid = irid0 * mix(0.3, 0.9, dorsal);
169
- tract = dorsal > 0.5 ? 'back' : 'breast';
170
- // underparts: fluffy, light
171
- const under = smoothstep(0.2, -0.5, up) * smoothstep(0.175, 0.13, p[1]);
172
- col = mix3(col, Pal.fluff, under * (male && Pal.breed === 'red' ? 0.4 : 0.85));
173
- fl = mix(fl, Pal.juv ? 0.01 : 0.012, under);
174
- if (under > 0.5) tract = 'fluff';
175
- // saddle / rump: the back rising into the tail
176
- const sw = smoothstep(J.synsacrum[2] + 0.015, J.synsacrum[2] - 0.045, p[2]) * smoothstep(-0.35, 0.25, up) * (bn === 'tail' ? 0 : 1);
177
- if (sw > 0) {
178
- col = mix3(col, Pal.saddle, sw);
179
- if (male) { fl = mix(fl, 0.012, sw); size = mix(size, 0.012, sw); gloss = mix(gloss, 0.55, sw); if (sw > 0.5) tract = 'saddle'; }
180
- }
181
- if (bn === 'tail') { col = mix3(Pal.tail, Pal.saddle, 0.35); irid = Pal.tailIrid; tract = 'tail'; }
182
- // flow: along the body, bending down around the flanks and the breast
183
- if (up < 0.3) flow = norm(add(flow, [0, -0.7 * (1 - up), 0]));
184
- if (tract === 'saddle') flow = norm(add(flow, [0, -1.2, 0]));
185
- }
186
- if (Pal.juv) {
187
- // chick down: a soft ball, chipmunk stripes down the back on brown breeds, a pale belly
188
- // (in a crease whose skin turns down from the ball's radial direction - the wing's bed under the
189
- // folded wing - by the radial direction: the bed's upper wall showed as a pale band along the wing)
190
- const rd = norm(sub(p, [0, J.hipL[1] + 0.01, -0.01])), wR = 1 - smoothstep(0.6, 0.95, dot(n, rd));
191
- const upJ = Math.max(up, mix(up, rd[1], wR)), dorsalJ = smoothstep(-0.25, 0.45, upJ);
192
- col = mix3(Pal.fluff, Pal.body, smoothstep(-0.6, 0.2, upJ));
193
- if (dorsalJ > 0.4) col = mix3(col, Pal.back, 0.7);
194
- if (Pal.stripe && dorsal > 0.55) {
195
- const st = Math.abs(p[0]);
196
- const band = smoothstep(0.012, 0.006, Math.abs(st - 0.022)) + smoothstep(0.008, 0.003, st);
197
- col = mix3(col, Pal.stripe, clamp(band, 0, 1) * 0.85);
198
- }
199
- mat = MAT.FUR; fl = 0.012; size = 0.004; gloss = 0.2; irid = 0;
200
- }
201
- }
202
- // chicks: all down (fur shells), no contour feathers yet
203
- if (Pal.juv && mat === MAT.FEATHER) { mat = MAT.FUR; fl = Math.max(fl, 0.009); }
204
- // per-feather markings (shader), by tract
205
- if (mat === MAT.FEATHER && !Pal.juv) {
206
- for (const mk of marks) {
207
- if (mk.where !== 'all' && !mk.where.includes(tract)) continue;
208
- mz = markZ(mk.mode, mk.amt * (tract === 'fluff' ? 0.5 : 1));
209
- mcol = mk.col;
210
- break;
211
- }
212
- }
213
- // red roosters: hackle and saddle feathers with a dark centre stripe, black-green tail
214
- if (male && Pal.breed === 'red' && (tract === 'hackle' || tract === 'saddle')) { mz = markZ(MARK.shaft, 0.35); mcol = srgb(0x3a1a0a); }
215
- // low-frequency colour variation
216
- const cv = fbm3(p[0] * 30 + (params.seed || 0), p[1] * 30, p[2] * 30, 3) - 0.5;
217
- const kv = mat === MAT.FEATHER ? 0.22 : mat === MAT.SKIN ? 0.12 : 0.1;
218
- col = [col[0] * (1 + kv * cv), col[1] * (1 + kv * cv), col[2] * (1 + kv * 0.8 * cv)];
219
- // comb: tangent to the surface
220
- const f = sub(flow, mul(n, dot(flow, n)));
221
- const fN = norm(Math.hypot(...f) > 1e-6 ? f : cross(n, [1, 0, 0]));
222
- comb.set(fN, v * 3);
223
- tint[v * 4] = col[0]; tint[v * 4 + 1] = col[1]; tint[v * 4 + 2] = col[2]; tint[v * 4 + 3] = mat;
224
- furLen[v] = fl;
225
- surf[v * 4] = gloss; surf[v * 4 + 1] = size * (params.size || 1);
226
- surf[v * 4 + 2] = mat === MAT.FEATHER ? mz : 0;
227
- surf[v * 4 + 3] = mat === MAT.FEATHER ? irid : 0;
228
- if (mcol) { patCol[v * 4] = mcol[0]; patCol[v * 4 + 1] = mcol[1]; patCol[v * 4 + 2] = mcol[2]; patCol[v * 4 + 3] = 0; }
229
- }
230
- return { comb, tint, pattern, mark, furLen, surf, patternColor: patCol };
231
- }
232
-
233
- // flight-feather card colours per breed: primaries with a lighter outer edge on red birds, black-green
234
- // sickles and tail on red roosters, barred / spangled vanes
235
- export function chickenFeatherColour(params) {
236
- const Pal = palette(params);
237
- const male = params.sex === 'male';
238
- return (kind, i, side, t, c, layer) => {
239
- const top = layer > 0;
240
- const covert = kind.endsWith('Covert');
241
- let rgb = Pal.flight, irid = 0, gloss = 0.4;
242
- if (kind === 'rectrix' || kind === 'tailCovert') { rgb = Pal.tail; irid = Pal.tailIrid; gloss = 0.5; }
243
- // (a spangled breed's flight feathers are mahogany edged, white only at the spangled tips)
244
- if (kind === 'primary' && c < -0.3) rgb = mix3(rgb, Pal.spangled ? mix3(Pal.body, Pal.flightEdge, 0.2) : Pal.flightEdge, 0.35);
245
- if (kind === 'primary' || kind === 'secondary') gloss = 0.22;
246
- if (kind === 'secondary' && top) {
247
- // folded, the secondaries show their outer vanes as a stack of edges below the covert shield:
248
- // a lighter fringe on each outer vane reads as feathers (a flat dark panel read as one plastic
249
- // slab); the tertials (innermost) lie on top along the back and are coloured like the coverts
250
- const lace = Pal.marks?.find((m) => m.mode === MARK.lace)?.col;
251
- // (each feather darker along its shaft and lighter toward its edges: the overlapping feathers
252
- // of the panel read one by one, not as a flat slab)
253
- const ac = Math.abs(c);
254
- // (a spangled breed's secondaries are mahogany with white tips, not white-edged)
255
- const edge = Pal.spangled ? mix3(Pal.body, Pal.flightEdge, 0.2) : Pal.flightEdge;
256
- // (vanes render lighter than the shingled skin around them: a little darker than the coverts)
257
- if (i >= 7) rgb = mix3(mix3(mix3(Pal.bow, Pal.flight, 0.45), lace || edge, 0.3 * ac), Pal.flight, 0.5 * (1 - ac) * (1 - t * 0.5)).map((x) => x * 0.82);
258
- else rgb = c < 0 ? mix3(rgb, edge, 0.6) : mix3(rgb, Pal.bow, 0.2);
259
- }
260
- if (covert && kind !== 'tailCovert') rgb = mix3(Pal.bow, Pal.body, 0.3);
261
- // the greater coverts along the folded wing's shield (coverts.js): the shield's colour, a slightly
262
- // darker base, no light fringe (a row of pale edges read as a comb)
263
- if (kind === 'wingCovert') rgb = mix3(Pal.bow, Pal.back, 0.3).map((x) => x * (0.7 + 0.12 * t));
264
- if (kind === 'tailCovert' && male && Pal.breed === 'red') { rgb = Pal.tail; irid = 0.8; }
265
- if (kind === 'tailCovert' && !male) rgb = mix3(Pal.saddle, Pal.tail, 0.2);
266
- // barred: light vanes with dark bars across them, drawn in the shader (a few per-vertex bars on a
267
- // card averaged to a plain grey band)
268
- let bar = null;
269
- if (Pal.barred) { rgb = srgb(0xd8d8d0); bar = { rgb: mix3(srgb(0xd8d8d0), srgb(0x1e1e20), male ? 0.66 : 0.78), period: kind === 'primary' || kind === 'rectrix' ? 0.0075 : 0.0062 }; }
270
- // (a chick's down has no spangles: its palette keeps the breed flag but no feather marks)
271
- if (Pal.spangled && Pal.marks.length && t > 0.85) rgb = mix3(rgb, Pal.marks[0].col, kind === 'primary' || kind === 'secondary' ? smoothstep(0.85, 1, t) : 1);
272
- if (!top) rgb = mix3(rgb, srgb(0x9a948c), 0.15);
273
- const k = 1 + (kind === 'secondary' ? 0.1 : 0.06) * Math.sin(i * 12.9898 + side * 3.1 + t * 2.1);
274
- return { rgb: [rgb[0] * k, rgb[1] * k, rgb[2] * k], gloss: top ? gloss : 0.3, irid: top ? irid : irid * 0.2, bar };
275
- };
276
- }
277
-
278
- // the greater covert cards on the folded wing (coverts.js) shaded as the shield's contour feathers
279
- // (material FEATHER: big shingles, the wing tract's colour and markings except the lace, which the
280
- // shingle shader would draw across a card; matte: a glossy card caught the sky as a lavender band)
281
- export function chickenWingCovertLook(params) {
282
- const Pal = palette(params);
283
- let mz = 0, mcol = null;
284
- for (const mk of Pal.marks || []) {
285
- if (mk.mode === MARK.lace) continue;
286
- if (mk.where !== 'all' && !mk.where.includes('wing')) continue;
287
- mz = markZ(mk.mode, mk.amt); mcol = mk.col; break;
288
- }
289
- // (no fur shells on a card: darker than the shield's base colour, whose down shells darken it)
290
- // (a rooster's wing is his dark bow colour: mixed with his bright back it read as an orange patch)
291
- const base = Pal.male ? mix3(Pal.bow, Pal.flight, 0.2) : mix3(Pal.bow, Pal.back, 0.4);
292
- return { rgb: base.map((x) => x * 0.99), gloss: 0.1, size: 0.035 * (params.size || 1), mz, mcol, irid: Pal.irid ? Pal.irid * 0.35 : 0, fur: 0.003 };
293
- }
294
-
295
- // the tertials on the folded wing (index.js restyle: their top layers shaded as contour feathers with down):
296
- // the wing tract's colour and markings, lacing included (they are big enough for the shingle shader's lace)
297
- export function chickenTertialLook(params) {
298
- const Pal = palette(params), L0 = chickenWingCovertLook(params);
299
- let mz = L0.mz, mcol = L0.mcol;
300
- for (const mk of Pal.marks || []) {
301
- if (mk.where !== 'all' && !mk.where.includes('wing')) continue;
302
- mz = markZ(mk.mode, mk.amt); mcol = mk.col; break;
303
- }
304
- return { ...L0, rgb: L0.rgb.map((x) => x * 1.15), size: 0.022 * (params.size || 1), gloss: 0.3, mz, mcol };
305
- }
306
-
307
- // a chick's wing cards restyled as down (wingLook.js downyWing): the top the down of the folded wing's
308
- // bed (back over body), the underside the pale underwing
309
- export function chickWingDownLook(params) {
310
- const Pal = palette(params);
311
- const top = mix3(Pal.back, Pal.body, 0.3);
312
- return { top, under: mix3(top, Pal.fluff, 0.35), fur: 0.012, furUnder: 0.004, furTip: 0.7, size: 0.004 * (params.size || 1), gloss: 0.2 };
313
- }