@bitefoundry/retrieviewer 0.0.0-stage → 0.0.1

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 (292) 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 +107 -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 +61 -2
  12. package/RELEASING.md +61 -0
  13. package/THIRD-PARTY-NOTICES.md +17 -0
  14. package/TRADEMARKS.md +21 -0
  15. package/braille.mjs +45 -0
  16. package/examples/bridge.py +62 -0
  17. package/examples/embed.mjs +15 -0
  18. package/examples/live.mjs +40 -0
  19. package/examples/plugin.mjs +21 -0
  20. package/integrations/opencode/runtime.mjs +195 -0
  21. package/integrations/opencode/tui.tsx +59 -0
  22. package/locomotion-core.mjs +21 -0
  23. package/locomotion-puppy.animal +0 -0
  24. package/package.json +125 -4
  25. package/pet-q5-manifest.json +118 -0
  26. package/puppy-clean.mjs +51 -0
  27. package/puppy-companion-interactions-v3-q5.bin.gz +0 -0
  28. package/puppy-companion-interactions-v3.json +1 -0
  29. package/puppy-companion-life.mjs +182 -0
  30. package/puppy-companion-objects.mjs +30 -0
  31. package/puppy-companion-sprites.mjs +14 -0
  32. package/puppy-continuous.mjs +57 -0
  33. package/puppy-face.mjs +46 -0
  34. package/puppy-frame-predictive.mjs +147 -0
  35. package/puppy-frame-store.mjs +108 -0
  36. package/puppy-mouth-anchor.json +1 -0
  37. package/puppy-mouth-anchor.mjs +33 -0
  38. package/puppy-paper-actions-v9-q5.bin.gz +0 -0
  39. package/puppy-paper-actions-v9.json +1 -0
  40. package/puppy-paper-actions.mjs +48 -0
  41. package/puppy-paper-approach-q5.bin.gz +0 -0
  42. package/puppy-paper-approach.json +1 -0
  43. package/puppy-paper-area.mjs +15 -0
  44. package/puppy-paper-arrival-seat-q5.bin.gz +0 -0
  45. package/puppy-paper-arrival-seat.json +1 -0
  46. package/puppy-paper-behaviors-q5.bin.gz +0 -0
  47. package/puppy-paper-behaviors.json +1 -0
  48. package/puppy-paper-behaviors.mjs +8 -0
  49. package/puppy-paper-contact.mjs +103 -0
  50. package/puppy-paper-director.mjs +21 -0
  51. package/puppy-paper-paw-transport.mjs +76 -0
  52. package/puppy-paper-rear-gallop-q5.bin.gz +0 -0
  53. package/puppy-paper-rear-gallop.json +1 -0
  54. package/puppy-paper-seat-q5.bin.gz +0 -0
  55. package/puppy-paper-seat.json +14 -0
  56. package/puppy-paper-seat.mjs +13 -0
  57. package/puppy-paper-trick-timing.mjs +58 -0
  58. package/puppy-paper-world.mjs +108 -0
  59. package/puppy-paper.mjs +271 -0
  60. package/puppy-stable-meta.json +1606 -0
  61. package/puppy-stable.mjs +72 -0
  62. package/puppy-stride-meta.json +343 -0
  63. package/puppy-stride-tweens-q5.bin.gz +0 -0
  64. package/puppy-zoomies.mjs +27 -0
  65. package/puppy-zoomies30.mjs +12 -0
  66. package/retrieviewer-cli.mjs +81 -0
  67. package/retrieviewer-config.mjs +49 -0
  68. package/retrieviewer-install.mjs +157 -0
  69. package/retrieviewer-plugin.d.mts +44 -0
  70. package/retrieviewer-plugin.mjs +97 -0
  71. package/retrieviewer-stdio.mjs +38 -0
  72. package/retrieviewer.d.mts +85 -0
  73. package/retrieviewer.mjs +142 -0
  74. package/vendor/procedural-animals/LICENSE +21 -0
  75. package/vendor/procedural-animals/package.json +40 -0
  76. package/vendor/procedural-animals/src/animal.js +146 -0
  77. package/vendor/procedural-animals/src/bake.js +51 -0
  78. package/vendor/procedural-animals/src/build.js +81 -0
  79. package/vendor/procedural-animals/src/core/build/coatKit.js +121 -0
  80. package/vendor/procedural-animals/src/core/build/featherCards.js +189 -0
  81. package/vendor/procedural-animals/src/core/build/finEdges.js +85 -0
  82. package/vendor/procedural-animals/src/core/build/furSlope.js +115 -0
  83. package/vendor/procedural-animals/src/core/build/mesh.js +67 -0
  84. package/vendor/procedural-animals/src/core/build/pipeline.js +272 -0
  85. package/vendor/procedural-animals/src/core/build/seams.js +183 -0
  86. package/vendor/procedural-animals/src/core/build/warp.js +112 -0
  87. package/vendor/procedural-animals/src/core/build/weights.js +393 -0
  88. package/vendor/procedural-animals/src/core/math/vec.js +81 -0
  89. package/vendor/procedural-animals/src/core/motion/actions.js +800 -0
  90. package/vendor/procedural-animals/src/core/motion/bird.js +3063 -0
  91. package/vendor/procedural-animals/src/core/motion/birdActions.js +1059 -0
  92. package/vendor/procedural-animals/src/core/motion/common.js +158 -0
  93. package/vendor/procedural-animals/src/core/motion/index.js +22 -0
  94. package/vendor/procedural-animals/src/core/motion/quadruped.js +2875 -0
  95. package/vendor/procedural-animals/src/core/motion/snake.js +1594 -0
  96. package/vendor/procedural-animals/src/core/motion/spider.js +1810 -0
  97. package/vendor/procedural-animals/src/core/motion/swimmer.js +1047 -0
  98. package/vendor/procedural-animals/src/core/motion/swimmerActions.js +613 -0
  99. package/vendor/procedural-animals/src/core/render/animalObject.js +262 -0
  100. package/vendor/procedural-animals/src/core/render/coatMaterial.js +1301 -0
  101. package/vendor/procedural-animals/src/core/render/dqs.js +159 -0
  102. package/vendor/procedural-animals/src/core/render/eyes.js +676 -0
  103. package/vendor/procedural-animals/src/core/render/membranes.js +77 -0
  104. package/vendor/procedural-animals/src/core/render/skeleton.js +41 -0
  105. package/vendor/procedural-animals/src/core/rig/bird.js +327 -0
  106. package/vendor/procedural-animals/src/core/rig/quadruped.js +76 -0
  107. package/vendor/procedural-animals/src/core/rig/rig.js +79 -0
  108. package/vendor/procedural-animals/src/core/rig/snake.js +76 -0
  109. package/vendor/procedural-animals/src/core/rig/spider.js +110 -0
  110. package/vendor/procedural-animals/src/core/rig/swimmer.js +181 -0
  111. package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +53 -0
  112. package/vendor/procedural-animals/src/core/sdf/mesher.js +238 -0
  113. package/vendor/procedural-animals/src/core/sdf/sdf.js +263 -0
  114. package/vendor/procedural-animals/src/index.d.ts +98 -0
  115. package/vendor/procedural-animals/src/index.js +29 -0
  116. package/vendor/procedural-animals/src/registry.js +48 -0
  117. package/vendor/procedural-animals/src/species/bear/behaviour.js +463 -0
  118. package/vendor/procedural-animals/src/species/bear/claws.js +147 -0
  119. package/vendor/procedural-animals/src/species/bear/coat.js +726 -0
  120. package/vendor/procedural-animals/src/species/bear/index.js +139 -0
  121. package/vendor/procedural-animals/src/species/bear/motion.js +112 -0
  122. package/vendor/procedural-animals/src/species/bear/regions.js +78 -0
  123. package/vendor/procedural-animals/src/species/bear/rig.js +112 -0
  124. package/vendor/procedural-animals/src/species/bear/sculpt.js +272 -0
  125. package/vendor/procedural-animals/src/species/boar/behaviour.js +335 -0
  126. package/vendor/procedural-animals/src/species/boar/coat.js +372 -0
  127. package/vendor/procedural-animals/src/species/boar/index.js +110 -0
  128. package/vendor/procedural-animals/src/species/boar/motion.js +85 -0
  129. package/vendor/procedural-animals/src/species/boar/regions.js +88 -0
  130. package/vendor/procedural-animals/src/species/boar/rig.js +111 -0
  131. package/vendor/procedural-animals/src/species/boar/sculpt.js +285 -0
  132. package/vendor/procedural-animals/src/species/cat/behaviour.js +559 -0
  133. package/vendor/procedural-animals/src/species/cat/coat.js +841 -0
  134. package/vendor/procedural-animals/src/species/cat/index.js +211 -0
  135. package/vendor/procedural-animals/src/species/cat/motion.js +101 -0
  136. package/vendor/procedural-animals/src/species/cat/regions.js +82 -0
  137. package/vendor/procedural-animals/src/species/cat/rig.js +100 -0
  138. package/vendor/procedural-animals/src/species/cat/sculpt.js +266 -0
  139. package/vendor/procedural-animals/src/species/cat/whiskers.js +110 -0
  140. package/vendor/procedural-animals/src/species/cheetah/coat.js +427 -0
  141. package/vendor/procedural-animals/src/species/cheetah/index.js +51 -0
  142. package/vendor/procedural-animals/src/species/cheetah/joints.js +3 -0
  143. package/vendor/procedural-animals/src/species/cheetah/motion.js +77 -0
  144. package/vendor/procedural-animals/src/species/cheetah/regions.js +95 -0
  145. package/vendor/procedural-animals/src/species/cheetah/rig.js +66 -0
  146. package/vendor/procedural-animals/src/species/cheetah/sculpt.js +158 -0
  147. package/vendor/procedural-animals/src/species/chicken/coat.js +313 -0
  148. package/vendor/procedural-animals/src/species/chicken/coverts.js +320 -0
  149. package/vendor/procedural-animals/src/species/chicken/index.js +110 -0
  150. package/vendor/procedural-animals/src/species/chicken/motion.js +177 -0
  151. package/vendor/procedural-animals/src/species/chicken/regions.js +66 -0
  152. package/vendor/procedural-animals/src/species/chicken/rig.js +144 -0
  153. package/vendor/procedural-animals/src/species/chicken/sculpt.js +389 -0
  154. package/vendor/procedural-animals/src/species/chicken/wingLook.js +66 -0
  155. package/vendor/procedural-animals/src/species/chicken/wingStack.js +124 -0
  156. package/vendor/procedural-animals/src/species/cow/behaviour.js +521 -0
  157. package/vendor/procedural-animals/src/species/cow/coat.js +465 -0
  158. package/vendor/procedural-animals/src/species/cow/index.js +118 -0
  159. package/vendor/procedural-animals/src/species/cow/motion.js +81 -0
  160. package/vendor/procedural-animals/src/species/cow/regions.js +98 -0
  161. package/vendor/procedural-animals/src/species/cow/rig.js +116 -0
  162. package/vendor/procedural-animals/src/species/cow/sculpt.js +339 -0
  163. package/vendor/procedural-animals/src/species/crow/coat.js +145 -0
  164. package/vendor/procedural-animals/src/species/crow/index.js +70 -0
  165. package/vendor/procedural-animals/src/species/crow/joints.js +3 -0
  166. package/vendor/procedural-animals/src/species/crow/motion.js +101 -0
  167. package/vendor/procedural-animals/src/species/crow/regions.js +50 -0
  168. package/vendor/procedural-animals/src/species/crow/rig.js +83 -0
  169. package/vendor/procedural-animals/src/species/crow/sculpt.js +118 -0
  170. package/vendor/procedural-animals/src/species/deer/behaviour.js +513 -0
  171. package/vendor/procedural-animals/src/species/deer/coat.js +391 -0
  172. package/vendor/procedural-animals/src/species/deer/index.js +106 -0
  173. package/vendor/procedural-animals/src/species/deer/motion.js +97 -0
  174. package/vendor/procedural-animals/src/species/deer/regions.js +60 -0
  175. package/vendor/procedural-animals/src/species/deer/rig.js +124 -0
  176. package/vendor/procedural-animals/src/species/deer/sculpt.js +297 -0
  177. package/vendor/procedural-animals/src/species/dog/behaviour.js +521 -0
  178. package/vendor/procedural-animals/src/species/dog/coat.js +495 -0
  179. package/vendor/procedural-animals/src/species/dog/index.js +144 -0
  180. package/vendor/procedural-animals/src/species/dog/motion.js +118 -0
  181. package/vendor/procedural-animals/src/species/dog/regions.js +61 -0
  182. package/vendor/procedural-animals/src/species/dog/rig.js +129 -0
  183. package/vendor/procedural-animals/src/species/dog/sculpt.js +246 -0
  184. package/vendor/procedural-animals/src/species/eagle/coat.js +250 -0
  185. package/vendor/procedural-animals/src/species/eagle/index.js +76 -0
  186. package/vendor/procedural-animals/src/species/eagle/joints.js +3 -0
  187. package/vendor/procedural-animals/src/species/eagle/motion.js +137 -0
  188. package/vendor/procedural-animals/src/species/eagle/regions.js +57 -0
  189. package/vendor/procedural-animals/src/species/eagle/rig.js +107 -0
  190. package/vendor/procedural-animals/src/species/eagle/sculpt.js +137 -0
  191. package/vendor/procedural-animals/src/species/fish/coat.js +271 -0
  192. package/vendor/procedural-animals/src/species/fish/index.js +88 -0
  193. package/vendor/procedural-animals/src/species/fish/motion.js +92 -0
  194. package/vendor/procedural-animals/src/species/fish/regions.js +27 -0
  195. package/vendor/procedural-animals/src/species/fish/rig.js +143 -0
  196. package/vendor/procedural-animals/src/species/fish/sculpt.js +214 -0
  197. package/vendor/procedural-animals/src/species/fish/variants.js +126 -0
  198. package/vendor/procedural-animals/src/species/fox/behaviour.js +314 -0
  199. package/vendor/procedural-animals/src/species/fox/coat.js +444 -0
  200. package/vendor/procedural-animals/src/species/fox/index.js +120 -0
  201. package/vendor/procedural-animals/src/species/fox/motion.js +81 -0
  202. package/vendor/procedural-animals/src/species/fox/regions.js +59 -0
  203. package/vendor/procedural-animals/src/species/fox/rig.js +91 -0
  204. package/vendor/procedural-animals/src/species/fox/sculpt.js +202 -0
  205. package/vendor/procedural-animals/src/species/frog/behaviour.js +590 -0
  206. package/vendor/procedural-animals/src/species/frog/coat.js +305 -0
  207. package/vendor/procedural-animals/src/species/frog/index.js +97 -0
  208. package/vendor/procedural-animals/src/species/frog/motion.js +69 -0
  209. package/vendor/procedural-animals/src/species/frog/regions.js +46 -0
  210. package/vendor/procedural-animals/src/species/frog/rig.js +156 -0
  211. package/vendor/procedural-animals/src/species/frog/sculpt.js +240 -0
  212. package/vendor/procedural-animals/src/species/goat/behaviour.js +509 -0
  213. package/vendor/procedural-animals/src/species/goat/coat.js +590 -0
  214. package/vendor/procedural-animals/src/species/goat/index.js +149 -0
  215. package/vendor/procedural-animals/src/species/goat/motion.js +95 -0
  216. package/vendor/procedural-animals/src/species/goat/regions.js +98 -0
  217. package/vendor/procedural-animals/src/species/goat/rig.js +181 -0
  218. package/vendor/procedural-animals/src/species/goat/sculpt.js +547 -0
  219. package/vendor/procedural-animals/src/species/horse/coat.js +361 -0
  220. package/vendor/procedural-animals/src/species/horse/coatSeam.js +122 -0
  221. package/vendor/procedural-animals/src/species/horse/index.js +80 -0
  222. package/vendor/procedural-animals/src/species/horse/motion.js +245 -0
  223. package/vendor/procedural-animals/src/species/horse/regions.js +60 -0
  224. package/vendor/procedural-animals/src/species/horse/rig.js +117 -0
  225. package/vendor/procedural-animals/src/species/horse/sculpt.js +316 -0
  226. package/vendor/procedural-animals/src/species/horse/seamWeights.js +272 -0
  227. package/vendor/procedural-animals/src/species/lion/behaviour.js +509 -0
  228. package/vendor/procedural-animals/src/species/lion/coat.js +1016 -0
  229. package/vendor/procedural-animals/src/species/lion/index.js +111 -0
  230. package/vendor/procedural-animals/src/species/lion/motion.js +87 -0
  231. package/vendor/procedural-animals/src/species/lion/regions.js +106 -0
  232. package/vendor/procedural-animals/src/species/lion/rig.js +110 -0
  233. package/vendor/procedural-animals/src/species/lion/sculpt.js +384 -0
  234. package/vendor/procedural-animals/src/species/lion/whiskers.js +132 -0
  235. package/vendor/procedural-animals/src/species/pig/behaviour.js +575 -0
  236. package/vendor/procedural-animals/src/species/pig/coat.js +730 -0
  237. package/vendor/procedural-animals/src/species/pig/ears.js +242 -0
  238. package/vendor/procedural-animals/src/species/pig/index.js +161 -0
  239. package/vendor/procedural-animals/src/species/pig/motion.js +105 -0
  240. package/vendor/procedural-animals/src/species/pig/regions.js +100 -0
  241. package/vendor/procedural-animals/src/species/pig/rig.js +152 -0
  242. package/vendor/procedural-animals/src/species/pig/sculpt.js +382 -0
  243. package/vendor/procedural-animals/src/species/rabbit/behaviour.js +605 -0
  244. package/vendor/procedural-animals/src/species/rabbit/coat.js +285 -0
  245. package/vendor/procedural-animals/src/species/rabbit/index.js +85 -0
  246. package/vendor/procedural-animals/src/species/rabbit/motion.js +85 -0
  247. package/vendor/procedural-animals/src/species/rabbit/regions.js +48 -0
  248. package/vendor/procedural-animals/src/species/rabbit/rig.js +99 -0
  249. package/vendor/procedural-animals/src/species/rabbit/sculpt.js +148 -0
  250. package/vendor/procedural-animals/src/species/rat/behaviour.js +539 -0
  251. package/vendor/procedural-animals/src/species/rat/coat.js +341 -0
  252. package/vendor/procedural-animals/src/species/rat/index.js +111 -0
  253. package/vendor/procedural-animals/src/species/rat/motion.js +90 -0
  254. package/vendor/procedural-animals/src/species/rat/regions.js +92 -0
  255. package/vendor/procedural-animals/src/species/rat/rig.js +112 -0
  256. package/vendor/procedural-animals/src/species/rat/sculpt.js +163 -0
  257. package/vendor/procedural-animals/src/species/rat/whiskers.js +119 -0
  258. package/vendor/procedural-animals/src/species/shark/coat.js +383 -0
  259. package/vendor/procedural-animals/src/species/shark/index.js +104 -0
  260. package/vendor/procedural-animals/src/species/shark/motion.js +69 -0
  261. package/vendor/procedural-animals/src/species/shark/regions.js +34 -0
  262. package/vendor/procedural-animals/src/species/shark/rig.js +194 -0
  263. package/vendor/procedural-animals/src/species/shark/sculpt.js +343 -0
  264. package/vendor/procedural-animals/src/species/shark/variants.js +105 -0
  265. package/vendor/procedural-animals/src/species/sheep/behaviour.js +522 -0
  266. package/vendor/procedural-animals/src/species/sheep/coat.js +529 -0
  267. package/vendor/procedural-animals/src/species/sheep/index.js +152 -0
  268. package/vendor/procedural-animals/src/species/sheep/motion.js +86 -0
  269. package/vendor/procedural-animals/src/species/sheep/neck.js +41 -0
  270. package/vendor/procedural-animals/src/species/sheep/regions.js +62 -0
  271. package/vendor/procedural-animals/src/species/sheep/rig.js +163 -0
  272. package/vendor/procedural-animals/src/species/sheep/sculpt.js +542 -0
  273. package/vendor/procedural-animals/src/species/snake/coat.js +315 -0
  274. package/vendor/procedural-animals/src/species/snake/index.js +73 -0
  275. package/vendor/procedural-animals/src/species/snake/motion.js +51 -0
  276. package/vendor/procedural-animals/src/species/snake/regions.js +51 -0
  277. package/vendor/procedural-animals/src/species/snake/rig.js +108 -0
  278. package/vendor/procedural-animals/src/species/snake/sculpt.js +122 -0
  279. package/vendor/procedural-animals/src/species/spider/coat.js +279 -0
  280. package/vendor/procedural-animals/src/species/spider/index.js +78 -0
  281. package/vendor/procedural-animals/src/species/spider/motion.js +72 -0
  282. package/vendor/procedural-animals/src/species/spider/regions.js +87 -0
  283. package/vendor/procedural-animals/src/species/spider/rig.js +118 -0
  284. package/vendor/procedural-animals/src/species/spider/sculpt.js +182 -0
  285. package/vendor/procedural-animals/src/species/wolf/behaviour.js +160 -0
  286. package/vendor/procedural-animals/src/species/wolf/coat.js +749 -0
  287. package/vendor/procedural-animals/src/species/wolf/index.js +107 -0
  288. package/vendor/procedural-animals/src/species/wolf/motion.js +80 -0
  289. package/vendor/procedural-animals/src/species/wolf/regions.js +57 -0
  290. package/vendor/procedural-animals/src/species/wolf/rig.js +87 -0
  291. package/vendor/procedural-animals/src/species/wolf/sculpt.js +339 -0
  292. package/vendor/procedural-animals/src/worker.js +29 -0
@@ -0,0 +1,320 @@
1
+ // The folded wing's coverts (photos side1 / side2 / three-quarter1 / rear_three-quarter: the coverts are
2
+ // a layered surface of shingles continuous with the body, lying ON the secondaries; the flight
3
+ // feathers show below and behind them). From the top:
4
+ // - the shield (sculpt.js coverts()): skin on the forearm's dorsal side, shaded with the body's
5
+ // contour-feather shingles (lesser and median coverts); its top is a plane fitted just above the
6
+ // flight-feather stack under it (wingStack.js: the highest card over the wing's motion), so it is
7
+ // no thicker than the stack it covers, and it reaches down below the wing plane (the feathers'
8
+ // roots are inside skin); the lid continues it over its upper rear corner and the back (the inner
9
+ // vanes and the primaries leave its rim there);
10
+ // - the greater coverts: rounded feather cards rigid on the forearm (this file), with the body's down,
11
+ // reaching into the shield and lying on its top, draped over its rim down onto the secondaries
12
+ // (above the stack in every wing pose), so the rim is a row of soft shingle ends rather than a skin
13
+ // edge over a dark gap, and the flight feathers come out from under them;
14
+ // - the flight feathers (core/build/featherCards.js), their greater covert cards dropped (motion.js
15
+ // feathersFor: cov.skip); the tertials restyled as contour feathers (wingLook.js).
16
+ // Plan coordinates: the ulna's (x from the wrist toward the elbow, y toward the trailing edge, mm at
17
+ // wingK 1); heights above the wing plane in mm (absolute: the feather stack's lift steps do not scale).
18
+ import { wingStack, insidePoly } from './wingStack.js';
19
+ import { MAT } from '../../core/build/coatKit.js';
20
+ import { add, sub, mul, norm, cross, dot } from '../../core/math/vec.js';
21
+
22
+ export const SHIELD = {
23
+ // the shield's outline (lesser / median coverts): front round the wrist, top edge along the leading
24
+ // edge, lower rim along the secondaries' bases, rear end at the elbow
25
+ core: [[-7, -6], [-4, -15], [4, -22], [18, -25], [36, -24], [52, -19], [64, -15], [71, -10], [74, -4], [72, 1], [67, 4], [60, 6], [50, 7], [38, 7.5], [26, 7], [15, 6], [6, 4], [-3, 1]],
26
+ // greater coverts: root (x, y), direction (deg from +x toward +y), length factor, depth inside the rim
27
+ // (mm, default inRoot); side by side along the lower rim and up the rear end, so their rounded ends make
28
+ // the scalloped rim (fitted alternately: every other card first, the ones between them on top)
29
+ cards: [[15, 3.6, 50, 0.8, 3], [21, 3.8, 48, 0.95], [30, 4.4, 45, 1.08], [39, 4.6, 43, 0.97], [48, 4.4, 41, 1.06], [57, 3.6, 37, 0.98], [65, 1.8, 29, 1.04], [71, -4, 14, 1.0]],
30
+ len: 21, halfW: 6.8, // card length (x the card's factor), half width (mm)
31
+ gap: 0.3, step: 0.3, coreGap: 0.45, coreRound: 3.5, coreDown: 2, // mm
32
+ // the lid over the upper rear corner and the back (plan mm), its gap above the stack, thickness, rim
33
+ // radius, blend (its lower edge stays above y -12 near x 68: card #7 lies under it)
34
+ lid: { poly: [[44, -22], [58, -31], [74, -31], [84, -19], [82, -12], [68, -14], [56, -16], [44, -18]], gap: 0.4, t: 5.2, round: 2.4, k: 0.008 },
35
+ // cards along the rim (fitted alternately), the cards' reach into the shield, their height on its top
36
+ // (+ a step per card they overlap there), the drape from its rim down to their planes, the width at
37
+ // the root (neighbours' roots side by side, their free ends overlapping)
38
+ rim: 8, inRoot: 8, onTop: 0.3, ordStep: 0.6, drape: 7, rootTaper: 0.55,
39
+ };
40
+
41
+ const cache = new Map();
42
+ /** Fitted layout: { core: { poly, plane [h0, hx, hy] (top), t }, cards: [{ x, y, a, len, w, plane }] } (plan mm, this individual) */
43
+ export function shieldLayout(form = {}) {
44
+ const key = JSON.stringify([form.wingK, form.priK, form.fwK, form.chick, form.up]);
45
+ if (cache.has(key)) return cache.get(key);
46
+ const C = SHIELD, wk = form.wingK ?? 1, S = wingStack(form);
47
+ const core = C.core.map(([x, y]) => [x * wk, y * wk]);
48
+ const cards = C.cards.map(([x, y, a, lk = 1, inR = C.inRoot], i) => {
49
+ const r = a * Math.PI / 180, d = [Math.cos(r), Math.sin(r)], s = [-d[1], d[0]];
50
+ const c = { i, x: x * wk, y: y * wk, d, s, len: C.len * lk * wk, w: C.halfW * wk, plane: null };
51
+ c.tipL = Math.min(c.len * 0.55, c.w * 1.5); c.body = c.len - c.tipL;
52
+ // (x, y): where the card's shaft leaves the shield; each side of the card starts inR mm inside the
53
+ // shield's outline (its root edge runs along the rim, on the shield's top)
54
+ const U0 = [];
55
+ for (let k = 0; k <= 20; k++) {
56
+ const v = (-1 + k / 10) * c.w;
57
+ let ue = -20 * wk;
58
+ for (let u = 20 * wk; u >= -20 * wk; u -= 0.2) if (insidePoly(core, c.x + d[0] * u + s[0] * v, c.y + d[1] * u + s[1] * v)) { ue = u + 0.2; break; }
59
+ U0.push(Math.min(ue - inR * wk, c.body));
60
+ }
61
+ c.u0 = (cc) => { const f = (cc + 1) * 10, k = Math.min(19, Math.floor(f)); return U0[k] + (U0[k + 1] - U0[k]) * (f - k); };
62
+ const poly = [];
63
+ for (let k = 0; k <= 10; k++) poly.push(cardPoint(c, 0, -1 + k / 5));
64
+ for (let k = 1; k <= 12; k++) poly.push(cardPoint(c, k / 12, 1));
65
+ for (let k = 11; k >= 1; k--) poly.push(cardPoint(c, k / 12, -1));
66
+ c.poly = poly;
67
+ return c;
68
+ });
69
+ // sample points of each card's footprint outside the shield (1 mm grid)
70
+ for (const c of cards) {
71
+ const xs = c.poly.map((p) => p[0]), ys = c.poly.map((p) => p[1]);
72
+ c.pts = [];
73
+ for (let y = Math.floor(Math.min(...ys)); y <= Math.ceil(Math.max(...ys)); y += 1) for (let x = Math.floor(Math.min(...xs)); x <= Math.ceil(Math.max(...xs)); x += 1) {
74
+ if (!insidePoly(c.poly, x, y) || insidePoly(core, x, y)) continue;
75
+ c.pts.push([x, y, S.near(x, y, 1.2)]);
76
+ }
77
+ }
78
+ // fit in stacking order: above the stack (+ gap + half the card's thickness) and above every earlier
79
+ // card where they overlap (+ the card's thickness + step); planar, tilted to follow the stack (least
80
+ // mean clearance)
81
+ const hOf = (pl, x, y) => pl[0] + pl[1] * x + pl[2] * y;
82
+ // fitting order: alternate cards along the rim first, then the ones between them (each lies on its two
83
+ // neighbours: no chain of overlaps piling up toward the elbow), the extra cards last
84
+ const nR = C.rim ?? cards.length;
85
+ const order = [...cards.slice(0, nR).filter((c) => c.i % 2 === 0), ...cards.slice(0, nR).filter((c) => c.i % 2 === 1), ...cards.slice(nR)];
86
+ const done = [];
87
+ for (const c of order) {
88
+ const need = c.pts.map(([x, y, h]) => {
89
+ let L = Number.isFinite(h) ? h + C.gap + 0.25 : -Infinity;
90
+ for (const cj of done) if (insidePoly(cj.poly, x, y)) L = Math.max(L, hOf(cj.plane, x, y) + 0.5 + C.step);
91
+ return [x, y, L];
92
+ }).filter((q) => Number.isFinite(q[2]));
93
+ let best = null;
94
+ for (let bx = -0.1; bx <= 0.3001; bx += 0.01) for (let by = -0.2; by <= 0.2001; by += 0.01) {
95
+ let a = -Infinity; for (const [x, y, L] of need) a = Math.max(a, L - bx * x - by * y);
96
+ if (!Number.isFinite(a)) a = 0;
97
+ let m = 0; for (const [x, y, L] of need) m += a + bx * x + by * y - L;
98
+ m /= Math.max(1, need.length);
99
+ if (!best || m < best.m - 1e-9) best = { m, plane: [a, bx, by] };
100
+ }
101
+ c.plane = best.plane;
102
+ c.fitGap = best.m;
103
+ if (!need.length) c.plane = [S.near(c.x, c.y, 3) + C.gap + 0.25, 0, 0];
104
+ done.push(c);
105
+ }
106
+ // each card's step above the shield's top where it lies on it: one above the highest earlier card it overlaps there
107
+ for (let q = 0; q < order.length; q++) {
108
+ const c = order[q];
109
+ let o = 0;
110
+ const xs = c.poly.map((p) => p[0]), ys = c.poly.map((p) => p[1]);
111
+ for (let y = Math.floor(Math.min(...ys)); y <= Math.ceil(Math.max(...ys)); y += 0.5) for (let x = Math.floor(Math.min(...xs)); x <= Math.ceil(Math.max(...xs)); x += 0.5) {
112
+ if (!insidePoly(c.poly, x, y) || distPoly(core, x, y) > (insidePoly(core, x, y) ? 1e9 : C.drape * wk)) continue;
113
+ for (let j = 0; j < q; j++) if (order[j].ord + 1 > o && insidePoly(order[j].poly, x, y)) o = order[j].ord + 1;
114
+ }
115
+ c.ord = o;
116
+ }
117
+ // the shield's top: above the stack inside it (+ coreGap) and above the covert cards' roots
118
+ const cxs = core.map((p) => p[0]), cys = core.map((p) => p[1]);
119
+ const need = [];
120
+ for (let y = Math.floor(Math.min(...cys)); y <= Math.ceil(Math.max(...cys)); y += 1) for (let x = Math.floor(Math.min(...cxs)); x <= Math.ceil(Math.max(...cxs)); x += 1) {
121
+ if (!insidePoly(core, x, y)) continue;
122
+ let L = S.near(x, y, 1.2) + C.coreGap;
123
+ if (Number.isFinite(L)) need.push([x, y, L]);
124
+ }
125
+ let best = null;
126
+ for (let bx = 0; bx <= 0.3001; bx += 0.005) for (let by = -0.2; by <= 0.2001; by += 0.005) {
127
+ let a = -Infinity; for (const [x, y, L] of need) a = Math.max(a, L - bx * x - by * y);
128
+ let m = 0; for (const [x, y, L] of need) m += a + bx * x + by * y - L;
129
+ if (!best || m < best.m) best = { m, plane: [a, bx, by] };
130
+ }
131
+ // thick enough to reach C.coreDown mm below the wing plane everywhere under it
132
+ let tMax = 0; for (const [x, y] of core) tMax = Math.max(tMax, hOf(best.plane, x, y) + C.coreDown);
133
+ const out = { core: { poly: core, plane: best.plane, t: tMax, round: C.coreRound }, cards, stack: S };
134
+ // the lid over the shield's upper rear corner: a plate above the stack (the inner vanes come out of the
135
+ // shield's rim there, beside the back, with nothing over them), its underside fitted just above the
136
+ // stack's highest card over the wing's motion
137
+ if (C.lid) {
138
+ const lp = C.lid.poly.map(([x, y]) => [x * wk, y * wk]);
139
+ const lneed = [];
140
+ const lx = lp.map((p) => p[0]), ly = lp.map((p) => p[1]);
141
+ for (let y = Math.floor(Math.min(...ly)); y <= Math.ceil(Math.max(...ly)); y += 1) for (let x = Math.floor(Math.min(...lx)); x <= Math.ceil(Math.max(...lx)); x += 1) {
142
+ if (!insidePoly(lp, x, y)) continue;
143
+ const h = S.near(x, y, 1.5);
144
+ if (Number.isFinite(h)) lneed.push([x, y, h + C.lid.gap]);
145
+ }
146
+ // (tilted so its top runs on from the shield's top as closely as it can: no tab standing up)
147
+ const lt = C.lid.t * wk, lpts = [];
148
+ for (let y = Math.floor(Math.min(...ly)); y <= Math.ceil(Math.max(...ly)); y += 1) for (let x = Math.floor(Math.min(...lx)); x <= Math.ceil(Math.max(...lx)); x += 1) if (insidePoly(lp, x, y)) lpts.push([x, y]);
149
+ let lb = null;
150
+ for (let bx = -0.3; bx <= 0.3001; bx += 0.01) for (let by = -0.4; by <= 0.4001; by += 0.01) {
151
+ let a = -Infinity; for (const [x, y, L] of lneed) a = Math.max(a, L - bx * x - by * y);
152
+ let m = 0; for (const [x, y] of lpts) { const d = a + bx * x + by * y + lt - hOf(best.plane, x, y); m += d * d; }
153
+ if (!lb || m < lb.m) lb = { m, plane: [a, bx, by] };
154
+ }
155
+ out.lid = { poly: lp, plane: lb.plane, t: lt, round: C.lid.round * wk, k: (C.lid.k ?? 0.003) * wk };
156
+ }
157
+ // a card's height (mm above the wing plane) at plan (x, y), s mm from its root edge: on the shield's top inside its
158
+ // outline (each card a step above the ones before it), draped over the rim down to its fitted plane outside
159
+ const top = best.plane;
160
+ out.cardH = (c, x, y, s) => {
161
+ const hTop = hOf(top, x, y) + C.onTop + C.ordStep * c.ord;
162
+ const hOut = hOf(c.plane, x, y);
163
+ const dOut = insidePoly(core, x, y) ? 0 : distPoly(core, x, y);
164
+ const f = 1 - smooth01(dOut / (C.drape * wk));
165
+ let h = hOut + (hTop - hOut) * f;
166
+ // (the root edge lies on the shield, in its down; a root sunk into the skin crossed the card before it)
167
+ void s;
168
+ return h;
169
+ };
170
+ cache.set(key, out);
171
+ return out;
172
+ }
173
+
174
+ const smooth01 = (t) => { const c = Math.min(1, Math.max(0, t)); return c * c * (3 - 2 * c); };
175
+ // distance from (x, y) to a polygon's outline
176
+ export function distPoly(poly, x, y) {
177
+ let m = Infinity;
178
+ for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
179
+ const [ax, ay] = poly[j], [bx, by] = poly[i], dx = bx - ax, dy = by - ay;
180
+ const t = Math.max(0, Math.min(1, ((x - ax) * dx + (y - ay) * dy) / (dx * dx + dy * dy || 1)));
181
+ m = Math.min(m, Math.hypot(x - ax - dx * t, y - ay - dy * t));
182
+ }
183
+ return m;
184
+ }
185
+
186
+ // a point of a covert card in the plan (mm): tau 0 (its root edge, along the shield's rim) .. 1 (the tip of
187
+ // its rounded end), cc -1 .. 1 across it
188
+ export function cardPoint(c, tau, cc) {
189
+ const u0 = c.u0(cc), u = u0 + tau * (c.len - u0);
190
+ let hw = u <= c.body ? c.w : c.w * Math.sqrt(Math.max(0, 1 - ((u - c.body) / c.tipL) ** 2));
191
+ // (narrower toward the root: neighbours' roots side by side, their free ends overlapping)
192
+ if (SHIELD.rootTaper) { const a = Math.min(1, Math.max(0, (u - u0) / Math.max(1e-6, c.body - u0))); hw *= SHIELD.rootTaper + (1 - SHIELD.rootTaper) * Math.min(1, a / 0.6); }
193
+ const v = cc * Math.max(hw, 0.05);
194
+ return [c.x + c.d[0] * u + c.s[0] * v, c.y + c.d[1] * u + c.s[1] * v, hw];
195
+ }
196
+
197
+ // plan (mm) -> bind space, in the ulna's frame from the bind joints (as sculpt.js coverts())
198
+ export function planFrame(J, s) {
199
+ const S = s > 0 ? 'L' : 'R';
200
+ const sh = J['shoulder' + S], el = J['elbow' + S], wr = J['wrist' + S];
201
+ let n = norm(cross(sub(el, sh), sub(wr, el)));
202
+ if (n[1] < 0) n = mul(n, -1);
203
+ const d = norm(sub(wr, el));
204
+ const t = mul(norm(cross(n, d)), s);
205
+ const X = mul(d, -1), Y = t;
206
+ return { wr, X, Y, n, Q: (x, y, h) => add(add(add(wr, mul(X, x * 0.001)), mul(Y, y * 0.001)), mul(n, h * 0.001)) };
207
+ }
208
+
209
+ /**
210
+ * The greater covert cards (surfaces block, rigid on the forearm bones), laid out as
211
+ * core/build/featherCards.js cards (two layers, rachis + two vane columns, material VANE).
212
+ * colour(kind, i, side, t, c, layer) as featherCards (kind 'wingCovert').
213
+ */
214
+ export function covertCards(ctx, colour, look = null) {
215
+ const { rig, params, Q } = ctx;
216
+ const form = params.form || {};
217
+ if (form.chick) return null;
218
+ const Lyt = shieldLayout(form);
219
+ const res = Q?.res ?? 1;
220
+ if (res >= 4) return null; // (the crowd tier drops coverts, as featherCards)
221
+ // (more rows than a flight feather: the card drapes over the shield's rim)
222
+ const nA = (res <= 1.35 ? 9 : res <= 2.1 ? 6 : res <= 3.1 ? 4 : 3) + 4;
223
+ const th = 0.0005;
224
+ const P = [], N = [], Cb = [], T = [], Sf = [], SI = [], I = [], X = [], PCL = [], FL = [];
225
+ for (const side of [1, -1]) {
226
+ const F = planFrame(rig.J, side), b = rig.BONE['ulna' + (side > 0 ? 'L' : 'R')];
227
+ for (const c of Lyt.cards) {
228
+ const [a0, ax, ay] = c.plane;
229
+ const h = (x, y) => a0 + ax * x + ay * y;
230
+ // card frame in bind space
231
+ const p0 = F.Q(c.x, c.y, h(c.x, c.y));
232
+ const A = norm(sub(F.Q(c.x + c.d[0], c.y + c.d[1], h(c.x + c.d[0], c.y + c.d[1])), p0));
233
+ const Sv = norm(sub(F.Q(c.x + c.s[0], c.y + c.s[1], h(c.x + c.s[0], c.y + c.s[1])), p0));
234
+ let Nn = norm(cross(A, Sv));
235
+ if (dot(Nn, F.n) < 0) Nn = mul(Nn, -1);
236
+ const v0 = P.length / 3;
237
+ const ts = []; for (let j = 0; j <= nA; j++) ts.push(0.5 - 0.5 * Math.cos(Math.PI * j / nA));
238
+ const COLS = [-1, -0.5, 0, 0.5, 1], nc = COLS.length;
239
+ const pt = (t, cc) => {
240
+ const [x, y] = cardPoint(c, t, cc);
241
+ const sR = t * (c.len - c.u0(cc));
242
+ return F.Q(x, y, Lyt.cardH ? Lyt.cardH(c, x, y, sR) : h(x, y));
243
+ };
244
+ const halfW = (t) => cardPoint(c, t, 0)[2];
245
+ for (const layer of [1, -1]) {
246
+ for (let j = 0; j <= nA; j++) {
247
+ const t = ts[j];
248
+ for (const cc of COLS) {
249
+ // local normal from the (draped) surface
250
+ const e = 0.02;
251
+ const dt = sub(pt(Math.min(1, t + e), cc), pt(Math.max(0, t - e), cc)), dc = sub(pt(t, Math.min(1, cc + e)), pt(t, Math.max(-1, cc - e)));
252
+ let nl = norm(cross(dt, dc));
253
+ if (!Number.isFinite(nl[0])) nl = Nn;
254
+ if (dot(nl, F.n) < 0) nl = mul(nl, -1);
255
+ const p = add(pt(t, cc), mul(nl, layer * th * 0.5 * (1 - 0.6 * t) - (layer > 0 ? 0 : 0)));
256
+ P.push(...p); N.push(...mul(nl, layer));
257
+ Cb.push(...norm(dt));
258
+ if (look) {
259
+ // shaded as the shield's contour feathers (material FEATHER, one big shingle per card)
260
+ const k = (1 + 0.06 * Math.sin(c.i * 12.9898 + side * 3.1)) * (layer > 0 ? 1 : 0.8);
261
+ T.push(look.rgb[0] * k, look.rgb[1] * k, look.rgb[2] * k, MAT.FEATHER);
262
+ Sf.push(look.gloss, look.size, look.mz, look.irid);
263
+ if (look.mcol) PCL.push([P.length / 3 - 1, look.mcol, 0]);
264
+ FL.push(layer > 0 ? look.fur ?? 0 : 0);
265
+ } else {
266
+ const col = colour('wingCovert', c.i, side, t, cc, layer);
267
+ T.push(col.rgb[0], col.rgb[1], col.rgb[2], MAT.VANE);
268
+ if (col.bar) PCL.push([P.length / 3 - 1, col.bar.rgb, -c.len * 0.001 / col.bar.period]);
269
+ // (across never reaches 0: no rachis line, a covert's shaft is hidden in its barbs)
270
+ Sf.push(col.gloss ?? 0.4, col.irid ?? 0, 0.3 + 0.7 * Math.abs(cc), t);
271
+ }
272
+ X.push(cc * halfW(t) * 0.001 * side);
273
+ SI.push(b.index, 0, 0, 0);
274
+ }
275
+ }
276
+ const base = v0 + (layer > 0 ? 0 : (nA + 1) * nc);
277
+ for (let j = 0; j < nA; j++) for (let k = 0; k < nc - 1; k++) {
278
+ const a = base + j * nc + k, bq = a + 1, c2 = a + nc, d = a + nc + 1;
279
+ I.push(a, c2, bq, bq, c2, d);
280
+ }
281
+ }
282
+ // winding: each triangle faces its layer's normal
283
+ for (let t = 0; t < I.length; t += 3) {
284
+ const a = I[t], bb = I[t + 1], c3 = I[t + 2];
285
+ if (a < v0) continue;
286
+ const e1 = [P[bb * 3] - P[a * 3], P[bb * 3 + 1] - P[a * 3 + 1], P[bb * 3 + 2] - P[a * 3 + 2]];
287
+ const e2 = [P[c3 * 3] - P[a * 3], P[c3 * 3 + 1] - P[a * 3 + 1], P[c3 * 3 + 2] - P[a * 3 + 2]];
288
+ const g = cross(e1, e2);
289
+ if (g[0] * N[a * 3] + g[1] * N[a * 3 + 1] + g[2] * N[a * 3 + 2] < 0) { I[t + 1] = c3; I[t + 2] = bb; }
290
+ }
291
+ }
292
+ }
293
+ const nV = P.length / 3;
294
+ const out = {
295
+ nV, pos: Float32Array.from(P), nrm: Float32Array.from(N), index: Uint32Array.from(I),
296
+ skinIndex: Uint16Array.from(SI), skinWeight: new Float32Array(nV * 4),
297
+ comb: Float32Array.from(Cb), tint: Float32Array.from(T), surf: Float32Array.from(Sf),
298
+ pattern: Float32Array.from(X), mark: new Float32Array(nV).fill(1), furLen: FL.length === nV ? Float32Array.from(FL) : new Float32Array(nV),
299
+ patternColor: new Float32Array(nV * 4),
300
+ };
301
+ for (const [v, rgb, n] of PCL) out.patternColor.set([rgb[0], rgb[1], rgb[2], n], v * 4);
302
+ for (let v = 0; v < nV; v++) out.skinWeight[v * 4] = 1;
303
+ return out;
304
+ }
305
+
306
+ // concatenate two surfaces blocks (indices of the second offset)
307
+ export function joinSurfaces(a, b) {
308
+ if (!b || !b.nV) return a;
309
+ if (!a || !a.nV) return b;
310
+ const cat = (x, y, T) => { const r = new T(x.length + y.length); r.set(x); r.set(y, x.length); return r; };
311
+ const idx = new Uint32Array(a.index.length + b.index.length);
312
+ idx.set(a.index); for (let i = 0; i < b.index.length; i++) idx[a.index.length + i] = b.index[i] + a.nV;
313
+ return {
314
+ nV: a.nV + b.nV, pos: cat(a.pos, b.pos, Float32Array), nrm: cat(a.nrm, b.nrm, Float32Array), index: idx,
315
+ skinIndex: cat(a.skinIndex, b.skinIndex, Uint16Array), skinWeight: cat(a.skinWeight, b.skinWeight, Float32Array),
316
+ comb: cat(a.comb, b.comb, Float32Array), tint: cat(a.tint, b.tint, Float32Array), surf: cat(a.surf, b.surf, Float32Array),
317
+ pattern: cat(a.pattern, b.pattern, Float32Array), mark: cat(a.mark, b.mark, Float32Array), furLen: cat(a.furLen, b.furLen, Float32Array),
318
+ patternColor: cat(a.patternColor, b.patternColor, Float32Array),
319
+ };
320
+ }
@@ -0,0 +1,110 @@
1
+ // Domestic chicken (Gallus gallus domesticus): hen, rooster and chick; breeds as variants (brown/red
2
+ // layer, white Leghorn, black Australorp, barred Plymouth Rock, buff Orpington, speckled Sussex).
3
+ // Body plan 'bird' (core/motion/bird.js): a ground bird with burst flight only.
4
+ import { chickenRig, chickenJoints } from './rig.js';
5
+ import { sculptChicken, eyeFor } from './sculpt.js';
6
+ import { chickenRegions } from './regions.js';
7
+ import { chickenCoat, chickenFeatherColour, chickenWingCovertLook, chickenTertialLook, chickWingDownLook } from './coat.js';
8
+ import { motion, wingFor, feathersFor } from './motion.js';
9
+ import { featherCards } from '../../core/build/featherCards.js';
10
+ import { covertCards, joinSurfaces } from './coverts.js';
11
+ import { restyleWing, downyWing } from './wingLook.js';
12
+ import { srgb } from '../../core/build/coatKit.js';
13
+
14
+ const FEATHER_EDGE = { red: 0.55, leghorn: 0.35, australorp: 1, barred: 0.4, buff: 0.4, speckled: 0.6 };
15
+ const BREEDS = ['red', 'leghorn', 'australorp', 'barred', 'buff', 'speckled'];
16
+ // body mass (kg) hen / cock per breed (breed standards); lengths scale with mass^(1/3)
17
+ const MASS = { red: [2.0, 3.0], leghorn: [1.8, 2.5], australorp: [2.6, 3.6], barred: [2.8, 3.6], buff: [3.0, 3.8], speckled: [3.0, 3.8] };
18
+ // loose-feathered heavy breeds carry part of their bulk as fluff
19
+ const FLUFF = { red: 1, leghorn: 0.95, australorp: 1.06, barred: 1.05, buff: 1.14, speckled: 1.05 };
20
+
21
+ // individual form (read by rig, sculpt, regions, coat and motion.individual)
22
+ function formOf(sex, age, breed, g) {
23
+ if (age === 'juvenile') {
24
+ // chick (~1-2 weeks, ~0.3 of the hen's size): big head, short neck, short legs, stubby wings with
25
+ // narrow pin feathers (wider ones swept through its round body opening and folding)
26
+ return {
27
+ chick: true, billK: 0.6, legK: 0.72, femurK: 0.7, tarK: 0.72, hipK: 0.74, neckK: 0.42, headK: 1.75, eyeK: 1.05, toeK: 0.85, toeR: 1.15,
28
+ wingK: 0.52, priK: 0.25, recK: 0.08, fwK: 0.45, fluff: 1.1,
29
+ headO: [0, 0.225, 0.085],
30
+ };
31
+ }
32
+ const f = { fluff: FLUFF[breed] * (1 + 0.03 * g()), headK: 1.12 };
33
+ if (sex === 'male') {
34
+ Object.assign(f, {
35
+ legK: 1.07, hipK: 1.06, neckK: 1.14, headK: 1.18, up: 13, tailUp: 30, spur: 0.8 + 0.4 * Math.abs(g()), sickles: (breed === 'leghorn' ? 1.08 : 1) * (1 + 0.06 * g()), recK: 1.25,
36
+ comb: 1.45 * (breed === 'leghorn' ? 1.12 : 1), combH: 2.2 * (breed === 'leghorn' ? 1.15 : 1) * (1 + 0.08 * g()), wattle: 2.1 * (1 + 0.1 * g()), earlobe: 1.4,
37
+ });
38
+ } else {
39
+ Object.assign(f, {
40
+ comb: breed === 'leghorn' ? 1.3 : 1, combH: (breed === 'leghorn' ? 1.9 : 1) * (1 + 0.12 * g()), combFlop: breed === 'leghorn' ? 0.9 : 0,
41
+ wattle: (breed === 'leghorn' ? 1.3 : 1) * (1 + 0.12 * g()), earlobe: breed === 'leghorn' ? 1.25 : 1, spur: 0,
42
+ up: breed === 'leghorn' ? 5 : 0,
43
+ });
44
+ }
45
+ return f;
46
+ }
47
+
48
+ export default {
49
+ id: 'chicken',
50
+ name: 'Chicken',
51
+ latin: 'Gallus gallus domesticus',
52
+ group: 'birds',
53
+ plan: 'bird',
54
+ covering: 'feathers',
55
+ variants: BREEDS,
56
+
57
+ // Seeded individual: breed (variant), sex (a flock is mostly hens), age (chick when asked, or now
58
+ // and then), size by breed and sex (mass^(1/3)), leg length, head and comb size, fluff and colour tone.
59
+ variation(R, o) {
60
+ const g = () => (R() + R() + R() - 1.5) / 1.5;
61
+ for (let i = 0; i < 5; i++) R(); // (decorrelates the first draws from the seed)
62
+ const r0 = R(), r1 = R(), r2 = R();
63
+ const breed = o.variant && BREEDS.includes(o.variant) ? o.variant : BREEDS[[0.3, 0.48, 0.63, 0.78, 0.9, 1].findIndex((x) => r0 < x)];
64
+ const sex = o.sex || (r1 < 0.34 ? 'male' : 'female');
65
+ const age = o.age || (r2 < 0.08 ? 'juvenile' : 'adult');
66
+ const juv = age === 'juvenile';
67
+ const m = MASS[breed][sex === 'male' ? 1 : 0] * (1 + 0.1 * g());
68
+ const size = juv ? 0.3 * (1 + 0.06 * g()) : Math.cbrt(m / 2.0);
69
+ const form = formOf(sex, age, breed, g);
70
+ const J = chickenJoints(form), HO = J._headO;
71
+ return {
72
+ sex, age, size, breed, variant: breed, form,
73
+ tone: 1 + 0.08 * g(),
74
+ warps: juv ? [] : [
75
+ { type: 'legs', k: 1 + 0.035 * g(), top: 0.09 },
76
+ { type: 'scaleAbout', c: HO, k: 1 + 0.03 * g(), r0: 0.03, r1: 0.06 },
77
+ { type: 'girth', k: 1 + 0.04 * g(), cy: 0.18, z0: -0.12, z1: 0.1, fade: 0.04 },
78
+ ],
79
+ };
80
+ },
81
+ rig: (params) => chickenRig(params.form),
82
+ sculpt: (m, rig, params) => sculptChicken(m, rig, params),
83
+ regions: chickenRegions,
84
+ coat: chickenCoat,
85
+ // flight-feather cards, and the folded wing's greater coverts along the covert shield's rim (coverts.js)
86
+ surfaces: (ctx) => {
87
+ const colour = chickenFeatherColour(ctx.params);
88
+ const fc = featherCards({ ...ctx, wing: wingFor(ctx.params.form), feathers: feathersFor(ctx.params.form), tail: { bindFan: 0.2 }, colour });
89
+ // (the folded wing's tertials read as contour feathers: shaded like the shield, with its down)
90
+ if (!ctx.params.form?.chick) restyleWing(fc, ctx.rig, chickenTertialLook(ctx.params));
91
+ // (a chick's wing is downy: its pin-feather cards wear the down around them)
92
+ else downyWing(fc, ctx.rig, chickWingDownLook(ctx.params));
93
+ return joinSurfaces(fc, covertCards(ctx, colour, chickenWingCovertLook(ctx.params)));
94
+ },
95
+ eyeSpecs: (params, rig) => [1, -1].map((side) => ({ side, spec: eyeFor(params.form), headOrigin: rig.headOrigin, bone: 'head', look: params.age === 'juvenile' ? EYE_JUV : EYE_LOOK })),
96
+ motion,
97
+ // pale plumage shows the shingle shading more than black: lower feather-edge contrast
98
+ render: (p) => ({ markColor: srgb(0x2a1a12), strandDensity: 700, clumpDensity: 1.2, shellScale: 1, finWidth: 0.3, featherEdge: FEATHER_EDGE[p.breed] ?? 0.6 }),
99
+ };
100
+
101
+ // Round pupil, orange (reddish-bay) iris, bird lids with a nictitating membrane.
102
+ export const EYE_LOOK = {
103
+ pupil: 'round',
104
+ lids: 'bird',
105
+ iris: { inner: srgb(0xe07a22), mid: srgb(0xeb9a30), hi: srgb(0xf6c050), outer: srgb(0xc8641c) },
106
+ sclera: { visible: false, color: [0.02, 0.02, 0.02] },
107
+ lidColor: srgb(0x8a3a34),
108
+ pupilSize: [0.3, 0.44],
109
+ };
110
+ export const EYE_JUV = { ...EYE_LOOK, iris: { inner: srgb(0x201a16), mid: srgb(0x3a2e26), hi: srgb(0x5a4838), outer: srgb(0x181410) }, lidColor: srgb(0x5a4a3a), pupilSize: [0.5, 0.62] };
@@ -0,0 +1,177 @@
1
+ // Chicken motion data for the bird engine (schema: src/core/motion/bird.js). Numbers are for the
2
+ // reference individual (params.size = 1: a ~2 kg brown layer hen, hip 0.21 m, 0.42 m bill to tail);
3
+ // the engine scales them by dynamic similarity.
4
+ //
5
+ // Ground: a strictly alternating walk (duty 0.72 -> 0.6) with the signature head bob (the head holds
6
+ // still in space for ~60 % of each step, then thrusts forward), a grounded run (duty ~0.5) and an
7
+ // aerial sprint (wings folded on the body). Chickens never hop to travel (hop only as a jump).
8
+ // Flight: burst flight only - wingbeats ~10 Hz, amplitude ~135 deg (laying hens, R. Soc. Open Sci.
9
+ // 2021), a flutter up onto a perch or a short escape flight, then a steep glide down (not sustained).
10
+ // Per individual (motion.individual): roosters attack with a flapping jump-kick (spurs), hens peck;
11
+ // roosters crow as an idle behaviour; chicks have stubby wings and no tail.
12
+ const G = (name, v, f, D, off, o) => ({ name, v, f, D, off, ...o });
13
+
14
+ // Wing (humerus, ulna, hand in metres; configurations in degrees, see core/rig/bird.js). The folded
15
+ // wing lies high on the flank, its primaries tucked under the secondaries, tips below the tail base.
16
+ export function wingFor(form = {}) {
17
+ const k = form.wingK ?? 1;
18
+ return {
19
+ lengths: [0.077 * k, 0.07 * k, 0.066 * k],
20
+ bind: { elev: -30, pitch: 0, alpha: 35, elbow: 95, wrist: 100, bend: 0, twist: 0 },
21
+ // folded: the wing plane leans out 14 deg from the vertical, on the barrel of the flank (fitted so
22
+ // the stack's outline lies on the body; the flank under it is flattened and bedded, sculpt.js
23
+ // flankUnderWing / wingPocket; leaning in more cut the primaries' tips into the rump); an upright
24
+ // individual (form.up: a rooster's torso is pitched up) folds it turned down at the back with the
25
+ // body, off the saddle (2 deg per deg of pitch: at 1.3 the primaries' tips cut into the thigh)
26
+ fold: { elev: -76, pitch: 4, alpha: 76 - 2.0 * (form.up ?? 0), elbow: 171, wrist: 170, bend: 0, twist: 0 },
27
+ glide: { elev: 6, pitch: 4, alpha: 6, elbow: 22, wrist: 12, bend: 2, twist: 2 },
28
+ // burst flight: fast, deep beats (the wing tips clap close above and below the body); a chick's
29
+ // stubby wings flutter above its round body (deep strokes dipped them into the ball of down)
30
+ flap: form.chick ? { freq: 8.5, amp: 70, mid: 30, down: 0.55, upFlex: 30, upWrist: 36, sweep: 12, twist: 12 } : { freq: 8.5, amp: 108, mid: 8, down: 0.55, upFlex: 40, upWrist: 48, sweep: 16, twist: 16 },
31
+ power: form.chick ? { freq: 9.6, amp: 78, mid: 32, down: 0.52, upFlex: 36, upWrist: 44, sweep: 14, twist: 14 } : { freq: 9.6, amp: 124, mid: 14, down: 0.52, upFlex: 52, upWrist: 62, sweep: 22, twist: 18 },
32
+ glideShare: 0.35,
33
+ };
34
+ }
35
+
36
+ // Flight feathers. 10 primaries (rounded galliform wing: p7-p8 longest; no emargination: the engine
37
+ // bends notched primaries up under load by their notch, and the outer three rose through each other), 10
38
+ // secondaries + tertials, 7 rectrices a side held as a steep "roof" (the two halves of the tail meet
39
+ // in an inverted V: fanned up and back, vanes near vertical); roosters add two sickles a side (long,
40
+ // arching central coverts) and chicks have only short pin feathers.
41
+ export function feathersFor(form = {}) {
42
+ const pk = form.priK ?? 1, rk = form.recK ?? 1, wk = form.fwK ?? 1;
43
+ // Stacking (every card lies on its neighbour, none cuts through it, folded or spread): each feather's
44
+ // root is lifted 0.8 mm above the next one in the overlap order (primaries: inner on top; secondaries:
45
+ // the tertials on top, all above the primaries), with nearly flat vanes (arch 3 % of the half width:
46
+ // the default 12 % dropped a neighbour's vane edge through the next card wherever they overlap
47
+ // sideways), little twist and droop (a twisted vane crossed its fanned neighbour); the folded
48
+ // primaries lie almost along the hand, under the secondaries (steeper fold angles lifted their outer
49
+ // vanes over the top of the wing into the back).
50
+ const LP = 0.0008, LS = 0.0008, LS0 = 0.008, ARCH = 0.03;
51
+ const P = [
52
+ [0.06, 0.128, 78, -4], [0.16, 0.136, 70, -2.5], [0.26, 0.145, 62, -1], [0.36, 0.154, 54, 0.5], [0.46, 0.163, 46, 2.7],
53
+ [0.56, 0.171, 38, 2.5], [0.66, 0.178, 30, 2.3], [0.76, 0.18, 22, 2], [0.87, 0.172, 14, 1], [0.98, 0.15, 6, 0.5],
54
+ ];
55
+ const primaries = P.map(([u, len, spread, fold], i) => ({ u, len: len * pk, width: 0.036 * wk, spread, fold, emarg: 0, tipRound: 0.5, outer: i < 3 ? 0.42 : 0.34, lift: (P.length - 1 - i) * LP, twist: 1, droop: 0.01, curve: 0.03, arch: ARCH,
56
+ // the innermost primary coverts lie wholly under the covert shield when folded (their roots at the
57
+ // wrist cut out through its front rim); the first one a little higher (half open, it crossed the
58
+ // third secondary under the shield's thin front)
59
+ ...(i < 2 ? { cov: { shift: 0.004, lenK: 0.3, ...(i === 0 && !form.chick ? { lift: 0.003 } : {}) } } : {}) }));
60
+ // (the tertials, innermost, are shorter: their rounded ends step up along the folded wing's top)
61
+ const S = [[0.03, 0.122], [0.13, 0.123], [0.23, 0.123], [0.33, 0.122], [0.43, 0.12], [0.53, 0.118], [0.63, 0.116], [0.73, 0.128], [0.83, 0.118], [0.93, 0.108]];
62
+ // greater coverts: sculpted as skin (sculpt.js coverts(): the shingled shield of the folded wing), no
63
+ // covert cards (a chick keeps its little covert cards: without them the metrics put its lying shank
64
+ // skin 0.8 mm into the ground, seed 3 - the cause is in the engine's lie, not traced)
65
+ // (a chick's inner secondaries are short pin feathers: longer ones swept into its round body as the wing
66
+ // opened and folded)
67
+ const ST = form.chick ? [1, 1, 1, 1, 1, 1, 0.9, 0.7, 0.62, 0.55] : null;
68
+ const secondaries = S.map(([u, len], i) => ({
69
+ u, len: (ST ? Math.min(len, 0.122) * ST[i] : len) * pk, width: 0.046 * wk, spread: 90 + i * 3.5, fold: 163 + i * 1.2, tipRound: i >= 7 && !form.chick ? 0.32 : 0.6, ...(i >= 7 && !form.chick ? { base0: 0.6 } : {}), outer: 0.42, lift: LS0 + i * LS, twist: 1, arch: ARCH,
70
+ cov: { skip: true },
71
+ }));
72
+ // rectrices: central -> outer. `bend` lifts the feather out of the tail plane (the pygostyle already
73
+ // points up and back), `twist` stands the vane up (roof), `fan` spreads it sideways when fanned. A hen's
74
+ // roof is steep at the ridge (the central pairs near vertical, 80 / 74 deg; at 68 the second crossed the
75
+ // first) and opens to 58 deg at the sides (at 44-50 the outer pairs' inner vanes met under the ridge),
76
+ // her rectrices straight (curved in toward the midline, the two halves crossed); a rooster's arched
77
+ // rectrices sit 6 mm further out from the midline with their vanes on edge (nearly vertical: each arc
78
+ // curves back and down in its own side's plane; tilted like a hen's roof, the arcs of the two sides
79
+ // curved in to the midline and crossed under the tail). No covert cards on the rectrices (each one's
80
+ // covert crossed its inner neighbour or the other side's at the ridge as the tail swayed and fanned;
81
+ // the uppertail coverts' mass, the saddle and the sickles cover the base), and a rooster's second sickle
82
+ // fans no wider than his first rectrix (at 6 deg it crossed it in the landing flare).
83
+ const R = [
84
+ [0.002, 0.13, 3, 12], [0.004, 0.128, 7, 6], [0.006, 0.125, 12, 0], [0.008, 0.12, 17, -6],
85
+ [0.01, 0.113, 22, -12], [0.012, 0.105, 27, -18], [0.014, 0.096, 32, -24],
86
+ ];
87
+ const rectrices = R.map(([x, len, fan, bend], i) => ({
88
+ x: form.sickles ? x * 1.4 + 0.006 : x, len: len * rk, width: (form.sickles ? 0.034 : 0.042) * wk, fan, fold: 1 + i * 0.4, bend: bend + (form.sickles ? -6 : 0), twist: form.sickles ? 90 - i : i === 0 ? 80 : i === 1 ? 74 : 72 - i * 2, lift: 0.0024 - i * 0.0003,
89
+ tipRound: 0.62, outer: 0.44, arc: form.sickles ? 55 + i * 5 : 0, cov: { skip: true },
90
+ }));
91
+ if (form.sickles) {
92
+ // sickles: long, narrow, arching back and down over the tail (roosters)
93
+ const sk = form.sickles;
94
+ rectrices.push(
95
+ { x: 0.001, len: 0.36 * sk, width: 0.03 * wk, fan: 2, fold: 0.5, bend: 30, twist: 90, lift: 0.004, tipRound: 0.8, outer: 0.46, arc: 118, droop: 0.02 },
96
+ { x: 0.003, len: 0.3 * sk, width: 0.026 * wk, fan: 3, fold: 1, bend: 18, twist: 90, lift: 0.0035, tipRound: 0.8, outer: 0.46, arc: 108, droop: 0.02 },
97
+ );
98
+ }
99
+ return { primaries, secondaries, rectrices, coverts: { primary: 0.4, secondary: 0.5, tail: form.sickles ? 0.62 : 0.55 } };
100
+ }
101
+
102
+ export const WING = wingFor();
103
+ export const FEATHERS = feathersFor();
104
+
105
+ const base = {
106
+ gears: { walk: 0.55, run: 1.9, fly: 5 },
107
+ maxSpeed: 7,
108
+ ground: { maxSpeed: 3.6, accel: [2.5, 5], decel: 5.5, turnRate: 5 },
109
+ gaits: [
110
+ // slow foraging walk -> preferred walk -> fast walk (head bob every step)
111
+ G('walk', 0.0, 1.3, 0.74, [0, 0.5], { lift: 0.03, bob: 0.004, sway: 0.008, pitch: 0, headBob: 1, wings: 0, tail: 0.5 }),
112
+ G('walk', 0.55, 1.9, 0.66, [0, 0.5], { lift: 0.038, bob: 0.006, sway: 0.009, pitch: -2, headBob: 1, wings: 0, tail: 0.7 }),
113
+ G('walk', 0.95, 2.4, 0.6, [0, 0.5], { lift: 0.04, bob: 0.007, sway: 0.007, pitch: -5, headBob: 0.8, wings: 0.03, tail: 0.7 }),
114
+ // grounded run (no aerial phase), then an aerial sprint; the wings stay folded on the body (part
115
+ // open they stood off the flank)
116
+ G('run', 1.4, 2.9, 0.52, [0, 0.5], { lift: 0.042, bob: 0.006, sway: 0.004, pitch: -12, headBob: 0.25, wings: 0, tail: 0.5 }),
117
+ G('run', 2.6, 3.6, 0.42, [0, 0.5], { lift: 0.046, bob: 0.005, sway: 0.003, pitch: -18, headBob: 0.05, wings: 0, tail: 0.4 }),
118
+ ],
119
+ feet: { spread: [0, 24, 2, -26], curl: 75, grip: 1, pad: 0.009, hock: 0.0085, sole: 0.0125 },
120
+ // belly section (bind, ref size): centre height, half height, half width
121
+ body: { tilt: 22, belly: { y: 0.15, hh: 0.08, hw: 0.068 } },
122
+ head: { bob: 1.33, bobHold: 0.62, yaw: 2.6, pitchUp: 1.0, pitchDown: 1.25, saccade: 1, cock: 0.45, jawRest: -2, radius: 0.017 },
123
+ tail: { walkBob: 5, sway: 4, flick: 1, fanRest: 0.02 },
124
+ wing: WING,
125
+ feathers: FEATHERS,
126
+ flight: {
127
+ minSpeed: 2.6, cruise: 5, maxSpeed: 7, climb: [2.4, -3.5], bankMax: 45, turnRate: 3.2,
128
+ clearance: 0.8, glideRatio: 2.5, sustained: false, maxTime: 2.5,
129
+ },
130
+ takeoff: { crouch: 0.18, jump: 2.4, angle: 50, beats: 6 },
131
+ landing: { approach: 4, flare: 0.4, touch: 1.2 },
132
+ actions: {
133
+ attack: { style: 'peck' },
134
+ // scratch the ground (two rakes of one foot, one or two of the other, step back), then peck
135
+ eat: { style: 'scratch', rate: 2.6 },
136
+ drink: {},
137
+ jump: { height: 0.25, distance: 0.35 },
138
+ // lying at rest with the wings folded on the body (the engine's default lie droops and part spreads
139
+ // them, sunning)
140
+ lie: { wings: 0 },
141
+ death: { wings: 0 },
142
+ // roosting: fluffed, settled on the hocks, head drawn into the shoulders (fluffed less than the engine's
143
+ // default: the torso swells about the hips and the flank rose into the folded primaries)
144
+ sleep: { style: 'sink', fluff: 0.4 },
145
+ idle: {},
146
+ },
147
+ };
148
+
149
+ // per-individual overrides (sex, age): read by the bird engine (motion.individual)
150
+ function individual(p = {}) {
151
+ const out = {};
152
+ const form = p.form || {};
153
+ if (form.wingK || form.priK || form.recK || form.sickles) {
154
+ out.wing = wingFor(form);
155
+ out.feathers = feathersFor(form);
156
+ }
157
+ if (p.age === 'juvenile') {
158
+ // chicks: short quick steps, no real flight (a flutter), peeping bill
159
+ // (short legs: quicker, shorter steps and lower speeds than a scaled-down hen)
160
+ out.gaits = base.gaits.map((g) => ({ ...g, f: g.f * 1.1, lift: g.lift * 1.1 }));
161
+ out.gears = { walk: 0.4, run: 1.25, fly: 3.2 };
162
+ out.ground = { ...base.ground, maxSpeed: 2.4 };
163
+ out.maxSpeed = 4;
164
+ out.flight = { ...base.flight, minSpeed: 2, cruise: 3.2, maxSpeed: 4, maxTime: 0.6, climb: [1.2, -3] };
165
+ out.body = { tilt: 18, belly: { y: 0.15, hh: 0.075, hw: 0.075 } };
166
+ out.actions = { ...base.actions, attack: { style: 'peck' }, eat: { style: 'peck', rate: 3 } };
167
+ out.feet = { ...base.feet, pad: 0.011 };
168
+ } else if (p.sex === 'male') {
169
+ // roosters: flapping jump-kick with the spurs; crow as an idle behaviour
170
+ out.actions = { ...base.actions, attack: { style: 'spur' }, idle: { crow: 0.22 } };
171
+ // the sickle tail stays half raised in flight (it would sweep the ground in the landing flare)
172
+ out.tail = { ...base.tail, flight: 0.45 };
173
+ }
174
+ return out;
175
+ }
176
+
177
+ export const motion = { ...base, individual };