@bitefoundry/retrieviewer 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/ASSET-PROVENANCE.md +6 -0
  2. package/ASSETS-LICENSE.md +2 -1
  3. package/ATTRIBUTION.md +6 -1
  4. package/COMFORT-ART.md +65 -0
  5. package/DESKTOP-PLATFORMS.md +75 -0
  6. package/INSTALLING.md +8 -5
  7. package/PLUGIN.md +13 -10
  8. package/PREREQUISITES.md +95 -0
  9. package/PUPPY-MEMORY.md +102 -1
  10. package/README.ko.md +110 -0
  11. package/README.md +119 -58
  12. package/RELEASING.md +27 -14
  13. package/THIRD-PARTY-NOTICES.md +5 -3
  14. package/braille.mjs +35 -9
  15. package/examples/live.mjs +2 -2
  16. package/integrations/desktop/platform.mjs +27 -0
  17. package/integrations/linux-overlay/README.md +83 -0
  18. package/integrations/linux-overlay/overlay.py +1094 -0
  19. package/integrations/macos-overlay/README.md +83 -0
  20. package/integrations/macos-overlay/overlay.jxa +639 -0
  21. package/integrations/opencode/runtime.mjs +4 -4
  22. package/integrations/opencode/tui.tsx +1 -1
  23. package/integrations/windows-overlay/Overlay.cs +4 -4
  24. package/integrations/windows-overlay/desktop.mjs +40 -8
  25. package/integrations/windows-overlay/protocol.mjs +11 -7
  26. package/integrations/windows-overlay/worker.mjs +13 -7
  27. package/package.json +41 -14
  28. package/puppy-comfort-sprites.mjs +25 -0
  29. package/puppy-companion-comfort-q5.bin.gz +0 -0
  30. package/puppy-companion-comfort.json +77 -0
  31. package/puppy-companion-life.mjs +49 -16
  32. package/puppy-companion-objects.mjs +12 -0
  33. package/puppy-frame-predictive.mjs +15 -9
  34. package/puppy-frame-store.mjs +2 -2
  35. package/puppy-paper-world.mjs +14 -0
  36. package/puppy-paper.mjs +65 -14
  37. package/retrieviewer-cli.mjs +10 -3
  38. package/retrieviewer-plugin.d.mts +1 -1
  39. package/retrieviewer-plugin.mjs +1 -1
  40. package/retrieviewer.d.mts +10 -4
  41. package/retrieviewer.mjs +20 -14
  42. package/locomotion-core.mjs +0 -21
  43. package/locomotion-puppy.animal +0 -0
  44. package/vendor/procedural-animals/package.json +0 -40
  45. package/vendor/procedural-animals/src/animal.js +0 -146
  46. package/vendor/procedural-animals/src/bake.js +0 -51
  47. package/vendor/procedural-animals/src/build.js +0 -81
  48. package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
  49. package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
  50. package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
  51. package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
  52. package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
  53. package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
  54. package/vendor/procedural-animals/src/core/build/seams.js +0 -183
  55. package/vendor/procedural-animals/src/core/build/warp.js +0 -112
  56. package/vendor/procedural-animals/src/core/build/weights.js +0 -393
  57. package/vendor/procedural-animals/src/core/math/vec.js +0 -81
  58. package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
  59. package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
  60. package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
  61. package/vendor/procedural-animals/src/core/motion/common.js +0 -158
  62. package/vendor/procedural-animals/src/core/motion/index.js +0 -22
  63. package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
  64. package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
  65. package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
  66. package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
  67. package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
  68. package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
  69. package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
  70. package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
  71. package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
  72. package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
  73. package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
  74. package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
  75. package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
  76. package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
  77. package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
  78. package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
  79. package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
  80. package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
  81. package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
  82. package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
  83. package/vendor/procedural-animals/src/index.d.ts +0 -98
  84. package/vendor/procedural-animals/src/index.js +0 -29
  85. package/vendor/procedural-animals/src/registry.js +0 -48
  86. package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
  87. package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
  88. package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
  89. package/vendor/procedural-animals/src/species/bear/index.js +0 -139
  90. package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
  91. package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
  92. package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
  93. package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
  94. package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
  95. package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
  96. package/vendor/procedural-animals/src/species/boar/index.js +0 -110
  97. package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
  98. package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
  99. package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
  100. package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
  101. package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
  102. package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
  103. package/vendor/procedural-animals/src/species/cat/index.js +0 -211
  104. package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
  105. package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
  106. package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
  107. package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
  108. package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
  109. package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
  110. package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
  111. package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
  112. package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
  113. package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
  114. package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
  115. package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
  116. package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
  117. package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
  118. package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
  119. package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
  120. package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
  121. package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
  122. package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
  123. package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
  124. package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
  125. package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
  126. package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
  127. package/vendor/procedural-animals/src/species/cow/index.js +0 -118
  128. package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
  129. package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
  130. package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
  131. package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
  132. package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
  133. package/vendor/procedural-animals/src/species/crow/index.js +0 -70
  134. package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
  135. package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
  136. package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
  137. package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
  138. package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
  139. package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
  140. package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
  141. package/vendor/procedural-animals/src/species/deer/index.js +0 -106
  142. package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
  143. package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
  144. package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
  145. package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
  146. package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
  147. package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
  148. package/vendor/procedural-animals/src/species/dog/index.js +0 -144
  149. package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
  150. package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
  151. package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
  152. package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
  153. package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
  154. package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
  155. package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
  156. package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
  157. package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
  158. package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
  159. package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
  160. package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
  161. package/vendor/procedural-animals/src/species/fish/index.js +0 -88
  162. package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
  163. package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
  164. package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
  165. package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
  166. package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
  167. package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
  168. package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
  169. package/vendor/procedural-animals/src/species/fox/index.js +0 -120
  170. package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
  171. package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
  172. package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
  173. package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
  174. package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
  175. package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
  176. package/vendor/procedural-animals/src/species/frog/index.js +0 -97
  177. package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
  178. package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
  179. package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
  180. package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
  181. package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
  182. package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
  183. package/vendor/procedural-animals/src/species/goat/index.js +0 -149
  184. package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
  185. package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
  186. package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
  187. package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
  188. package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
  189. package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
  190. package/vendor/procedural-animals/src/species/horse/index.js +0 -80
  191. package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
  192. package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
  193. package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
  194. package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
  195. package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
  196. package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
  197. package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
  198. package/vendor/procedural-animals/src/species/lion/index.js +0 -111
  199. package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
  200. package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
  201. package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
  202. package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
  203. package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
  204. package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
  205. package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
  206. package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
  207. package/vendor/procedural-animals/src/species/pig/index.js +0 -161
  208. package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
  209. package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
  210. package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
  211. package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
  212. package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
  213. package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
  214. package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
  215. package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
  216. package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
  217. package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
  218. package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
  219. package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
  220. package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
  221. package/vendor/procedural-animals/src/species/rat/index.js +0 -111
  222. package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
  223. package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
  224. package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
  225. package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
  226. package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
  227. package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
  228. package/vendor/procedural-animals/src/species/shark/index.js +0 -104
  229. package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
  230. package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
  231. package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
  232. package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
  233. package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
  234. package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
  235. package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
  236. package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
  237. package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
  238. package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
  239. package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
  240. package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
  241. package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
  242. package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
  243. package/vendor/procedural-animals/src/species/snake/index.js +0 -73
  244. package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
  245. package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
  246. package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
  247. package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
  248. package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
  249. package/vendor/procedural-animals/src/species/spider/index.js +0 -78
  250. package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
  251. package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
  252. package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
  253. package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
  254. package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
  255. package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
  256. package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
  257. package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
  258. package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
  259. package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
  260. package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
  261. package/vendor/procedural-animals/src/worker.js +0 -29
@@ -1,320 +0,0 @@
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
- }
@@ -1,110 +0,0 @@
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] };
@@ -1,177 +0,0 @@
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 };