@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,66 +0,0 @@
1
- // Meshing plan: body (incl. wing arms and legs) at 2.0 mm, head + the top of the neck at 0.9 mm
2
- // (overlapping the body at the cut and cross-faded; the thin comb and wattles need the fine cells),
3
- // eyelid patches at 0.4 mm, and the lower mandible as its own rigid surface so the bill can open.
4
- // Cells scale with the quality tier (Q.res). Everything is computed from the individual's rig (the
5
- // head sits higher on a rooster, the comb is taller).
6
- import { eyeFrameOf } from '../../core/sdf/eyeSocket.js';
7
- import { lerp, norm, sub, smoothstep } from '../../core/math/vec.js';
8
- import { NECK_SEGS } from './rig.js';
9
- import { eyeFor } from './sculpt.js';
10
-
11
- export function neckCut(J) {
12
- const a = J['neck' + (NECK_SEGS - 1)];
13
- const d = norm(sub(J.occiput, a));
14
- const c = lerp(a, J.occiput, 0.5);
15
- return { c, d, band: 0.0045 };
16
- }
17
-
18
- export function eyePatch(rig, form) {
19
- const E = eyeFor(form), HO = rig.headOrigin, k = form.headK ?? 1;
20
- return { R: 0.011 * k, B: 0.0022 * k, h: 0.0004 * k, centres: [1, -1].map((s) => eyeFrameOf(E, HO, s).c) };
21
- }
22
-
23
- export function chickenRegions(rig, params, Q) {
24
- const J = rig.J, form = params.form || {};
25
- const NC = neckCut(J), B = NC.band, r = Q.res;
26
- const neckS = (x, y, z) => (x - NC.c[0]) * NC.d[0] + (y - NC.c[1]) * NC.d[1] + (z - NC.c[2]) * NC.d[2];
27
- const EP = eyePatch(rig, form);
28
- const eyeW = (x, y, z) => {
29
- let dmin = 1e9;
30
- for (const c of EP.centres) dmin = Math.min(dmin, Math.hypot(x - c[0], y - c[1], z - c[2]));
31
- return 1 - smoothstep(EP.R - EP.B, EP.R + EP.B, dmin);
32
- };
33
- const patches = Q.eyePatches ? EP.centres.map((c) => ({ c, R: EP.R, B: EP.B, h: EP.h * Math.max(1, r) })) : [];
34
- const HO = rig.headOrigin, hk = form.headK ?? 1;
35
- const juv = !!form.chick;
36
- // body box: wings bound half open reach out to the side
37
- const top = Math.max(J.occiput[1], J.tailTip[1]) + 0.06;
38
- const hbox = {
39
- min: [HO[0] - 0.034 * hk, HO[1] - 0.06 * hk * (form.wattle ?? 1) - 0.01, HO[2] - 0.075 * hk],
40
- max: [HO[0] + 0.034 * hk, HO[1] + 0.058 * hk * (form.combH ?? 1), HO[2] + 0.055 * hk],
41
- };
42
- const male = params.sex === 'male' && !juv; // (bigger comb, wattles and hackle: slightly coarser cells keep the budgets)
43
- const hBody = (juv ? 0.0024 : male ? 0.00216 : 0.0021) * r, hHead = (juv ? 0.0012 : male ? 0.00098 : 0.00092) * r;
44
- return {
45
- jobs: [
46
- [
47
- { name: 'body', part: 'body', bmin: [-0.26, -0.004, -0.2], bmax: [0.26, top, 0.2], h: hBody, F: 4, clip: (x, y, z) => neckS(x, y, z) < B },
48
- ],
49
- [
50
- { name: 'head', part: 'body', bmin: hbox.min, bmax: hbox.max, h: hHead, F: 6, clip: (x, y, z) => neckS(x, y, z) > -B, patches },
51
- { name: 'jaw', part: 'jaw', bmin: [HO[0] - 0.01 * hk, HO[1] - 0.016 * hk, HO[2] + 0.008 * hk], bmax: [HO[0] + 0.01 * hk, HO[1] - 0.002 * hk, HO[2] + 0.047 * hk], h: 0.0007 * r * hk, F: 6, rigidBone: 'jaw' },
52
- ],
53
- ],
54
- fade(x, y, z, name, patch) {
55
- const sN = neckS(x, y, z);
56
- if (name === 'body') return 1 - smoothstep(-B, B, sN);
57
- if (name === 'head') {
58
- // (the head surface reaches 1.5 mm past the body's cut, so no see-through crack shows)
59
- let f = smoothstep(-B - 0.0015, B - 0.0015, sN);
60
- if (patches.length) { const ew = eyeW(x, y, z); f *= patch ? ew : 1 - ew; }
61
- return f;
62
- }
63
- return 1;
64
- },
65
- };
66
- }
@@ -1,144 +0,0 @@
1
- // Chicken skeleton in bind pose (metres). Forward = +Z, up = +Y, the bird's left = +X; ground at y = 0,
2
- // the feet under the centre of mass. Reference individual: a ~2 kg brown layer hen standing relaxed
3
- // (hip height 0.21 m, back 0.27 m, crown 0.345 m, bill tip to tail tip 0.42 m). Leg bones from layer
4
- // osteometry (Animals 2020: tibiotarsus 117-120 mm; femur ~0.65 and tarsometatarsus ~0.68 of it);
5
- // wing bones humerus 77, ulna 70, hand 66 mm. The femur points forward and down inside the
6
- // body (knee hidden in the feathers), the drumstick runs down and back to the hock at 85 mm, the
7
- // scaled shank stands almost vertical.
8
- //
9
- // The rig adapts to the individual (params.form, see index.js): roosters stand more upright on longer
10
- // legs with a longer neck and carry two sickle feathers a side; chicks have a round body, a big head
11
- // on a short neck, short legs and stubby wings.
12
- import { buildRig } from '../../core/rig/rig.js';
13
- import { birdBones, birdLimbs, neckChain, wingJoints, featherJoints } from '../../core/rig/bird.js';
14
- import { wingFor, feathersFor } from './motion.js';
15
-
16
- export const NECK_SEGS = 4;
17
- // head-local origin (between the eyes) of the reference hen
18
- export const HEAD_O = [0, 0.328, 0.108];
19
-
20
- const n2 = (y, z) => { const l = Math.hypot(y, z); return [0, y / l, z / l]; };
21
- const D = Math.PI / 180;
22
-
23
- // rotate a point about the x axis through c (pitch the torso up by a, radians)
24
- const pitchAbout = (p, c, a) => {
25
- const y = p[1] - c[1], z = p[2] - c[2], ca = Math.cos(a), sa = Math.sin(a);
26
- return [p[0], c[1] + y * ca + z * sa, c[2] - y * sa + z * ca];
27
- };
28
-
29
- export function headOrigin(form = {}) {
30
- return form.headO || HEAD_O;
31
- }
32
-
33
- // torso transform of an individual: the reference torso lifted with the hip and pitched up about it
34
- export function torsoFn(form = {}) {
35
- const hipY = 0.205 * (form.hipK ?? 1), up = (form.up ?? 0) * D, dyH = hipY - 0.205;
36
- const c = [0, hipY, -0.028];
37
- return (p) => pitchAbout([p[0], p[1] + dyH, p[2]], c, up);
38
- }
39
-
40
- export function chickenJoints(form = {}) {
41
- const legK = form.legK ?? 1, neckK = form.neckK ?? 1;
42
- const juv = !!form.chick;
43
- // ---- legs (left), from the hip down
44
- const femur = 0.078 * (form.femurK ?? legK), tib = 0.118 * legK, tar = 0.08 * (form.tarK ?? legK);
45
- const hip = [0.03, 0.205 * (form.hipK ?? 1), -0.028];
46
- const fa = 32 * D;
47
- const knee = [0.042, hip[1] - femur * Math.sin(fa), hip[2] + femur * Math.cos(fa)];
48
- const lean = 16 * D;
49
- const mtpY = 0.009;
50
- const ankleY = mtpY + tar * Math.cos(lean);
51
- const dy = knee[1] - ankleY, dz = Math.sqrt(Math.max(1e-6, tib * tib - dy * dy));
52
- const ankle = [0.034, ankleY, knee[2] - dz];
53
- const mtp = [0.03, mtpY, ankle[2] + tar * Math.sin(lean)];
54
- // ---- torso and head (reference hen), pitched up about the hip for an upright carriage
55
- const T = torsoFn(form);
56
- const J = {
57
- synsacrum: T([0, 0.218, -0.04]),
58
- tailBase: T([0, 0.244, -0.128]),
59
- tailTip: T([0, 0.262, -0.156]),
60
- neckBase: T([0, 0.25, 0.07]),
61
- shoulderL: T([0.057, 0.232, 0.052]),
62
- hipL: hip, kneeL: knee, ankleL: ankle, mtpL: mtp,
63
- };
64
- if (form.tailUp) {
65
- // roosters carry the tail higher: pitch the pygostyle up about its base
66
- const a = form.tailUp * D, b = J.tailBase, t = J.tailTip;
67
- J.tailTip = pitchAbout(t, b, -a);
68
- }
69
- if (juv) {
70
- // chick: round body, the tail stub barely out of the down, neck base forward
71
- J.synsacrum = [0, hip[1] + 0.012, -0.03];
72
- J.tailBase = [0, hip[1] + 0.02, -0.075];
73
- J.tailTip = [0, hip[1] + 0.03, -0.088];
74
- J.neckBase = [0, hip[1] + 0.05, 0.045];
75
- // (the shoulder near the ball's surface: the folded wing lies on the ball, not inside it)
76
- J.shoulderL = [0.068, hip[1] + 0.045, 0.03];
77
- }
78
- // head: the reference head, carried by the neck (longer neck -> higher head)
79
- const HO = headOrigin(form);
80
- const hk = form.headK ?? 1;
81
- const occ0 = [0, HO[1] - 0.01 * hk, HO[2] - 0.02 * hk];
82
- // neck: from the neck base to the occiput; its length scales with neckK (and the torso pitch)
83
- const nb = J.neckBase;
84
- const occ = juv ? [0, nb[1] + 0.042, nb[2] + 0.012] : [0, nb[1] + (occ0[1] - 0.25) * neckK, nb[2] + (occ0[2] - 0.07) * neckK];
85
- const ho = [0, occ[1] + 0.01 * hk, occ[2] + 0.02 * hk];
86
- J.occiput = occ;
87
- const bk = form.billK ?? 1;
88
- J.bill = [0, ho[1] - 0.007 * hk * bk, ho[2] + (0.017 + 0.027 * bk) * hk];
89
- J.jawHinge = [0, ho[1] - 0.012 * hk, ho[2] - 0.007 * hk];
90
- J.jawTip = [0, ho[1] - 0.012 * hk, ho[2] + (0.017 + 0.023 * bk) * hk];
91
- J._headO = ho;
92
- // toes: III (middle) forward, II inner, IV outer, I (hallux) back; two segments each, on the ground
93
- const toe = (j, yawDeg, a, b, back = false) => {
94
- const y = (yawDeg * Math.PI) / 180, m = J.mtpL;
95
- const dir = back ? [Math.sin(y), 0, -Math.cos(y)] : [Math.sin(y), 0, Math.cos(y)];
96
- J[`t${j}mL`] = [m[0] + dir[0] * a, 0.005, m[2] + dir[2] * a];
97
- J[`t${j}tL`] = [m[0] + dir[0] * (a + b), 0.0035, m[2] + dir[2] * (a + b)];
98
- };
99
- const tk = form.toeK ?? 1;
100
- toe(3, 3, 0.032 * tk, 0.027 * tk);
101
- toe(2, -24, 0.024 * tk, 0.021 * tk);
102
- toe(4, 27, 0.026 * tk, 0.022 * tk);
103
- toe(1, -10, 0.013 * tk, 0.013 * tk, true);
104
- const t0 = juv ? n2(1, 0.5) : n2(1, 0.62), t1 = juv ? n2(1, 0.2) : n2(1, 0.05);
105
- neckChain(J, NECK_SEGS, t0, t1, 0.42);
106
- const wing = wingFor(form), feathers = feathersFor(form);
107
- wingJoints(J, wing);
108
- featherJoints(J, wing, feathers, { bindFan: 0.2 });
109
- return J;
110
- }
111
-
112
- export function chickenRig(form = {}) {
113
- const J = chickenJoints(form);
114
- const HO = J._headO;
115
- delete J._headO;
116
- const F = feathersFor(form);
117
- const neck = Array.from({ length: NECK_SEGS - 1 }, (_, i) => 'neck' + (NECK_SEGS - 1 - i));
118
- const neckBones = Array.from({ length: NECK_SEGS }, (_, i) => 'neck' + (NECK_SEGS - 1 - i));
119
- const rig = buildRig({
120
- joints: J,
121
- unit: 0.34,
122
- headOrigin: HO,
123
- bones: birdBones({ neckSegs: NECK_SEGS, jaw: true, primaries: F.primaries.length, secondaries: F.secondaries.length, rectrices: F.rectrices.length }),
124
- axial: {
125
- points: ['bill', 'occiput', ...neck, 'neckBase', 'synsacrum', 'tailBase', 'tailTip'],
126
- bones: ['head', ...neckBones, 'chest', 'pelvis', 'tail'],
127
- // wide blends along the (thick, hackled) neck: the skull's influence runs down the neck and the
128
- // neck base blends far into the breast, so head-down / head-up poses bend the whole neck
129
- blend: Object.fromEntries([
130
- [1, [-0.22, 0.1]],
131
- ...Array.from({ length: NECK_SEGS - 1 }, (_, k) => [2 + k, [-0.035, 0.035]]),
132
- [1 + NECK_SEGS, [-0.5, 0.035]],
133
- ]),
134
- },
135
- limbs: birdLimbs({
136
- leg: { tCore: 0.95, aCore: 0.04, aBody: -0.045, midX: 0.014 },
137
- wing: { tCore: 0.3, aCore: 0.06, aBody: form.chick ? -0.16 : -0.05, midX: 0.02 },
138
- }),
139
- appendages: [],
140
- webTags: ['flankfold', 'scapular'],
141
- });
142
- rig.headO = HO;
143
- return rig;
144
- }
@@ -1,389 +0,0 @@
1
- // The chicken sculpted as a signed distance field: the feathered silhouette (contour feathers, the
2
- // fluffy underparts, hackles and saddle are part of the body shape; flight feathers and the tail are
3
- // cards, see core/build/featherCards.js), the bare red head furniture (single comb, wattles,
4
- // earlobes, facial skin), a short stout bill, scaled shanks and toes and, on roosters, spurs.
5
- // Every primitive is attached to a bone and a group (axial / legL / wingL / jaw). Torso primitives are
6
- // written for the reference hen and carried through the individual's torso transform (roosters stand
7
- // more upright); head primitives are head-local (see headLocal) and scale with the head.
8
- import { NECK_SEGS, torsoFn } from './rig.js';
9
- import { add, sub, mul, lerp, norm, cross, dot } from '../../core/math/vec.js';
10
- import { sculptEyeSocket } from '../../core/sdf/eyeSocket.js';
11
- import { wingFK, makeWingFrames, degs, featherFrame, makeFeatherFrame, resolveFeathers } from '../../core/rig/bird.js';
12
- import { vaneWidth } from '../../core/build/featherCards.js';
13
- import { wingFor, feathersFor } from './motion.js';
14
- import { shieldLayout, planFrame } from './coverts.js';
15
-
16
- // Eye (head-local, left, reference head): lateral (yaw 66 deg), big (globe r 7 mm), round aperture
17
- // ~9.5 mm, orange iris (see index.js)
18
- export const EYE = { c: [0.0122, 0.0008, 0.0015], r: 0.0068, back: 0.0021, yaw: 1.15, pitch: 0.06, lid: 0.0008, R: 0.0049, d: 0.0003, off: 0.0, tilt: 0, irisZ: 0.0045, irisR: 0.0047 };
19
-
20
- export function eyeFor(form = {}) {
21
- const k = form.headK ?? 1, e = form.eyeK ?? 1;
22
- return { ...EYE, c: EYE.c.map((x) => x * k), r: EYE.r * k * e, back: EYE.back * k * e, lid: EYE.lid * k, R: EYE.R * k * e, d: EYE.d * k * e, irisZ: EYE.irisZ * k * e, irisR: EYE.irisR * k * e };
23
- }
24
-
25
- export function sculptChicken(m, rig, params = {}) {
26
- const J = rig.J, form = params.form || {};
27
- const T = torsoFn(form);
28
- const HO = rig.headOrigin, hk = form.headK ?? 1;
29
- const hl = (v) => [HO[0] + v[0] * hk, HO[1] + v[1] * hk, HO[2] + v[2] * hk];
30
- // bill: scaled about its base (a chick's is short)
31
- const bk = form.billK ?? 1;
32
- const hb = (v) => hl([v[0] * bk, v[1] * bk, 0.017 + (v[2] - 0.017) * bk]);
33
- const tv = (v) => { const a = T([0, 0, 0]), b = T(v); return norm(sub(b, a)); };
34
- // ellipsoid whose local Y follows ydir and local X follows (roughly) xdir; r = [x, y, z]
35
- const ellY = (o) => {
36
- const y = norm(o.ydir);
37
- let x = o.xdir || [1, 0, 0];
38
- x = norm(sub(x, mul(y, dot(x, y))));
39
- const z = cross(x, y);
40
- return m.ell({ ...o, axis: z, up: y });
41
- };
42
- const A = { bone: 'chest' }, Pv = { bone: 'pelvis' };
43
- const juv = !!form.chick, male = params.sex === 'male' && !juv;
44
- const fl = form.fluff ?? 1; // loose-feathered breeds are bulkier underneath
45
-
46
- if (juv) {
47
- sculptChickBody(m, J, form);
48
- // (its folded wing lies on the ball in a shallow bed: folded inside the ball, every wing beat brought
49
- // the feathers out through its down)
50
- flankUnderWing(m, J, form, FLANK_CHICK);
51
- wingPocket(m, J, form);
52
- }
53
- else {
54
- // ------------------------------------------------------------ TORSO (feathered)
55
- const E = (o) => m.ell({ ...o, c: T(o.c), axis: tv(o.axis || [0, 0, 1]), up: tv(o.up || [0, 1, 0]) });
56
- E({ ...A, tag: 'breast', c: [0, 0.184, 0.06], r: [0.066, 0.078, 0.074], axis: [0, 0.3, 1], k: 0 });
57
- E({ ...A, tag: 'keel', c: [0, 0.142, 0.036], r: [0.054, 0.054, 0.064], k: 0.03 });
58
- E({ ...A, tag: 'mantle', c: [0, 0.236, -0.012], r: [0.064, 0.048, 0.108], axis: [0, 0.03, 1], k: 0.03 });
59
- E({ ...Pv, tag: 'belly', c: [0, 0.136 - 0.006 * (fl - 1), -0.055], r: [0.064 * fl, 0.066 * fl, 0.086], k: 0.035 });
60
- E({ ...Pv, tag: 'cushion', c: [0, 0.246, -0.108], r: [0.052, 0.052, 0.062], axis: [0, 0.5, -1], k: 0.035 });
61
- E({ ...Pv, tag: 'vent', c: [0, 0.165, -0.128], r: [0.052 * fl, 0.062, 0.052], k: 0.03 });
62
- E({ ...A, tag: 'crop', c: [0, 0.222, 0.092], r: [0.034, 0.034, 0.03], k: 0.03 });
63
- for (const s of [1, -1]) {
64
- E({ ...Pv, tag: 'flankfold', c: [0.048 * s * fl, 0.15, -0.025], r: [0.03, 0.058, 0.08], k: 0.03 });
65
- E({ ...A, tag: 'scapular', c: [0.04 * s, 0.25, 0.008], r: [0.026, 0.018, 0.06], axis: [0, 0.08, 1], k: 0.025 });
66
- E({ ...Pv, tag: 'fluff', c: [0.034 * s * fl, 0.1, -0.062], r: [0.03 * fl, 0.034, 0.058], k: 0.03 });
67
- }
68
- if (male) {
69
- // saddle hackles: long pointed feathers hanging from the back over the wing tips and thighs
70
- for (const s of [1, -1]) E({ ...Pv, tag: 'saddle', c: [0.034 * s, 0.22, -0.09], r: [0.028, 0.052, 0.055], axis: [0, -0.6, -1], k: 0.03 });
71
- }
72
- flankPad(m, J, form);
73
- flankUnderWing(m, J, form);
74
- wingPocket(m, J, form);
75
- wingBend(m, J, form);
76
- // tail coverts (the base of the roof-shaped tail; the rectrices are cards)
77
- const tb = J.tailBase, tt = J.tailTip;
78
- const td = norm(sub(tt, tb));
79
- m.ell({ bone: 'tail', tag: 'uppertail', c: add(lerp(tb, tt, 0.6), mul(td, 0.012)), r: [0.024, 0.034, 0.03], axis: td, up: [0, 1, 0], k: 0.025 });
80
- m.ell({ bone: 'tail', tag: 'undertail', c: add(lerp(tb, tt, 0.3), [0, -0.022, -0.01]), r: [0.028, 0.03, 0.03], k: 0.025 });
81
- }
82
-
83
- // ---------------------------------------------------------------- NECK (hackles)
84
- const nj = ['neckBase', ...Array.from({ length: NECK_SEGS - 1 }, (_, i) => 'neck' + (i + 1)), 'occiput'];
85
- const r0 = (juv ? 0.03 : 0.036) * (male ? 1.08 : 1), r1 = 0.0175 * hk;
86
- const nr = nj.map((_, i) => { const u = i / NECK_SEGS; return r0 + (r1 - r0) * Math.pow(u, 0.75); });
87
- for (let i = 0; i < NECK_SEGS; i++) m.cone({ bone: 'neck' + i, tag: 'neck', a: J[nj[i]], b: J[nj[i + 1]], ra: nr[i], rb: nr[i + 1], k: 0.02 });
88
- if (!juv) {
89
- // the hackle cape: neck feathers flowing down over the shoulders (long and full on roosters)
90
- const nb = J.neckBase, n1 = J.neck1, n2 = J.neck2;
91
- const back = [0, 0.004, -0.018];
92
- m.ell({ bone: 'neck0', tag: 'hackle', c: add(lerp(nb, n1, 0.4), back), r: [0.042 * (male ? 1.12 : 1), 0.04, 0.036], k: 0.025 });
93
- m.ell({ bone: 'neck1', tag: 'hackle', c: add(lerp(n1, n2, 0.5), [0, 0, -0.01]), r: [0.03 * (male ? 1.1 : 1), 0.03, 0.028], k: 0.02 });
94
- if (male) m.ell({ bone: 'neck0', tag: 'hackle', c: add(nb, [0, -0.01, -0.03]), r: [0.05, 0.04, 0.04], k: 0.03 });
95
- }
96
-
97
- // ---------------------------------------------------------------- HEAD (head-local, see HO)
98
- const H = { bone: 'head' };
99
- m.ell({ ...H, tag: 'cranium', c: hl([0, 0.003, -0.006]), r: [0.0142 * hk, 0.0152 * hk, 0.02 * hk], k: 0.01 });
100
- m.ell({ ...H, tag: 'crown', c: hl([0, 0.0095, 0.007]), r: [0.0105 * hk, 0.0078 * hk, 0.016 * hk], axis: norm([0, -0.25, 1]), k: 0.008 });
101
- m.ell({ ...H, tag: 'nape', c: hl([0, -0.005, -0.017]), r: [0.0135 * hk, 0.0165 * hk, 0.016 * hk], k: 0.01 });
102
- m.ell({ ...H, tag: 'chin', c: hl([0, -0.0135, 0.008]), r: [0.0085 * hk, 0.0085 * hk, 0.017 * hk], axis: norm([0, 0.2, 1]), k: 0.008 });
103
- const EYEI = eyeFor(form);
104
- for (const s of [1, -1]) {
105
- m.ell({ ...H, tag: 'face', c: hl([0.0074 * s, -0.0058, 0.0075]), r: [0.006 * hk, 0.0092 * hk, 0.013 * hk], k: 0.007 });
106
- m.ell({ ...H, tag: 'brow', c: hl([0.0095 * s, 0.0082, 0.003]), r: [0.0058 * hk, 0.0045 * hk, 0.011 * hk], k: 0.005 });
107
- sculptEyeSocket(m, EYEI, HO, s, { bone: 'head' });
108
- }
109
- // upper mandible: stout, triangular in profile, the culmen continuing the forehead down to the tip;
110
- // the lores taper the face into it
111
- for (const s of [1, -1]) m.ell({ ...H, tag: 'lores', c: hl([0.0042 * s, -0.0025, 0.017]), r: [0.0048 * hk, 0.0078 * hk, 0.009 * hk], k: 0.006 });
112
- m.ell({ ...H, tag: 'bill', c: hb([0, -0.0025, 0.027]), r: [0.0048 * hk * bk, 0.0068 * hk * bk, 0.0115 * hk * bk], axis: norm([0, -0.16, 1]), k: 0.005 });
113
- m.cone({ ...H, tag: 'bill', a: hb([0, -0.0004, 0.031]), b: hb([0, -0.0072, 0.0452]), ra: 0.0042 * hk * bk, rb: 0.0007 * hk * bk, k: 0.004 });
114
- m.cone({ ...H, tag: 'bill', a: hb([0, -0.006, 0.03]), b: hb([0, -0.0075, 0.043]), ra: 0.0035 * hk * bk, rb: 0.0008 * hk * bk, k: 0.003 });
115
- for (const s of [1, -1]) m.ell({ ...H, tag: 'nostril', c: hb([0.0038 * s, 0.0006, 0.0262]), r: [0.001 * hk * bk, 0.0008 * hk * bk, 0.0022 * hk * bk], k: 0.0006, carve: true });
116
- // lower mandible (own surface so the bill can open)
117
- const Jw = { bone: 'jaw', part: 'jaw' };
118
- m.ell({ ...Jw, tag: 'mandible', c: hb([0, -0.0082, 0.026]), r: [0.0052 * hk * bk, 0.0028 * hk * bk, 0.013 * hk * bk], axis: norm([0, 0.05, 1]), k: 0.003 });
119
- m.cone({ ...Jw, tag: 'mandible', a: hb([0, -0.0082, 0.033]), b: hb([0, -0.0078, 0.0418]), ra: 0.0034 * hk * bk, rb: 0.0007 * hk * bk, k: 0.003 });
120
-
121
- if (!juv) {
122
- // single comb: a thin serrated blade along the crown from the bill base back over the nape
123
- const cb = form.comb ?? 1, ch = form.combH ?? 1, flop = form.combFlop ?? 0;
124
- const C = (v) => {
125
- // a large hen's comb (leghorn) flops over to one side: bend the blade about the crown line
126
- let [x, y, z] = v;
127
- if (flop) { const a = flop * Math.max(0, y - 0.012) / 0.03; x += Math.sin(a) * (y - 0.012) * 0.9; y = 0.012 + (y - 0.012) * Math.cos(a); }
128
- return hl([x, y, z]);
129
- };
130
- const bladeZ = [0.024 * 1, -0.016 - 0.012 * (cb - 1)];
131
- const zs = (u) => bladeZ[0] + (bladeZ[1] - bladeZ[0]) * u;
132
- m.ell({ ...H, tag: 'comb', thin: true, c: C([0, 0.0165, zs(0.45)]), r: [0.0021 * hk, 0.0075 * Math.sqrt(ch) * hk, 0.024 * cb * hk], axis: norm([0, 0.08, 1]), k: 0.004 });
133
- // the leader: the blade continues back over the nape
134
- m.ell({ ...H, tag: 'comb', thin: true, c: C([0, 0.018 + 0.004 * ch, zs(0.98)]), r: [0.0019 * hk, 0.0075 * ch * hk, 0.009 * cb * hk], axis: norm([0, 0.3, -1]), k: 0.004 });
135
- const nPts = 5;
136
- for (let i = 0; i < nPts; i++) {
137
- const u = (i + 0.5) / nPts;
138
- const h = (0.012 + 0.009 * Math.sin(Math.PI * (0.15 + 0.8 * u))) * ch;
139
- const z = zs(0.08 + 0.78 * u);
140
- const tilt = -0.3 + 0.6 * u; // front points lean forward, rear points back
141
- m.ell({ ...H, tag: 'comb', thin: true, c: C([0, 0.021 + h * 0.52, z]), r: [0.0019 * hk, h * 0.6 * hk, 0.0036 * cb * hk], axis: norm([0, tilt, 1]), up: norm([0, 1, -tilt]), k: 0.0016 });
142
- }
143
- // wattles: two rounded lobes hanging under the bill
144
- const wl = form.wattle ?? 1;
145
- for (const s of [1, -1]) {
146
- m.ell({ ...H, tag: 'wattle', thin: true, c: hl([0.0024 * s, -0.0145 - 0.0068 * wl, 0.0225]), r: [0.0022 * hk, 0.0082 * wl * hk, 0.0096 * Math.sqrt(wl) * hk], axis: norm([0, 0.15, 1]), k: 0.005 });
147
- }
148
- // earlobes: flat ovals below and behind the eye
149
- const el = form.earlobe ?? 1;
150
- for (const s of [1, -1]) {
151
- m.ell({ ...H, tag: 'earlobe', c: hl([0.0118 * s, -0.0105 - 0.002 * (el - 1), -0.009]), r: [0.0024 * hk, 0.0052 * el * hk, 0.0042 * el * hk], axis: norm([0, 0.3, 1]), k: 0.0025 });
152
- }
153
- }
154
-
155
- // ---------------------------------------------------------------- LEGS
156
- for (const s of [1, -1]) {
157
- const S = s > 0 ? 'L' : 'R', g = 'leg' + S;
158
- const j = (n) => J[n + S];
159
- const kn = j('knee'), an = j('ankle'), mt = j('mtp');
160
- // drumstick: feathered almost to the hock, blended into the belly fluff
161
- ellY({ bone: 'tibia' + S, group: g, tag: 'thigh', c: lerp(kn, an, 0.22), ydir: sub(an, kn), r: [0.026 * fl, 0.046, 0.03 * fl], k: 0.03 });
162
- m.cone({ bone: 'tibia' + S, group: g, tag: 'trousers', a: lerp(kn, an, 0.3), b: lerp(kn, an, 0.84), ra: 0.02 * fl, rb: 0.0095, k: 0.014 });
163
- m.cone({ bone: 'tibia' + S, group: g, tag: 'shank', a: lerp(kn, an, 0.78), b: an, ra: 0.0068, rb: 0.0064, k: 0.004 });
164
- m.sphere({ bone: 'tarsus' + S, group: g, tag: 'hock', c: add(an, [0, 0, -0.0012]), rad: 0.0074, k: 0.004 });
165
- // shank: oval (deeper front to back), scaled
166
- m.cone({ bone: 'tarsus' + S, group: g, tag: 'tarsus', a: an, b: mt, ra: 0.0062, rb: 0.0056, k: 0.003 });
167
- m.sphere({ bone: 'tarsus' + S, group: g, tag: 'pad', c: add(mt, [0, -0.0004, 0.001]), rad: 0.0052, k: 0.003 });
168
- // spur: on the inner rear of the shank, a third of the way up, curving up and back
169
- const sp = form.spur ?? 0;
170
- if (sp > 0) {
171
- const base = lerp(mt, an, 0.3);
172
- const dir = norm([-0.45 * s, 0.25, -1]);
173
- const tip = add(add(base, mul(dir, 0.02 * sp)), [0, 0.004 * sp, 0]);
174
- m.cone({ bone: 'tarsus' + S, group: g, tag: 'spur', a: add(base, mul(dir, 0.003)), b: tip, ra: 0.0036 * Math.min(1.2, sp + 0.3), rb: 0.0009, k: 0.0025 });
175
- }
176
- for (const t of [1, 2, 3, 4]) {
177
- const a = mt, b = J[`t${t}m${S}`], c = J[`t${t}t${S}`];
178
- const tk = form.toeR ?? 1;
179
- const r0 = (t === 1 ? 0.0038 : 0.0044) * tk;
180
- m.cone({ bone: `toe${t}a${S}`, group: g, tag: 'toe', a, b, ra: r0, rb: 0.0036 * tk, k: 0.003 });
181
- m.cone({ bone: `toe${t}b${S}`, group: g, tag: 'toe', a: b, b: lerp(b, c, 0.7), ra: 0.0036 * tk, rb: 0.0027 * tk, k: 0.0025 });
182
- m.cone({ bone: `toe${t}b${S}`, group: g, tag: 'claw', a: lerp(b, c, 0.62), b: add(c, [0, -0.0012, 0]), ra: 0.0021 * tk, rb: 0.0005, k: 0.0012 });
183
- }
184
- }
185
-
186
- // ---------------------------------------------------------------- WINGS (arm; flight feathers are cards)
187
- const wk = form.wingK ?? 1;
188
- // the arm's flesh hangs below the bones (ventral) and is thin above them, so the coverts lie on its
189
- // dorsal side (a 9-12 mm arm above the bone line buried the covert cards: they cut out through it)
190
- // (a chick's arm hangs further below its bones and blends into the ball over less: the folded pin
191
- // feathers lie on it with the ball close under it, and a wider web stretched as the wing beat)
192
- const AV = form.chick ? 1.4 : 0.8, AT = 0.75;
193
- for (const s of [1, -1]) {
194
- const S = s > 0 ? 'L' : 'R', g = 'wing' + S;
195
- const sh = J['shoulder' + S], el = J['elbow' + S], wr = J['wrist' + S], tp = J['handTip' + S];
196
- let n = norm(cross(sub(el, sh), sub(wr, el)));
197
- if (n[1] < 0) n = mul(n, -1);
198
- const seg = (a, b, bone, thick, chord, back, tag, k = 0.01) => {
199
- const d = norm(sub(b, a));
200
- const t = mul(norm(cross(n, d)), s); // trailing side
201
- const c = add(add(lerp(a, b, 0.5), mul(t, back)), mul(n, -thick * AV));
202
- return ellY({ bone, group: g, tag, c, ydir: d, xdir: n, r: [thick, Math.hypot(...sub(b, a)) * 0.58, chord], k });
203
- };
204
- seg(sh, el, 'humerus' + S, 0.012 * wk * AT, 0.02 * wk, 0.005 * wk, 'arm', form.chick ? 0.006 : 0.014);
205
- seg(el, wr, 'ulna' + S, 0.009 * wk * AT, 0.018 * wk, 0.006 * wk, 'arm');
206
- seg(wr, tp, 'hand' + S, 0.0065 * wk, 0.016 * wk, 0.005 * wk, 'hand', 0.007);
207
- // the bend of the wing: one rounded, feathered knob from the patagium to the wrist that the covert
208
- // roots grow from (the feather stack stands ~1 cm above the bones there; a thin knob left a hollow
209
- // ringed by the coverts' roots)
210
- const pa = lerp(sh, el, 0.3);
211
- ellY({ bone: 'ulna' + S, group: g, tag: 'patagium', c: add(lerp(pa, wr, 0.55), mul(n, 0.0005 * wk)), ydir: sub(wr, pa), xdir: n, r: [0.0085 * wk, Math.hypot(...sub(wr, pa)) * 0.62 + 0.004 * wk, 0.0085 * wk], k: 0.009 });
212
- m.sphere({ bone: 'hand' + S, group: g, tag: 'wrist', c: wr, rad: 0.0085 * wk, k: 0.007 });
213
- coverts(m, J, form, s);
214
- }
215
- }
216
-
217
- // The wing's coverts as skin: the folded wing's shield on the forearm (coverts.js: its outline, its top
218
- // fitted just above the flight-feather stack, the row of greater covert cards along its rim, the lid over
219
- // its upper rear corner). A chick has none: its arm is down-covered skin and its pin feathers leave it at
220
- // their roots (its old covert plate stood up through its folded feathers once the wing lay on the ball).
221
- function coverts(m, J, form, s) {
222
- if (form.chick) return;
223
- const S = s > 0 ? 'L' : 'R';
224
- const F = planFrame(J, s);
225
- // the shield: a slab whose top is the fitted plane (plan mm, heights mm), reaching below the wing plane
226
- const L = shieldLayout(form).core, [h0, hx, hy] = L.plane;
227
- const q0 = F.Q(0, 0, h0);
228
- const U = norm(sub(F.Q(1, 0, h0 + hx), q0));
229
- let V = sub(F.Q(0, 1, h0 + hy), q0);
230
- V = norm(sub(V, mul(U, dot(V, U))));
231
- let Np = cross(U, V);
232
- if (dot(Np, F.n) < 0) Np = mul(Np, -1);
233
- const th = L.t * 0.001;
234
- const o = add(q0, mul(Np, -th / 2));
235
- const poly = L.poly.map(([x, y]) => { const q = sub(F.Q(x, y, h0 + hx * x + hy * y), q0); return [dot(q, U), dot(q, V)]; });
236
- m.fin({ bone: 'ulna' + S, group: 'wing' + S, tag: 'coverts', o, u: U, v: V, poly, t: th, round: Math.min(th / 2, L.round * 0.001), k: 0.003, bias: 0.008 });
237
- const Ld = shieldLayout(form).lid;
238
- if (Ld) {
239
- // the lid over the upper rear corner: a plate whose underside is its fitted plane (above the stack)
240
- const [l0, lx, ly] = Ld.plane;
241
- const r0 = F.Q(0, 0, l0);
242
- const LU = norm(sub(F.Q(1, 0, l0 + lx), r0));
243
- let LV = sub(F.Q(0, 1, l0 + ly), r0);
244
- LV = norm(sub(LV, mul(LU, dot(LV, LU))));
245
- let LN = cross(LU, LV);
246
- if (dot(LN, F.n) < 0) LN = mul(LN, -1);
247
- const lt = Ld.t * 0.001;
248
- const lpoly = Ld.poly.map(([x, y]) => { const q = sub(F.Q(x, y, l0 + lx * x + ly * y), r0); return [dot(q, LU), dot(q, LV)]; });
249
- m.fin({ bone: 'ulna' + S, group: 'wing' + S, tag: 'coverts', o: add(r0, mul(LN, lt / 2)), u: LU, v: LV, poly: lpoly, t: lt, round: Math.min(lt / 2, Ld.round * 0.001), k: Ld.k, bias: 0.008 });
250
- }
251
- }
252
- // chick: a round ball of down with a big head on a short neck (reference space of a scaled-up chick)
253
- function sculptChickBody(m, J, form) {
254
- const A = { bone: 'chest' }, Pv = { bone: 'pelvis' };
255
- const hy = J.hipL[1];
256
- m.ell({ ...A, tag: 'breast', c: [0, hy + 0.03, 0.03], r: [0.07, 0.07, 0.07], k: 0 });
257
- m.ell({ ...Pv, tag: 'belly', c: [0, hy - 0.005, -0.025], r: [0.072, 0.065, 0.08], k: 0.04 });
258
- m.ell({ ...Pv, tag: 'cushion', c: [0, hy + 0.035, -0.06], r: [0.055, 0.05, 0.05], k: 0.04 });
259
- m.ell({ bone: 'tail', tag: 'uppertail', c: lerp(J.tailBase, J.tailTip, 0.6), r: [0.02, 0.02, 0.02], k: 0.03 });
260
- for (const s of [1, -1]) {
261
- m.ell({ ...Pv, tag: 'flankfold', c: [0.05 * s, hy - 0.01, -0.02], r: [0.03, 0.05, 0.06], k: 0.035 });
262
- m.ell({ ...A, tag: 'scapular', c: [0.045 * s, hy + 0.045, 0.01], r: [0.028, 0.022, 0.045], k: 0.03 });
263
- m.ell({ ...Pv, tag: 'fluff', c: [0.035 * s, hy - 0.045, -0.035], r: [0.03, 0.03, 0.045], k: 0.03 });
264
- }
265
- void form;
266
- }
267
-
268
- // The flank under the folded wing is flatter than the barrel of the body around it (the folded wing
269
- // makes the side of a resting bird flat, photos): one broad, soft carver whose inner face is the folded
270
- // wing's plane under its stack (the bottom of the folded primaries), so the body narrows smoothly under
271
- // the wing and the slab bed below (wingPocket) only takes the last few millimetres. Smooth everywhere:
272
- // in flight the flank under the open wing is flattened, not dented. FLANK: centre in the wing's plan
273
- // frame (mm, as coverts.js), radii (along, across, depth, mm), the bed's depth under the wing plane
274
- // (mm) and the blend (m).
275
- export const FLANK = { c: [90, 22], r: [100, 50, 30], under: 1, fluff: 35, k: 0.02 };
276
- // a chick's bed: broad and shallow on its round ball
277
- export const FLANK_CHICK = { c: [80, 8], r: [140, 120, 30], under: 2.5, fluff: 0, k: 0.008 };
278
- function flankUnderWing(m, J, form, C = FLANK) {
279
- const W = wingFor(form), wk = form.wingK ?? 1;
280
- const L = { h: W.lengths[0], u: W.lengths[1], m: W.lengths[2] };
281
- const fr = wingFK(makeWingFrames(), 1, L, degs(W.fold));
282
- const sh = J.shoulderL;
283
- const V = (o) => [o.x, o.y, o.z];
284
- const wr = add(sh, V(fr.wrist)), d = V(fr.dU), n = V(fr.nU), t = norm(cross(n, d));
285
- const k = 0.001 * wk;
286
- // (loose-feathered breeds bulge more under the wing: the flank flattens deeper with the fluff)
287
- const under = C.under + C.fluff * Math.max(0, (form.fluff ?? 1) - 1);
288
- const c0 = add(add(add(wr, mul(d, -C.c[0] * k)), mul(t, C.c[1] * k)), mul(n, (C.r[2] - under) * k));
289
- for (const s of [1, -1]) {
290
- const mr = (p) => [p[0] * s, p[1], p[2]];
291
- m.ell({ bone: 'chest', tag: 'flankFlat', carve: true, c: mr(c0), r: [C.r[1] * k, C.r[2] * k, C.r[0] * k], axis: mr(mul(d, -1)), up: mr(n), k: C.k * wk });
292
- }
293
- }
294
-
295
- // The flank under the front of the folded wing filled out to its bed (the barrel curves in under the
296
- // wing's front and the stack's lower edge stood off it over a dark hollow, deepest on an upright rooster);
297
- // carved to the bed by flankUnderWing / wingPocket after it. PAD: centre in the wing's plan (mm), radii
298
- // (along, across, depth), the centre's height above the wing plane (mm), blend (m).
299
- export const PAD = { c: [10, 20], r: [45, 22, 14], h: -11, k: 0.016 };
300
- function flankPad(m, J, form) {
301
- const W = wingFor(form), wk = form.wingK ?? 1, C = PAD;
302
- const L = { h: W.lengths[0], u: W.lengths[1], m: W.lengths[2] };
303
- const fr = wingFK(makeWingFrames(), 1, L, degs(W.fold));
304
- const V = (o) => [o.x, o.y, o.z];
305
- const wr = add(J.shoulderL, V(fr.wrist)), d = V(fr.dU), n = V(fr.nU), t = norm(cross(n, d));
306
- const c0 = add(add(add(wr, mul(d, -C.c[0] * 0.001 * wk)), mul(t, C.c[1] * 0.001 * wk)), mul(n, C.h * 0.001));
307
- for (const s of [1, -1]) {
308
- const mr = (p) => [p[0] * s, p[1], p[2]];
309
- m.ell({ bone: 'chest', tag: 'flankPad', c: mr(c0), r: [C.r[1] * 0.001 * wk, C.r[2] * 0.001, C.r[0] * 0.001 * wk], axis: mr(mul(d, -1)), up: mr(n), k: C.k });
310
- }
311
- }
312
-
313
- // The bend of the folded wing tucks under the breast and shoulder feathers (photos: the wrist does not
314
- // show; the front of the folded wing disappears into the side of the breast): a soft mound of the body
315
- // over the folded wrist and the front of the covert shield, from the folded wing's pose (plan mm as
316
- // coverts.js: centre, radii along x / y / the wing's normal, the centre's height above the wing plane).
317
- export const BEND = { c: [-9, -3], r: [19, 20, 14], h: -1.5, k: 0.014 };
318
- function wingBend(m, J, form) {
319
- const W = wingFor(form), wk = form.wingK ?? 1, C = BEND;
320
- const L = { h: W.lengths[0], u: W.lengths[1], m: W.lengths[2] };
321
- const fr = wingFK(makeWingFrames(), 1, L, degs(W.fold));
322
- const V = (o) => [o.x, o.y, o.z];
323
- const wr = add(J.shoulderL, V(fr.wrist)), d = V(fr.dU), n = V(fr.nU), t = norm(cross(n, d));
324
- const c0 = add(add(add(wr, mul(d, -C.c[0] * 0.001 * wk)), mul(t, C.c[1] * 0.001 * wk)), mul(n, C.h * 0.001));
325
- for (const s of [1, -1]) {
326
- const mr = (p) => [p[0] * s, p[1], p[2]];
327
- m.ell({ bone: 'chest', tag: 'wingBend', c: mr(c0), r: [C.r[1] * 0.001 * wk, C.r[2] * 0.001, C.r[0] * 0.001 * wk], axis: mr(mul(d, -1)), up: mr(n), k: C.k });
328
- }
329
- }
330
-
331
- // The wing pocket: the folded wing lies ON the flank (photos: the wing is a shield on the side of the
332
- // body, its flight feathers stacked on the contour feathers), so the flank under it is carved to a bed
333
- // just under the folded stack: one flat slab carver per folded card (primaries, secondaries and their
334
- // coverts: exact planar-polygon distance, the card's own outline inset a little), whose inner face is
335
- // the card's underside less a gap (2 mm: lying, the pelvis turns against the chest and the bed came up to the
336
- // lowest primary). The union of the slabs is the stack's underside, so the bed
337
- // follows its outline: no hollow is carved beyond the cards (a single ellipsoid left a trench around
338
- // the wing), and where the folded wing lies on the barrel of the flank the carve fades to nothing at
339
- // its edges. The folded wing comes from motion.js (wing.fold through the rig's shoulder), so the bed
340
- // follows every individual (a rooster's pitched torso, a fluffy breed's wider flanks, short chick
341
- // wings). Carvers only cut what was sculpted before them: the torso, not the wing's own arm, the legs,
342
- // neck or tail coverts.
343
- export function wingPocket(m, J, form = {}) {
344
- const W = wingFor(form), F = resolveFeathers(feathersFor(form)), cov = F.coverts;
345
- const L = { h: W.lengths[0], u: W.lengths[1], m: W.lengths[2] };
346
- const fr = wingFK(makeWingFrames(), 1, L, degs(W.fold));
347
- const sh = J.shoulderL;
348
- const P0 = { x: sh[0] + fr.wrist.x, y: sh[1] + fr.wrist.y, z: sh[2] + fr.wrist.z };
349
- const ff = makeFeatherFrame();
350
- const g = 0.002, T = 0.03, inset = 0.004, k = 0.008;
351
- const V = (o) => [o.x, o.y, o.z];
352
- const slab = (f, o = {}) => {
353
- const A = V(ff.axis), N = V(ff.normal), Tv = norm(cross(N, A));
354
- const fo = o.shape ? { ...f, ...o.shape } : f;
355
- const len = f.len * (o.lenK || 1), w = f.width * (o.widthK || 1);
356
- const root = add(add(V(ff.root), mul(N, o.lift || 0)), mul(A, o.shift || 0));
357
- const arch = fo.arch ?? 0.12;
358
- // the card in pieces along its length (more where it droops more), each slab as low as the piece's lowest point (the
359
- // droop at its outer end, the vane edges, half the card's thickness)
360
- const nS = Math.max(2, Math.min(7, Math.ceil((fo.droop || 0) * len / 0.002)));
361
- const SEG = Array.from({ length: nS + 1 }, (_, j) => 0.04 + 0.96 * Math.sqrt(j / nS));
362
- for (let q = 0; q < nS; q++) {
363
- const t0 = SEG[q], t1 = SEG[q + 1];
364
- const drop = (fo.droop || 0) * len * t1 * t1 + arch * w * 0.66 + 0.00025;
365
- const poly = [], back = [];
366
- for (let i = 0; i <= 4; i++) {
367
- const t = t0 + (t1 - t0) * i / 4, [wo, wi] = vaneWidth(fo, Math.min(t, 0.99), w), cu = (fo.curve || 0) * len * t * t;
368
- poly.push([t * len, cu + Math.max(0, wi - inset)]);
369
- back.push([t * len, cu - Math.max(0, wo - inset)]);
370
- }
371
- const pts = poly.concat(back.reverse());
372
- for (const s of [1, -1]) {
373
- const mr = (p) => [p[0] * s, p[1], p[2]];
374
- const o0 = add(root, mul(N, T / 2 - g - drop));
375
- m.fin({ bone: 'chest', tag: 'wingPocket', carve: true, o: mr(o0), u: mr(A), v: mr(Tv), poly: pts, t: T, round: 0.006, k });
376
- }
377
- }
378
- };
379
- for (const f of F.primaries) {
380
- featherFrame(ff, P0, fr.dM, fr.nM, L.m, 1, f, f.fold, false);
381
- slab(f);
382
- slab(f, { lenK: cov.primary * (1 - 0.25 * f.i / Math.max(1, f.n - 1)), widthK: 1.05, lift: 0.0022, shift: -0.004, shape: { emarg: 0, tipRound: 0.6, outer: 0.45, curve: 0.02 } });
383
- }
384
- for (const f of F.secondaries) {
385
- featherFrame(ff, P0, fr.dU, fr.nU, L.u, 1, f, f.fold, true);
386
- slab(f);
387
- if (!f.cov?.skip) slab(f, { lenK: cov.secondary, widthK: 1.15, lift: 0.0028, shift: -0.006, shape: { tipRound: 0.65, outer: 0.45, curve: 0.02 } });
388
- }
389
- }