@bitefoundry/retrieviewer 0.0.3 → 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 +6 -1
- 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 +117 -59
- package/RELEASING.md +23 -12
- package/THIRD-PARTY-NOTICES.md +5 -3
- package/braille.mjs +35 -9
- package/examples/live.mjs +2 -2
- package/integrations/linux-overlay/overlay.py +2 -2
- package/integrations/macos-overlay/overlay.jxa +8 -6
- 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/protocol.mjs +11 -7
- package/package.json +34 -13
- 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-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,444 +0,0 @@
|
|
|
1
|
-
// The red fox's coat, painted per vertex in reference space.
|
|
2
|
-
//
|
|
3
|
-
// Colour fields follow the red fox's pattern (Lariviere & Pasitschniak-Arts 1996):
|
|
4
|
-
// rufous-orange back, flanks, head and brush, brightest on the head, shoulders and flanks;
|
|
5
|
-
// white upper lips, cheeks, chin, throat and chest bib, a pale grey-white belly; black "stockings"
|
|
6
|
-
// from the paws up the front of the forelegs to the elbows and over the hind feet up to the hocks
|
|
7
|
-
// (a dark stripe runs on up the front of the shin); black backs of the ears with a white-furred
|
|
8
|
-
// inside; dark tear lines from the inner eye corners toward the lips; a black lip line and nose; the
|
|
9
|
-
// brush has black-tipped guard hair (the shader's agouti band), a dark tail-gland spot near its
|
|
10
|
-
// base and a white tip. Morphs: red (default), cross (a dark cross over the shoulders and down the
|
|
11
|
-
// spine, dark legs and belly, grizzled flanks), silver (black with silver-tipped guard hair, white
|
|
12
|
-
// tail tip), urban (duller, greyer, grizzled winter coat). Kits: woolly, sandy grey-brown with dark
|
|
13
|
-
// legs and a pale face.
|
|
14
|
-
// Fur length: long ruff and cheek fluff, long flanks and breeches, the huge brush; short sleek face,
|
|
15
|
-
// muzzle and lower legs.
|
|
16
|
-
import { HEAD_O, MUZZLE_Z0, HS } from './rig.js';
|
|
17
|
-
import { neckS } from './regions.js';
|
|
18
|
-
import { SDFModel } from '../../core/sdf/sdf.js';
|
|
19
|
-
import { norm, sub, dot, cross, len, add, mul, smoothstep, clamp, mix, rng, fbm3, vnoise3 } from '../../core/math/vec.js';
|
|
20
|
-
import { srgb, mix3, MAT, smoothField } from '../../core/build/coatKit.js';
|
|
21
|
-
|
|
22
|
-
const P3 = {
|
|
23
|
-
// sRGB swatches, neutral-light albedo
|
|
24
|
-
red: {
|
|
25
|
-
back: 0xb4582a, flank: 0xc46a32, lowFlank: 0xc97a42, head: 0xca7236, muzzleTop: 0xb46a34, shoulder: 0xc56a32,
|
|
26
|
-
white: 0xece8e2, belly: 0xd8d2ca, stocking: 0x19140f, stockingEdge: 0x3a2418, earBack: 0x1e1814, earInner: 0xe6dccb,
|
|
27
|
-
tail: 0xa45a2c, tailUnder: 0xc08450, tailTip: 0xf0ebe2, gland: 0x3a2618, tear: 0x3e2a1e, rump: 0xc98a58, dark: 0x2a1c14,
|
|
28
|
-
ag: { back: 0.35, flank: 0.1, head: 0.05, leg: 0, tail: 0.55 },
|
|
29
|
-
},
|
|
30
|
-
cross: {
|
|
31
|
-
back: 0x8a5634, flank: 0x9c6a44, lowFlank: 0x8a6448, head: 0xa8703e, muzzleTop: 0x7a5234, shoulder: 0x8e5a36,
|
|
32
|
-
white: 0xcfc8bc, belly: 0x3a3430, stocking: 0x151210, stockingEdge: 0x2a2018, earBack: 0x1a1512, earInner: 0xcfc4b2,
|
|
33
|
-
tail: 0x6e4a32, tailUnder: 0x8a6448, tailTip: 0xe8e2d8, gland: 0x2a1c14, tear: 0x2a1c14, rump: 0x8a6448, dark: 0x1e1a18,
|
|
34
|
-
ag: { back: 0.55, flank: 0.45, head: 0.15, leg: 0, tail: 0.7 },
|
|
35
|
-
},
|
|
36
|
-
silver: {
|
|
37
|
-
back: 0x8e8c8a, flank: 0x7a7876, lowFlank: 0x2e2c2a, head: 0x5e5c5a, muzzleTop: 0x201e1c, shoulder: 0x74726f,
|
|
38
|
-
white: 0x5a5856, belly: 0x1e1c1a, stocking: 0x121010, stockingEdge: 0x181614, earBack: 0x141210, earInner: 0x6a6866,
|
|
39
|
-
tail: 0x242220, tailUnder: 0x1c1a18, tailTip: 0xeae6de, gland: 0x141210, tear: 0x141210, rump: 0x3a3836, dark: 0x161412,
|
|
40
|
-
ag: { back: 0.85, flank: 0.8, head: 0.6, leg: 0.1, tail: 0.3 },
|
|
41
|
-
},
|
|
42
|
-
urban: {
|
|
43
|
-
back: 0x7e4a2e, flank: 0x96684a, lowFlank: 0x9a7a62, head: 0x9a6440, muzzleTop: 0x8a5a3a, shoulder: 0x86522f,
|
|
44
|
-
white: 0xd8d2c8, belly: 0xa8a098, stocking: 0x1c1712, stockingEdge: 0x3a2a1e, earBack: 0x1e1814, earInner: 0xd6cab8,
|
|
45
|
-
tail: 0x6e4630, tailUnder: 0x8e6a50, tailTip: 0xe0dad0, gland: 0x2a1c14, tear: 0x3a2618, rump: 0x9a7a62, dark: 0x2a1c14,
|
|
46
|
-
ag: { back: 0.6, flank: 0.55, head: 0.15, leg: 0, tail: 0.65 },
|
|
47
|
-
},
|
|
48
|
-
};
|
|
49
|
-
const KIT = 0x7a6450; // woolly sandy grey-brown natal / juvenile coat
|
|
50
|
-
|
|
51
|
-
export function palette(p) {
|
|
52
|
-
const base = P3[p.variant] || P3.red;
|
|
53
|
-
const k = p.coatWarmth || 0, l = p.coatLightness || 0, juv = p.juv || 0;
|
|
54
|
-
const kit = srgb(KIT).map((c) => c * (p.variant === 'silver' ? 0.45 : 1));
|
|
55
|
-
const out = { ag: base.ag };
|
|
56
|
-
for (const [key, hex] of Object.entries(base)) {
|
|
57
|
-
if (key === 'ag') continue;
|
|
58
|
-
let c = srgb(hex);
|
|
59
|
-
// warmth shifts red against blue; the white parts stay white
|
|
60
|
-
const wk = /white|belly|earInner|tailTip/.test(key) ? 0.25 : 1;
|
|
61
|
-
c = [c[0] * (1 + (0.1 * k + l) * wk), c[1] * (1 + (0.01 * k + l) * wk), c[2] * (1 - (0.12 * k - l) * wk)];
|
|
62
|
-
// kits: most of the pattern is washed into the woolly juvenile coat (face, stockings, ears and the
|
|
63
|
-
// tail tip stay)
|
|
64
|
-
const keep = /white|earInner|tailTip/.test(key) ? 0.6 : /stocking|earBack/.test(key) ? 0.7 : /head|muzzleTop/.test(key) ? 0.45 : 0.15;
|
|
65
|
-
if (juv > 0) c = mix3(c, kit, juv * (1 - keep));
|
|
66
|
-
out[key] = c;
|
|
67
|
-
}
|
|
68
|
-
// eyelids (the eye shader's lidColor): furred in the face colour round the eye, a little darker; the
|
|
69
|
-
// shader darkens their margin itself, so a blink or a closed eye reads as a furred lid with a dark
|
|
70
|
-
// line (it was near black: every blink, sleep and death showed glossy black beads)
|
|
71
|
-
out.lid = mix3(out.head, out.tear, 0.25).map((c) => c * 0.85);
|
|
72
|
-
return out;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function foxCoat(ctx) {
|
|
76
|
-
const { model, rig, pos, nrm, regionOf: partOf, weights, nV, params } = ctx;
|
|
77
|
-
const { BONES, AXIAL } = rig;
|
|
78
|
-
const J = rig.J;
|
|
79
|
-
const AX_LEN = weights.axialLengths;
|
|
80
|
-
const C = palette(params);
|
|
81
|
-
const AG = C.ag;
|
|
82
|
-
const juv = params.juv || 0;
|
|
83
|
-
const hw = params.headW || 1, mz = params.muzzle || 1;
|
|
84
|
-
const ruffK = params.ruff ?? 1;
|
|
85
|
-
const bibK = params.bib ?? 1; // extent of the white bib / belly
|
|
86
|
-
const stockK = params.stockings ?? 1; // how far up the black stockings reach
|
|
87
|
-
const tipK = params.tailTip ?? 1; // length of the white tail tip (0 = none)
|
|
88
|
-
const tearK = params.tear ?? 1;
|
|
89
|
-
const variant = params.variant || 'red';
|
|
90
|
-
const nOff = (params.coatSeed || 0) % 997;
|
|
91
|
-
const { dominant, axialS, skinIndex, skinWeight, limbMember, limbWhich } = weights;
|
|
92
|
-
const P = (v) => [pos[v * 3], pos[v * 3 + 1], pos[v * 3 + 2]];
|
|
93
|
-
const N = (v) => [nrm[v * 3], nrm[v * 3 + 1], nrm[v * 3 + 2]];
|
|
94
|
-
const sOcc = AX_LEN[1], sNeckBase = AX_LEN[3], sTailBase = AX_LEN[8], sTip = AX_LEN[AX_LEN.length - 1];
|
|
95
|
-
const tailLen = sTip - sTailBase;
|
|
96
|
-
const eyePrims = model.prims.filter((p) => p.tag === 'eyesocket');
|
|
97
|
-
const nosePrim = model.prims.find((p) => p.tag === 'nose');
|
|
98
|
-
const caninePrims = model.prims.filter((p) => p.tag === 'canine');
|
|
99
|
-
const jawPrims = model.forPart('jaw').filter((p) => p.tag !== 'canine');
|
|
100
|
-
const bodyPrims = model.forPart('body');
|
|
101
|
-
const headPrims = bodyPrims.filter((p) => p.bone === 'head' && !p.carve && p.tag !== 'canine');
|
|
102
|
-
const earPrims = model.prims.filter((p) => p.tag === 'ear');
|
|
103
|
-
const isLimb = BONES.map((b) => /^(scapula|humerus|radius|metacarpus|fpaw|femur|tibia|metatarsus|hpaw)/.test(b.name));
|
|
104
|
-
const isPaw = BONES.map((b) => /^(fpaw|hpaw)/.test(b.name));
|
|
105
|
-
const isFront = BONES.map((b) => /^(scapula|humerus|radius|metacarpus|fpaw)/.test(b.name));
|
|
106
|
-
// reference heights
|
|
107
|
-
const yEl = J.elbowL[1], yHock = J.hockL[1], yKnee = J.kneeL[1], yBack = J.thoraxRear[1];
|
|
108
|
-
const zSh = J.shoulderL[2], zHip = J.hipL[2];
|
|
109
|
-
// head-local coordinates of a reference-space point (undo head width and muzzle stretch)
|
|
110
|
-
const headLocal = (p) => {
|
|
111
|
-
const x = (p[0] - HEAD_O[0]) / hw / HS, y = (p[1] - HEAD_O[1]) / HS;
|
|
112
|
-
let z = (p[2] - HEAD_O[2]) / HS;
|
|
113
|
-
if (z > MUZZLE_Z0) z = MUZZLE_Z0 + (z - MUZZLE_Z0) / mz;
|
|
114
|
-
return [x, y, z];
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
// --- regions per vertex (0 torso, 1 neck, 2 head, 4 tail, 5 ear, 6 jaw) and limb blend
|
|
118
|
-
const region = new Uint8Array(nV);
|
|
119
|
-
const legness = new Float32Array(nV);
|
|
120
|
-
const legBone = new Int16Array(nV).fill(-1);
|
|
121
|
-
const junction = new Float32Array(nV);
|
|
122
|
-
const tailT = new Float32Array(nV);
|
|
123
|
-
for (let v = 0; v < nV; v++) {
|
|
124
|
-
const bn = BONES[dominant[v]].name;
|
|
125
|
-
const p = P(v);
|
|
126
|
-
let lb = -1, lw = 0;
|
|
127
|
-
for (let k = 0; k < 4; k++) {
|
|
128
|
-
const b = skinIndex[v * 4 + k], w = skinWeight[v * 4 + k];
|
|
129
|
-
if (isLimb[b] && w > lw) { lw = w; lb = b; }
|
|
130
|
-
}
|
|
131
|
-
legBone[v] = lb;
|
|
132
|
-
const m = limbMember[v];
|
|
133
|
-
legness[v] = lb >= 0 ? smoothstep(0.15, 0.85, m) : 0;
|
|
134
|
-
junction[v] = lb >= 0 ? 4 * m * (1 - m) : 0;
|
|
135
|
-
if (partOf[v] === 2) region[v] = 6;
|
|
136
|
-
else if (bn.startsWith('ear')) region[v] = 5;
|
|
137
|
-
else if (axialS[v] > sTailBase + 0.012 && bn.startsWith('tail')) { region[v] = 4; tailT[v] = clamp((axialS[v] - sTailBase) / tailLen, 0, 1); }
|
|
138
|
-
else if (axialS[v] < sOcc + 0.006 || (partOf[v] === 1 && neckS(p[0], p[1], p[2]) > 0.012)) region[v] = 2;
|
|
139
|
-
else if (axialS[v] < sNeckBase) region[v] = 1;
|
|
140
|
-
else region[v] = 0;
|
|
141
|
-
if (region[v] >= 2) { legness[v] = 0; junction[v] = 0; }
|
|
142
|
-
}
|
|
143
|
-
const underFactor = (v) => {
|
|
144
|
-
const n = N(v), p = P(v), li = limbWhich[v];
|
|
145
|
-
if (li < 0 || junction[v] <= 0) return 0;
|
|
146
|
-
if (li <= 1) return junction[v] * Math.max(smoothstep(0.15, -0.55, n[2]) * smoothstep(yEl + 0.1, yEl + 0.05, p[1]), smoothstep(0.2, -0.6, n[1]));
|
|
147
|
-
return junction[v] * smoothstep(0.35, -0.45, n[1] + 0.35 * Math.abs(n[2]));
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
// --- ventral (white underside) factor: throat, bib, belly, inner thighs
|
|
151
|
-
const ventral = new Float32Array(nV);
|
|
152
|
-
const yBib = yEl + 0.13 * bibK; // top of the white bib on the chest front
|
|
153
|
-
for (let v = 0; v < nV; v++) {
|
|
154
|
-
const p = P(v), n = N(v), r = region[v];
|
|
155
|
-
let w = 0;
|
|
156
|
-
if (r === 0) {
|
|
157
|
-
w = smoothstep(-0.45, -0.85, n[1]);
|
|
158
|
-
// chest front between the forelegs: the white bib, continuing the throat
|
|
159
|
-
if (p[2] > zSh - 0.05) w = Math.max(w, smoothstep(yBib, yBib - 0.035, p[1] + 0.012 * (fbm3(p[0] * 40, p[1] * 40, p[2] * 40, 2) - 0.5)) * smoothstep(0.042, 0.018, Math.abs(p[0])) * smoothstep(-0.3, 0.35, n[2]));
|
|
160
|
-
w *= smoothstep(yBack - 0.02, yBack - 0.08, p[1]);
|
|
161
|
-
} else if (r === 1) {
|
|
162
|
-
// throat and the front of the neck ruff
|
|
163
|
-
w = smoothstep(0.4, -0.05, n[1] + 0.65 * Math.abs(n[0]) - 0.45 * Math.max(0, n[2]));
|
|
164
|
-
} else if (r === 2 || r === 6) {
|
|
165
|
-
const h = headLocal(p);
|
|
166
|
-
w = smoothstep(-0.028, -0.05, h[1]) * smoothstep(-0.1, -0.6, n[1]) + (r === 6 ? 0.8 : 0);
|
|
167
|
-
}
|
|
168
|
-
const L = legness[v];
|
|
169
|
-
if (L > 0) {
|
|
170
|
-
const side = p[0] >= 0 ? 1 : -1;
|
|
171
|
-
const inner = smoothstep(0.1, -0.6, n[0] * side);
|
|
172
|
-
const wl = inner * 0.75 * smoothstep(yKnee - 0.01, yKnee + 0.05, p[1]) * (isFront[legBone[v]] ? 0.4 : 1) + smoothstep(-0.3, -0.85, n[1]) * 0.4 * smoothstep(yKnee - 0.02, yKnee + 0.04, p[1]);
|
|
173
|
-
w = mix(w, wl, L);
|
|
174
|
-
}
|
|
175
|
-
w = Math.max(w, underFactor(v) * 0.6 * smoothstep(-0.1, -0.5, n[1]));
|
|
176
|
-
ventral[v] = clamp(w, 0, 1);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// --- comb (hair flow), bind space
|
|
180
|
-
const comb = new Float32Array(nV * 3);
|
|
181
|
-
for (let v = 0; v < nV; v++) {
|
|
182
|
-
const p = P(v), n = N(v), r = region[v];
|
|
183
|
-
let d;
|
|
184
|
-
const bone = BONES[dominant[v]];
|
|
185
|
-
if (r === 5) {
|
|
186
|
-
d = norm(sub(bone.tail, bone.head));
|
|
187
|
-
} else if (r === 2 || r === 6) {
|
|
188
|
-
const h = headLocal(p);
|
|
189
|
-
// out from the nose over the face; the cheek ruff sweeps back, out and down
|
|
190
|
-
const fromNose = norm(sub(h, [0, -0.01, 0.165]));
|
|
191
|
-
d = norm(add(fromNose, [0, -0.2, -0.5]));
|
|
192
|
-
if (h[2] < 0.01 && Math.abs(h[0]) > 0.03) d = norm(add(d, [Math.sign(h[0]) * 0.7, -0.6, -0.7]));
|
|
193
|
-
} else {
|
|
194
|
-
const seg = weights.segT[v * 2] | 0;
|
|
195
|
-
const a = AXIAL.points[seg], b = AXIAL.points[Math.min(seg + 1, AXIAL.points.length - 1)];
|
|
196
|
-
d = norm(sub(b, a));
|
|
197
|
-
if (r === 0) d = norm(add(d, [0, -0.45 * Math.abs(n[0]), 0]));
|
|
198
|
-
if (r === 1) d = norm(add(d, [0, -0.55, 0])); // the ruff hangs down and back
|
|
199
|
-
const L = legness[v];
|
|
200
|
-
if (L > 0 && legBone[v] >= 0) {
|
|
201
|
-
const lbn = BONES[legBone[v]];
|
|
202
|
-
let dl = norm(sub(lbn.tail, lbn.head));
|
|
203
|
-
if (isPaw[legBone[v]]) dl = norm(add(dl, [0, 0, 0.4]));
|
|
204
|
-
else dl = norm(add(dl, [0, -0.2, -0.3]));
|
|
205
|
-
d = norm(add(mul(d, 1 - L), mul(dl, L)));
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
let t = sub(d, mul(n, dot(d, n)));
|
|
209
|
-
if (len(t) < 1e-4) t = cross(n, [1, 0, 0]);
|
|
210
|
-
t = norm(t);
|
|
211
|
-
comb[v * 3] = t[0]; comb[v * 3 + 1] = t[1]; comb[v * 3 + 2] = t[2];
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// --- per-vertex paint
|
|
215
|
-
const furLen = new Float32Array(nV);
|
|
216
|
-
const tint = new Float32Array(nV * 4);
|
|
217
|
-
const markSDF = new Float32Array(nV).fill(1);
|
|
218
|
-
const surf = new Float32Array(nV * 4);
|
|
219
|
-
const g3 = (h, c, rr) => Math.exp(-(((Math.abs(h[0]) - c[0]) / rr[0]) ** 2 + ((h[1] - c[1]) / rr[1]) ** 2 + ((h[2] - c[2]) / rr[2]) ** 2));
|
|
220
|
-
// distance (head-local) from a point to the segment a-b, mirrored to the left side
|
|
221
|
-
const segD = (h, a, b) => {
|
|
222
|
-
const q = [Math.abs(h[0]), h[1], h[2]];
|
|
223
|
-
const ab = sub(b, a), t = clamp(dot(sub(q, a), ab) / dot(ab, ab), 0, 1);
|
|
224
|
-
return { d: len(sub(q, add(a, mul(ab, t)))), t };
|
|
225
|
-
};
|
|
226
|
-
const tailSegDorsal = (v) => {
|
|
227
|
-
const bone = BONES[dominant[v]];
|
|
228
|
-
const d = norm(sub(bone.tail, bone.head));
|
|
229
|
-
return norm([0, -d[2], d[1]]);
|
|
230
|
-
};
|
|
231
|
-
const cross_ = variant === 'cross';
|
|
232
|
-
|
|
233
|
-
for (let v = 0; v < nV; v++) {
|
|
234
|
-
const p = P(v), n = N(v), r = region[v];
|
|
235
|
-
let col, fl = 0.02, ag = 0, mat = MAT.FUR, mark = 1, under = 0.4;
|
|
236
|
-
// low-frequency noise (ragged pattern edges) and a finer field
|
|
237
|
-
const nz = fbm3(p[0] * 12 + nOff, p[1] * 12, p[2] * 12, 3) - 0.5;
|
|
238
|
-
const nz2 = vnoise3(p[0] * 70 + nOff, p[1] * 70, p[2] * 70) - 0.5;
|
|
239
|
-
if (r === 0 || r === 1) {
|
|
240
|
-
const up = n[1];
|
|
241
|
-
const vent = ventral[v];
|
|
242
|
-
const dors = smoothstep(-0.1, 0.7, up + 0.3 * nz);
|
|
243
|
-
col = mix3(C.lowFlank, C.flank, smoothstep(-0.4, 0.2, up + 0.25 * nz));
|
|
244
|
-
col = mix3(col, C.back, dors * 0.85);
|
|
245
|
-
ag = mix(AG.flank, AG.back, dors);
|
|
246
|
-
if (r === 0) {
|
|
247
|
-
// brighter shoulders; grizzled hips and rump in the dull coats
|
|
248
|
-
const sh = Math.exp(-(((p[2] - zSh + 0.01) / 0.05) ** 2)) * smoothstep(-0.3, 0.3, n[0] * (p[0] >= 0 ? 1 : -1));
|
|
249
|
-
col = mix3(col, C.shoulder, sh * 0.6);
|
|
250
|
-
const rump = smoothstep(zHip + 0.02, zHip - 0.05, p[2]) * smoothstep(-0.2, -0.8, n[2]) * smoothstep(yBack + 0.02, yBack - 0.06, p[1]);
|
|
251
|
-
col = mix3(col, C.rump, rump * 0.6);
|
|
252
|
-
// cross morph: a dark stripe down the spine crossed by one over the shoulders
|
|
253
|
-
if (cross_) {
|
|
254
|
-
const spine = smoothstep(0.4, 0.8, up + 0.15 * nz) * smoothstep(zHip - 0.06, zHip + 0.02, p[2]);
|
|
255
|
-
const bar = Math.exp(-(((p[2] - zSh - 0.035 + 0.02 * nz) / 0.05) ** 2)) * smoothstep(yEl + 0.02, yBack - 0.04, p[1]);
|
|
256
|
-
const c = clamp(Math.max(spine, bar), 0, 1);
|
|
257
|
-
col = mix3(col, C.dark, c * 0.92);
|
|
258
|
-
ag = mix(ag, 0.3, c);
|
|
259
|
-
}
|
|
260
|
-
col = mix3(col, C.belly, vent);
|
|
261
|
-
// the white bib is whiter than the belly
|
|
262
|
-
const bib = smoothstep(zSh - 0.06, zSh + 0.01, p[2]) * vent;
|
|
263
|
-
col = mix3(col, C.white, bib);
|
|
264
|
-
ag *= 1 - vent;
|
|
265
|
-
// guard-hair lengths: flanks, long over the shoulders and hips, a belly fringe
|
|
266
|
-
fl = mix(0.017, 0.024, smoothstep(0.1, 0.85, up)) * (1 + 0.1 * nz2);
|
|
267
|
-
fl = mix(fl, 0.014, smoothstep(0.3, 0.9, vent));
|
|
268
|
-
fl = Math.max(fl, 0.022 * bib);
|
|
269
|
-
if (p[2] < zHip) fl = Math.max(fl, 0.024 * rump);
|
|
270
|
-
} else {
|
|
271
|
-
// neck: rufous above, the white throat below, the ruff long and soft
|
|
272
|
-
col = mix3(col, C.white, smoothstep(0.2, 0.65, vent + 0.15 * nz));
|
|
273
|
-
ag *= 1 - smoothstep(0.2, 0.6, vent);
|
|
274
|
-
fl = mix(0.026, 0.024, vent) * (0.85 + 0.15 * ruffK) * (1 + 0.1 * nz2);
|
|
275
|
-
if (cross_) col = mix3(col, C.dark, smoothstep(0.6, 0.95, up) * 0.6);
|
|
276
|
-
}
|
|
277
|
-
const L = legness[v];
|
|
278
|
-
if (L > 0) {
|
|
279
|
-
const lb = legBone[v];
|
|
280
|
-
const front = lb >= 0 && isFront[lb];
|
|
281
|
-
const side = p[0] >= 0 ? 1 : -1;
|
|
282
|
-
const outer = smoothstep(-0.2, 0.5, n[0] * side);
|
|
283
|
-
// upper leg: body colour (orange thighs, white inside)
|
|
284
|
-
let lc = mix3(col, C.belly, smoothstep(0.2, 0.7, ventral[v]) * (1 - outer));
|
|
285
|
-
// the black stockings: forelegs from the paw up to the elbow (highest on the front), a thin
|
|
286
|
-
// dark line up the front of the upper arm; hind feet up to the hock and a dark stripe up
|
|
287
|
-
// the front of the shin
|
|
288
|
-
let st;
|
|
289
|
-
const e = 0.012 * nz;
|
|
290
|
-
if (front) {
|
|
291
|
-
const top = yEl + 0.01 * stockK + 0.02 * smoothstep(-0.2, 0.8, n[2]);
|
|
292
|
-
st = smoothstep(top + 0.012, top - 0.012, p[1] + e);
|
|
293
|
-
st = Math.max(st, 0.8 * smoothstep(0.4, 0.85, n[2]) * smoothstep(yEl + 0.075, yEl + 0.03, p[1]) * stockK);
|
|
294
|
-
} else {
|
|
295
|
-
const top = yHock + 0.012 + 0.03 * stockK * smoothstep(0.1, 0.8, n[2]);
|
|
296
|
-
st = smoothstep(top + 0.012, top - 0.012, p[1] + e);
|
|
297
|
-
// dark front of the shin (from the hock up toward the stifle)
|
|
298
|
-
st = Math.max(st, 0.85 * smoothstep(0.35, 0.8, n[2]) * smoothstep(yKnee - 0.01, yHock + 0.03, p[1]) * stockK);
|
|
299
|
-
}
|
|
300
|
-
st = clamp(st * (variant === 'silver' ? 1 : 1), 0, 1);
|
|
301
|
-
lc = mix3(lc, mix3(C.stockingEdge, C.stocking, smoothstep(0.3, 0.9, st)), st);
|
|
302
|
-
let lf = mix(0.007, 0.018, smoothstep(front ? yEl - 0.06 : yHock, front ? yEl + 0.06 : yKnee + 0.04, p[1]));
|
|
303
|
-
// breeches on the back of the thighs, a little feathering behind the forearm
|
|
304
|
-
if (!front) lf = Math.max(lf, 0.024 * smoothstep(-0.1, -0.7, n[2]) * smoothstep(yKnee - 0.04, yKnee + 0.05, p[1]));
|
|
305
|
-
else lf = Math.max(lf, 0.009 * smoothstep(-0.2, -0.8, n[2]) * smoothstep(yEl - 0.1, yEl - 0.02, p[1]));
|
|
306
|
-
if (lb >= 0 && isPaw[lb]) { lf = 0.005; lc = C.stocking; }
|
|
307
|
-
col = mix3(col, lc, L);
|
|
308
|
-
ag = mix(ag, AG.leg * (1 - st), L);
|
|
309
|
-
fl = mix(fl, lf, L);
|
|
310
|
-
}
|
|
311
|
-
under = 0.45;
|
|
312
|
-
} else if (r === 4) {
|
|
313
|
-
// the brush: rufous with black-tipped guard hair (strongest on top), a dark tail-gland spot near
|
|
314
|
-
// the base, paler underside, white tip
|
|
315
|
-
const t = tailT[v];
|
|
316
|
-
const dors = dot(n, tailSegDorsal(v));
|
|
317
|
-
const top = smoothstep(-0.45, 0.55, dors + 0.3 * nz);
|
|
318
|
-
col = mix3(C.tailUnder, C.tail, top);
|
|
319
|
-
ag = AG.tail * (0.55 + 0.45 * top) * smoothstep(0.02, 0.2, t);
|
|
320
|
-
const gl = Math.exp(-(((t - 0.14) / 0.05) ** 2)) * smoothstep(0.2, 0.75, dors);
|
|
321
|
-
col = mix3(col, C.gland, gl * 0.75);
|
|
322
|
-
// a darker band before the white tip (dark-tipped hair crowding at the end)
|
|
323
|
-
const tipStart = 1 - 0.17 * tipK;
|
|
324
|
-
const band = Math.exp(-(((t - tipStart + 0.06) / 0.07) ** 2));
|
|
325
|
-
col = mix3(col, C.dark, band * 0.35);
|
|
326
|
-
const tip = tipK > 0 ? smoothstep(tipStart - 0.02, tipStart + 0.04, t + 0.035 * nz) : 0;
|
|
327
|
-
col = mix3(col, C.tailTip, tip);
|
|
328
|
-
ag *= 1 - tip;
|
|
329
|
-
fl = mix(0.024, 0.04, smoothstep(0.0, 0.35, t)) * (1 - 0.35 * smoothstep(0.88, 1, t));
|
|
330
|
-
under = 0.4;
|
|
331
|
-
} else if (r === 5) {
|
|
332
|
-
// ears: black backs, the black running round the rim; the inside furred white
|
|
333
|
-
const earP = earPrims[p[0] > 0 ? 0 : 3];
|
|
334
|
-
const faceDir = [earP.P[9], earP.P[10], earP.P[11]];
|
|
335
|
-
const upE = [earP.P[6], earP.P[7], earP.P[8]];
|
|
336
|
-
const lat = [earP.P[3], earP.P[4], earP.P[5]];
|
|
337
|
-
const front = dot(n, faceDir);
|
|
338
|
-
const rel = sub(p, [earP.P[0], earP.P[1], earP.P[2]]);
|
|
339
|
-
const ht = dot(rel, upE) / 0.095; // ~0 base .. 1 tip
|
|
340
|
-
const edge = Math.abs(dot(rel, lat)) / (0.022 * Math.max(0.25, 1 - ht));
|
|
341
|
-
if (front > 0.25) {
|
|
342
|
-
col = mix3(C.head, C.earInner, smoothstep(0.25, 0.7, front) * (1 - smoothstep(0.75, 1.05, edge)));
|
|
343
|
-
fl = 0.012 * (1 - smoothstep(0.4, 1.0, ht));
|
|
344
|
-
} else {
|
|
345
|
-
// the back: black, orange at the very base where the head fur runs onto it
|
|
346
|
-
col = mix3(C.earBack, C.head, smoothstep(0.12, -0.05, ht) * 0.9);
|
|
347
|
-
fl = 0.005;
|
|
348
|
-
}
|
|
349
|
-
ag = 0;
|
|
350
|
-
} else {
|
|
351
|
-
// ---------------- head & jaw
|
|
352
|
-
const h = headLocal(p);
|
|
353
|
-
col = C.head;
|
|
354
|
-
ag = AG.head;
|
|
355
|
-
// muzzle top a little darker and duller
|
|
356
|
-
const mtop = smoothstep(0.05, 0.1, h[2]) * smoothstep(-0.1, 0.5, n[1]);
|
|
357
|
-
col = mix3(col, C.muzzleTop, mtop * 0.6);
|
|
358
|
-
// white mask: upper lips, muzzle sides low down, cheeks (the white cheek ruff), chin, throat
|
|
359
|
-
const lipSide = smoothstep(0.035, 0.065, h[2]) * smoothstep(-0.018, -0.032, h[1] - 0.06 * (h[2] - 0.1)) * smoothstep(0.1, 0.5, Math.abs(n[0]));
|
|
360
|
-
const cheek = smoothstep(-0.01, -0.03, h[1] + 0.25 * (h[2] - 0.02) + 0.01 * nz) * smoothstep(0.075, 0.02, h[2]) * smoothstep(0.012, 0.03, Math.abs(h[0]));
|
|
361
|
-
const lowFace = smoothstep(-0.03, -0.05, h[1]) * smoothstep(-0.1, -0.6, n[1]);
|
|
362
|
-
const throat = smoothstep(-0.034, -0.055, h[1]) * smoothstep(0.08, 0.03, h[2]);
|
|
363
|
-
let mask = clamp(Math.max(lipSide, cheek, lowFace, throat, r === 6 ? 0.85 : 0), 0, 1);
|
|
364
|
-
col = mix3(col, C.white, mask);
|
|
365
|
-
ag *= 1 - mask;
|
|
366
|
-
// dark tear line: from the inner eye corner down and forward toward the upper lip
|
|
367
|
-
const tl = segD(h, [0.025, 0.012, 0.05], [0.017, -0.018, 0.085]);
|
|
368
|
-
const tear = Math.exp(-((tl.d / (0.0045 + 0.003 * tl.t)) ** 2)) * tearK * (1 - 0.6 * juv);
|
|
369
|
-
col = mix3(col, C.tear, tear * 0.85);
|
|
370
|
-
// cheek ruff: long white fluff with an orange / dark edge toward the neck
|
|
371
|
-
const ruffW = smoothstep(-0.015, -0.06, h[2]) * smoothstep(0.03, 0.05, Math.abs(h[0])) * smoothstep(0.015, -0.015, h[1]);
|
|
372
|
-
// fur length: sleek muzzle and face, longer crown and cheeks, flaring cheek ruff
|
|
373
|
-
fl = mix(0.009, 0.0035, smoothstep(0.02, 0.1, h[2]));
|
|
374
|
-
if (h[1] > 0.03 && h[2] < 0.02) fl = 0.009;
|
|
375
|
-
fl = Math.max(fl, 0.024 * (0.8 + 0.2 * ruffK) * ruffW);
|
|
376
|
-
if (r === 6) fl = mix(0.004, 0.012, smoothstep(0.08, 0.0, h[2]));
|
|
377
|
-
// the throat under the jaw runs into the long fur of the neck ruff (no step at the region seam)
|
|
378
|
-
if (r === 2) fl = mix(fl, 0.024, smoothstep(-0.05, -0.075, h[1]) * smoothstep(0.06, 0.0, h[2]));
|
|
379
|
-
// back of the head blends into the neck
|
|
380
|
-
if (r === 2 && h[2] < -0.07) {
|
|
381
|
-
const b = smoothstep(-0.07, -0.11, h[2]);
|
|
382
|
-
fl = mix(fl, 0.02, b);
|
|
383
|
-
}
|
|
384
|
-
// eye rims (black lid margins)
|
|
385
|
-
for (const e of eyePrims) {
|
|
386
|
-
const de = SDFModel.dist(e, p[0], p[1], p[2]);
|
|
387
|
-
if (Math.abs(de) < 0.0032) mark = Math.min(mark, Math.abs(de) - 0.0013);
|
|
388
|
-
if (Math.abs(de) < 0.0011) { mat = MAT.DARK_SKIN; fl = 0; }
|
|
389
|
-
else if (Math.abs(de) < 0.0032) fl = Math.min(fl, 0.001);
|
|
390
|
-
}
|
|
391
|
-
// nose leather
|
|
392
|
-
const dn = SDFModel.dist(nosePrim, p[0], p[1], p[2]);
|
|
393
|
-
if (dn < 0.0015 && h[2] > 0.138) { mat = MAT.NOSE; col = srgb(0x1a1616); fl = 0; }
|
|
394
|
-
else if (dn < 0.0035 && h[2] > 0.13) { mark = Math.min(mark, dn - 0.0022); fl = Math.min(fl, 0.0015); }
|
|
395
|
-
// lips: head vertices near the jaw surface, jaw vertices near the head surface (black lip line)
|
|
396
|
-
// (the lip line ends at the mouth corner, z ~0.025: behind it the cheek's jowl wraps the jaw's side and
|
|
397
|
-
// the line along their seam ran back under the cheek fur as a dark crease. Skin facing out (the jowl's
|
|
398
|
-
// side and underside, the jaw's outer side) is never the mouth's lining: it shows when the mouth opens,
|
|
399
|
-
// and painted as the lining it drew a dark pocket behind the mouth corner; buried in the other surface it
|
|
400
|
-
// keeps fur only as long as it stays inside it)
|
|
401
|
-
const lipZ = smoothstep(0.012, 0.03, h[2]);
|
|
402
|
-
const nOut = n[0] * Math.sign(h[0] || 1);
|
|
403
|
-
if (partOf[v] !== 2) {
|
|
404
|
-
const dj = SDFModel.evalList(jawPrims, p[0], p[1], p[2]);
|
|
405
|
-
const lining = h[2] > 0.025 ? nOut < 0.55 || n[1] > 0.3 : nOut < 0.2 && n[1] > -0.5;
|
|
406
|
-
if (dj < -0.0004 && lining) { mat = MAT.MOUTH; col = srgb(0x6e3438); fl = 0; }
|
|
407
|
-
else if (dj < -0.0004) fl = Math.min(fl, Math.max(0, -dj - 0.0015));
|
|
408
|
-
else if (dj < 0.006) { mark = Math.min(mark, mix(1, dj - 0.0018, lipZ)); fl = Math.min(fl, mix(fl, mix(0, 0.003, smoothstep(0.002, 0.006, dj)), lipZ)); }
|
|
409
|
-
} else {
|
|
410
|
-
const dh = SDFModel.evalList(headPrims, p[0], p[1], p[2]);
|
|
411
|
-
const lining = nOut < 0.45 || n[1] > 0.35;
|
|
412
|
-
if (dh < 0.0 && lining) { mat = MAT.MOUTH; col = srgb(0x6e3438); fl = 0; }
|
|
413
|
-
else if (dh < 0.0) fl = Math.min(fl, Math.max(0, -dh - 0.0015));
|
|
414
|
-
else if (dh < 0.005) { mark = Math.min(mark, mix(1, dh - 0.0015, lipZ)); fl = Math.min(fl, mix(fl, mix(0, 0.003, smoothstep(0.0015, 0.005, dh)), lipZ)); }
|
|
415
|
-
}
|
|
416
|
-
// teeth
|
|
417
|
-
for (const c of caninePrims) if (SDFModel.dist(c, p[0], p[1], p[2]) < 0.0008) { mat = MAT.KERATIN; col = srgb(0xe8e0cc); fl = 0; mark = 1; }
|
|
418
|
-
under = 0.3;
|
|
419
|
-
}
|
|
420
|
-
// kits: woolly and uniform
|
|
421
|
-
if (juv > 0 && mat === MAT.FUR) {
|
|
422
|
-
fl = mix(fl, Math.max(fl * 0.8, r === 2 || r === 6 ? 0.008 : 0.016), juv);
|
|
423
|
-
ag *= 1 - 0.8 * juv;
|
|
424
|
-
}
|
|
425
|
-
// low-frequency colour variation
|
|
426
|
-
const cvh = fbm3(p[0] * 6 + 5 + nOff, p[1] * 6, p[2] * 6, 2) - 0.5;
|
|
427
|
-
if (mat === MAT.FUR) col = [col[0] * (1 + 0.14 * nz + 0.1 * cvh + 0.06 * nz2), col[1] * (1 + 0.12 * nz + 0.06 * nz2), col[2] * (1 + 0.1 * nz - 0.08 * cvh + 0.06 * nz2)];
|
|
428
|
-
markSDF[v] = mark;
|
|
429
|
-
furLen[v] = fl;
|
|
430
|
-
tint[v * 4] = col[0]; tint[v * 4 + 1] = col[1]; tint[v * 4 + 2] = col[2]; tint[v * 4 + 3] = mat;
|
|
431
|
-
surf[v * 4 + 2] = mat === MAT.FUR ? clamp(ag * (0.85 + 0.3 * nz2), 0, 1) : 0;
|
|
432
|
-
surf[v * 4 + 3] = mat === MAT.FUR ? under : 0;
|
|
433
|
-
if (mat === MAT.KERATIN) surf[v * 4] = 0.7;
|
|
434
|
-
if (mat === MAT.NOSE) surf[v * 4] = 0.55;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// smooth fur length so the shells do not step (bare skin stays locked)
|
|
438
|
-
smoothField(furLen, weights.neighbors, 3, (v) => tint[v * 4 + 3] > 0);
|
|
439
|
-
|
|
440
|
-
void rng;
|
|
441
|
-
const pattern = new Float32Array(nV).fill(1);
|
|
442
|
-
const patternColor = new Float32Array(nV * 4);
|
|
443
|
-
return { comb, tint, pattern, mark: markSDF, furLen, patternColor, surf, region, ventral, tailT };
|
|
444
|
-
}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// Red fox (Vulpes vulpes). A small, light, long-legged canid with a narrow pointed muzzle, big black-
|
|
2
|
-
// backed ears, vertical-slit pupils, black stockings, a white bib and a huge white-tipped brush; trots
|
|
3
|
-
// in a near single-file line and hunts small prey with a high arcing "mousing" pounce.
|
|
4
|
-
// Colour morphs are variants (createAnimal('fox', { variant: 'silver' })) or come from the seed.
|
|
5
|
-
import { foxRig, HEAD_O } from './rig.js';
|
|
6
|
-
import { sculptFox, eyeOf } from './sculpt.js';
|
|
7
|
-
import { foxRegions } from './regions.js';
|
|
8
|
-
import { foxCoat, palette } from './coat.js';
|
|
9
|
-
import { motion } from './motion.js';
|
|
10
|
-
import { rng } from '../../core/math/vec.js';
|
|
11
|
-
|
|
12
|
-
// [id, name, seeded frequency]
|
|
13
|
-
const VARIANTS = [
|
|
14
|
-
['red', 'Red fox', 0.7],
|
|
15
|
-
['cross', 'Cross fox', 0.12],
|
|
16
|
-
['silver', 'Silver fox', 0.08],
|
|
17
|
-
['urban', 'Urban fox (dark winter coat)', 0.1],
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
export default {
|
|
21
|
-
id: 'fox',
|
|
22
|
-
name: 'Red fox',
|
|
23
|
-
latin: 'Vulpes vulpes',
|
|
24
|
-
group: 'paws',
|
|
25
|
-
plan: 'quadruped',
|
|
26
|
-
covering: 'fur',
|
|
27
|
-
variants: VARIANTS.map(([id, name]) => ({ id, name, latin: 'Vulpes vulpes' })),
|
|
28
|
-
|
|
29
|
-
// Seeded individual. Morph (red 70 %, cross 12 %, silver 8 %, urban 10 %, or opts.variant); dog
|
|
30
|
-
// foxes ~15-20 % heavier (+4 % withers height), broader head and muzzle, fuller ruff; vixens finer;
|
|
31
|
-
// kits (age 'juvenile', ~10-12 weeks): about half size, big domed head, short muzzle, very big ears,
|
|
32
|
-
// short legs and brush, woolly sandy coat, blue-grey eyes. Individuals vary in leg length, body
|
|
33
|
-
// length, muzzle, ears, brush, the extent of the white bib, stockings and tail tip, colour warmth.
|
|
34
|
-
variation(R, o) {
|
|
35
|
-
const sex = o.sex || (R() < 0.5 ? 'male' : 'female');
|
|
36
|
-
const age = o.age || 'adult';
|
|
37
|
-
const juv = age === 'juvenile' ? 1 : 0;
|
|
38
|
-
const male = sex === 'male';
|
|
39
|
-
const g = () => (R() + R() + R() - 1.5) / 1.5; // ~[-1, 1], peaked
|
|
40
|
-
// morph from its own hashed stream (consecutive seeds must not correlate)
|
|
41
|
-
const M = rng(Math.imul((o.seed ?? 1) + 0x3c6ef372, 0x9e3779b1) ^ 0x5be0cd19);
|
|
42
|
-
for (let i = 0; i < 3; i++) M();
|
|
43
|
-
let variant = o.variant && VARIANTS.some((v) => v[0] === o.variant) ? o.variant : null;
|
|
44
|
-
if (!variant) {
|
|
45
|
-
let x = M();
|
|
46
|
-
variant = 'red';
|
|
47
|
-
for (const [id, , p] of VARIANTS) { if (x < p) { variant = id; break; } x -= p; }
|
|
48
|
-
} else M();
|
|
49
|
-
const size = (male ? 1.04 : 0.96) * (1 + 0.04 * g()) * (juv ? 0.55 : 1);
|
|
50
|
-
const legs = 1 + 0.03 * g() - 0.1 * juv;
|
|
51
|
-
const head = (male ? 1.03 : 0.98) * (1 + 0.02 * g());
|
|
52
|
-
const coatSeed = Math.floor(R() * 1e6);
|
|
53
|
-
// (every draw is made whatever the morph, so that a morph never changes the individual: the silver
|
|
54
|
-
// fox's stockings ignore theirs)
|
|
55
|
-
const morphed = (v, x) => (variant === 'silver' ? v : x);
|
|
56
|
-
return {
|
|
57
|
-
sex, age, size, variant, juv,
|
|
58
|
-
muzzle: (male ? 1.02 : 0.99) * (1 + 0.04 * g()) * (juv ? 0.7 : 1),
|
|
59
|
-
headW: (male ? 1.05 : 0.98) * (1 + 0.025 * g()) * (juv ? 1.06 : 1),
|
|
60
|
-
ear: (1 + 0.05 * g()) * (juv ? 1.12 : 1),
|
|
61
|
-
eyeK: juv ? 1.18 : 1,
|
|
62
|
-
tail: (1 + 0.05 * g()) * (juv ? 0.72 : 1),
|
|
63
|
-
tailBrush: (1 + 0.07 * g()) * (juv ? 0.75 : 1),
|
|
64
|
-
ruff: (male ? 1.1 : 0.9) + 0.12 * g() - 0.2 * juv,
|
|
65
|
-
slim: (male ? 1.04 : 0.97) * (1 + 0.03 * g()) * (juv ? 1.08 : 1),
|
|
66
|
-
boneK: juv ? 1.12 : 1,
|
|
67
|
-
pawK: juv ? 1.15 : 1,
|
|
68
|
-
bib: 1 + 0.25 * g(),
|
|
69
|
-
stockings: morphed(1, Math.max(0.2, 1 + 0.45 * g())),
|
|
70
|
-
tailTip: M() < 0.08 && variant === 'red' ? 0 : 0.75 + 0.5 * M(), // 70-90 % of foxes have a white tip
|
|
71
|
-
tear: 0.7 + 0.5 * M(),
|
|
72
|
-
coatWarmth: 1.3 * g(),
|
|
73
|
-
coatLightness: 0.16 * g(),
|
|
74
|
-
coatSeed,
|
|
75
|
-
minThick: 0.0022,
|
|
76
|
-
warps: [
|
|
77
|
-
{ type: 'legs', k: legs, top: 0.25 },
|
|
78
|
-
{ type: 'length', k: 1 + 0.03 * g() - 0.05 * juv, z0: -0.19, z1: 0.24 },
|
|
79
|
-
{ type: 'scaleAbout', c: HEAD_O, k: head * (juv ? 1.3 : 1), r0: 0.05, r1: 0.12 },
|
|
80
|
-
// big kit paws
|
|
81
|
-
...(juv ? [[0.028, 0.2], [-0.028, 0.2], [0.033, -0.2], [-0.033, -0.2]].map(([x, z]) => ({ type: 'scaleAbout', c: [x, 0.015, z], k: 1.18, r0: 0.018, r1: 0.04 })) : []),
|
|
82
|
-
],
|
|
83
|
-
};
|
|
84
|
-
},
|
|
85
|
-
rig: (params) => foxRig(params),
|
|
86
|
-
sculpt: (m, rig, params) => sculptFox(m, rig, params),
|
|
87
|
-
regions: foxRegions,
|
|
88
|
-
coat: foxCoat,
|
|
89
|
-
eyeSpecs: (params) => {
|
|
90
|
-
const look = eyeLookOf(params);
|
|
91
|
-
return [1, -1].map((side) => ({ side, spec: eyeOf(params), headOrigin: HEAD_O, bone: 'head', look }));
|
|
92
|
-
},
|
|
93
|
-
motion,
|
|
94
|
-
render: {
|
|
95
|
-
markColor: [0.012, 0.01, 0.009],
|
|
96
|
-
strandDensity: 1400,
|
|
97
|
-
clumpDensity: 0.9,
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
// Vertical slit pupil (elliptical in bright light, dilating to round in the dark), amber to yellow-
|
|
102
|
-
// orange iris (#c8943c with a darker ring #7a4a1c), no visible sclera, black lid margins.
|
|
103
|
-
export const EYE_LOOK = {
|
|
104
|
-
pupil: 'slit',
|
|
105
|
-
lids: 'mammal',
|
|
106
|
-
iris: { inner: [0.5, 0.26, 0.04], mid: [0.62, 0.32, 0.06], hi: [0.8, 0.5, 0.14], outer: [0.19, 0.065, 0.012] },
|
|
107
|
-
sclera: { color: [0.2, 0.15, 0.11], visible: false },
|
|
108
|
-
lidColor: [0.45, 0.14, 0.035], // (per individual: eyeLookOf)
|
|
109
|
-
pupilSize: [0.12, 0.75],
|
|
110
|
-
};
|
|
111
|
-
// kits: blue-grey eyes (turn amber at ~4-5 months)
|
|
112
|
-
export const KIT_EYE = {
|
|
113
|
-
...EYE_LOOK,
|
|
114
|
-
iris: { inner: [0.1, 0.13, 0.17], mid: [0.2, 0.25, 0.32], hi: [0.36, 0.42, 0.5], outer: [0.06, 0.07, 0.09] },
|
|
115
|
-
};
|
|
116
|
-
// the lids are furred in the individual's face colour (the shader darkens the margin itself), so a
|
|
117
|
-
// blink, the curled sleep and death show a closed, furred lid with a dark line, not a black bead
|
|
118
|
-
function eyeLookOf(params) {
|
|
119
|
-
return { ...(params.juv ? KIT_EYE : EYE_LOOK), lidColor: palette(params).lid };
|
|
120
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
// Red fox motion data for the quadruped engine (schema: src/core/motion/quadruped.js).
|
|
2
|
-
// Numbers are for the reference individual (params.size = 1, withers 0.40 m, ~6 kg); the engine scales
|
|
3
|
-
// them by dynamic similarity for kits and big dog foxes.
|
|
4
|
-
//
|
|
5
|
-
// Gaits (Elbroch 2003, Heglund & Taylor 1988, Alexander & Jayes 1983): the trot
|
|
6
|
-
// is the fox's travelling gait. Lateral-sequence walk (0.4-1.0 m/s, 1.2-1.8 Hz, duty 0.60-0.70) used
|
|
7
|
-
// when hunting and investigating; trot (1.0-3.0 m/s, typically ~2 m/s, 2.4-3.2 Hz, duty 0.38-0.48,
|
|
8
|
-
// hind of each diagonal ~3 % first) in a near single-file line (trail straddle ~7.5 cm: `width`
|
|
9
|
-
// narrows the stance per row); transverse lope (3-6 m/s, right lead, 3.0-3.5 Hz); rotary gallop
|
|
10
|
-
// (LH-RH-RF-LF, 3.5-4.2 Hz, duty 0.20-0.28) with strong spinal flexion up to ~13 m/s (48 km/h).
|
|
11
|
-
// Trot -> gallop 1.53 M^0.24 = 2.4 m/s by scaling; foxes hold the trot to ~3 m/s.
|
|
12
|
-
import { foxHooks } from './behaviour.js';
|
|
13
|
-
|
|
14
|
-
const G = (name, v, f, D, off, o) => ({ name, v, f, D, off, ...o });
|
|
15
|
-
|
|
16
|
-
export const motion = {
|
|
17
|
-
// fox behaviour: mousing pounce, listening (ear swivels, head tilt), tail as a counterweight,
|
|
18
|
-
// curled sleep with the brush over the nose, the upright sit with the tail round the forefeet
|
|
19
|
-
hooks: foxHooks,
|
|
20
|
-
maxSpeed: 13,
|
|
21
|
-
accel: [5, 9],
|
|
22
|
-
decel: 9,
|
|
23
|
-
turnRate: 2.8,
|
|
24
|
-
latAccelMax: 11,
|
|
25
|
-
gears: { walk: 0.8, trot: 2.0, canter: 3.6, gallop: 8 },
|
|
26
|
-
gallopBlend: [3.4, 6.5],
|
|
27
|
-
gaits: [
|
|
28
|
-
G('walk', 0.0, 1.1, 0.72, [0.25, 0.75, 0.0, 0.5], { liftF: 0.032, liftH: 0.027, bobF: 0.003, bobH: 0.003, flex: 0.0, lat: 0.05, fold: 1.0, heel: 35, tail: 0, drop: 0.0, width: 0.85 }),
|
|
29
|
-
G('walk', 0.85, 1.55, 0.63, [0.25, 0.75, 0.0, 0.5], { liftF: 0.04, liftH: 0.032, bobF: 0.005, bobH: 0.005, flex: 0.0, lat: 0.05, fold: 1.2, heel: 42, tail: 0.12, drop: 0.0, width: 0.7 }),
|
|
30
|
-
G('trot', 1.2, 2.45, 0.47, [0.53, 0.03, 0.0, 0.5], { liftF: 0.053, liftH: 0.045, bobF: 0.009, bobH: 0.009, flex: 0.02, lat: 0.015, fold: 1.45, heel: 50, tail: 0.3, drop: 0.003, width: 0.5 }),
|
|
31
|
-
G('trot', 2.8, 2.95, 0.39, [0.53, 0.03, 0.0, 0.5], { liftF: 0.064, liftH: 0.054, bobF: 0.012, bobH: 0.012, flex: 0.03, lat: 0.01, fold: 1.6, heel: 58, tail: 0.4, drop: 0.006, width: 0.48 }),
|
|
32
|
-
G('canter', 3.6, 3.1, 0.35, [0.3, 0.45, 0.0, 0.3], { liftF: 0.085, liftH: 0.075, bobF: 0.012, bobH: 0.018, flex: 0.2, lat: 0, fold: 1.8, heel: 62, tail: 0.6, drop: 0.01, width: 0.75 }),
|
|
33
|
-
G('gallop', 6, 3.55, 0.27, [0.52, 0.42, 0.0, 0.1], { liftF: 0.105, liftH: 0.095, bobF: 0.016, bobH: 0.024, flex: 0.34, lat: 0, fold: 1.9, heel: 68, tail: 0.8, drop: 0.016, width: 1 }),
|
|
34
|
-
G('gallop', 12, 4.1, 0.21, [0.52, 0.42, 0.0, 0.1], { liftF: 0.125, liftH: 0.115, bobF: 0.016, bobH: 0.026, flex: 0.44, lat: 0, fold: 2.0, heel: 72, tail: 0.9, drop: 0.026, width: 1 }),
|
|
35
|
-
],
|
|
36
|
-
feet: {
|
|
37
|
-
front: { type: 'digitigrade', curl: 55 },
|
|
38
|
-
hind: { type: 'digitigrade', curl: 65 },
|
|
39
|
-
},
|
|
40
|
-
stance: { width: 1, gallopWidth: 0.6, sprawl: 0, crouch: 0, scuff: [11, 18, 0] },
|
|
41
|
-
// torso cross-sections (bind, reference size): centre height, half height, half width (incl. coat)
|
|
42
|
-
body: {
|
|
43
|
-
chest: { y: 0.305, hh: 0.112, hw: 0.068 },
|
|
44
|
-
pelvis: { y: 0.31, hh: 0.11, hw: 0.076 }, // incl. the folded thighs a lying fox rests on
|
|
45
|
-
back: 0.036,
|
|
46
|
-
},
|
|
47
|
-
head: {
|
|
48
|
-
// [speed, raise (m), reach (m), pitch (rad, + = nose down)]: standing, the head is held up at or
|
|
49
|
-
// above the withers, muzzle near level; the trot lowers it toward the back line with the muzzle
|
|
50
|
-
// pointing down and ahead; the gallop stretches it forward
|
|
51
|
-
carriage: [[0, 0.09, -0.02, -0.02], [0.8, -0.008, 0.01, 0.16], [2.0, -0.045, 0.026, 0.3], [4.2, -0.04, 0.032, 0.25], [8, -0.037, 0.043, 0.18]],
|
|
52
|
-
stab: [[0, 0], [0.7, 0.22], [1.5, 0.3], [4, 0.34], [8, 0.6]],
|
|
53
|
-
neckBend: 42, neckPivot: 0.6, yaw: 1.3, pitchUp: 0.6, pitchDown: 0.75,
|
|
54
|
-
},
|
|
55
|
-
tail: {
|
|
56
|
-
// [speed, pitch per segment from horizontal (deg), base -> tip]: at rest a shallow downward curve
|
|
57
|
-
// with the tip just off the ground; held level with a slight droop in the trot (the brush floats
|
|
58
|
-
// behind, never curled over the back); straight out behind as a counterweight in the gallop
|
|
59
|
-
carriage: [
|
|
60
|
-
[0.0, [-24, -32, -38, -41, -43, -43, -42, -40, -37, -33]],
|
|
61
|
-
[0.8, [-14, -20, -24, -27, -28, -28, -27, -25, -22, -19]],
|
|
62
|
-
[2.0, [-8, -10, -12, -13, -13, -12, -11, -9, -7, -5]],
|
|
63
|
-
[4.2, [-5, -7, -7, -7, -6, -5, -4, -3, -2, -1]],
|
|
64
|
-
[8, [-3, -4, -4, -3, -2, -1, 0, 1, 1, 2]],
|
|
65
|
-
],
|
|
66
|
-
stiffness: 0.85, sway: 6, flick: 0, wag: 0, swish: 0, curl: 0,
|
|
67
|
-
balance: 0.65, // the brush is a counterweight and rudder in turns and speed changes
|
|
68
|
-
radius: [0.05, 0.052], // (the brush: coat included)
|
|
69
|
-
},
|
|
70
|
-
ears: { rest: [0, 0], mobility: 1.2, speedFlatten: 0.5, twitch: 1.2, prick: 0.5 },
|
|
71
|
-
breath: { rate: 0.35, amp: 0.012, pant: true, pantRate: 4.0, pantAmp: 0.05, heatSpeed: 5 },
|
|
72
|
-
actions: {
|
|
73
|
-
attack: { style: 'pounce' }, // (the mousing pounce is a species action, behaviour.js)
|
|
74
|
-
eat: { style: 'tear', dropF: 0.3, dropH: 0.1, ahead: 0.75 },
|
|
75
|
-
drink: { dropF: 0.34, dropH: 0.12, ahead: 0.75 },
|
|
76
|
-
jump: { height: 0.6, distance: 2.0 },
|
|
77
|
-
sit: { dropH: 0.9 },
|
|
78
|
-
lie: {},
|
|
79
|
-
sleep: { style: 'curl' },
|
|
80
|
-
},
|
|
81
|
-
};
|