@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,559 +0,0 @@
|
|
|
1
|
-
// Cat behaviour layer for the quadruped engine (species.motion.hooks, see core/motion/actions.js).
|
|
2
|
-
//
|
|
3
|
-
// update(P, dt, layer) every frame over the built-in actions: mood (annoyed -> the whole tail
|
|
4
|
-
// lashes side to side at ~1 Hz and the ears turn out sideways, "airplane
|
|
5
|
-
// ears"), slow blinks (idle, sitting, loafing), the walking head held level,
|
|
6
|
-
// lapping at ~3.8 laps / s when drinking, the head tilted to shear with the
|
|
7
|
-
// carnassials when eating, the tail wrapped round the forepaws when sitting and
|
|
8
|
-
// over the nose when curled asleep, automatic idle variants (grooming, a slow
|
|
9
|
-
// blink, ear scans)
|
|
10
|
-
// pose(engine, dt) after the engine's solve: the ears swivel independently toward "sounds" and
|
|
11
|
-
// flatten sideways when angry; the tail tip twitches while hunting
|
|
12
|
-
// actions attack (stalk crouch, rear-end wiggle, then the pounce: forepaws strike
|
|
13
|
-
// down together, bite), hit (flinch, then the arched-back "Halloween" threat:
|
|
14
|
-
// stiff legs, bristling fur and bottle-brush tail, ears flat, hissing),
|
|
15
|
-
// loaf (sternal with every paw tucked under), groom (licks a forepaw, wipes it
|
|
16
|
-
// over the ear and face), knead, stalk (crouched creep with a twitching tail
|
|
17
|
-
// tip), slowblink
|
|
18
|
-
//
|
|
19
|
-
// Distances are cat metres at the reference size (x cfg.s); posture offsets the engine multiplies by
|
|
20
|
-
// cfg.k (fwd, side, headRaise, neckReach) are divided by cfg.unit.
|
|
21
|
-
import * as THREE from 'three';
|
|
22
|
-
import { clamp, lerp, smooth, TAU, tv, tqa, tableAt } from '../../core/motion/common.js';
|
|
23
|
-
import { mx, mxLeg, ONESHOTS, POSTURES } from '../../core/motion/actions.js';
|
|
24
|
-
import { whiskerSamples, WHISKER_BASE, WHISKER_TIP } from './whiskers.js';
|
|
25
|
-
|
|
26
|
-
const W_SAMPLES = whiskerSamples();
|
|
27
|
-
|
|
28
|
-
const _q = new THREE.Quaternion(), _q2 = new THREE.Quaternion(), _s = new THREE.Vector3(1, 1, 1);
|
|
29
|
-
const _p = new THREE.Vector3(), _a = new THREE.Vector3(), _pOld = new THREE.Vector3(), _pNew = new THREE.Vector3(), _pPrev = new THREE.Vector3(), _d = new THREE.Vector3();
|
|
30
|
-
const sm = (w) => w * w * (3 - 2 * w);
|
|
31
|
-
const U = (e) => e.cfg.unit; // engine units -> cat metres
|
|
32
|
-
|
|
33
|
-
// per-engine behaviour state
|
|
34
|
-
function B(e) {
|
|
35
|
-
if (!e._cat) {
|
|
36
|
-
e._cat = {
|
|
37
|
-
annoyed: 0, hunt: 0, lashPh: e.rand() * TAU,
|
|
38
|
-
ear: [{ sw: 0, v: 0, target: 0, tNext: 0.4 }, { sw: 0, v: 0, target: 0, tNext: 1.1 }],
|
|
39
|
-
earOut: 0, twitchPh: 0, twitch: 0, whisk: [{ a: 0, v: 0, lift: 0, back: 0 }, { a: 0, v: 0, lift: 0, back: 0 }], wLocal: null, fanT: 0,
|
|
40
|
-
blinkT: -1, blinkIn: 4 + e.rand() * 6, idleT: 8 + e.rand() * 6,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
return e._cat;
|
|
44
|
-
}
|
|
45
|
-
const busy = (L) => L.postures.some((p) => p.target > 0) || L.oneshots.some((a) => !a.stopping);
|
|
46
|
-
const running = (L, name) => L.oneshots.find((a) => a.name === name && a.w > 0);
|
|
47
|
-
const posture = (L, name) => L.postures.find((p) => p.name === name && p.w > 0);
|
|
48
|
-
|
|
49
|
-
// ------------------------------------------------------------------------------------------------
|
|
50
|
-
// update: body language on top of every action
|
|
51
|
-
function update(P, dt, L) {
|
|
52
|
-
const e = L.engine, b = B(e), cfg = e.cfg;
|
|
53
|
-
const vn = e.speed / cfg.sq;
|
|
54
|
-
const t = e.time;
|
|
55
|
-
|
|
56
|
-
// ---- mood: annoyed (hit, attacked, or asked for), hunting (stalk, pounce crouch)
|
|
57
|
-
let annoyedT = e.input.mood === 'annoyed' ? 1 : 0, huntT = 0;
|
|
58
|
-
for (const a of L.oneshots) {
|
|
59
|
-
if (a.name === 'hit' && a.w > 0) annoyedT = Math.max(annoyedT, 1);
|
|
60
|
-
if (a.name === 'attack' && a.w > 0 && a.phase !== 'air') huntT = Math.max(huntT, a.w);
|
|
61
|
-
if (a.name === 'stalk' && a.w > 0) huntT = Math.max(huntT, a.w);
|
|
62
|
-
}
|
|
63
|
-
if (b.hitAfter > 0) { b.hitAfter -= dt; annoyedT = Math.max(annoyedT, clamp(b.hitAfter / 2, 0, 1)); }
|
|
64
|
-
b.annoyed += (annoyedT - b.annoyed) * (1 - Math.exp(-dt * (annoyedT > b.annoyed ? 4 : 0.8)));
|
|
65
|
-
b.hunt += (huntT - b.hunt) * (1 - Math.exp(-dt * 5));
|
|
66
|
-
// lashing: the whole tail sweeps side to side (~1 Hz), faster and wider the angrier
|
|
67
|
-
if (b.annoyed > 0.01) {
|
|
68
|
-
b.lashPh += dt * TAU * lerp(0.7, 1.3, b.annoyed);
|
|
69
|
-
const k = b.annoyed * (1 - P.tailGround * 0.7);
|
|
70
|
-
P.tailSide += Math.sin(b.lashPh) * 0.85 * k;
|
|
71
|
-
mx(P, 'tailIdle', 0, k);
|
|
72
|
-
mx(P, 'earFlat', Math.max(P.earFlat, 0.35), k);
|
|
73
|
-
}
|
|
74
|
-
b.earOut = b.annoyed;
|
|
75
|
-
|
|
76
|
-
// ---- walking: the head held level and steady (a cat's gaze locks on)
|
|
77
|
-
const walk = smooth(0.05, 0.4, vn) * (1 - smooth(1.2, 2.2, vn)) * P.gaitW;
|
|
78
|
-
if (walk > 0) P.headPitch -= 0.04 * walk;
|
|
79
|
-
|
|
80
|
-
// ---- sitting upright: the tail curls round the forepaws on the ground
|
|
81
|
-
const sit = posture(L, 'sit');
|
|
82
|
-
if (sit) {
|
|
83
|
-
const w = sm(clamp(sit.w, 0, 1)) * smooth(0.4, 1.4, sit.t);
|
|
84
|
-
mx(P, 'tailSide', sit.side * 1.6, w); mx(P, 'tailCurl', sit.side * 3.2, w); mx(P, 'tailStiff', 0.8, w); mx(P, 'tailGround', 0.7, w);
|
|
85
|
-
mx(P, 'headRaise', 0.03 / U(e) * 0.35, w);
|
|
86
|
-
}
|
|
87
|
-
// ---- lying on its side (dead): the big round head rests on its cheek, higher than the engine's
|
|
88
|
-
// (cheetah-proportioned) default
|
|
89
|
-
for (const p of L.postures) {
|
|
90
|
-
if (p.name === 'death') {
|
|
91
|
-
const w = sm(clamp(p.w, 0, 1)) * smooth(0.35, 1.0, p.t); P.headPos.y += 0.035 * cfg.s * w;
|
|
92
|
-
// (lying on its side the lower paws rest tilted on their edge: carry the body a few mm higher)
|
|
93
|
-
// (6.5 mm: a blue cat's hind paw on its edge still pressed 2.9 mm into the ground at 5)
|
|
94
|
-
P.lift += (0.009 / cfg.unit) * sm(clamp(p.w, 0, 1)) * smooth(0.5, 0.9, p.t);
|
|
95
|
-
// the limp tail: the engine lays it 'down' in the pelvis frame, which points sideways on a body lying on
|
|
96
|
-
// its side (it floated 7-10 cm up); swept round toward the ground side it drapes onto the ground
|
|
97
|
-
// (tail joints 20 -> 91 mm root to tip, both fall sides)
|
|
98
|
-
mx(P, 'tailSide', -p.side * 2.1, sm(clamp(p.w, 0, 1)) * smooth(0.6, 1.4, p.t));
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
// ---- curled asleep: a tight ring, the tail wrapped round along the body toward the head, head on the forepaws
|
|
102
|
-
const sleep = posture(L, 'sleep');
|
|
103
|
-
if (sleep && sleep.tune.style !== 'lateral') {
|
|
104
|
-
const c = sm(clamp(sleep.w, 0, 1)) * smooth(1.2, 3.2, sleep.t);
|
|
105
|
-
mx(P, 'bend', sleep.side * 1.02, c); mx(P, 'tailCurl', sleep.side * 3.0, c); mx(P, 'tailStiff', 0.6, c); mx(P, 'tailGround', 0.9, c);
|
|
106
|
-
mx(P, 'headYaw', sleep.side * 0.75, c); mx(P, 'flex', 0.25, c);
|
|
107
|
-
// (the head resting on the forepaws a little higher: a big round head's lower cheek went into the ground)
|
|
108
|
-
P.headPos.y += 0.005 * cfg.s * c;
|
|
109
|
-
}
|
|
110
|
-
// ---- drinking: lapping (the tongue flicks up a column of water ~3.8 times a second)
|
|
111
|
-
const dr = running(L, 'drink');
|
|
112
|
-
if (dr) {
|
|
113
|
-
const w = sm(dr.w);
|
|
114
|
-
P.jaw = lerp(P.jaw, 0.06 + 0.09 * Math.max(0, Math.sin(dr.t * 3.8 * TAU)), w);
|
|
115
|
-
mx(P, 'tailLift', -0.45, w); mx(P, 'tailGround', 0.45, w); // (crouched: the tail low, its tip on the ground)
|
|
116
|
-
mx(P, 'jawOmega', 40, w);
|
|
117
|
-
mx(P, 'earFlat', 0.1, w);
|
|
118
|
-
}
|
|
119
|
-
// ---- eating: head tilted to shear with the carnassials, with little head shakes
|
|
120
|
-
const eat = running(L, 'eat');
|
|
121
|
-
if (eat) {
|
|
122
|
-
const w = sm(eat.w);
|
|
123
|
-
P.headRoll += w * (0.35 * Math.sin(eat.t * 0.9) + 0.08 * Math.sin(eat.t * 11) * smooth(0.6, 0.9, Math.sin(eat.t * 1.7)));
|
|
124
|
-
mx(P, 'tailLift', -0.45, w); mx(P, 'tailGround', 0.45, w);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// ---- the upper lids rest a little over the iris (a flatter, heavier upper lid: face1, face2, lying1);
|
|
128
|
-
// wide open when hunting or startled
|
|
129
|
-
P.eyelid = Math.max(P.eyelid, 0.12 * (1 - b.hunt) * (1 - 0.6 * b.annoyed));
|
|
130
|
-
|
|
131
|
-
// ---- slow blink ("cat kiss"): idle standing, sitting, loafing; or on demand (the slowblink action)
|
|
132
|
-
const calm = (L.idle.w > 0.9 && !busy(L)) || posture(L, 'sit') || posture(L, 'loaf') || posture(L, 'lie');
|
|
133
|
-
if (b.blinkT < 0) {
|
|
134
|
-
if (calm && !b.annoyed) b.blinkIn -= dt;
|
|
135
|
-
if (b.blinkIn <= 0) { b.blinkT = 0; b.blinkIn = 6 + e.rand() * 10; }
|
|
136
|
-
}
|
|
137
|
-
if (b.blinkT >= 0) {
|
|
138
|
-
b.blinkT += dt;
|
|
139
|
-
const bt = b.blinkT;
|
|
140
|
-
const lid = smooth(0, 0.55, bt) * (1 - smooth(1.4, 2.1, bt));
|
|
141
|
-
P.eyelid = Math.max(P.eyelid, 0.88 * lid);
|
|
142
|
-
P.headPitch += 0.06 * lid; // a small nod with it
|
|
143
|
-
if (bt > 2.2) b.blinkT = -1;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// ---- idle variants: grooming, an ear scan, a slow blink
|
|
147
|
-
if (e.idleVariants !== false && L.idle.w > 0.98 && !busy(L) && !e.input.look && !e.input.follow) {
|
|
148
|
-
b.idleT -= dt;
|
|
149
|
-
if (b.idleT <= 0) {
|
|
150
|
-
b.idleT = 7 + e.rand() * 9;
|
|
151
|
-
const r = e.rand();
|
|
152
|
-
if (r < 0.4) L.play('groom');
|
|
153
|
-
else if (r < 0.7) b.blinkIn = 0;
|
|
154
|
-
else { b.ear[0].tNext = 0; b.ear[1].tNext = 0.15; }
|
|
155
|
-
}
|
|
156
|
-
} else if (busy(L)) b.idleT = Math.max(b.idleT, 3);
|
|
157
|
-
|
|
158
|
-
// ---- hunting: tail low and straight, its tip twitching; ears pricked forward
|
|
159
|
-
if (b.hunt > 0.01) {
|
|
160
|
-
mx(P, 'tailLift', -0.35, b.hunt); mx(P, 'tailIdle', 0, b.hunt); mx(P, 'tailStiff', 1.3, b.hunt);
|
|
161
|
-
mx(P, 'earFlat', -0.15, b.hunt);
|
|
162
|
-
}
|
|
163
|
-
b.twitch = b.hunt;
|
|
164
|
-
// whisker fan (pose hook): forward when hunting or walking, back when eating, drinking, angry, asleep
|
|
165
|
-
const eatW = Math.max(dr ? dr.w : 0, eat ? eat.w : 0);
|
|
166
|
-
b.fanT = 0.4 * b.hunt + 0.12 * walk - 0.5 * b.annoyed - 0.4 * eatW - 0.3 * clamp(P.eyelid, 0, 1);
|
|
167
|
-
void t;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// whisker samples in the whisker bone's bind-local frame, mapped from the reference head (whiskers.js)
|
|
171
|
-
// onto this individual's bone (scaled by the bone's length)
|
|
172
|
-
const _w = Array.from({ length: 40 }, () => new THREE.Vector3());
|
|
173
|
-
function whiskerLocal(e, kk) {
|
|
174
|
-
const s = kk ? -1 : 1, S = kk ? 'R' : 'L';
|
|
175
|
-
const i = e.sk.bones.indexOf(e.bone['whisker' + S]);
|
|
176
|
-
const inv = e.sk.bind[i].clone().invert();
|
|
177
|
-
const Jb = e.J['whiskerBase' + S], Jt = e.J['whiskerTip' + S];
|
|
178
|
-
const refLen = Math.hypot(WHISKER_TIP[0] - WHISKER_BASE[0], WHISKER_TIP[1] - WHISKER_BASE[1], WHISKER_TIP[2] - WHISKER_BASE[2]);
|
|
179
|
-
const k = Jb.distanceTo(Jt) / refLen;
|
|
180
|
-
return W_SAMPLES.map((p) => new THREE.Vector3(Jb.x + (p[0] - WHISKER_BASE[0]) * s * k, Jb.y + (p[1] - WHISKER_BASE[1]) * k, Jb.z + (p[2] - WHISKER_BASE[2]) * k).applyMatrix4(inv));
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// ------------------------------------------------------------------------------------------------
|
|
184
|
-
// pose: independent ear swivels, airplane ears, whiskers, tail-tip twitch
|
|
185
|
-
function pose(e, dt) {
|
|
186
|
-
const b = B(e), P = e.P, cfg = e.cfg;
|
|
187
|
-
if (e.lod >= 2) return;
|
|
188
|
-
const awake = 1 - P.eyelid * 0.8;
|
|
189
|
-
const still = 1 - smooth(0.5, 3, e.speed / cfg.sq);
|
|
190
|
-
// ---- ears
|
|
191
|
-
if (cfg.hasEars) {
|
|
192
|
-
for (let k = 0; k < 2; k++) {
|
|
193
|
-
const E = b.ear[k], s = k === 0 ? 1 : -1;
|
|
194
|
-
const bone = k === 0 ? e.bone.earL : e.bone.earR;
|
|
195
|
-
if (!bone) continue;
|
|
196
|
-
// a new "sound" every 1-4 s: often sideways or back, sometimes straight ahead; each ear on its own
|
|
197
|
-
E.tNext -= dt;
|
|
198
|
-
if (E.tNext <= 0) {
|
|
199
|
-
E.tNext = 1 + e.rand() * 3.5;
|
|
200
|
-
E.target = e.rand() < 0.35 ? 0 : (e.rand() - 0.3) * 0.86 * s; // (up to ~35 deg out, ~15 in: the skin of the crown between the ears stretched > 3x beyond)
|
|
201
|
-
}
|
|
202
|
-
// (none lying on the side or with the head on the ground: the engine keeps the pinnae out of it)
|
|
203
|
-
const want = E.target * still * awake * (1 - Math.max(0, P.earFlat)) * (1 - b.hunt) * (1 - smooth(0.25, 0.7, Math.abs(P.roll))) * (1 - clamp(P.headW, 0, 1));
|
|
204
|
-
const om = 16; // fast, critically damped swivel (~0.1 s)
|
|
205
|
-
E.v += (om * om * (want - E.sw) - 2 * om * E.v) * dt;
|
|
206
|
-
E.sw += E.v * dt;
|
|
207
|
-
const out = b.earOut;
|
|
208
|
-
if (Math.abs(E.sw) < 1e-4 && out < 1e-3) continue;
|
|
209
|
-
const base = _p.setFromMatrixPosition(bone.matrixWorld);
|
|
210
|
-
_q.setFromRotationMatrix(bone.matrixWorld);
|
|
211
|
-
// swivel about the pinna's own axis
|
|
212
|
-
_a.set(0, 1, 0).applyQuaternion(_q);
|
|
213
|
-
_q.premultiply(tqa(_a, E.sw + out * 0.42 * s));
|
|
214
|
-
// airplane ears: turned out and down to the side, openings facing back
|
|
215
|
-
if (out > 1e-3) {
|
|
216
|
-
const hq = e.headPose.quaternion;
|
|
217
|
-
_d.set(0, 0, 1).applyQuaternion(hq);
|
|
218
|
-
_q.premultiply(tqa(_d, -s * 0.36 * out)); // (0.55 / 0.45: the crown between the ears stretched > 3x)
|
|
219
|
-
}
|
|
220
|
-
bone.matrixWorld.compose(base, _q, _s);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
// ---- whiskers: fanned / swept (b.fanT), and lifted clear of the ground
|
|
224
|
-
for (let k = 0; k < 2; k++) {
|
|
225
|
-
const S = k ? 'R' : 'L', s = k ? -1 : 1;
|
|
226
|
-
const bone = e.bone['whisker' + S];
|
|
227
|
-
if (!bone) break;
|
|
228
|
-
const W = b.whisk[k];
|
|
229
|
-
const om = 12;
|
|
230
|
-
W.v += (om * om * (b.fanT - W.a) - 2 * om * W.v) * dt;
|
|
231
|
-
W.a += W.v * dt;
|
|
232
|
-
if (!b.wLocal) b.wLocal = [0, 1].map((kk) => whiskerLocal(e, kk));
|
|
233
|
-
const base = _p.setFromMatrixPosition(bone.matrixWorld);
|
|
234
|
-
_q.setFromRotationMatrix(bone.matrixWorld);
|
|
235
|
-
_a.set(0, 1, 0).applyQuaternion(e.headPose.quaternion);
|
|
236
|
-
_q.premultiply(tqa(_a, -s * W.a));
|
|
237
|
-
bone.matrixWorld.compose(base, _q, _s);
|
|
238
|
-
// ground: sweep the fan back along the cheek (about the head's up axis) just enough, the way a cat
|
|
239
|
-
// lays its whiskers back against a surface; lift it about its root for what remains. Rises at once,
|
|
240
|
-
// relaxes slowly.
|
|
241
|
-
// (look ahead by the head's fall: a collapsing body drops the face 0.5 m/s)
|
|
242
|
-
const vDown = W.y0 === undefined || dt <= 0 ? 0 : Math.max(0, (W.y0 - base.y) / dt);
|
|
243
|
-
W.y0 = base.y;
|
|
244
|
-
const margin = 0.009 * cfg.s + Math.min(0.06 * cfg.s, vDown * 0.12);
|
|
245
|
-
const near = base.y - e.terrainH(base.x, base.z) < 0.09 * cfg.s + margin * 2;
|
|
246
|
-
let needB = 0, needL = 0;
|
|
247
|
-
if (near) {
|
|
248
|
-
const pts = b.wLocal[k];
|
|
249
|
-
for (let i = 0; i < pts.length; i++) _w[i + 1].copy(pts[i]).applyMatrix4(bone.matrixWorld).sub(base);
|
|
250
|
-
const nP = pts.length;
|
|
251
|
-
const clearAt = (phi) => {
|
|
252
|
-
let worst = 0;
|
|
253
|
-
_q2.setFromAxisAngle(_a, s * phi);
|
|
254
|
-
for (let i = 1; i <= nP; i++) {
|
|
255
|
-
const p = _d.copy(_w[i]).applyQuaternion(_q2).add(base);
|
|
256
|
-
worst = Math.min(worst, p.y - (e.terrainH(p.x, p.z) + margin)); // (margin: the fan follows on a spring)
|
|
257
|
-
}
|
|
258
|
-
return worst;
|
|
259
|
-
};
|
|
260
|
-
// smallest sweep that clears, interpolated between steps (continuous in the pose)
|
|
261
|
-
let pw = clearAt(0);
|
|
262
|
-
needB = 0;
|
|
263
|
-
if (pw < 0) {
|
|
264
|
-
needB = 1.7;
|
|
265
|
-
for (let i = 1; i <= 8; i++) {
|
|
266
|
-
const w = clearAt(i * 0.2125);
|
|
267
|
-
if (w >= 0) { needB = (i - 1 + -pw / Math.max(1e-6, w - pw)) * 0.2125; break; }
|
|
268
|
-
pw = w;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
const rest = clearAt(needB);
|
|
272
|
-
if (rest < 0) needL = Math.asin(clamp(-rest / (0.05 * cfg.s), 0, 1)) * 1.2;
|
|
273
|
-
}
|
|
274
|
-
// critically damped springs (fast: ~0.1 s), so the fan never snaps
|
|
275
|
-
const omb = 40;
|
|
276
|
-
W.vb = (W.vb || 0) + (omb * omb * (needB - W.back) - 2 * omb * (W.vb || 0)) * dt; W.back = Math.max(0, W.back + W.vb * dt);
|
|
277
|
-
W.vl = (W.vl || 0) + (omb * omb * (needL - W.lift) - 2 * omb * (W.vl || 0)) * dt; W.lift = Math.max(0, W.lift + W.vl * dt);
|
|
278
|
-
if (W.back > 1e-4) _q.premultiply(tqa(_a, s * W.back));
|
|
279
|
-
if (W.lift > 1e-4) {
|
|
280
|
-
const tip = _d.copy(b.wLocal[k][0]).applyMatrix4(bone.matrixWorld).sub(base).applyQuaternion(tqa(_a, s * W.back)).normalize();
|
|
281
|
-
const ax = _w[0].crossVectors(tip, THREE.Object3D.DEFAULT_UP);
|
|
282
|
-
if (ax.lengthSq() > 1e-8) _q.premultiply(tqa(ax.normalize(), W.lift));
|
|
283
|
-
}
|
|
284
|
-
if (W.back > 1e-4 || W.lift > 1e-4) bone.matrixWorld.compose(base, _q, _s);
|
|
285
|
-
}
|
|
286
|
-
// ---- tail tip twitch (hunting / focused): the last third flicks side to side
|
|
287
|
-
const tw = b.twitch;
|
|
288
|
-
if (tw > 0.01 && cfg.tailN) {
|
|
289
|
-
b.twitchPh += dt * TAU * 2.2;
|
|
290
|
-
const n = cfg.tailN, i0 = Math.floor(n * 0.62);
|
|
291
|
-
const amp = tw * (0.2 * Math.sin(b.twitchPh) + 0.12 * Math.sin(b.twitchPh * 2.3 + 1));
|
|
292
|
-
_q2.identity();
|
|
293
|
-
for (let j = i0; j < n; j++) {
|
|
294
|
-
const bone = e.bone[e.tailNames[j]];
|
|
295
|
-
if (!bone) continue;
|
|
296
|
-
_pOld.setFromMatrixPosition(bone.matrixWorld);
|
|
297
|
-
if (j === i0) _pNew.copy(_pOld);
|
|
298
|
-
else _pNew.add(_d.copy(_pOld).sub(_pPrev).applyQuaternion(_q2));
|
|
299
|
-
_pPrev.copy(_pOld);
|
|
300
|
-
_q2.premultiply(tqa(THREE.Object3D.DEFAULT_UP, amp * (j - i0 + 1) / (n - i0)));
|
|
301
|
-
_q.setFromRotationMatrix(bone.matrixWorld).premultiply(_q2);
|
|
302
|
-
bone.matrixWorld.compose(_pNew, _q, _s);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// ------------------------------------------------------------------------------------------------
|
|
308
|
-
// attack: stalk crouch with the rear-end wiggle, then the pounce: a short leap (the engine's jump
|
|
309
|
-
// mechanics, with its push-off) with the forepaws reaching forward, landing forepaws first to pin the
|
|
310
|
-
// prey with both paws, and a bite. Running: the built-in bite-lunge.
|
|
311
|
-
const WIGGLE = 1.25; // s of crouch + wiggle before the leap
|
|
312
|
-
const POUNCE = { height: 0.12, distance: 0.55, land: [0.5, 0.3] };
|
|
313
|
-
const attack = {
|
|
314
|
-
kind: 'oneshot', fade: 0.15, needsStand: true, airborne: true,
|
|
315
|
-
start(inst, L) {
|
|
316
|
-
const e = L.engine;
|
|
317
|
-
inst.run = smooth(1.2, 3, e.speed / e.cfg.sq);
|
|
318
|
-
inst.delay = inst.run > 0.5 ? 0 : (inst.opts.wiggle ?? WIGGLE) * e.cfg.sq;
|
|
319
|
-
inst.dur = Infinity;
|
|
320
|
-
if (inst.run > 0.5) {
|
|
321
|
-
inst.lunge = { ...inst, tune: { style: 'bite-lunge' } };
|
|
322
|
-
ONESHOTS.attack.start(inst.lunge, L);
|
|
323
|
-
}
|
|
324
|
-
},
|
|
325
|
-
update(inst, dt, L) {
|
|
326
|
-
const e = L.engine;
|
|
327
|
-
if (inst.lunge) { inst.lunge.t = inst.t; return ONESHOTS.attack.update.call(ONESHOTS.attack, inst.lunge, dt, L); }
|
|
328
|
-
if (inst.t < inst.delay) return false;
|
|
329
|
-
if (!inst.leap) {
|
|
330
|
-
inst.leap = { ...inst, t: 0, tune: POUNCE, opts: { target: inst.opts.target } };
|
|
331
|
-
ONESHOTS.jump.start(inst.leap, L);
|
|
332
|
-
}
|
|
333
|
-
const J = inst.leap;
|
|
334
|
-
J.t = inst.t - inst.delay;
|
|
335
|
-
const done = ONESHOTS.jump.update(J, dt, L);
|
|
336
|
-
inst.phase = J.phase;
|
|
337
|
-
if (inst.landT !== undefined && inst.t - inst.landT > 0.75) return true;
|
|
338
|
-
void done; void e;
|
|
339
|
-
return false;
|
|
340
|
-
},
|
|
341
|
-
onLand(inst, L) {
|
|
342
|
-
if (inst.lunge) return ONESHOTS.attack.onLand.call(ONESHOTS.attack, inst.lunge, L);
|
|
343
|
-
if (!inst.leap) return;
|
|
344
|
-
ONESHOTS.jump.onLand(inst.leap, L);
|
|
345
|
-
inst.landT = inst.t;
|
|
346
|
-
// the strike: both forepaws pin, then the bite
|
|
347
|
-
const e = L.engine;
|
|
348
|
-
const p = e.legs[0].contact.clone().lerp(e.legs[1].contact, 0.5);
|
|
349
|
-
const dir = inst.opts.target ? inst.opts.target.clone().sub(e.pos).setY(0).normalize() : e.forward(e.heading, new THREE.Vector3());
|
|
350
|
-
e.emit('attackHit', { position: p, direction: dir, style: 'pounce' });
|
|
351
|
-
},
|
|
352
|
-
apply(P, w, inst, L) {
|
|
353
|
-
const e = L.engine, t = inst.t, cfg = e.cfg, s = cfg.s;
|
|
354
|
-
if (inst.lunge) return ONESHOTS.attack.apply(P, w, inst.lunge, L);
|
|
355
|
-
if (inst.opts.target) { P.look = inst.opts.target; mx(P, 'lookW', 1, w); }
|
|
356
|
-
// the stalk crouch: chest low, elbows up, head low and forward, gaze locked; the hindquarters
|
|
357
|
-
// tread from foot to foot (the butt wiggle) before the leap
|
|
358
|
-
const c = smooth(0, 0.35, t) * (1 - smooth(inst.delay - 0.1, inst.delay + 0.15, t)) * w;
|
|
359
|
-
mx(P, 'dropF', 0.52, c); mx(P, 'dropH', 0.5, c); mx(P, 'fwd', -0.01 / U(e), c);
|
|
360
|
-
mx(P, 'headRaise', -0.014 / U(e), c); mx(P, 'neckReach', 0.012 / U(e), c); mx(P, 'headPitch', -0.1, c);
|
|
361
|
-
const ears = w * (inst.landT === undefined ? 1 : 1 - smooth(0.3, 0.7, t - inst.landT));
|
|
362
|
-
mx(P, 'earFlat', -0.2, ears); mx(P, 'earTwitch', 0, ears);
|
|
363
|
-
const wig = smooth(0.3, 0.55, t) * (1 - smooth(inst.delay - 0.2, inst.delay - 0.05, t));
|
|
364
|
-
const ph = Math.sin(t * TAU * 3.2);
|
|
365
|
-
P.side += 0.006 / U(e) * ph * wig * w;
|
|
366
|
-
P.roll += 0.06 * ph * wig * w;
|
|
367
|
-
mx(P, 'dropH', 0.42 - 0.12 * Math.abs(ph), wig * w);
|
|
368
|
-
const J = inst.leap;
|
|
369
|
-
if (!J) return;
|
|
370
|
-
ONESHOTS.jump.apply(P, w, J, L);
|
|
371
|
-
// forepaws: reach forward in the flight, strike down together and pin on landing
|
|
372
|
-
const fwd = e.forward(e.heading, tv()), lat = e.left(e.heading, tv());
|
|
373
|
-
let reach = 0, ahead = 0, up = 0;
|
|
374
|
-
if (J.phase === 'air') {
|
|
375
|
-
const T = (2 * J.vy) / 9.81, x = clamp((J.t - J.tAir) / T, 0, 1);
|
|
376
|
-
reach = smooth(0, 0.3, x); ahead = 0.065; up = 0.05 * (1 - smooth(0, 1, x));
|
|
377
|
-
mx(P, 'jaw', 0.35, w * smooth(0.4, 0.9, x)); mx(P, 'jawOmega', 25, w);
|
|
378
|
-
} else if (J.phase === 'land') {
|
|
379
|
-
const x = J.t - J.tLand;
|
|
380
|
-
reach = 1 - smooth(0.35, 0.7, x); ahead = 0.065; up = 0;
|
|
381
|
-
mx(P, 'jaw', 0.45 * (1 - smooth(0.1, 0.3, x)), w); mx(P, 'jawOmega', 30, w);
|
|
382
|
-
const bite = smooth(0.05, 0.2, x) * (1 - smooth(0.4, 0.7, x));
|
|
383
|
-
mx(P, 'headRaise', -0.02 / U(e), bite * w); mx(P, 'headPitch', 0.35, bite * w);
|
|
384
|
-
}
|
|
385
|
-
if (reach > 0) {
|
|
386
|
-
for (let i = 0; i < 2; i++) {
|
|
387
|
-
const Ld = e.legs[i].def;
|
|
388
|
-
const tp = tv().copy(e.fr.shC).addScaledVector(fwd, ahead * s).addScaledVector(lat, Ld.s * Ld.cx);
|
|
389
|
-
tp.y = e.terrainH(tp.x, tp.z) + up * s;
|
|
390
|
-
const k = reach * w;
|
|
391
|
-
P.legs[i].target.lerp(tp, k / Math.max(1e-3, P.legs[i].reach + k));
|
|
392
|
-
mxLeg(P, i, 'reach', 1, k);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
},
|
|
396
|
-
};
|
|
397
|
-
|
|
398
|
-
// hit: the built-in flinch (and push), then the arched-back threat with bristling fur and a hiss
|
|
399
|
-
const hit = {
|
|
400
|
-
kind: 'oneshot', fade: 0.12,
|
|
401
|
-
start(inst, L) {
|
|
402
|
-
ONESHOTS.hit.start(inst, L);
|
|
403
|
-
inst.dur = 2.6;
|
|
404
|
-
B(L.engine).hitAfter = 6;
|
|
405
|
-
},
|
|
406
|
-
update(inst) { return inst.t >= inst.dur; },
|
|
407
|
-
apply(P, w, inst, L) {
|
|
408
|
-
const e = L.engine, t = inst.t;
|
|
409
|
-
ONESHOTS.hit.apply(P, w, inst, L);
|
|
410
|
-
// the arch: back humped high, legs stiff and straight, body raised, head low with the ears flat
|
|
411
|
-
// back, mouth open in a hiss, fur (and the tail: bottle brush) standing on end
|
|
412
|
-
const a = smooth(0.18, 0.55, t) * (1 - smooth(2.0, 2.6, t)) * w;
|
|
413
|
-
mx(P, 'flex', 0.82, a); mx(P, 'dropF', -0.12, a); mx(P, 'dropH', -0.16, a);
|
|
414
|
-
mx(P, 'fwd', -0.012 / U(e), a);
|
|
415
|
-
mx(P, 'headRaise', -0.03 / U(e) * 0.5, a); mx(P, 'headPitch', 0.05, a); mx(P, 'lookW', 0.6, a);
|
|
416
|
-
mx(P, 'tailLift', 0.85, a); mx(P, 'tailStiff', 2.0, a); mx(P, 'tailIdle', 0, a); mx(P, 'tailGround', 0, a); // (the tail upright: 2.2 swung it forward over the back and tore the skin under its root)
|
|
417
|
-
mx(P, 'earFlat', 0.55, a); mx(P, 'earTwitch', 0, a); // (0.65 stretched the crown between the ears > 3x)
|
|
418
|
-
const hiss = smooth(0.45, 0.6, t) * (1 - smooth(1.3, 1.55, t));
|
|
419
|
-
mx(P, 'jaw', 0.42, hiss * w); mx(P, 'jawOmega', 30, w);
|
|
420
|
-
mx(P, 'eyelid', 0.15, a);
|
|
421
|
-
P.furRaise = Math.max(P.furRaise, smooth(0.15, 0.4, t) * (1 - smooth(2.1, 2.6, t)) * w);
|
|
422
|
-
mx(P, 'legGait', 0, a * 0.6);
|
|
423
|
-
},
|
|
424
|
-
};
|
|
425
|
-
|
|
426
|
-
// loaf: sternal, every paw tucked out of sight under the body, tail along the flank, eyes half shut
|
|
427
|
-
const o_ = { foreBack: 0.09, hindFwd: 0.28, hindIn: 0.35 };
|
|
428
|
-
const loaf = {
|
|
429
|
-
kind: 'posture', fadeIn: 1.3, fadeOut: 1.0,
|
|
430
|
-
apply(P, w, inst, L) {
|
|
431
|
-
const e = L.engine, cfg = e.cfg, fr = e.fr;
|
|
432
|
-
POSTURES.lie.apply(P, w, inst, L);
|
|
433
|
-
// forepaws tucked back under the chest, the hind paws under the thighs: nothing shows but a round loaf
|
|
434
|
-
// (the forepaws 5 % of a leg behind the shoulder showed under the chest front, the hind paws beside the flank)
|
|
435
|
-
const k = smooth(0.2, 0.9, w);
|
|
436
|
-
for (let i = 0; i < 4; i++) {
|
|
437
|
-
const Ld = e.legs[i].def, front = i < 2;
|
|
438
|
-
const tp = front ? e.bodyToWorld(Ld.cx * Ld.s * 0.75, 0, cfg.zS - o_.foreBack * Ld.len, e.heading, e.pos, tv())
|
|
439
|
-
: e.bodyToWorld(Ld.cx * Ld.s * 1.1, 0, cfg.zH + o_.hindFwd * Ld.len, e.heading, e.pos, tv());
|
|
440
|
-
tp.y = e.terrainH(tp.x, tp.z) + 0.01 * cfg.s;
|
|
441
|
-
P.legs[i].target.copy(tp);
|
|
442
|
-
// (the hind legs keep the lie's fold, the metatarsus flat on the ground, and draw their paws half way in:
|
|
443
|
-
// reaching all the way, the free hock stood out of the flank)
|
|
444
|
-
mxLeg(P, i, 'reach', front ? 1 : o_.hindIn, k);
|
|
445
|
-
if (front) mxLeg(P, i, 'fold', 0, k);
|
|
446
|
-
}
|
|
447
|
-
const c = smooth(0.6, 1.8, inst.t) * w;
|
|
448
|
-
// the tail wrapped forward along the flank (swept out sideways it lay out behind with the tip up)
|
|
449
|
-
mx(P, 'tailSide', 0, c); mx(P, 'tailCurl', inst.side * 3.2, c); mx(P, 'tailStiff', 0.6, c); mx(P, 'tailGround', 0.9, c);
|
|
450
|
-
mx(P, 'headRaise', -0.01 / U(e), c); mx(P, 'headPitch', 0.12, c);
|
|
451
|
-
mx(P, 'eyelid', 0.45, smooth(2, 4, inst.t) * w);
|
|
452
|
-
mx(P, 'breathRate', 0.7, c);
|
|
453
|
-
void fr;
|
|
454
|
-
},
|
|
455
|
-
};
|
|
456
|
-
|
|
457
|
-
// groom: sits back, lifts a forepaw to the mouth and licks it, then wipes it over the ear and face
|
|
458
|
-
const groom = {
|
|
459
|
-
kind: 'oneshot', fade: 0.4,
|
|
460
|
-
start(inst, L) {
|
|
461
|
-
inst.dur = inst.opts.loop ? Infinity : (inst.opts.duration ?? 6.5);
|
|
462
|
-
inst.side = inst.opts.side ?? (L.engine.rand() < 0.5 ? 1 : -1);
|
|
463
|
-
inst.sitTune = { ...(L.engine.cfg.actions.sit || {}) };
|
|
464
|
-
},
|
|
465
|
-
update(inst) { return inst.t >= inst.dur; },
|
|
466
|
-
apply(P, w, inst, L) {
|
|
467
|
-
const e = L.engine, cfg = e.cfg, t = inst.t, s = cfg.s;
|
|
468
|
-
// sit down for it (unless already sitting)
|
|
469
|
-
const sitW = smooth(0, 1.0, t) * (1 - smooth(inst.dur - 0.9, inst.dur, t)) * w;
|
|
470
|
-
if (!posture(L, 'sit')) POSTURES.sit.apply(P, sitW, { tune: inst.sitTune, side: -inst.side, t }, L);
|
|
471
|
-
const up = smooth(0.8, 1.4, t) * (1 - smooth(inst.dur - 1.2, inst.dur - 0.6, t)) * w;
|
|
472
|
-
if (up <= 0) return;
|
|
473
|
-
const i = inst.side > 0 ? 0 : 1; // the paw on this side
|
|
474
|
-
// cycle: lick the paw 4 times (~0.3 s each), then 2 wipes over the ear and down the cheek
|
|
475
|
-
const cyc = (t - 1.4) % 2.6, lick = cyc < 1.3, wipe = !lick ? (cyc - 1.3) / 1.3 : 0;
|
|
476
|
-
const fwd = e.forward(e.heading, tv()), lat = e.left(e.heading, tv());
|
|
477
|
-
const hp = e.headPose.position;
|
|
478
|
-
const tp = tv().copy(hp).addScaledVector(fwd, 0.062 * s).addScaledVector(lat, inst.side * 0.006 * s);
|
|
479
|
-
tp.y = hp.y - 0.068 * s;
|
|
480
|
-
if (!lick) {
|
|
481
|
-
// wipe: the paw rises past the ear and draws down over the cheek (the head turns into it)
|
|
482
|
-
const u = Math.sin(Math.PI * wipe);
|
|
483
|
-
tp.addScaledVector(lat, inst.side * 0.012 * s * u).addScaledVector(fwd, -0.006 * s * u);
|
|
484
|
-
tp.y += 0.014 * s * u;
|
|
485
|
-
}
|
|
486
|
-
P.legs[i].target.lerp(tp, up / Math.max(1e-3, P.legs[i].reach + up));
|
|
487
|
-
mxLeg(P, i, 'reach', 1, up * 0.7);
|
|
488
|
-
mx(P, 'lookW', 0, up);
|
|
489
|
-
if (lick) {
|
|
490
|
-
// head down to the paw, the tongue (jaw) flicking
|
|
491
|
-
mx(P, 'headPitch', 0.7 + 0.1 * Math.sin(t * TAU * 3.2), up); mx(P, 'headYaw', inst.side * 0.25, up);
|
|
492
|
-
mx(P, 'jaw', 0.05 + 0.1 * Math.max(0, Math.sin(t * TAU * 3.2)), up); mx(P, 'jawOmega', 30, up);
|
|
493
|
-
mx(P, 'eyelid', 0.55, up);
|
|
494
|
-
} else {
|
|
495
|
-
mx(P, 'headPitch', 0.35, up); mx(P, 'headYaw', inst.side * 0.45 * Math.sin(Math.PI * wipe), up);
|
|
496
|
-
mx(P, 'headRoll', inst.side * 0.28 * Math.sin(Math.PI * wipe), up);
|
|
497
|
-
mx(P, 'earFlat', 0.4 * Math.sin(Math.PI * wipe), up);
|
|
498
|
-
mx(P, 'eyelid', 0.8, up);
|
|
499
|
-
}
|
|
500
|
-
mx(P, 'headRaise', -0.004 / U(e), up);
|
|
501
|
-
},
|
|
502
|
-
};
|
|
503
|
-
|
|
504
|
-
// knead: treads the forepaws alternately (~1.5 Hz), eyes half shut
|
|
505
|
-
const knead = {
|
|
506
|
-
kind: 'oneshot', fade: 0.3, needsStand: true,
|
|
507
|
-
start(inst) { inst.dur = inst.opts.loop ? Infinity : (inst.opts.duration ?? 4); },
|
|
508
|
-
update(inst) { return inst.t >= inst.dur; },
|
|
509
|
-
apply(P, w, inst, L) {
|
|
510
|
-
const e = L.engine, s = e.cfg.s, t = inst.t;
|
|
511
|
-
mx(P, 'gaitW', 0, w); mx(P, 'legGait', 0, w);
|
|
512
|
-
mx(P, 'dropF', 0.25, w); mx(P, 'eyelid', 0.6, w); mx(P, 'tailLift', 0.4, w);
|
|
513
|
-
const k = w * smooth(0.2, 0.5, t) * (1 - smooth(inst.dur - 0.4, inst.dur, t));
|
|
514
|
-
for (let i = 0; i < 2; i++) {
|
|
515
|
-
const ph = t * TAU * 1.5 + (i ? Math.PI : 0);
|
|
516
|
-
const lift = Math.max(0, Math.sin(ph));
|
|
517
|
-
const tp = tv().copy(e.legs[i].plant);
|
|
518
|
-
tp.y += 0.018 * s * lift;
|
|
519
|
-
tp.addScaledVector(e.forward(e.heading, tv()), 0.006 * s * lift);
|
|
520
|
-
P.legs[i].target.copy(tp);
|
|
521
|
-
mxLeg(P, i, 'reach', 1, k);
|
|
522
|
-
}
|
|
523
|
-
},
|
|
524
|
-
};
|
|
525
|
-
|
|
526
|
-
// stalk: the crouched creep (drive it with a slow walk): belly low, shoulders up, head low and
|
|
527
|
-
// forward, tail low with its tip twitching, eyes on the target
|
|
528
|
-
const stalk = {
|
|
529
|
-
kind: 'oneshot', fade: 0.5,
|
|
530
|
-
start(inst) { inst.dur = inst.opts.loop ? Infinity : (inst.opts.duration ?? 5); },
|
|
531
|
-
update(inst) { return inst.t >= inst.dur; },
|
|
532
|
-
apply(P, w, inst, L) {
|
|
533
|
-
const e = L.engine;
|
|
534
|
-
// (the rump as low as the chest: a back rising from low shoulders to the loin read as the opposite of
|
|
535
|
-
// the stalking photo's high shoulder blades)
|
|
536
|
-
mx(P, 'dropF', 0.42, w); mx(P, 'dropH', 0.46, w);
|
|
537
|
-
mx(P, 'headRaise', -0.03 / U(e) * 0.45, w); mx(P, 'neckReach', 0.01 / U(e), w); mx(P, 'headPitch', -0.08, w);
|
|
538
|
-
mx(P, 'speedScale', 0.5, w);
|
|
539
|
-
if (inst.opts.target) { P.look = inst.opts.target; mx(P, 'lookW', 1, w); }
|
|
540
|
-
},
|
|
541
|
-
};
|
|
542
|
-
|
|
543
|
-
// slowblink on demand
|
|
544
|
-
const slowblink = {
|
|
545
|
-
kind: 'oneshot', fade: 0.2,
|
|
546
|
-
start(inst, L) { inst.dur = 2.3; B(L.engine).blinkT = 0; },
|
|
547
|
-
update(inst) { return inst.t >= inst.dur; },
|
|
548
|
-
apply() {},
|
|
549
|
-
};
|
|
550
|
-
|
|
551
|
-
export const hooks = {
|
|
552
|
-
update, pose,
|
|
553
|
-
actions: {
|
|
554
|
-
attack, hit, loaf, groom, knead, stalk, slowblink,
|
|
555
|
-
// (a light animal gets up from its side quickly: over the default 1.6 s a hind paw re-stepped
|
|
556
|
-
// while the lying leg pose still held it and landed with a jump on a slope)
|
|
557
|
-
death: { ...POSTURES.death, kind: 'posture', fadeOut: 1.2 },
|
|
558
|
-
},
|
|
559
|
-
};
|