@bitefoundry/retrieviewer 0.0.0-stage → 0.0.2

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 (297) hide show
  1. package/ASSET-PROVENANCE.md +43 -0
  2. package/ASSETS-LICENSE.md +58 -0
  3. package/ATTRIBUTION.md +54 -0
  4. package/EMBEDDING.md +96 -0
  5. package/INSTALLING.md +126 -0
  6. package/LICENSE +16 -0
  7. package/LICENSE-CODE +21 -0
  8. package/PLUGIN.md +110 -0
  9. package/PUPPY-MEMORY.md +57 -0
  10. package/PUPPY-Q5-COMPARISON.md +73 -0
  11. package/README.md +86 -2
  12. package/RELEASING.md +70 -0
  13. package/THIRD-PARTY-NOTICES.md +17 -0
  14. package/TRADEMARKS.md +21 -0
  15. package/WINDOWS-COMPANION.md +113 -0
  16. package/braille.mjs +45 -0
  17. package/examples/bridge.py +62 -0
  18. package/examples/embed.mjs +15 -0
  19. package/examples/live.mjs +40 -0
  20. package/examples/plugin.mjs +21 -0
  21. package/integrations/opencode/runtime.mjs +195 -0
  22. package/integrations/opencode/tui.tsx +59 -0
  23. package/integrations/windows-overlay/Overlay.cs +259 -0
  24. package/integrations/windows-overlay/desktop.mjs +87 -0
  25. package/integrations/windows-overlay/protocol.mjs +39 -0
  26. package/integrations/windows-overlay/worker.mjs +60 -0
  27. package/locomotion-core.mjs +21 -0
  28. package/locomotion-puppy.animal +0 -0
  29. package/package.json +131 -4
  30. package/pet-q5-manifest.json +118 -0
  31. package/puppy-clean.mjs +51 -0
  32. package/puppy-companion-interactions-v3-q5.bin.gz +0 -0
  33. package/puppy-companion-interactions-v3.json +1 -0
  34. package/puppy-companion-life.mjs +182 -0
  35. package/puppy-companion-objects.mjs +30 -0
  36. package/puppy-companion-sprites.mjs +14 -0
  37. package/puppy-continuous.mjs +57 -0
  38. package/puppy-face.mjs +46 -0
  39. package/puppy-frame-predictive.mjs +147 -0
  40. package/puppy-frame-store.mjs +108 -0
  41. package/puppy-mouth-anchor.json +1 -0
  42. package/puppy-mouth-anchor.mjs +33 -0
  43. package/puppy-paper-actions-v9-q5.bin.gz +0 -0
  44. package/puppy-paper-actions-v9.json +1 -0
  45. package/puppy-paper-actions.mjs +48 -0
  46. package/puppy-paper-approach-q5.bin.gz +0 -0
  47. package/puppy-paper-approach.json +1 -0
  48. package/puppy-paper-area.mjs +15 -0
  49. package/puppy-paper-arrival-seat-q5.bin.gz +0 -0
  50. package/puppy-paper-arrival-seat.json +1 -0
  51. package/puppy-paper-behaviors-q5.bin.gz +0 -0
  52. package/puppy-paper-behaviors.json +1 -0
  53. package/puppy-paper-behaviors.mjs +8 -0
  54. package/puppy-paper-contact.mjs +103 -0
  55. package/puppy-paper-director.mjs +21 -0
  56. package/puppy-paper-paw-transport.mjs +76 -0
  57. package/puppy-paper-rear-gallop-q5.bin.gz +0 -0
  58. package/puppy-paper-rear-gallop.json +1 -0
  59. package/puppy-paper-seat-q5.bin.gz +0 -0
  60. package/puppy-paper-seat.json +14 -0
  61. package/puppy-paper-seat.mjs +13 -0
  62. package/puppy-paper-trick-timing.mjs +58 -0
  63. package/puppy-paper-world.mjs +108 -0
  64. package/puppy-paper.mjs +271 -0
  65. package/puppy-stable-meta.json +1606 -0
  66. package/puppy-stable.mjs +72 -0
  67. package/puppy-stride-meta.json +343 -0
  68. package/puppy-stride-tweens-q5.bin.gz +0 -0
  69. package/puppy-zoomies.mjs +27 -0
  70. package/puppy-zoomies30.mjs +12 -0
  71. package/retrieviewer-cli.mjs +94 -0
  72. package/retrieviewer-config.mjs +49 -0
  73. package/retrieviewer-install.mjs +157 -0
  74. package/retrieviewer-plugin.d.mts +44 -0
  75. package/retrieviewer-plugin.mjs +97 -0
  76. package/retrieviewer-stdio.mjs +38 -0
  77. package/retrieviewer.d.mts +85 -0
  78. package/retrieviewer.mjs +142 -0
  79. package/vendor/procedural-animals/LICENSE +21 -0
  80. package/vendor/procedural-animals/package.json +40 -0
  81. package/vendor/procedural-animals/src/animal.js +146 -0
  82. package/vendor/procedural-animals/src/bake.js +51 -0
  83. package/vendor/procedural-animals/src/build.js +81 -0
  84. package/vendor/procedural-animals/src/core/build/coatKit.js +121 -0
  85. package/vendor/procedural-animals/src/core/build/featherCards.js +189 -0
  86. package/vendor/procedural-animals/src/core/build/finEdges.js +85 -0
  87. package/vendor/procedural-animals/src/core/build/furSlope.js +115 -0
  88. package/vendor/procedural-animals/src/core/build/mesh.js +67 -0
  89. package/vendor/procedural-animals/src/core/build/pipeline.js +272 -0
  90. package/vendor/procedural-animals/src/core/build/seams.js +183 -0
  91. package/vendor/procedural-animals/src/core/build/warp.js +112 -0
  92. package/vendor/procedural-animals/src/core/build/weights.js +393 -0
  93. package/vendor/procedural-animals/src/core/math/vec.js +81 -0
  94. package/vendor/procedural-animals/src/core/motion/actions.js +800 -0
  95. package/vendor/procedural-animals/src/core/motion/bird.js +3063 -0
  96. package/vendor/procedural-animals/src/core/motion/birdActions.js +1059 -0
  97. package/vendor/procedural-animals/src/core/motion/common.js +158 -0
  98. package/vendor/procedural-animals/src/core/motion/index.js +22 -0
  99. package/vendor/procedural-animals/src/core/motion/quadruped.js +2875 -0
  100. package/vendor/procedural-animals/src/core/motion/snake.js +1594 -0
  101. package/vendor/procedural-animals/src/core/motion/spider.js +1810 -0
  102. package/vendor/procedural-animals/src/core/motion/swimmer.js +1047 -0
  103. package/vendor/procedural-animals/src/core/motion/swimmerActions.js +613 -0
  104. package/vendor/procedural-animals/src/core/render/animalObject.js +262 -0
  105. package/vendor/procedural-animals/src/core/render/coatMaterial.js +1301 -0
  106. package/vendor/procedural-animals/src/core/render/dqs.js +159 -0
  107. package/vendor/procedural-animals/src/core/render/eyes.js +676 -0
  108. package/vendor/procedural-animals/src/core/render/membranes.js +77 -0
  109. package/vendor/procedural-animals/src/core/render/skeleton.js +41 -0
  110. package/vendor/procedural-animals/src/core/rig/bird.js +327 -0
  111. package/vendor/procedural-animals/src/core/rig/quadruped.js +76 -0
  112. package/vendor/procedural-animals/src/core/rig/rig.js +79 -0
  113. package/vendor/procedural-animals/src/core/rig/snake.js +76 -0
  114. package/vendor/procedural-animals/src/core/rig/spider.js +110 -0
  115. package/vendor/procedural-animals/src/core/rig/swimmer.js +181 -0
  116. package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +53 -0
  117. package/vendor/procedural-animals/src/core/sdf/mesher.js +238 -0
  118. package/vendor/procedural-animals/src/core/sdf/sdf.js +263 -0
  119. package/vendor/procedural-animals/src/index.d.ts +98 -0
  120. package/vendor/procedural-animals/src/index.js +29 -0
  121. package/vendor/procedural-animals/src/registry.js +48 -0
  122. package/vendor/procedural-animals/src/species/bear/behaviour.js +463 -0
  123. package/vendor/procedural-animals/src/species/bear/claws.js +147 -0
  124. package/vendor/procedural-animals/src/species/bear/coat.js +726 -0
  125. package/vendor/procedural-animals/src/species/bear/index.js +139 -0
  126. package/vendor/procedural-animals/src/species/bear/motion.js +112 -0
  127. package/vendor/procedural-animals/src/species/bear/regions.js +78 -0
  128. package/vendor/procedural-animals/src/species/bear/rig.js +112 -0
  129. package/vendor/procedural-animals/src/species/bear/sculpt.js +272 -0
  130. package/vendor/procedural-animals/src/species/boar/behaviour.js +335 -0
  131. package/vendor/procedural-animals/src/species/boar/coat.js +372 -0
  132. package/vendor/procedural-animals/src/species/boar/index.js +110 -0
  133. package/vendor/procedural-animals/src/species/boar/motion.js +85 -0
  134. package/vendor/procedural-animals/src/species/boar/regions.js +88 -0
  135. package/vendor/procedural-animals/src/species/boar/rig.js +111 -0
  136. package/vendor/procedural-animals/src/species/boar/sculpt.js +285 -0
  137. package/vendor/procedural-animals/src/species/cat/behaviour.js +559 -0
  138. package/vendor/procedural-animals/src/species/cat/coat.js +841 -0
  139. package/vendor/procedural-animals/src/species/cat/index.js +211 -0
  140. package/vendor/procedural-animals/src/species/cat/motion.js +101 -0
  141. package/vendor/procedural-animals/src/species/cat/regions.js +82 -0
  142. package/vendor/procedural-animals/src/species/cat/rig.js +100 -0
  143. package/vendor/procedural-animals/src/species/cat/sculpt.js +266 -0
  144. package/vendor/procedural-animals/src/species/cat/whiskers.js +110 -0
  145. package/vendor/procedural-animals/src/species/cheetah/coat.js +427 -0
  146. package/vendor/procedural-animals/src/species/cheetah/index.js +51 -0
  147. package/vendor/procedural-animals/src/species/cheetah/joints.js +3 -0
  148. package/vendor/procedural-animals/src/species/cheetah/motion.js +77 -0
  149. package/vendor/procedural-animals/src/species/cheetah/regions.js +95 -0
  150. package/vendor/procedural-animals/src/species/cheetah/rig.js +66 -0
  151. package/vendor/procedural-animals/src/species/cheetah/sculpt.js +158 -0
  152. package/vendor/procedural-animals/src/species/chicken/coat.js +313 -0
  153. package/vendor/procedural-animals/src/species/chicken/coverts.js +320 -0
  154. package/vendor/procedural-animals/src/species/chicken/index.js +110 -0
  155. package/vendor/procedural-animals/src/species/chicken/motion.js +177 -0
  156. package/vendor/procedural-animals/src/species/chicken/regions.js +66 -0
  157. package/vendor/procedural-animals/src/species/chicken/rig.js +144 -0
  158. package/vendor/procedural-animals/src/species/chicken/sculpt.js +389 -0
  159. package/vendor/procedural-animals/src/species/chicken/wingLook.js +66 -0
  160. package/vendor/procedural-animals/src/species/chicken/wingStack.js +124 -0
  161. package/vendor/procedural-animals/src/species/cow/behaviour.js +521 -0
  162. package/vendor/procedural-animals/src/species/cow/coat.js +465 -0
  163. package/vendor/procedural-animals/src/species/cow/index.js +118 -0
  164. package/vendor/procedural-animals/src/species/cow/motion.js +81 -0
  165. package/vendor/procedural-animals/src/species/cow/regions.js +98 -0
  166. package/vendor/procedural-animals/src/species/cow/rig.js +116 -0
  167. package/vendor/procedural-animals/src/species/cow/sculpt.js +339 -0
  168. package/vendor/procedural-animals/src/species/crow/coat.js +145 -0
  169. package/vendor/procedural-animals/src/species/crow/index.js +70 -0
  170. package/vendor/procedural-animals/src/species/crow/joints.js +3 -0
  171. package/vendor/procedural-animals/src/species/crow/motion.js +101 -0
  172. package/vendor/procedural-animals/src/species/crow/regions.js +50 -0
  173. package/vendor/procedural-animals/src/species/crow/rig.js +83 -0
  174. package/vendor/procedural-animals/src/species/crow/sculpt.js +118 -0
  175. package/vendor/procedural-animals/src/species/deer/behaviour.js +513 -0
  176. package/vendor/procedural-animals/src/species/deer/coat.js +391 -0
  177. package/vendor/procedural-animals/src/species/deer/index.js +106 -0
  178. package/vendor/procedural-animals/src/species/deer/motion.js +97 -0
  179. package/vendor/procedural-animals/src/species/deer/regions.js +60 -0
  180. package/vendor/procedural-animals/src/species/deer/rig.js +124 -0
  181. package/vendor/procedural-animals/src/species/deer/sculpt.js +297 -0
  182. package/vendor/procedural-animals/src/species/dog/behaviour.js +521 -0
  183. package/vendor/procedural-animals/src/species/dog/coat.js +495 -0
  184. package/vendor/procedural-animals/src/species/dog/index.js +144 -0
  185. package/vendor/procedural-animals/src/species/dog/motion.js +118 -0
  186. package/vendor/procedural-animals/src/species/dog/regions.js +61 -0
  187. package/vendor/procedural-animals/src/species/dog/rig.js +129 -0
  188. package/vendor/procedural-animals/src/species/dog/sculpt.js +246 -0
  189. package/vendor/procedural-animals/src/species/eagle/coat.js +250 -0
  190. package/vendor/procedural-animals/src/species/eagle/index.js +76 -0
  191. package/vendor/procedural-animals/src/species/eagle/joints.js +3 -0
  192. package/vendor/procedural-animals/src/species/eagle/motion.js +137 -0
  193. package/vendor/procedural-animals/src/species/eagle/regions.js +57 -0
  194. package/vendor/procedural-animals/src/species/eagle/rig.js +107 -0
  195. package/vendor/procedural-animals/src/species/eagle/sculpt.js +137 -0
  196. package/vendor/procedural-animals/src/species/fish/coat.js +271 -0
  197. package/vendor/procedural-animals/src/species/fish/index.js +88 -0
  198. package/vendor/procedural-animals/src/species/fish/motion.js +92 -0
  199. package/vendor/procedural-animals/src/species/fish/regions.js +27 -0
  200. package/vendor/procedural-animals/src/species/fish/rig.js +143 -0
  201. package/vendor/procedural-animals/src/species/fish/sculpt.js +214 -0
  202. package/vendor/procedural-animals/src/species/fish/variants.js +126 -0
  203. package/vendor/procedural-animals/src/species/fox/behaviour.js +314 -0
  204. package/vendor/procedural-animals/src/species/fox/coat.js +444 -0
  205. package/vendor/procedural-animals/src/species/fox/index.js +120 -0
  206. package/vendor/procedural-animals/src/species/fox/motion.js +81 -0
  207. package/vendor/procedural-animals/src/species/fox/regions.js +59 -0
  208. package/vendor/procedural-animals/src/species/fox/rig.js +91 -0
  209. package/vendor/procedural-animals/src/species/fox/sculpt.js +202 -0
  210. package/vendor/procedural-animals/src/species/frog/behaviour.js +590 -0
  211. package/vendor/procedural-animals/src/species/frog/coat.js +305 -0
  212. package/vendor/procedural-animals/src/species/frog/index.js +97 -0
  213. package/vendor/procedural-animals/src/species/frog/motion.js +69 -0
  214. package/vendor/procedural-animals/src/species/frog/regions.js +46 -0
  215. package/vendor/procedural-animals/src/species/frog/rig.js +156 -0
  216. package/vendor/procedural-animals/src/species/frog/sculpt.js +240 -0
  217. package/vendor/procedural-animals/src/species/goat/behaviour.js +509 -0
  218. package/vendor/procedural-animals/src/species/goat/coat.js +590 -0
  219. package/vendor/procedural-animals/src/species/goat/index.js +149 -0
  220. package/vendor/procedural-animals/src/species/goat/motion.js +95 -0
  221. package/vendor/procedural-animals/src/species/goat/regions.js +98 -0
  222. package/vendor/procedural-animals/src/species/goat/rig.js +181 -0
  223. package/vendor/procedural-animals/src/species/goat/sculpt.js +547 -0
  224. package/vendor/procedural-animals/src/species/horse/coat.js +361 -0
  225. package/vendor/procedural-animals/src/species/horse/coatSeam.js +122 -0
  226. package/vendor/procedural-animals/src/species/horse/index.js +80 -0
  227. package/vendor/procedural-animals/src/species/horse/motion.js +245 -0
  228. package/vendor/procedural-animals/src/species/horse/regions.js +60 -0
  229. package/vendor/procedural-animals/src/species/horse/rig.js +117 -0
  230. package/vendor/procedural-animals/src/species/horse/sculpt.js +316 -0
  231. package/vendor/procedural-animals/src/species/horse/seamWeights.js +272 -0
  232. package/vendor/procedural-animals/src/species/lion/behaviour.js +509 -0
  233. package/vendor/procedural-animals/src/species/lion/coat.js +1016 -0
  234. package/vendor/procedural-animals/src/species/lion/index.js +111 -0
  235. package/vendor/procedural-animals/src/species/lion/motion.js +87 -0
  236. package/vendor/procedural-animals/src/species/lion/regions.js +106 -0
  237. package/vendor/procedural-animals/src/species/lion/rig.js +110 -0
  238. package/vendor/procedural-animals/src/species/lion/sculpt.js +384 -0
  239. package/vendor/procedural-animals/src/species/lion/whiskers.js +132 -0
  240. package/vendor/procedural-animals/src/species/pig/behaviour.js +575 -0
  241. package/vendor/procedural-animals/src/species/pig/coat.js +730 -0
  242. package/vendor/procedural-animals/src/species/pig/ears.js +242 -0
  243. package/vendor/procedural-animals/src/species/pig/index.js +161 -0
  244. package/vendor/procedural-animals/src/species/pig/motion.js +105 -0
  245. package/vendor/procedural-animals/src/species/pig/regions.js +100 -0
  246. package/vendor/procedural-animals/src/species/pig/rig.js +152 -0
  247. package/vendor/procedural-animals/src/species/pig/sculpt.js +382 -0
  248. package/vendor/procedural-animals/src/species/rabbit/behaviour.js +605 -0
  249. package/vendor/procedural-animals/src/species/rabbit/coat.js +285 -0
  250. package/vendor/procedural-animals/src/species/rabbit/index.js +85 -0
  251. package/vendor/procedural-animals/src/species/rabbit/motion.js +85 -0
  252. package/vendor/procedural-animals/src/species/rabbit/regions.js +48 -0
  253. package/vendor/procedural-animals/src/species/rabbit/rig.js +99 -0
  254. package/vendor/procedural-animals/src/species/rabbit/sculpt.js +148 -0
  255. package/vendor/procedural-animals/src/species/rat/behaviour.js +539 -0
  256. package/vendor/procedural-animals/src/species/rat/coat.js +341 -0
  257. package/vendor/procedural-animals/src/species/rat/index.js +111 -0
  258. package/vendor/procedural-animals/src/species/rat/motion.js +90 -0
  259. package/vendor/procedural-animals/src/species/rat/regions.js +92 -0
  260. package/vendor/procedural-animals/src/species/rat/rig.js +112 -0
  261. package/vendor/procedural-animals/src/species/rat/sculpt.js +163 -0
  262. package/vendor/procedural-animals/src/species/rat/whiskers.js +119 -0
  263. package/vendor/procedural-animals/src/species/shark/coat.js +383 -0
  264. package/vendor/procedural-animals/src/species/shark/index.js +104 -0
  265. package/vendor/procedural-animals/src/species/shark/motion.js +69 -0
  266. package/vendor/procedural-animals/src/species/shark/regions.js +34 -0
  267. package/vendor/procedural-animals/src/species/shark/rig.js +194 -0
  268. package/vendor/procedural-animals/src/species/shark/sculpt.js +343 -0
  269. package/vendor/procedural-animals/src/species/shark/variants.js +105 -0
  270. package/vendor/procedural-animals/src/species/sheep/behaviour.js +522 -0
  271. package/vendor/procedural-animals/src/species/sheep/coat.js +529 -0
  272. package/vendor/procedural-animals/src/species/sheep/index.js +152 -0
  273. package/vendor/procedural-animals/src/species/sheep/motion.js +86 -0
  274. package/vendor/procedural-animals/src/species/sheep/neck.js +41 -0
  275. package/vendor/procedural-animals/src/species/sheep/regions.js +62 -0
  276. package/vendor/procedural-animals/src/species/sheep/rig.js +163 -0
  277. package/vendor/procedural-animals/src/species/sheep/sculpt.js +542 -0
  278. package/vendor/procedural-animals/src/species/snake/coat.js +315 -0
  279. package/vendor/procedural-animals/src/species/snake/index.js +73 -0
  280. package/vendor/procedural-animals/src/species/snake/motion.js +51 -0
  281. package/vendor/procedural-animals/src/species/snake/regions.js +51 -0
  282. package/vendor/procedural-animals/src/species/snake/rig.js +108 -0
  283. package/vendor/procedural-animals/src/species/snake/sculpt.js +122 -0
  284. package/vendor/procedural-animals/src/species/spider/coat.js +279 -0
  285. package/vendor/procedural-animals/src/species/spider/index.js +78 -0
  286. package/vendor/procedural-animals/src/species/spider/motion.js +72 -0
  287. package/vendor/procedural-animals/src/species/spider/regions.js +87 -0
  288. package/vendor/procedural-animals/src/species/spider/rig.js +118 -0
  289. package/vendor/procedural-animals/src/species/spider/sculpt.js +182 -0
  290. package/vendor/procedural-animals/src/species/wolf/behaviour.js +160 -0
  291. package/vendor/procedural-animals/src/species/wolf/coat.js +749 -0
  292. package/vendor/procedural-animals/src/species/wolf/index.js +107 -0
  293. package/vendor/procedural-animals/src/species/wolf/motion.js +80 -0
  294. package/vendor/procedural-animals/src/species/wolf/regions.js +57 -0
  295. package/vendor/procedural-animals/src/species/wolf/rig.js +87 -0
  296. package/vendor/procedural-animals/src/species/wolf/sculpt.js +339 -0
  297. package/vendor/procedural-animals/src/worker.js +29 -0
@@ -0,0 +1,66 @@
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
+ }
@@ -0,0 +1,158 @@
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
+ }
@@ -0,0 +1,313 @@
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
+ }