@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,118 +0,0 @@
|
|
|
1
|
-
// Spider skeleton in bind pose (metres; dimensions below are written in millimetres).
|
|
2
|
-
// Forward = +Z, up = +Y, the animal's left = +X. Two variants share the rig: the wolf spider
|
|
3
|
-
// (Lycosidae, reference female Hogna carolinensis, body 25 mm) and the tarantula (Theraphosidae,
|
|
4
|
-
// reference female Brachypelma hamorii, body 60 mm).
|
|
5
|
-
import { buildRig } from '../../core/rig/rig.js';
|
|
6
|
-
import { spiderBones, spiderLimbs, planarChain, solveBindElevations, legJoints, palpJoints, AXIAL_POINTS, AXIAL_BONES } from '../../core/rig/spider.js';
|
|
7
|
-
|
|
8
|
-
const D2R = Math.PI / 180;
|
|
9
|
-
const mm = (v) => v.map((x) => x * 0.001);
|
|
10
|
-
|
|
11
|
-
// Per-variant anatomy (mm, degrees). leg: [I, II, III, IV] total lengths; seg: segment fractions
|
|
12
|
-
// coxa, trochanter, femur, patella, tibia, metatarsus, tarsus; el: bind elevations of the segments
|
|
13
|
-
// (the metatarsus is solved so the claw rests on the ground); r: segment radii (base, end).
|
|
14
|
-
export const VARIANTS = {
|
|
15
|
-
wolf: {
|
|
16
|
-
unit: 0.013,
|
|
17
|
-
bodyLen: 25,
|
|
18
|
-
axial: { front: [0, 7.4, 6.5], ceph: [0, 7.6, 1.6], pedA: [0, 6.3, -4.5], pedB: [0, 6.1, -5.7], abdEnd: [0, 5.4, -17.2], spinTip: [0, 4.7, -18.5] },
|
|
19
|
-
carapace: { len: 11, wid: 8.6, top: 9.9, rearTop: 7.3, bottom: 4.5, headW: 5.2 },
|
|
20
|
-
abdomen: { c: [0, 6.5, -11.4], r: [3.9, 3.35, 6.1] },
|
|
21
|
-
chel: { base: [0.95, 7.0, 6.1], tip: [0.9, 3.8, 7.0], fang: [0.15, 4.25, 6.75], r: [0.95, 0.72], fangR: 0.2 },
|
|
22
|
-
coxa: { y: 5.1, x: [2.35, 2.75, 2.75, 2.45], z: [3.3, 1.4, -0.6, -2.6], az: [30, 66, 112, 150] },
|
|
23
|
-
leg: [35, 33, 31, 43],
|
|
24
|
-
seg: [0.08, 0.05, 0.26, 0.12, 0.2, 0.19, 0.1],
|
|
25
|
-
el: [-14, 4, 30, -6, -28, 0, -14],
|
|
26
|
-
legR: [[1.05, 0.95], [0.84, 0.8], [0.8, 0.68], [0.7, 0.63], [0.63, 0.53], [0.5, 0.4], [0.39, 0.29]],
|
|
27
|
-
hindR: 1.06,
|
|
28
|
-
tipY: 0.32,
|
|
29
|
-
palp: { base: [1.75, 5.2, 5.4], az: 14, len: 16, seg: [0.12, 0.08, 0.3, 0.15, 0.18, 0.17], el: [-30, -10, 15, -30, 0, -50], r: [[0.62, 0.55], [0.5, 0.48], [0.46, 0.42], [0.42, 0.4], [0.4, 0.37], [0.37, 0.28]], tipY: 0.55 },
|
|
30
|
-
spinR: 0.45,
|
|
31
|
-
},
|
|
32
|
-
tarantula: {
|
|
33
|
-
unit: 0.028,
|
|
34
|
-
bodyLen: 60,
|
|
35
|
-
axial: { front: [0, 13.2, 12.8], ceph: [0, 14.2, 3.5], pedA: [0, 12.0, -11.6], pedB: [0, 11.8, -13.6], abdEnd: [0, 10.8, -41.5], spinTip: [0, 9.2, -46] },
|
|
36
|
-
carapace: { len: 25, wid: 23.5, top: 16.2, rearTop: 14.0, bottom: 7.4, headW: 13 },
|
|
37
|
-
abdomen: { c: [0, 12.4, -27.6], r: [12.0, 9.6, 14.4] },
|
|
38
|
-
chel: { base: [3.0, 12.6, 11.2], tip: [2.9, 9.4, 18.0], fang: [2.6, 4.9, 16.4], r: [3.1, 2.4], fangR: 0.75 },
|
|
39
|
-
coxa: { y: 8.6, x: [5.8, 6.7, 6.7, 6.0], z: [6.2, 2.0, -2.6, -7.0], az: [26, 60, 114, 150] },
|
|
40
|
-
leg: [65, 60, 55, 72.5],
|
|
41
|
-
seg: [0.09, 0.06, 0.25, 0.14, 0.2, 0.16, 0.1],
|
|
42
|
-
el: [-10, 6, 34, -4, -30, 0, -13],
|
|
43
|
-
legR: [[3.0, 2.7], [2.4, 2.3], [2.3, 2.0], [2.05, 1.95], [1.95, 1.75], [1.65, 1.45], [1.45, 1.25]],
|
|
44
|
-
hindR: 1.04,
|
|
45
|
-
tipY: 1.3,
|
|
46
|
-
palp: { base: [4.6, 8.4, 10.8], az: 16, len: 37, seg: [0.14, 0.08, 0.28, 0.16, 0.18, 0.16], el: [-30, -10, 15, -30, 0, -40], r: [[2.2, 2.0], [1.9, 1.8], [1.8, 1.65], [1.65, 1.55], [1.55, 1.45], [1.45, 1.2]], tipY: 1.3 },
|
|
47
|
-
spinR: 1.3,
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// Anatomy of one individual: the variant's reference numbers with the seeded proportions of
|
|
52
|
-
// params (legK: leg length factor, abdK: abdomen size, palpBulb: male palpal bulbs).
|
|
53
|
-
export function spiderDims(params = {}) {
|
|
54
|
-
const V = VARIANTS[params.variant] || VARIANTS.wolf;
|
|
55
|
-
const legK = params.legK || 1, abdK = params.abdK || 1;
|
|
56
|
-
const d = JSON.parse(JSON.stringify(V));
|
|
57
|
-
d.variant = VARIANTS[params.variant] ? params.variant : 'wolf';
|
|
58
|
-
d.leg = V.leg.map((l) => l * legK);
|
|
59
|
-
d.palp.len = V.palp.len * (0.5 + 0.5 * legK);
|
|
60
|
-
d.abdomen.r = V.abdomen.r.map((r) => r * abdK);
|
|
61
|
-
// a bigger abdomen hangs further back from the pedicel
|
|
62
|
-
d.abdomen.c = [0, V.abdomen.c[1] + (abdK - 1) * 0.4 * V.abdomen.r[1], V.abdomen.c[2] - (abdK - 1) * V.abdomen.r[2]];
|
|
63
|
-
d.axial.abdEnd = [0, V.axial.abdEnd[1] - (abdK - 1) * 0.3 * V.abdomen.r[1], V.axial.abdEnd[2] - 2 * (abdK - 1) * V.abdomen.r[2]];
|
|
64
|
-
d.axial.spinTip = [0, V.axial.spinTip[1] - (abdK - 1) * 0.3 * V.abdomen.r[1], V.axial.spinTip[2] - 2 * (abdK - 1) * V.abdomen.r[2]];
|
|
65
|
-
d.palpBulb = params.palpBulb || 0;
|
|
66
|
-
return d;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function spiderJoints(params = {}) {
|
|
70
|
-
const d = spiderDims(params);
|
|
71
|
-
const J = {};
|
|
72
|
-
for (const [k, v] of Object.entries(d.axial)) J[k] = mm(v);
|
|
73
|
-
J.cheBaseL = mm(d.chel.base);
|
|
74
|
-
J.cheTipL = mm(d.chel.tip);
|
|
75
|
-
J.fangTipL = mm(d.chel.fang);
|
|
76
|
-
for (let i = 1; i <= 4; i++) {
|
|
77
|
-
const L = d.leg[i - 1];
|
|
78
|
-
const lens = d.seg.map((f) => f * L * 0.001);
|
|
79
|
-
const base = mm([d.coxa.x[i - 1], d.coxa.y, d.coxa.z[i - 1]]);
|
|
80
|
-
const el = solveBindElevations(base[1], lens, d.el.map((e) => e * D2R), 5, d.tipY * 0.001);
|
|
81
|
-
planarChain(J, legJoints(i, 'L'), base, d.coxa.az[i - 1] * D2R, el, lens, 1);
|
|
82
|
-
}
|
|
83
|
-
{
|
|
84
|
-
const P = d.palp;
|
|
85
|
-
const lens = P.seg.map((f) => f * P.len * 0.001);
|
|
86
|
-
const base = mm(P.base);
|
|
87
|
-
// the tibia takes up the height so the tarsus meets the ground slanting forward
|
|
88
|
-
const el = solveBindElevations(base[1], lens, P.el.map((e) => e * D2R), 4, P.tipY * 0.001);
|
|
89
|
-
planarChain(J, palpJoints('L'), base, P.az * D2R, el, lens, 1);
|
|
90
|
-
}
|
|
91
|
-
return J;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function spiderRig(params = {}) {
|
|
95
|
-
const d = spiderDims(params);
|
|
96
|
-
const J = spiderJoints(params);
|
|
97
|
-
const U = d.unit;
|
|
98
|
-
return buildRig({
|
|
99
|
-
joints: J,
|
|
100
|
-
unit: U,
|
|
101
|
-
headOrigin: J.ceph,
|
|
102
|
-
meta: { dims: d },
|
|
103
|
-
bones: spiderBones(),
|
|
104
|
-
axial: {
|
|
105
|
-
points: AXIAL_POINTS,
|
|
106
|
-
bones: AXIAL_BONES,
|
|
107
|
-
// the carapace is rigid: head and prosoma share it (the engine never bends them apart); the
|
|
108
|
-
// pedicel is a short stalk, blended narrowly into the abdomen
|
|
109
|
-
blend: { 1: [-0.1, 0.1], 2: [-0.012, 0.004], 3: [-0.004, 0.02] },
|
|
110
|
-
},
|
|
111
|
-
limbs: spiderLimbs({
|
|
112
|
-
leg: { tCore: 0.5, aCore: 0.05, aBody: -0.05, midX: 0.06 },
|
|
113
|
-
palp: { tCore: 0.45, aCore: 0.04, aBody: -0.05, midX: 0.04 },
|
|
114
|
-
}),
|
|
115
|
-
appendages: [],
|
|
116
|
-
webTags: [],
|
|
117
|
-
});
|
|
118
|
-
}
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
// The spider, sculpted as a signed distance field (reference space, metres).
|
|
2
|
-
//
|
|
3
|
-
// Parts (meshed separately, see regions.js): 'body' (prosoma, pedicel, abdomen, spinnerets, palps,
|
|
4
|
-
// coxae and trochanters), one part per leg ('legL1' .. 'legR4': coxa -> tarsus, the coxa and
|
|
5
|
-
// trochanter duplicated so both surfaces agree across the cut), 'chelL'/'chelR' (rigid chelicerae)
|
|
6
|
-
// and 'fangL'/'fangR' (rigid fangs). Eyes are glossy domes (look.lids 'simple') set in shallow
|
|
7
|
-
// sockets on the head.
|
|
8
|
-
import { spiderDims } from './rig.js';
|
|
9
|
-
import { legJoints, legBones, palpJoints, palpBones } from '../../core/rig/spider.js';
|
|
10
|
-
import { add, sub, mul, lerp, norm, cross, len } from '../../core/math/vec.js';
|
|
11
|
-
import { eyeFrameOf } from '../../core/sdf/eyeSocket.js';
|
|
12
|
-
import { QUALITY } from '../../core/build/pipeline.js';
|
|
13
|
-
|
|
14
|
-
const M = 0.001;
|
|
15
|
-
const mm = (v) => v.map((x) => x * M);
|
|
16
|
-
|
|
17
|
-
// Eyes per variant (mm, head-local: relative to the ceph joint; left side). r: radius; yaw: outward
|
|
18
|
-
// divergence of the view axis (rad, > PI/2 looks backward); pitch: upward tilt; back: how far the
|
|
19
|
-
// dome centre sits inside the surface point.
|
|
20
|
-
export const EYES = {
|
|
21
|
-
// Lycosidae 4-2-2: a straight anterior row of 4 small eyes above the chelicerae, 2 huge posterior
|
|
22
|
-
// median eyes looking forward, 2 posterior lateral eyes on top looking up and back
|
|
23
|
-
wolf: [
|
|
24
|
-
// (set into the carapace surface: the domes bulge ~0.4 r; the PME sit on the front of the face)
|
|
25
|
-
{ name: 'PME', c: [1.02, 1.2, 4.57], r: 0.47, yaw: 0.14, pitch: 0.02, back: 0.2 },
|
|
26
|
-
{ name: 'PLE', c: [1.78, 1.54, 2.72], r: 0.3, yaw: 2.1, pitch: 0.75, back: 0.14 },
|
|
27
|
-
{ name: 'AME', c: [0.42, 0.3, 5.26], r: 0.22, yaw: 0.05, pitch: -0.05, back: 0.07 },
|
|
28
|
-
{ name: 'ALE', c: [1.0, 0.3, 5.05], r: 0.17, yaw: 0.55, pitch: -0.05, back: 0.05 },
|
|
29
|
-
],
|
|
30
|
-
// Theraphosidae: 8 small eyes clustered on a raised ocular tubercle
|
|
31
|
-
tarantula: [
|
|
32
|
-
{ name: 'AME', c: [0.62, 2.55, 6.1], r: 0.5, yaw: 0.08, pitch: 0.5, back: 0.2 },
|
|
33
|
-
{ name: 'ALE', c: [1.62, 2.05, 6.25], r: 0.52, yaw: 0.6, pitch: 0.25, back: 0.2 },
|
|
34
|
-
{ name: 'PME', c: [0.85, 2.6, 5.05], r: 0.3, yaw: 0.5, pitch: 1.0, back: 0.12 },
|
|
35
|
-
{ name: 'PLE', c: [1.72, 2.2, 4.75], r: 0.42, yaw: 1.7, pitch: 0.45, back: 0.16 },
|
|
36
|
-
],
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export function eyeSpec(e) {
|
|
40
|
-
const r = e.r * M;
|
|
41
|
-
return { c: mm(e.c), r, back: e.back * M, yaw: e.yaw, pitch: e.pitch, tilt: 0, lid: 0, R: r * 1.1, d: r * 0.6, off: 0, irisZ: r * 0.6, irisR: r * 0.8, name: e.name };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// minimum radius of thin parts per quality tier (coarse meshes would lose the tarsi otherwise)
|
|
45
|
-
const MIN_R = { hero: 0, high: 0, medium: 0.26, low: 0.4, crowd: 0.58 }; // ~ one cell: legs stay >= 2 voxels thick
|
|
46
|
-
|
|
47
|
-
export function sculptSpider(m, rig, params) {
|
|
48
|
-
const J = rig.J, d = spiderDims(params);
|
|
49
|
-
const F = d.unit / 0.013; // size relative to the wolf spider
|
|
50
|
-
const minR = (MIN_R[params.quality] ?? 0) * M * F;
|
|
51
|
-
const R = (r) => Math.max(r * M, minR);
|
|
52
|
-
const HO = J.ceph;
|
|
53
|
-
const hl = (v) => add(HO, mm(v));
|
|
54
|
-
const X = [1, 0, 0];
|
|
55
|
-
const ellY = (o) => {
|
|
56
|
-
const y = norm(o.ydir);
|
|
57
|
-
const z = norm(cross(o.lateral || X, y));
|
|
58
|
-
return m.ell({ ...o, axis: z, up: y });
|
|
59
|
-
};
|
|
60
|
-
const wolf = d.variant === 'wolf';
|
|
61
|
-
const C = d.carapace;
|
|
62
|
-
const z0 = J.pedA[2] / M, z1 = J.front[2] / M, Lc = z1 - z0;
|
|
63
|
-
const B = { bone: 'prosoma', group: 'axial', part: 'body' };
|
|
64
|
-
const H = { bone: 'head', group: 'axial', part: 'body' };
|
|
65
|
-
|
|
66
|
-
// ------------------------------------------------------------------ PROSOMA
|
|
67
|
-
// carapace: thoracic dome, raised cephalic region, sloping rear; sternum below
|
|
68
|
-
const thTop = C.rearTop + (C.top - C.rearTop) * (wolf ? 0.55 : 0.75);
|
|
69
|
-
m.ell({ ...B, tag: 'thorax', c: mm([0, (thTop + C.bottom) / 2, z0 + 0.42 * Lc]), r: mm([C.wid / 2, (thTop - C.bottom) / 2, 0.41 * Lc]), k: 0 });
|
|
70
|
-
m.ell({ ...B, tag: 'thoraxRear', c: mm([0, (C.rearTop + C.bottom) / 2 + 0.2 * F, z0 + 0.2 * Lc]), r: mm([C.wid * 0.36, (C.rearTop - C.bottom) / 2, 0.2 * Lc]), k: 0.9 * M * F });
|
|
71
|
-
m.ell({ ...H, tag: 'cephalic', c: mm([0, C.top - (wolf ? 2.3 : 3.2) * F, z0 + 0.78 * Lc]), r: mm([C.headW / 2, (wolf ? 2.3 : 3.2) * F, 0.26 * Lc]), axis: norm([0, wolf ? 0.18 : 0.05, 1]), k: 1.2 * M * F });
|
|
72
|
-
// clypeus: the face between the anterior eyes and the chelicerae
|
|
73
|
-
m.ell({ ...H, tag: 'clypeus', c: add(J.front, mm([0, -0.2 * F, -0.9 * F])), r: mm([C.headW * 0.36, 1.1 * F, 0.9 * F]), k: 0.8 * M * F });
|
|
74
|
-
m.ell({ ...B, tag: 'sternum', c: mm([0, C.bottom + 0.45 * F, z0 + 0.5 * Lc]), r: mm([C.wid * 0.27, 0.7 * F, 0.3 * Lc]), k: 0.8 * M * F });
|
|
75
|
-
// labium and endites (mouthparts between the palp coxae)
|
|
76
|
-
m.ell({ ...B, tag: 'labium', c: mm([0, C.bottom + 0.6 * F, z0 + 0.86 * Lc]), r: mm([0.9 * F, 0.55 * F, 0.9 * F]), k: 0.5 * M * F });
|
|
77
|
-
// fovea: a short median groove on the thoracic dome, and the cephalic groove
|
|
78
|
-
m.ell({ ...B, tag: 'fovea', c: mm([0, thTop + 0.02 * F, z0 + 0.36 * Lc]), r: mm([0.16 * F, 0.3 * F, 0.9 * F]), k: 0.25 * M * F, carve: true });
|
|
79
|
-
if (!wolf) {
|
|
80
|
-
// tarantula: low wide carapace with a raised ocular tubercle
|
|
81
|
-
m.ell({ ...H, tag: 'tubercle', c: hl([0, 1.7, 5.4]), r: mm([2.3, 1.3, 1.9]), k: 1.1 * M * F });
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// ------------------------------------------------------------------ EYES (sockets; the domes are eye meshes)
|
|
85
|
-
for (const e of EYES[d.variant]) {
|
|
86
|
-
const E = eyeSpec(e);
|
|
87
|
-
for (const s of [1, -1]) {
|
|
88
|
-
const ef = eyeFrameOf(E, HO, s);
|
|
89
|
-
// a raised rim around the lens, cut open by the socket the dome sits in
|
|
90
|
-
m.sphere({ ...H, tag: 'eyerim', c: add(ef.c, mul(ef.z, -E.r * 0.25)), rad: E.r * 1.05, k: E.r * 0.6 });
|
|
91
|
-
m.sphere({ ...H, tag: 'eyesocket', c: add(ef.c, mul(ef.z, E.r * 0.1)), rad: E.r * 0.98, k: E.r * 0.15, carve: true });
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// ------------------------------------------------------------------ PEDICEL, ABDOMEN, SPINNERETS
|
|
96
|
-
const A = { bone: 'abdomen', group: 'axial', part: 'body' };
|
|
97
|
-
m.cone({ bone: 'pedicel', group: 'axial', part: 'body', tag: 'pedicel', a: J.pedA, b: J.pedB, ra: (wolf ? 0.75 : 1.9) * M * F / F * (wolf ? 1 : 1), rb: (wolf ? 0.7 : 1.8) * M, k: 0.3 * M * F });
|
|
98
|
-
const ac = mm(d.abdomen.c), ar = mm(d.abdomen.r);
|
|
99
|
-
m.ell({ ...A, tag: 'abdomen', c: ac, r: ar, axis: norm([0, 0.06, 1]), k: 0 });
|
|
100
|
-
m.ell({ ...A, tag: 'abdomenFront', c: add(ac, [0, -ar[1] * 0.05, ar[2] * 0.52]), r: [ar[0] * 0.7, ar[1] * 0.72, ar[2] * 0.45], k: 1.0 * M * F });
|
|
101
|
-
m.ell({ ...A, tag: 'abdomenRear', c: add(ac, [0, -ar[1] * 0.12, -ar[2] * 0.6]), r: [ar[0] * 0.72, ar[1] * 0.72, ar[2] * 0.42], k: 1.2 * M * F });
|
|
102
|
-
// spinnerets: wolf 3 short pairs; tarantula 2 visible pairs, the posterior pair long and finger-like
|
|
103
|
-
const SP = { bone: 'spinnerets', group: 'axial', part: 'body', tag: 'spinneret' };
|
|
104
|
-
const st = J.abdEnd, sd = norm(sub(J.spinTip, J.abdEnd)), sl = len(sub(J.spinTip, J.abdEnd));
|
|
105
|
-
for (const s of [1, -1]) {
|
|
106
|
-
if (wolf) {
|
|
107
|
-
m.cone({ ...SP, a: add(st, mm([0.45 * s, -0.25, 0.3])), b: add(add(st, mul(sd, sl * 0.9)), mm([0.5 * s, -0.2, 0])), ra: d.spinR * M, rb: d.spinR * 0.7 * M, k: 0.25 * M });
|
|
108
|
-
m.cone({ ...SP, a: add(st, mm([0.2 * s, -0.6, 0.3])), b: add(add(st, mul(sd, sl * 0.7)), mm([0.2 * s, -0.55, 0])), ra: d.spinR * 0.8 * M, rb: d.spinR * 0.55 * M, k: 0.25 * M });
|
|
109
|
-
} else {
|
|
110
|
-
m.cone({ ...SP, a: add(st, mm([1.1 * s, -0.4, 0.8])), b: add(add(st, mul(sd, sl * 1.15)), mm([1.9 * s, 0.9, 0])), ra: d.spinR * M, rb: d.spinR * 0.62 * M, k: 0.8 * M });
|
|
111
|
-
m.cone({ ...SP, a: add(st, mm([0.55 * s, -1.2, 0.8])), b: add(add(st, mul(sd, sl * 0.45)), mm([0.6 * s, -1.4, 0])), ra: d.spinR * 0.6 * M, rb: d.spinR * 0.45 * M, k: 0.6 * M });
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// ------------------------------------------------------------------ CHELICERAE AND FANGS (rigid parts)
|
|
116
|
-
for (const S of ['L', 'R']) {
|
|
117
|
-
const s = S === 'L' ? 1 : -1;
|
|
118
|
-
const b0 = J['cheBase' + S], b1 = J['cheTip' + S], ft = J['fangTip' + S];
|
|
119
|
-
const CH = { bone: 'chelicera' + S, group: 'chel' + S, part: 'chel' + S };
|
|
120
|
-
const cr = d.chel.r.map((r) => r * M);
|
|
121
|
-
const dir = norm(sub(b1, b0));
|
|
122
|
-
m.cone({ ...CH, tag: 'chelicera', a: b0, b: add(b1, mul(dir, -cr[1] * 0.4)), ra: cr[0], rb: cr[1], k: 0 });
|
|
123
|
-
// the stout basal boss bulging forward (wolf) / the long forward-projecting paturon (tarantula)
|
|
124
|
-
ellY({ ...CH, tag: 'chelicera', c: add(lerp(b0, b1, 0.35), mm([0.1 * s * F, 0, (wolf ? 0.35 : 0.8) * F])), ydir: dir, r: [cr[0] * 0.92, len(sub(b1, b0)) * 0.4, cr[0] * 0.95], k: 0.5 * M * F });
|
|
125
|
-
// fang groove with its row of teeth: a shallow furrow on the inner face
|
|
126
|
-
ellY({ ...CH, tag: 'fangGroove', c: add(lerp(b0, b1, 0.8), mm([-0.55 * s * F, 0, 0.1 * F])), ydir: dir, r: [cr[1] * 0.35, len(sub(b1, b0)) * 0.22, cr[1] * 0.4], k: 0.2 * M * F, carve: true });
|
|
127
|
-
const FG = { bone: 'fang' + S, group: 'fang' + S, part: 'fang' + S, tag: 'fang' };
|
|
128
|
-
const fr = d.chel.fangR * M;
|
|
129
|
-
// a curved fang: base, then bending toward the tip
|
|
130
|
-
const fd = norm(sub(ft, b1)), fl = len(sub(ft, b1));
|
|
131
|
-
const bend = norm(cross(fd, [s, 0, 0]));
|
|
132
|
-
const mid = add(lerp(b1, ft, 0.5), mul(bend, fl * 0.12));
|
|
133
|
-
m.cone({ ...FG, a: add(b1, mul(fd, -fr * 0.5)), b: mid, ra: fr, rb: fr * 0.62, k: 0.08 * M * F });
|
|
134
|
-
m.cone({ ...FG, a: mid, b: ft, ra: fr * 0.62, rb: fr * 0.12, k: 0.08 * M * F });
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// ------------------------------------------------------------------ PALPS (body part)
|
|
138
|
-
for (const S of ['L', 'R']) {
|
|
139
|
-
const pj = palpJoints(S), pb = palpBones(S);
|
|
140
|
-
const g = { group: 'P' + S, part: 'body' };
|
|
141
|
-
for (let k = 0; k < pb.length; k++) {
|
|
142
|
-
const [ra, rb] = d.palp.r[k];
|
|
143
|
-
const a = J[pj[k]], b = J[pj[k + 1]];
|
|
144
|
-
m.cone({ ...g, bone: pb[k], tag: k === 0 ? 'palpcoxa' : 'palp', a, b, ra: R(ra * F / F), rb: R(rb), k: (k === 0 ? 0.6 : 0.09) * M * F });
|
|
145
|
-
if (k > 0 && k < pb.length - 1) m.sphere({ ...g, bone: pb[k], tag: 'knuckle', c: b, rad: R(rb * 1.08), k: 0.08 * M * F });
|
|
146
|
-
}
|
|
147
|
-
if (d.palpBulb > 0) {
|
|
148
|
-
// male: the swollen cymbium / palpal bulb ("boxing gloves")
|
|
149
|
-
const a = J[pj[5]], b = J[pj[6]];
|
|
150
|
-
// (swollen but compact: about the width of the palp tibia plus a third)
|
|
151
|
-
ellY({ ...g, bone: pb[5], tag: 'palpbulb', c: lerp(a, b, 0.5), ydir: sub(b, a), r: mm([0.65 * (0.62 * F * d.palpBulb + 0.3 * F), len(sub(b, a)) / M * 0.36, 0.65 * (0.7 * F * d.palpBulb + 0.3 * F)]), k: 0.2 * M * F });
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// ------------------------------------------------------------------ LEGS
|
|
156
|
-
for (const S of ['L', 'R']) {
|
|
157
|
-
for (let i = 1; i <= 4; i++) {
|
|
158
|
-
const lj = legJoints(i, S), lb = legBones(i, S), key = S + i;
|
|
159
|
-
const thick = i === 4 ? d.hindR : i === 3 ? (1 + d.hindR) / 2 : 1;
|
|
160
|
-
for (let k = 0; k < 7; k++) {
|
|
161
|
-
const [ra, rb] = d.legR[k];
|
|
162
|
-
const a = J[lj[k]], b = J[lj[k + 1]];
|
|
163
|
-
const parts = k <= 2 ? ['body', 'leg' + key] : ['leg' + key];
|
|
164
|
-
for (const part of parts) {
|
|
165
|
-
const g = { group: key, part, bone: lb[k] };
|
|
166
|
-
if (k === 0) {
|
|
167
|
-
// coxa: a stout cylinder set into the prosoma between carapace margin and sternum
|
|
168
|
-
m.cone({ ...g, tag: 'coxa', a: add(a, mul(norm(sub(b, a)), -0.6 * M * F)), b, ra: R(ra * thick), rb: R(rb * thick), k: part === 'body' ? 0.55 * M * F : 0.1 * M * F });
|
|
169
|
-
} else {
|
|
170
|
-
m.cone({ ...g, tag: ['coxa', 'troch', 'femur', 'patella', 'tibia', 'meta', 'tarsus'][k], a, b, ra: R(ra * thick), rb: R(rb * thick), k: 0.07 * M * F });
|
|
171
|
-
// swollen joint condyles: the knee (femur-patella) is the biggest
|
|
172
|
-
if (k < 6) m.sphere({ ...g, tag: 'knuckle', c: add(b, mul(norm(sub(b, a)), -rb * 0.25 * M)), rad: R(rb * thick * (k === 2 ? 1.12 : 1.06)), k: 0.07 * M * F });
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
// claw tuft: the rounded tarsus tip
|
|
177
|
-
const tip = J[lj[7]], ta = J[lj[6]];
|
|
178
|
-
m.sphere({ group: key, part: 'leg' + key, bone: lb[6], tag: 'claws', c: add(tip, mul(norm(sub(ta, tip)), d.legR[6][1] * 0.3 * M)), rad: R(d.legR[6][1] * thick * 1.02), k: 0.06 * M * F });
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return m;
|
|
182
|
-
}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
// Wolf body language, layered over the core actions every frame (species.motion.hooks.update, see
|
|
2
|
-
// core/motion/actions.js).
|
|
3
|
-
//
|
|
4
|
-
// Tail carriage by mood (Schenkel 1947 in Mech & Boitani 2003): hangs at rest, ~level in the
|
|
5
|
-
// travelling trot (the carriage table in motion.js), raised stiff above the back in a threat or an
|
|
6
|
-
// attack, tucked between the hind legs when hit or afraid. Ears: pricked forward when alert (a look
|
|
7
|
-
// target), pinned flat in an attack (core) and when howling. Hackles: the long guard hair of the
|
|
8
|
-
// mane, cape and saddle lifts during an attack (P.furRaise -> the coat shader). Snarl: the jaw opens
|
|
9
|
-
// on the crouch before the bite so the canines show. Howling: an idle variant every 25-60 s of
|
|
10
|
-
// standing still (or on demand via `motion.input.howl = true`): head thrown back 50-60 deg, ears
|
|
11
|
-
// back, jaw half open in an "O", lasting 3-6 s.
|
|
12
|
-
import { clamp, smooth, lerp, angDiff } from '../../core/motion/common.js';
|
|
13
|
-
import { mx, mxLegs } from '../../core/motion/actions.js';
|
|
14
|
-
const sm = (w) => w * w * (3 - 2 * w);
|
|
15
|
-
|
|
16
|
-
// moveTo: a wolf slows down to turn onto a point close beside or behind it. The engine caps the speed
|
|
17
|
-
// only by the heading error (1.5 sk beyond 1.2 rad), so with the wolf's calm turn rate (1.8 rad/s) a
|
|
18
|
-
// target inside its turning circle was circled without end. A point is reachable
|
|
19
|
-
// on a turn of radius R only while it lies outside the turning circle on its side: R < d / (2 sin err)
|
|
20
|
-
// (d distance, err bearing from the heading). The speed is capped so the radius at the engine's yaw
|
|
21
|
-
// limit, v / w(v), keeps a margin inside that bound; near the point and well off the heading the wolf
|
|
22
|
-
// all but pivots, then goes. (Engine-wide, the same cap belongs in quadruped.js drive().)
|
|
23
|
-
const ARRIVE_MARGIN = 0.8;
|
|
24
|
-
function arriveCap(e, st) {
|
|
25
|
-
const inp = e.input, cfg = e.cfg;
|
|
26
|
-
// arrived (drive() dropped the target and zeroed the speed): stand facing the way it went instead of
|
|
27
|
-
// pivoting on to the last bearing of the point (a front paw dragged ~2 % S in that pivot)
|
|
28
|
-
if (st.tgt && !inp.target && !inp.follow && !inp.speed && Math.hypot(st.tgt.x - e.pos.x, st.tgt.z - e.pos.z) < 0.5 * cfg.k + 0.03 * e.speed) {
|
|
29
|
-
inp.heading = e.heading + 0.25 * e.yawRate;
|
|
30
|
-
e.wantHeading = inp.heading;
|
|
31
|
-
}
|
|
32
|
-
st.tgt = inp.target && !inp.follow ? (st.tgt || { x: 0, z: 0 }) : null;
|
|
33
|
-
if (!st.tgt) return;
|
|
34
|
-
st.tgt.x = inp.target.x; st.tgt.z = inp.target.z;
|
|
35
|
-
if (!(e.wantSpeed > 0.05) || e.air?.active) return;
|
|
36
|
-
const dx = inp.target.x - e.pos.x, dz = inp.target.z - e.pos.z, d = Math.hypot(dx, dz);
|
|
37
|
-
const err = Math.abs(angDiff(e.heading, Math.atan2(dx, dz))), sn = Math.sin(err);
|
|
38
|
-
if (sn < 1e-3) return;
|
|
39
|
-
const rMax = (ARRIVE_MARGIN * d) / (2 * sn);
|
|
40
|
-
// the engine's yaw-rate limit at speed v (quadruped.js step: pivots are slower than turns on the move)
|
|
41
|
-
const wAt = (v) => Math.min(cfg.turnRate * lerp(0.55, 1, smooth(0.3, 2, v / cfg.sq)), cfg.latAccelMax / Math.max(v, 0.5 * cfg.sk));
|
|
42
|
-
if (e.wantSpeed / wAt(e.wantSpeed) <= rMax) return;
|
|
43
|
-
// v / w(v) grows with v: bisect for the fastest speed whose turning radius fits
|
|
44
|
-
let lo = 0, hi = e.wantSpeed;
|
|
45
|
-
for (let i = 0; i < 12; i++) { const m = 0.5 * (lo + hi); if (m / wAt(m) <= rMax) lo = m; else hi = m; }
|
|
46
|
-
// (a point ahead that the straight line passes within the stop radius needs no turn: the cap fades out)
|
|
47
|
-
const stopR = 0.35 * cfg.k + 0.02 * e.speed;
|
|
48
|
-
e.wantSpeed = lerp(e.wantSpeed, lo, err < 1.2 ? smooth(0.4 * stopR, 0.8 * stopR, d * sn) : 1);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function wolfUpdate(P, dt, L) {
|
|
52
|
-
const e = L.engine;
|
|
53
|
-
const st = L._wolf || (L._wolf = { howlIn: 25 + e.rand() * 20, howlT: -1, howlDur: 4, howlW: 0 });
|
|
54
|
-
arriveCap(e, st);
|
|
55
|
-
// (the sleeping forepaw pull-back below overrides this animal's fold placement only while it sleeps)
|
|
56
|
-
if (st.acts && st.acts.fold && !L.postures.some((p) => p.name === 'sleep')) st.acts.fold = undefined;
|
|
57
|
-
let raise = 0;
|
|
58
|
-
|
|
59
|
-
for (const a of L.oneshots) {
|
|
60
|
-
const w = sm(a.w);
|
|
61
|
-
if (w <= 0) continue;
|
|
62
|
-
if (a.name === 'attack') {
|
|
63
|
-
const t = a.t;
|
|
64
|
-
// threat -> lunge: hackles up, tail raised stiff above the back, snarl before the bite
|
|
65
|
-
raise = Math.max(raise, w * (0.5 + 0.5 * smooth(0, 0.2, t)));
|
|
66
|
-
mx(P, 'tailLift', 0.75, w); mx(P, 'tailStiff', 1.8, w);
|
|
67
|
-
const snarl = smooth(0.0, 0.12, t) * (1 - smooth(0.22, 0.3, t));
|
|
68
|
-
P.jaw = Math.max(P.jaw, 0.3 * snarl * w); // (the lower fangs come clear of the upper lip)
|
|
69
|
-
mx(P, 'headRaise', -0.035, snarl * w);
|
|
70
|
-
} else if (a.name === 'hit') {
|
|
71
|
-
// flinch: tail clamped between the hind legs, ears flat (core), body drops (core)
|
|
72
|
-
const k = w * (1 - smooth(0.45, 0.75, a.t) * 0.6);
|
|
73
|
-
mx(P, 'tailLift', -0.8, k); mx(P, 'tailStiff', 1.6, k); mx(P, 'tailIdle', 0, k);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
// dying / dead: ears folded back flat against the neck
|
|
77
|
-
for (const p of L.postures) {
|
|
78
|
-
if (p.name === 'death') { const w = sm(clamp(p.w, 0, 1)) * smooth(0.3, 1.0, p.t); mx(P, 'earFlat', 1.15, w); mx(P, 'earTwitch', 0, w); mx(P, 'headRoll', p.side * 0.8, w); P.headPos.y += 0.05 * e.cfg.s * w; }
|
|
79
|
-
}
|
|
80
|
-
// curled sleep (curled1: a ring on one hip, the nose tucked by the tail). The spine
|
|
81
|
-
// bends into a C (2.2 rad, rolled 0.45 onto the hip, the hind legs to the inside); the head turns back
|
|
82
|
-
// along the inside of the curl and rests on the ground by the hind feet (yaw 2.3 rad; the occiput 20 cm
|
|
83
|
-
// inside and 5 cm ahead of the turned chest's shoulders, 10 cm up: further back, the throat's stretch
|
|
84
|
-
// > 3x rose past 4 % of its triangles); the brush sweeps round the outside of the hind feet and forward
|
|
85
|
-
// to the nose (tailSide 3.4 curves it progressively, tailCurl -0.5 holds the root back: the old 2.4 rad
|
|
86
|
-
// turned it near the root and tucked it under the belly). The forelegs stay forward on the ground, as in
|
|
87
|
-
// curled1: tucked (the core's tuck places them in the unbent body frame, ~26 cm off, and the elbow
|
|
88
|
-
// flipped on the way out), reached (the paw stands up) or turned with the chest (the inner elbow dropped
|
|
89
|
-
// into the ground: 7-23 mm) they failed the metrics. (roll 0.45: 0.65 pressed the lower forearm 9-14 mm
|
|
90
|
-
// into the ground, 0.5 up to 6 mm)
|
|
91
|
-
for (const p of L.postures) {
|
|
92
|
-
if (p.name === 'sleep' && p.tune.style !== 'lateral') {
|
|
93
|
-
const c = sm(clamp(p.w, 0, 1)) * smooth(1.2, 3.2, p.t), side = p.side, k = e.cfg.k, fr = e.fr;
|
|
94
|
-
mx(P, 'roll', side * 0.45, c); mx(P, 'bend', side * 2.2, c);
|
|
95
|
-
mxLegs(P, 'side', 0, 0.55, c); mxLegs(P, 'spread', 0, 0, c);
|
|
96
|
-
// forelegs drawn back under the head (curled1: the paws just show at the front of the ring, not a leg's
|
|
97
|
-
// length ahead of it like a sphinx's): the engine's fold places the forepaw at zS + actions.fold.front.z
|
|
98
|
-
// leg lengths, flat on the ground; this animal's own copy of that tuning moves it 25 cm back once the
|
|
99
|
-
// curl has settled, the forearm and paw kept flat and the elbows folding up beside the chest. (A 'reach'
|
|
100
|
-
// blend stood the paw up and swung the elbow 10 mm into the ground; a 'sit' blend stood the forelegs up
|
|
101
|
-
// like posts; the core's tuck places the paw in the unbent body frame, ~26 cm off.) Skin penetration
|
|
102
|
-
// 0.30-0.62 % S (seeds 1-4, every morph, both sides).
|
|
103
|
-
const cF = sm(clamp(p.w, 0, 1)) * smooth(2.6, 4.4, p.t);
|
|
104
|
-
if (!st.acts) { st.acts = { ...e.cfg.actions }; e.cfg.actions = st.acts; }
|
|
105
|
-
const L0 = e.legs[0].def, z0 = (0.5 * L0.Lr + L0.Lmc) / L0.len;
|
|
106
|
-
// (k -1.45, beta 0 and z0 are the engine's own fold values: continuous as the pull-back fades)
|
|
107
|
-
st.acts.fold = cF > 1e-3 ? { front: { z: z0 - (cF * 0.25 * k) / L0.len, k: -1.45, beta: 0 } } : undefined;
|
|
108
|
-
mx(P, 'headYaw', side * 2.3, c);
|
|
109
|
-
// the chest's flat forward and left (its frame is the last frame's: the posture changes slowly)
|
|
110
|
-
const q = fr.qCh;
|
|
111
|
-
let fx = 2 * (q.x * q.z + q.w * q.y), fz = 1 - 2 * (q.x * q.x + q.y * q.y);
|
|
112
|
-
const fl = Math.hypot(fx, fz) || 1; fx /= fl; fz /= fl;
|
|
113
|
-
const lat = side * 0.2 * k, fwd = 0.05 * k;
|
|
114
|
-
const tx = fr.shC.x + fz * lat + fx * fwd, tz = fr.shC.z - fx * lat + fz * fwd;
|
|
115
|
-
const hp = P.headPos;
|
|
116
|
-
hp.x += (tx - hp.x) * c; hp.z += (tz - hp.z) * c; hp.y += (e.terrainH(tx, tz) + 0.1 * k - hp.y) * c;
|
|
117
|
-
mx(P, 'tailCurl', side * -0.5, c); mx(P, 'tailSide', side * 3.4, c); mx(P, 'tailStiff', 0.7, c);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// lying: rolled onto one hip, both hind legs to that side (lying1), not a symmetric sphinx
|
|
122
|
-
for (const p of L.postures) {
|
|
123
|
-
if (p.name === 'lie') {
|
|
124
|
-
const w = sm(clamp(p.w, 0, 1)) * smooth(0.6, 1.8, p.t);
|
|
125
|
-
mx(P, 'roll', p.side * 0.25, w);
|
|
126
|
-
mxLegs(P, 'side', 0, 0.5, w);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// alert: ears pricked forward while watching something
|
|
131
|
-
const idleW = L.idle.w;
|
|
132
|
-
if (e.input.look && raise < 0.01) mx(P, 'earFlat', -0.18, clamp(P.lookW, 0, 1));
|
|
133
|
-
|
|
134
|
-
// howling (idle variant)
|
|
135
|
-
const still = idleW > 0.95 && !L.postures.length && !L.oneshots.some((a) => !a.stopping && a.name !== 'hit');
|
|
136
|
-
if (st.howlT < 0) {
|
|
137
|
-
if (still) st.howlIn -= dt;
|
|
138
|
-
if (e.input.howl && idleW > 0.3) { e.input.howl = false; st.howlIn = 0; }
|
|
139
|
-
if (st.howlIn <= 0 && still) { st.howlT = 0; st.howlDur = 3 + e.rand() * 3; }
|
|
140
|
-
} else {
|
|
141
|
-
st.howlT += dt;
|
|
142
|
-
if (!still && idleW < 0.6) st.howlT = Math.max(st.howlT, st.howlDur);
|
|
143
|
-
if (st.howlT > st.howlDur + 1.2) { st.howlT = -1; st.howlIn = 25 + e.rand() * 35; }
|
|
144
|
-
}
|
|
145
|
-
const hw = st.howlT < 0 ? 0 : smooth(0, 0.9, st.howlT) * (1 - smooth(st.howlDur, st.howlDur + 1.2, st.howlT));
|
|
146
|
-
st.howlW = hw;
|
|
147
|
-
if (hw > 0.001) {
|
|
148
|
-
const w = hw * idleW;
|
|
149
|
-
mx(P, 'lookW', 0, w);
|
|
150
|
-
mx(P, 'headRaise', 0.07, w); mx(P, 'neckReach', -0.03, w);
|
|
151
|
-
mx(P, 'headPitch', -1.0, w);
|
|
152
|
-
// the "O" opens after the head is up, with a slight waver
|
|
153
|
-
const o = smooth(0.5, 1.2, st.howlT) * (1 - smooth(st.howlDur - 0.3, st.howlDur + 0.4, st.howlT));
|
|
154
|
-
mx(P, 'jaw', 0.2 + 0.03 * Math.sin(st.howlT * 5.1), o * w); mx(P, 'jawOmega', 6, w);
|
|
155
|
-
mx(P, 'earFlat', 0.55, w); mx(P, 'earTwitch', 0, w);
|
|
156
|
-
mx(P, 'breathAmp', 0.4, w); mx(P, 'eyelid', 0.45, o * w);
|
|
157
|
-
mx(P, 'dropH', 0.05, w);
|
|
158
|
-
}
|
|
159
|
-
P.furRaise = Math.max(P.furRaise || 0, raise);
|
|
160
|
-
}
|