@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.
- package/ASSET-PROVENANCE.md +6 -0
- package/ASSETS-LICENSE.md +2 -1
- package/ATTRIBUTION.md +6 -1
- package/COMFORT-ART.md +65 -0
- package/DESKTOP-PLATFORMS.md +75 -0
- package/INSTALLING.md +8 -5
- package/PLUGIN.md +13 -10
- package/PREREQUISITES.md +95 -0
- package/PUPPY-MEMORY.md +102 -1
- package/README.ko.md +110 -0
- package/README.md +119 -58
- package/RELEASING.md +27 -14
- package/THIRD-PARTY-NOTICES.md +5 -3
- package/braille.mjs +35 -9
- package/examples/live.mjs +2 -2
- package/integrations/desktop/platform.mjs +27 -0
- package/integrations/linux-overlay/README.md +83 -0
- package/integrations/linux-overlay/overlay.py +1094 -0
- package/integrations/macos-overlay/README.md +83 -0
- package/integrations/macos-overlay/overlay.jxa +639 -0
- package/integrations/opencode/runtime.mjs +4 -4
- package/integrations/opencode/tui.tsx +1 -1
- package/integrations/windows-overlay/Overlay.cs +4 -4
- package/integrations/windows-overlay/desktop.mjs +40 -8
- package/integrations/windows-overlay/protocol.mjs +11 -7
- package/integrations/windows-overlay/worker.mjs +13 -7
- package/package.json +41 -14
- package/puppy-comfort-sprites.mjs +25 -0
- package/puppy-companion-comfort-q5.bin.gz +0 -0
- package/puppy-companion-comfort.json +77 -0
- package/puppy-companion-life.mjs +49 -16
- package/puppy-companion-objects.mjs +12 -0
- package/puppy-frame-predictive.mjs +15 -9
- package/puppy-frame-store.mjs +2 -2
- package/puppy-paper-world.mjs +14 -0
- package/puppy-paper.mjs +65 -14
- package/retrieviewer-cli.mjs +10 -3
- package/retrieviewer-plugin.d.mts +1 -1
- package/retrieviewer-plugin.mjs +1 -1
- package/retrieviewer.d.mts +10 -4
- package/retrieviewer.mjs +20 -14
- package/locomotion-core.mjs +0 -21
- package/locomotion-puppy.animal +0 -0
- package/vendor/procedural-animals/package.json +0 -40
- package/vendor/procedural-animals/src/animal.js +0 -146
- package/vendor/procedural-animals/src/bake.js +0 -51
- package/vendor/procedural-animals/src/build.js +0 -81
- package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
- package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
- package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
- package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
- package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
- package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
- package/vendor/procedural-animals/src/core/build/seams.js +0 -183
- package/vendor/procedural-animals/src/core/build/warp.js +0 -112
- package/vendor/procedural-animals/src/core/build/weights.js +0 -393
- package/vendor/procedural-animals/src/core/math/vec.js +0 -81
- package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
- package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
- package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
- package/vendor/procedural-animals/src/core/motion/common.js +0 -158
- package/vendor/procedural-animals/src/core/motion/index.js +0 -22
- package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
- package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
- package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
- package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
- package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
- package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
- package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
- package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
- package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
- package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
- package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
- package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
- package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
- package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
- package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
- package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
- package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
- package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
- package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
- package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
- package/vendor/procedural-animals/src/index.d.ts +0 -98
- package/vendor/procedural-animals/src/index.js +0 -29
- package/vendor/procedural-animals/src/registry.js +0 -48
- package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
- package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
- package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
- package/vendor/procedural-animals/src/species/bear/index.js +0 -139
- package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
- package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
- package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
- package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
- package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
- package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
- package/vendor/procedural-animals/src/species/boar/index.js +0 -110
- package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
- package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
- package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
- package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
- package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
- package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
- package/vendor/procedural-animals/src/species/cat/index.js +0 -211
- package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
- package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
- package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
- package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
- package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
- package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
- package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
- package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
- package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
- package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
- package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
- package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
- package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
- package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
- package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
- package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
- package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
- package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
- package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
- package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
- package/vendor/procedural-animals/src/species/cow/index.js +0 -118
- package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
- package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
- package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
- package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
- package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
- package/vendor/procedural-animals/src/species/crow/index.js +0 -70
- package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
- package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
- package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
- package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
- package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
- package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
- package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
- package/vendor/procedural-animals/src/species/deer/index.js +0 -106
- package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
- package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
- package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
- package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
- package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
- package/vendor/procedural-animals/src/species/dog/index.js +0 -144
- package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
- package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
- package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
- package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
- package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
- package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
- package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
- package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
- package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
- package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
- package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
- package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
- package/vendor/procedural-animals/src/species/fish/index.js +0 -88
- package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
- package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
- package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
- package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
- package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
- package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
- package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
- package/vendor/procedural-animals/src/species/fox/index.js +0 -120
- package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
- package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
- package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
- package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
- package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
- package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
- package/vendor/procedural-animals/src/species/frog/index.js +0 -97
- package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
- package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
- package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
- package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
- package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
- package/vendor/procedural-animals/src/species/goat/index.js +0 -149
- package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
- package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
- package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
- package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
- package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
- package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
- package/vendor/procedural-animals/src/species/horse/index.js +0 -80
- package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
- package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
- package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
- package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
- package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
- package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
- package/vendor/procedural-animals/src/species/lion/index.js +0 -111
- package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
- package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
- package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
- package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
- package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
- package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
- package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
- package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
- package/vendor/procedural-animals/src/species/pig/index.js +0 -161
- package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
- package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
- package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
- package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
- package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
- package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
- package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
- package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
- package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
- package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
- package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
- package/vendor/procedural-animals/src/species/rat/index.js +0 -111
- package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
- package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
- package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
- package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
- package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
- package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
- package/vendor/procedural-animals/src/species/shark/index.js +0 -104
- package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
- package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
- package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
- package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
- package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
- package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
- package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
- package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
- package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
- package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
- package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
- package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
- package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
- package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
- package/vendor/procedural-animals/src/species/snake/index.js +0 -73
- package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
- package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
- package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
- package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
- package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
- package/vendor/procedural-animals/src/species/spider/index.js +0 -78
- package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
- package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
- package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
- package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
- package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
- package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
- package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
- package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
- package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
- package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
- package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
- 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 };
|