@voqalize/avatar 0.2.2 → 0.4.0
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/LICENSE +21 -661
- package/LICENSE-CC-BY-4.0 +396 -0
- package/README.md +191 -662
- package/assets/README.md +48 -0
- package/assets/tanya.glb +0 -0
- package/assets/tara.glb +0 -0
- package/assets/tushar.glb +0 -0
- package/client/Avatar.tsx +57 -0
- package/client/AvatarClient.ts +818 -0
- package/client/arjun.ts +26 -0
- package/client/createAvatar.ts +177 -0
- package/client/createCanvasAvatar.ts +72 -0
- package/client/index.ts +44 -0
- package/client/internal.ts +108 -0
- package/client/interviewer-female.ts +4 -0
- package/client/interviewer-male.ts +4 -0
- package/client/ishita.ts +26 -0
- package/client/kabir.ts +26 -0
- package/client/meera.ts +26 -0
- package/client/naina.ts +26 -0
- package/client/playout.ts +95 -0
- package/client/professional-female-a.ts +4 -0
- package/client/professional-female-b.ts +4 -0
- package/client/professional-male-a.ts +4 -0
- package/client/professional-male-b.ts +4 -0
- package/client/react.ts +13 -0
- package/client/supports.ts +28 -0
- package/client/three/assets.ts +24 -0
- package/client/three/budgets.ts +27 -0
- package/client/three/holds.ts +64 -0
- package/client/three/internal.ts +54 -0
- package/client/three/motion-limits.json +116 -0
- package/client/three/sequences.ts +281 -0
- package/client/three/tanya.ts +69 -0
- package/client/three/tara-rig.ts +1562 -0
- package/client/three/tara.ts +76 -0
- package/client/three/tushar.ts +65 -0
- package/client/types.ts +235 -0
- package/client/useAvatar.ts +74 -0
- package/client/vikram.ts +26 -0
- package/dist/Avatar.d.ts +44 -0
- package/dist/Avatar.d.ts.map +1 -0
- package/{client/dist → dist}/Avatar.js +2 -2
- package/dist/Avatar.js.map +1 -0
- package/dist/AvatarClient.d.ts +274 -0
- package/dist/AvatarClient.d.ts.map +1 -0
- package/dist/AvatarClient.js +712 -0
- package/dist/AvatarClient.js.map +1 -0
- package/dist/arjun.d.ts +7 -0
- package/dist/arjun.d.ts.map +1 -0
- package/dist/arjun.js +20 -0
- package/dist/arjun.js.map +1 -0
- package/dist/createAvatar.d.ts +135 -0
- package/dist/createAvatar.d.ts.map +1 -0
- package/dist/createAvatar.js +75 -0
- package/dist/createAvatar.js.map +1 -0
- package/dist/createCanvasAvatar.d.ts +22 -0
- package/dist/createCanvasAvatar.d.ts.map +1 -0
- package/dist/createCanvasAvatar.js +47 -0
- package/dist/createCanvasAvatar.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/internal.d.ts +34 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +41 -0
- package/dist/internal.js.map +1 -0
- package/dist/interviewer-female.d.ts +4 -0
- package/dist/interviewer-female.d.ts.map +1 -0
- package/dist/interviewer-female.js +3 -0
- package/dist/interviewer-female.js.map +1 -0
- package/dist/interviewer-male.d.ts +4 -0
- package/dist/interviewer-male.d.ts.map +1 -0
- package/dist/interviewer-male.js +3 -0
- package/dist/interviewer-male.js.map +1 -0
- package/dist/ishita.d.ts +7 -0
- package/dist/ishita.d.ts.map +1 -0
- package/dist/ishita.js +20 -0
- package/dist/ishita.js.map +1 -0
- package/dist/kabir.d.ts +7 -0
- package/dist/kabir.d.ts.map +1 -0
- package/dist/kabir.js +20 -0
- package/dist/kabir.js.map +1 -0
- package/dist/meera.d.ts +7 -0
- package/dist/meera.d.ts.map +1 -0
- package/dist/meera.js +20 -0
- package/dist/meera.js.map +1 -0
- package/dist/naina.d.ts +7 -0
- package/dist/naina.d.ts.map +1 -0
- package/dist/naina.js +20 -0
- package/dist/naina.js.map +1 -0
- package/dist/playout.d.ts +42 -0
- package/dist/playout.d.ts.map +1 -0
- package/dist/playout.js +85 -0
- package/dist/playout.js.map +1 -0
- package/dist/professional-female-a.d.ts +4 -0
- package/dist/professional-female-a.d.ts.map +1 -0
- package/dist/professional-female-a.js +3 -0
- package/dist/professional-female-a.js.map +1 -0
- package/dist/professional-female-b.d.ts +4 -0
- package/dist/professional-female-b.d.ts.map +1 -0
- package/dist/professional-female-b.js +3 -0
- package/dist/professional-female-b.js.map +1 -0
- package/dist/professional-male-a.d.ts +4 -0
- package/dist/professional-male-a.d.ts.map +1 -0
- package/dist/professional-male-a.js +3 -0
- package/dist/professional-male-a.js.map +1 -0
- package/dist/professional-male-b.d.ts +4 -0
- package/dist/professional-male-b.d.ts.map +1 -0
- package/dist/professional-male-b.js +3 -0
- package/dist/professional-male-b.js.map +1 -0
- package/dist/react.d.ts +13 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +13 -0
- package/dist/react.js.map +1 -0
- package/dist/supports.d.ts +20 -0
- package/dist/supports.d.ts.map +1 -0
- package/dist/supports.js +26 -0
- package/dist/supports.js.map +1 -0
- package/dist/three/assets.d.ts +24 -0
- package/dist/three/assets.d.ts.map +1 -0
- package/dist/three/assets.js +22 -0
- package/dist/three/assets.js.map +1 -0
- package/dist/three/budgets.d.ts +17 -0
- package/dist/three/budgets.d.ts.map +1 -0
- package/dist/three/budgets.js +21 -0
- package/dist/three/budgets.js.map +1 -0
- package/dist/three/holds.d.ts +33 -0
- package/dist/three/holds.d.ts.map +1 -0
- package/dist/three/holds.js +56 -0
- package/dist/three/holds.js.map +1 -0
- package/dist/three/internal.d.ts +52 -0
- package/dist/three/internal.d.ts.map +1 -0
- package/dist/three/internal.js +49 -0
- package/dist/three/internal.js.map +1 -0
- package/dist/three/motion-limits.json +116 -0
- package/dist/three/sequences.d.ts +71 -0
- package/dist/three/sequences.d.ts.map +1 -0
- package/dist/three/sequences.js +262 -0
- package/dist/three/sequences.js.map +1 -0
- package/dist/three/tanya.d.ts +35 -0
- package/dist/three/tanya.d.ts.map +1 -0
- package/dist/three/tanya.js +51 -0
- package/dist/three/tanya.js.map +1 -0
- package/dist/three/tara-rig.d.ts +403 -0
- package/dist/three/tara-rig.d.ts.map +1 -0
- package/dist/three/tara-rig.js +1500 -0
- package/dist/three/tara-rig.js.map +1 -0
- package/dist/three/tara.d.ts +35 -0
- package/dist/three/tara.d.ts.map +1 -0
- package/dist/three/tara.js +58 -0
- package/dist/three/tara.js.map +1 -0
- package/dist/three/tushar.d.ts +31 -0
- package/dist/three/tushar.d.ts.map +1 -0
- package/dist/three/tushar.js +47 -0
- package/dist/three/tushar.js.map +1 -0
- package/dist/types.d.ts +149 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +140 -0
- package/dist/types.js.map +1 -0
- package/dist/useAvatar.d.ts +39 -0
- package/dist/useAvatar.d.ts.map +1 -0
- package/dist/useAvatar.js +35 -0
- package/dist/useAvatar.js.map +1 -0
- package/dist/vikram.d.ts +7 -0
- package/dist/vikram.d.ts.map +1 -0
- package/dist/vikram.js +20 -0
- package/dist/vikram.js.map +1 -0
- package/package.json +110 -25
- package/src/avatar.d.ts +218 -120
- package/src/avatar.js +950 -213
- package/src/behavior.d.ts +42 -0
- package/src/behavior.js +114 -0
- package/src/camera.js +29 -0
- package/src/canvas/author/parts/eye.mjs +722 -0
- package/src/canvas/author/parts/hand.mjs +1156 -0
- package/src/canvas/author/parts/mouth.mjs +741 -0
- package/src/canvas/author/parts/nose.mjs +100 -0
- package/src/canvas/author/parts/skin-detail.mjs +67 -0
- package/src/canvas/author/path.mjs +283 -0
- package/src/canvas/author/rig.mjs +405 -0
- package/src/canvas/avatars/round/face.d.mts +3 -0
- package/src/canvas/avatars/round/face.mjs +1307 -0
- package/src/canvas/create-rig.d.ts +15 -0
- package/src/canvas/create-rig.js +100 -0
- package/src/canvas/data/img/professional-female-a-hair-back.webp +0 -0
- package/src/canvas/data/img/professional-female-a-hair-front.webp +0 -0
- package/src/canvas/data/img/professional-female-a-top-body.webp +0 -0
- package/src/canvas/data/img/professional-female-b-hair-back.webp +0 -0
- package/src/canvas/data/img/professional-female-b-hair-front.webp +0 -0
- package/src/canvas/data/img/professional-female-b-top-body.webp +0 -0
- package/src/canvas/data/img/professional-male-a-hair-back.webp +0 -0
- package/src/canvas/data/img/professional-male-a-hair-front.webp +0 -0
- package/src/canvas/data/img/professional-male-a-top-body.webp +0 -0
- package/src/canvas/data/img/professional-male-b-hair-back.webp +0 -0
- package/src/canvas/data/img/professional-male-b-hair-front.webp +0 -0
- package/src/canvas/data/img/professional-male-b-top-body.webp +0 -0
- package/src/canvas/data/img/round-m3-hair-back.webp +0 -0
- package/src/canvas/data/img/round-m3-hair-front.webp +0 -0
- package/src/canvas/data/img/round-m3-top-body.webp +0 -0
- package/src/canvas/data/img/round-w1-hair-back.webp +0 -0
- package/src/canvas/data/img/round-w1-hair-front.webp +0 -0
- package/src/canvas/data/img/round-w1-top-body.webp +0 -0
- package/src/canvas/data/interviewer-female.rig.json +1 -0
- package/src/canvas/data/interviewer-male.rig.json +1 -0
- package/src/canvas/data/professional-female-a.rig.json +1 -0
- package/src/canvas/data/professional-female-b.rig.json +1 -0
- package/src/canvas/data/professional-male-a.rig.json +1 -0
- package/src/canvas/data/professional-male-b.rig.json +1 -0
- package/src/canvas/src/live.js +508 -0
- package/src/canvas/src/render2d.js +218 -0
- package/src/canvas/src/rig.js +297 -0
- package/src/canvas/src/vocab.js +96 -0
- package/src/clips.js +18 -7
- package/src/conformance.js +119 -0
- package/src/emotions.js +8 -5
- package/src/face-core.js +27 -1
- package/src/face-myna.d.ts +7 -0
- package/src/face-myna.js +192 -131
- package/src/face-peep-control-plane.js +167 -0
- package/src/face-peep.d.ts +7 -0
- package/src/face-peep.js +274 -116
- package/src/face-wren.d.ts +7 -0
- package/src/face-wren.js +17 -19
- package/src/faces.d.ts +12 -0
- package/src/faces.js +53 -0
- package/src/gaze.js +434 -58
- package/src/hand.js +120 -91
- package/src/head.js +134 -0
- package/src/idle.js +227 -119
- package/src/interjections.js +200 -31
- package/src/params.js +8 -4
- package/src/perform.js +7 -9
- package/src/prosody.js +647 -0
- package/src/rig.d.ts +24 -0
- package/src/rig.js +32 -0
- package/src/speech-timing.js +23 -0
- package/src/visemes.js +110 -24
- package/client/dist/Avatar.d.ts +0 -27
- package/client/dist/Avatar.d.ts.map +0 -1
- package/client/dist/Avatar.js.map +0 -1
- package/client/dist/AvatarClient.d.ts +0 -139
- package/client/dist/AvatarClient.d.ts.map +0 -1
- package/client/dist/AvatarClient.js +0 -223
- package/client/dist/AvatarClient.js.map +0 -1
- package/client/dist/index.d.ts +0 -22
- package/client/dist/index.d.ts.map +0 -1
- package/client/dist/index.js +0 -22
- package/client/dist/index.js.map +0 -1
- package/client/dist/types.d.ts +0 -86
- package/client/dist/types.d.ts.map +0 -1
- package/client/dist/types.js +0 -31
- package/client/dist/types.js.map +0 -1
- package/client/dist/useAvatar.d.ts +0 -42
- package/client/dist/useAvatar.d.ts.map +0 -1
- package/client/dist/useAvatar.js +0 -51
- package/client/dist/useAvatar.js.map +0 -1
- package/client/src/Avatar.tsx +0 -33
- package/client/src/AvatarClient.ts +0 -270
- package/client/src/index.ts +0 -22
- package/client/src/types.ts +0 -104
- package/client/src/useAvatar.ts +0 -85
- package/docs/contract-avatar.md +0 -371
- package/docs/contract-protocol.md +0 -461
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How far each character may hold its head off centre, as the mixer wants it:
|
|
3
|
+
* pose units per axis, ready to hand to `createSvgAvatar` as `headHold`.
|
|
4
|
+
*
|
|
5
|
+
* The angles themselves are in `motion-limits.json` and are only
|
|
6
|
+
* there. They were read off the three faces by the person who owns how they
|
|
7
|
+
* look, one axis at a time, at the surface a call actually shows — which is
|
|
8
|
+
* the only way this kind of number can be got, and the reason nothing here
|
|
9
|
+
* recomputes, adjusts or second-guesses one. This file is the unit change and
|
|
10
|
+
* nothing else.
|
|
11
|
+
*
|
|
12
|
+
* An axis the file marks for re-measurement is not enforced: it was read off an
|
|
13
|
+
* asset that has since been fixed, and holding the driver to a defect that no
|
|
14
|
+
* longer exists is worse than the defect. It falls back to the tightest angle
|
|
15
|
+
* still live on that axis across the other characters instead of falling out of
|
|
16
|
+
* the budget altogether, which is what it used to do. That is not a way of
|
|
17
|
+
* believing the stale number by the back door — it is the same budget the
|
|
18
|
+
* faces nobody has any doubt about are already held to. Dropping the axis made
|
|
19
|
+
* the one face nobody can currently vouch for the only one driven with no
|
|
20
|
+
* budget at all, and speech asks for about nine degrees of yaw before a budget
|
|
21
|
+
* trims it.
|
|
22
|
+
*/
|
|
23
|
+
import LIMITS from "./motion-limits.json" with { type: "json" };
|
|
24
|
+
import { HEAD_CLAMP, HEAD_DEG } from "./tara-rig.js";
|
|
25
|
+
/** Degrees of each axis per pose unit, which is `HEAD_DEG` at the clamp. */
|
|
26
|
+
const PER_UNIT = {
|
|
27
|
+
headYaw: HEAD_DEG.yaw / HEAD_CLAMP,
|
|
28
|
+
headPitch: HEAD_DEG.pitch / HEAD_CLAMP,
|
|
29
|
+
headRoll: HEAD_DEG.roll / HEAD_CLAMP,
|
|
30
|
+
};
|
|
31
|
+
const AXIS = { headYaw: "yaw", headPitch: "pitch", headRoll: "roll" };
|
|
32
|
+
/** What the file says about one character's axis, if it says anything live. */
|
|
33
|
+
const live = (name, axis) => {
|
|
34
|
+
const measured = LIMITS.characters[name];
|
|
35
|
+
const entry = measured?.[axis];
|
|
36
|
+
return entry && !entry.remeasure ? entry : undefined;
|
|
37
|
+
};
|
|
38
|
+
/** The tightest angle any character is still vouched for on this axis. */
|
|
39
|
+
function safest(axis) {
|
|
40
|
+
const angles = Object.keys(LIMITS.characters)
|
|
41
|
+
.map((name) => live(name, axis)?.safe)
|
|
42
|
+
.filter((deg) => deg !== undefined);
|
|
43
|
+
return angles.length ? Math.min(...angles) : undefined;
|
|
44
|
+
}
|
|
45
|
+
/** `name` as the limits file spells it: tara, tushar, tanya. */
|
|
46
|
+
export function headHold(name) {
|
|
47
|
+
const out = {};
|
|
48
|
+
for (const channel of Object.keys(AXIS)) {
|
|
49
|
+
const axis = AXIS[channel];
|
|
50
|
+
const deg = live(name, axis)?.safe ?? safest(axis);
|
|
51
|
+
if (deg !== undefined)
|
|
52
|
+
out[channel] = deg / PER_UNIT[channel];
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=holds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"holds.js","sourceRoot":"","sources":["../../client/three/holds.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,MAAM,MAAM,sBAAsB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAErD,4EAA4E;AAC5E,MAAM,QAAQ,GAAG;IACf,OAAO,EAAE,QAAQ,CAAC,GAAG,GAAG,UAAU;IAClC,SAAS,EAAE,QAAQ,CAAC,KAAK,GAAG,UAAU;IACtC,QAAQ,EAAE,QAAQ,CAAC,IAAI,GAAG,UAAU;CAC5B,CAAC;AAEX,MAAM,IAAI,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAW,CAAC;AAM/E,+EAA+E;AAC/E,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,IAAY,EAAwB,EAAE;IAChE,MAAM,QAAQ,GAAI,MAAM,CAAC,UAAsD,CAAC,IAAI,CAAC,CAAC;IACtF,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAyB,CAAC;IACvD,OAAO,KAAK,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC,CAAC;AAEF,0EAA0E;AAC1E,SAAS,MAAM,CAAC,IAAY;IAC1B,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;SAC1C,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;SACrC,MAAM,CAAC,CAAC,GAAG,EAAiB,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC;IACrD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACzD,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,QAAQ,CAAC,IAAoC;IAC3D,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAA0B,EAAE,CAAC;QACjE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;QACnD,IAAI,GAAG,KAAK,SAAS;YAAE,GAAG,CAAC,OAAO,CAAC,GAAG,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The 2.5-D rig, below the `createAvatar` modules — `/internal`, no semver promise.
|
|
3
|
+
*
|
|
4
|
+
* `tara.ts`, `tushar.ts` and `tanya.ts` are what a consumer gets: one
|
|
5
|
+
* `createAvatar` each, the mixer behind it, nothing to configure. This is the
|
|
6
|
+
* other door, for a page whose subject is the *rig* rather than the call — the
|
|
7
|
+
* renderer with no mixer in front of it, the three compiled characters, and the
|
|
8
|
+
* head envelope their channels are scaled by. Its readers are the rig instruments
|
|
9
|
+
* in the working tree, and nothing that ships.
|
|
10
|
+
*
|
|
11
|
+
* It exists because those instruments were reaching around the package instead,
|
|
12
|
+
* by relative path into its source, and two of them carried their own copy of
|
|
13
|
+
* the head envelope — with a comment saying the copy would quietly lie the day
|
|
14
|
+
* the envelope moved. It moved on 2026-09-18. One export is cheaper than that
|
|
15
|
+
* warning, and it is the same `/internal` spelling this package already uses for
|
|
16
|
+
* the mixer.
|
|
17
|
+
*/
|
|
18
|
+
export { ASSETS as CHARACTERS } from "./assets.js";
|
|
19
|
+
export type { CharacterName } from "./assets.js";
|
|
20
|
+
export { createTaraRig, EYE_DEG, HEAD_CLAMP, HEAD_DEG, TARA_TUNING } from "./tara-rig.js";
|
|
21
|
+
export type { TaraRigOptions } from "./tara-rig.js";
|
|
22
|
+
export { HARD_BUDGET, pixelRatioFor, SHIPPING_SURFACE } from "./budgets.js";
|
|
23
|
+
/**
|
|
24
|
+
* The authored motion tables these characters are driven by.
|
|
25
|
+
*
|
|
26
|
+
* `tara.ts` and its siblings hand them to the mixer and nobody else sees them,
|
|
27
|
+
* which is right for a consumer: a face's clips are not a configuration. An
|
|
28
|
+
* instrument that drives the mixer directly — a scripted take, where the script
|
|
29
|
+
* *is* the server — needs the same two tables, and the alternative was a
|
|
30
|
+
* relative import into the package's own source of the kind this file exists to
|
|
31
|
+
* end.
|
|
32
|
+
*/
|
|
33
|
+
export { BLENDER_ACTIONS, BLENDER_SEQUENCES, BLENDER_SUPPORTS } from "./sequences.js";
|
|
34
|
+
/**
|
|
35
|
+
* The head budget each character is driven under, and the measurements it comes
|
|
36
|
+
* from.
|
|
37
|
+
*
|
|
38
|
+
* An instrument that watches a character move has to mount the *shipping*
|
|
39
|
+
* character or it is watching something else, and `headHold` is the one option
|
|
40
|
+
* `tara.ts` passes that a lab page would otherwise have to guess at — the
|
|
41
|
+
* budget is load-bearing, not a margin: speech asks for about nine degrees of
|
|
42
|
+
* yaw before it trims one. The limits themselves come along because a page that
|
|
43
|
+
* plots degrees has to draw the band, and reading it out of the same file the
|
|
44
|
+
* budget is derived from is the only way the two cannot disagree.
|
|
45
|
+
*
|
|
46
|
+
* Read-only, both of them. Nothing here recomputes a measured angle
|
|
47
|
+
* (`holds.ts`).
|
|
48
|
+
*/
|
|
49
|
+
export { headHold } from "./holds.js";
|
|
50
|
+
export type { HeadHold } from "./holds.js";
|
|
51
|
+
export { default as MOTION_LIMITS } from "./motion-limits.json";
|
|
52
|
+
//# sourceMappingURL=internal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../client/three/internal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC1F,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAE5E;;;;;;;;;GASG;AACH,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEtF;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,sBAAsB,CAAuB"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The 2.5-D rig, below the `createAvatar` modules — `/internal`, no semver promise.
|
|
3
|
+
*
|
|
4
|
+
* `tara.ts`, `tushar.ts` and `tanya.ts` are what a consumer gets: one
|
|
5
|
+
* `createAvatar` each, the mixer behind it, nothing to configure. This is the
|
|
6
|
+
* other door, for a page whose subject is the *rig* rather than the call — the
|
|
7
|
+
* renderer with no mixer in front of it, the three compiled characters, and the
|
|
8
|
+
* head envelope their channels are scaled by. Its readers are the rig instruments
|
|
9
|
+
* in the working tree, and nothing that ships.
|
|
10
|
+
*
|
|
11
|
+
* It exists because those instruments were reaching around the package instead,
|
|
12
|
+
* by relative path into its source, and two of them carried their own copy of
|
|
13
|
+
* the head envelope — with a comment saying the copy would quietly lie the day
|
|
14
|
+
* the envelope moved. It moved on 2026-09-18. One export is cheaper than that
|
|
15
|
+
* warning, and it is the same `/internal` spelling this package already uses for
|
|
16
|
+
* the mixer.
|
|
17
|
+
*/
|
|
18
|
+
export { ASSETS as CHARACTERS } from "./assets.js";
|
|
19
|
+
export { createTaraRig, EYE_DEG, HEAD_CLAMP, HEAD_DEG, TARA_TUNING } from "./tara-rig.js";
|
|
20
|
+
export { HARD_BUDGET, pixelRatioFor, SHIPPING_SURFACE } from "./budgets.js";
|
|
21
|
+
/**
|
|
22
|
+
* The authored motion tables these characters are driven by.
|
|
23
|
+
*
|
|
24
|
+
* `tara.ts` and its siblings hand them to the mixer and nobody else sees them,
|
|
25
|
+
* which is right for a consumer: a face's clips are not a configuration. An
|
|
26
|
+
* instrument that drives the mixer directly — a scripted take, where the script
|
|
27
|
+
* *is* the server — needs the same two tables, and the alternative was a
|
|
28
|
+
* relative import into the package's own source of the kind this file exists to
|
|
29
|
+
* end.
|
|
30
|
+
*/
|
|
31
|
+
export { BLENDER_ACTIONS, BLENDER_SEQUENCES, BLENDER_SUPPORTS } from "./sequences.js";
|
|
32
|
+
/**
|
|
33
|
+
* The head budget each character is driven under, and the measurements it comes
|
|
34
|
+
* from.
|
|
35
|
+
*
|
|
36
|
+
* An instrument that watches a character move has to mount the *shipping*
|
|
37
|
+
* character or it is watching something else, and `headHold` is the one option
|
|
38
|
+
* `tara.ts` passes that a lab page would otherwise have to guess at — the
|
|
39
|
+
* budget is load-bearing, not a margin: speech asks for about nine degrees of
|
|
40
|
+
* yaw before it trims one. The limits themselves come along because a page that
|
|
41
|
+
* plots degrees has to draw the band, and reading it out of the same file the
|
|
42
|
+
* budget is derived from is the only way the two cannot disagree.
|
|
43
|
+
*
|
|
44
|
+
* Read-only, both of them. Nothing here recomputes a measured angle
|
|
45
|
+
* (`holds.ts`).
|
|
46
|
+
*/
|
|
47
|
+
export { headHold } from "./holds.js";
|
|
48
|
+
export { default as MOTION_LIMITS } from "./motion-limits.json" with { type: "json" };
|
|
49
|
+
//# sourceMappingURL=internal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.js","sourceRoot":"","sources":["../../client/three/internal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AAGnD,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE1F,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAE5E;;;;;;;;;GASG;AACH,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEtF;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,sBAAsB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
{
|
|
2
|
+
"what": "How far each character may HOLD its head off centre, in degrees, measured by eye. A sustained pose is the strict case and this is the strict number: past it a static turn stops reading as a head that turned, because the eye behind a flat projection never foreshortens. `holds.ts` converts these into the mixer's pose units and `test/three/presence.test.ts` gates LISTENING and SPEAKING against them.",
|
|
3
|
+
"versus": "This is not `HEAD_DEG` and is much smaller than it. `HEAD_DEG` (tara-rig.ts) is the envelope any motion may REACH — set by where the projection itself tears, which a rendered ladder put past 21 degrees of yaw on tara. A transient that returns is forgiven what a held pose is not, so a nod may pass through an angle this file will not let the head sit at.",
|
|
4
|
+
"units": "degrees from rest, either side, per axis driven alone from rest",
|
|
5
|
+
"surface": {
|
|
6
|
+
"cssWidth": 400,
|
|
7
|
+
"cssHeight": 300,
|
|
8
|
+
"devicePixelRatio": 2,
|
|
9
|
+
"magnification": 1
|
|
10
|
+
},
|
|
11
|
+
"measured": {
|
|
12
|
+
"on": "2026-09-18",
|
|
13
|
+
"by": "owner",
|
|
14
|
+
"using": "the hold-and-move rig instrument in the working tree, which pins one axis at a fixed angle",
|
|
15
|
+
"how": "static held pose, one axis at a time from rest, judged by eye at the shipping surface",
|
|
16
|
+
"safe": "reads as a head that turned, with nothing to notice",
|
|
17
|
+
"limit": "the last angle before something is visibly wrong"
|
|
18
|
+
},
|
|
19
|
+
"characters": {
|
|
20
|
+
"tara": {
|
|
21
|
+
"yaw": {
|
|
22
|
+
"safe": 6,
|
|
23
|
+
"limit": 7
|
|
24
|
+
},
|
|
25
|
+
"pitch": {
|
|
26
|
+
"safe": 5,
|
|
27
|
+
"limit": 6
|
|
28
|
+
},
|
|
29
|
+
"roll": {
|
|
30
|
+
"safe": 6,
|
|
31
|
+
"limit": 7
|
|
32
|
+
},
|
|
33
|
+
"defects": [
|
|
34
|
+
{
|
|
35
|
+
"axis": "yaw",
|
|
36
|
+
"from": 7,
|
|
37
|
+
"what": "the eye does not foreshorten or narrow; it is what gives the turn away first"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"axis": "roll",
|
|
41
|
+
"from": 0,
|
|
42
|
+
"what": "the transition reads as a hinge rather than a neck bending, at any angle"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
"tushar": {
|
|
47
|
+
"yaw": {
|
|
48
|
+
"safe": 6,
|
|
49
|
+
"limit": 7
|
|
50
|
+
},
|
|
51
|
+
"pitch": {
|
|
52
|
+
"safe": 5,
|
|
53
|
+
"limit": 6
|
|
54
|
+
},
|
|
55
|
+
"roll": {
|
|
56
|
+
"safe": 6,
|
|
57
|
+
"limit": 7
|
|
58
|
+
},
|
|
59
|
+
"defects": [
|
|
60
|
+
{
|
|
61
|
+
"axis": "yaw",
|
|
62
|
+
"from": 7,
|
|
63
|
+
"what": "the eye does not foreshorten or narrow; it is what gives the turn away first"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"axis": "roll",
|
|
67
|
+
"from": 0,
|
|
68
|
+
"what": "the transition reads as a hinge rather than a neck bending, at any angle"
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
"tanya": {
|
|
73
|
+
"yaw": {
|
|
74
|
+
"safe": 5,
|
|
75
|
+
"limit": 5.5,
|
|
76
|
+
"remeasure": "every defect this was measured from was fixed on 2026-09-19 (8ba16e8 the neck under the jaw, 6c5c141 the hair that hangs past it), so the number is a record of the old asset and not of this one. Nothing may gate on it until the owner drives her again."
|
|
77
|
+
},
|
|
78
|
+
"pitch": {
|
|
79
|
+
"safe": 5,
|
|
80
|
+
"limit": 6
|
|
81
|
+
},
|
|
82
|
+
"roll": {
|
|
83
|
+
"safe": 1,
|
|
84
|
+
"limit": 1,
|
|
85
|
+
"remeasure": "every defect this was measured from was fixed on 2026-09-19 (8ba16e8 the neck under the jaw, 6c5c141 the hair that hangs past it), so the number is a record of the old asset and not of this one. Nothing may gate on it until the owner drives her again."
|
|
86
|
+
},
|
|
87
|
+
"defects": [
|
|
88
|
+
{
|
|
89
|
+
"axis": "yaw",
|
|
90
|
+
"from": 5.5,
|
|
91
|
+
"what": "a black area opens along the jaw line",
|
|
92
|
+
"fixed": "2026-09-19"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"axis": "yaw",
|
|
96
|
+
"from": 5.5,
|
|
97
|
+
"what": "something around the neck moves incorrectly",
|
|
98
|
+
"fixed": "2026-09-19"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"axis": "roll",
|
|
102
|
+
"from": 1,
|
|
103
|
+
"what": "a gap opens between the neck and the face on the far side",
|
|
104
|
+
"fixed": "2026-09-19"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"axis": "roll",
|
|
108
|
+
"from": 2,
|
|
109
|
+
"what": "the hair breaks up",
|
|
110
|
+
"fixed": "2026-09-19"
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"remeasure": "An axis carrying `remeasure` was measured on an asset that has since changed. It stays as written \u2014 a measurement is not edited by someone who did not make it \u2014 and a gate skips it and says so."
|
|
116
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { AvatarSupport } from "../internal.js";
|
|
2
|
+
type Keyframes = Record<string, [number, number][]>;
|
|
3
|
+
interface Sequence {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly label: string;
|
|
6
|
+
readonly text: string;
|
|
7
|
+
readonly duration: number;
|
|
8
|
+
readonly keys: Keyframes;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* What a server may address on a Blender avatar by name, beyond the two every
|
|
12
|
+
* avatar owes it.
|
|
13
|
+
*
|
|
14
|
+
* Shared by every character in this package rather than owned by tara, because
|
|
15
|
+
* they are all driven through the same 30 channels. A character that needs its
|
|
16
|
+
* own shape of one of these overrides that entry; it does not get a second
|
|
17
|
+
* table.
|
|
18
|
+
*/
|
|
19
|
+
export declare const BLENDER_SEQUENCES: Readonly<{
|
|
20
|
+
NOD_SMALL: Sequence;
|
|
21
|
+
NOD_ASSESS: Sequence;
|
|
22
|
+
NOD_REALIZE: Sequence;
|
|
23
|
+
NOD_NO: Sequence;
|
|
24
|
+
}>;
|
|
25
|
+
export type BlenderSequenceId = keyof typeof BLENDER_SEQUENCES;
|
|
26
|
+
/**
|
|
27
|
+
* The Blender avatars' own shape for one of the mixer's own actions, passed to
|
|
28
|
+
* it as `actions`. Same ids, same intent; only the rendering is theirs.
|
|
29
|
+
*
|
|
30
|
+
* **`ACK_NOD` is the continuer here.** It is the nod a server sends while the
|
|
31
|
+
* user is still talking — "mm-hm, go on" — and that is half of all nods and
|
|
32
|
+
* most of what this avatar does, because it listens far more than it speaks.
|
|
33
|
+
* The shared clip is two strokes that render 15° on this head, which is past
|
|
34
|
+
* even agreement (6–10°) and is what the owner read as the head dropping. A
|
|
35
|
+
* server that means agreement or realisation, and knows a Blender avatar is
|
|
36
|
+
* mounted, asks for `NOD_ASSESS` or `NOD_REALIZE`.
|
|
37
|
+
*
|
|
38
|
+
* Aliased rather than restated, so the continuer and the portable nod cannot
|
|
39
|
+
* drift apart.
|
|
40
|
+
*
|
|
41
|
+
* The other shared clips with head keys stay shared, because they already
|
|
42
|
+
* land inside their meaning on tara: `GESTURE_APPROVE` renders 8.8° of
|
|
43
|
+
* chin-down (agreement's band), `GESTURE_GREET` 2.9° of chin-up, and
|
|
44
|
+
* `GESTURE_WAIT` 5.2° of yaw.
|
|
45
|
+
*/
|
|
46
|
+
export declare const BLENDER_ACTIONS: Readonly<{
|
|
47
|
+
ACK_NOD: {
|
|
48
|
+
id: string;
|
|
49
|
+
label: string;
|
|
50
|
+
text: string;
|
|
51
|
+
duration: number;
|
|
52
|
+
keys: Keyframes;
|
|
53
|
+
};
|
|
54
|
+
}>;
|
|
55
|
+
/**
|
|
56
|
+
* What every character in this package answers to — each one's `supports`, the
|
|
57
|
+
* optional declaration a driving UI reads (`AvatarSupport`).
|
|
58
|
+
*
|
|
59
|
+
* Derived rather than written down, because the three parts already exist: the
|
|
60
|
+
* two ids every avatar owes a server, the mixer's own clip catalogue these
|
|
61
|
+
* characters inherit whole, and this file's own names. A hand-kept fourth copy
|
|
62
|
+
* would only be able to disagree with them. `BLENDER_ACTIONS` adds nothing —
|
|
63
|
+
* it re-shapes an id the mixer already has.
|
|
64
|
+
*
|
|
65
|
+
* It is one list for tara, tushar and tanya for the same reason the tables are:
|
|
66
|
+
* they are one rig driven through one set of channels. A character that stops
|
|
67
|
+
* being able to do one of these owes its own `supports`, not an edit here.
|
|
68
|
+
*/
|
|
69
|
+
export declare const BLENDER_SUPPORTS: AvatarSupport;
|
|
70
|
+
export {};
|
|
71
|
+
//# sourceMappingURL=sequences.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sequences.d.ts","sourceRoot":"","sources":["../../client/three/sequences.ts"],"names":[],"mappings":"AA8DA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,KAAK,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AACpD,UAAU,QAAQ;IAChB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;CAC1B;AAiJD;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB;;;;;EAE5B,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,iBAAiB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,eAAe;;;;cAvLX,MAAM;kBACF,MAAM;cACV,SAAS;;EAuLxB,CAAC;AAOH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,EAAE,aAM7B,CAAC"}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Blender avatars' own addressable motions, and their own shape for the one
|
|
3
|
+
* shared action whose keys do not fit a head that turns in degrees.
|
|
4
|
+
*
|
|
5
|
+
* These are *shapes*, authored in a rig whose pose unit is a degree, and a
|
|
6
|
+
* server addresses them by name with `cmd: "action"` when it knows which avatar
|
|
7
|
+
* is mounted. The wire's action vocabulary is open, so they need no promotion
|
|
8
|
+
* and are not trying to get one; a face without them ignores the message
|
|
9
|
+
* ([contract-wire.md](../../../docs/contract-wire.md) § Action).
|
|
10
|
+
*
|
|
11
|
+
* **Why nods get three shapes and one intent.** A 2025 ICMI motion-capture
|
|
12
|
+
* corpus of 90 attentive-listening dialogues separates nodding into three types
|
|
13
|
+
* and publishes the distribution (research-biomechanics.md § 3.3):
|
|
14
|
+
*
|
|
15
|
+
* | type | what it co-occurs with | share of nods | mean duration |
|
|
16
|
+
* |---|---|---:|---:|
|
|
17
|
+
* | `short` | continuer backchannel — "mm-hm, go on" | 49% | 0.83 s |
|
|
18
|
+
* | `long` | assessment, lexical response — "yes, that's right" | 40% | 1.42 s |
|
|
19
|
+
* | `long_p` | a cognitive shift — "ah, I see" | 12% | 1.75 s |
|
|
20
|
+
*
|
|
21
|
+
* Their gloss: "nodding co-occurring with continuer backchannel has a smaller
|
|
22
|
+
* average range of movement, whereas that co-occurring with assessment
|
|
23
|
+
* backchannel and lexical responses has a larger average range", and "nodding
|
|
24
|
+
* with swinging up is regarded to reflect a cognitive shift in the listener."
|
|
25
|
+
*
|
|
26
|
+
* That is three different things to say, not three sizes of one thing — which
|
|
27
|
+
* is exactly why they are this avatar's own names and not three spellings of
|
|
28
|
+
* one. `ACKNOWLEDGE` remains the portable "acknowledge the user" that every
|
|
29
|
+
* renderer answers, and resolves to the continuer here; a server that knows it
|
|
30
|
+
* is driving tara can say *which* nod.
|
|
31
|
+
*
|
|
32
|
+
* **How big, in degrees** (research-head-rotation.md § 2.3, peak-to-peak):
|
|
33
|
+
* a continuer 3–5°, one stroke that returns as far as it went; agreement 6–10°,
|
|
34
|
+
* single, ample and stressed; "oh, I see" 6–10°, opening upward. People's nods
|
|
35
|
+
* are narrower than they look — Blomsma 2024 measures 5.95° on average at
|
|
36
|
+
* backchannel opportunities, Kato 2026 about 4° — and a nod past them stops
|
|
37
|
+
* reading as listening and starts reading as the head dropping.
|
|
38
|
+
*
|
|
39
|
+
* **§ 3.4's structural laws hold in every clip here**, because the paper's
|
|
40
|
+
* finding is that flat repeated cycles are what real nods are not:
|
|
41
|
+
*
|
|
42
|
+
* 1. *Anticipatory rising* — a longer nod starts bigger, from the first
|
|
43
|
+
* cycle. The head knows how long the nod will be before it begins.
|
|
44
|
+
* 2. *Declination* — each cycle is smaller than the one before it, by about
|
|
45
|
+
* 0.7× (Mori 2025).
|
|
46
|
+
* 3. *Under 1.5 Hz* — above it a nod reads as impatience rather than
|
|
47
|
+
* attention, and the head's own 160 ms smoothing eats most of it anyway.
|
|
48
|
+
* People repeat nods at 2–3.5 Hz; the cap is a perceptual choice and it
|
|
49
|
+
* stays, so a repeated nod here is slower than a person's.
|
|
50
|
+
*
|
|
51
|
+
* **Amplitudes are pre-compensated and the numbers are not free.** A stroke is
|
|
52
|
+
* a target the head chases at a 160 ms time constant, so what renders is well
|
|
53
|
+
* under what is written. `test/nods.test.ts` steps the real mixer and holds
|
|
54
|
+
* each clip's rendered degrees to its band; the degrees quoted below are its.
|
|
55
|
+
*
|
|
56
|
+
* TARA-SPECIFIC: the keys are pose units, and a pose unit becomes degrees
|
|
57
|
+
* through the mounted avatar's `HEAD_DEG` — tara's is 24° of pitch at the
|
|
58
|
+
* ±1.4 clamp, 17.1° a unit. A second Blender avatar with another envelope
|
|
59
|
+
* renders these same keys at other angles, and the degrees are recorded per
|
|
60
|
+
* character where they are measured rather than here.
|
|
61
|
+
*/
|
|
62
|
+
import { ACTION_IDS, ACTIONS, CORE_ACTION_IDS } from "../internal.js";
|
|
63
|
+
/**
|
|
64
|
+
* The continuer. "Go on, I'm with you" — half of all nods, and the one the
|
|
65
|
+
* avatar would be doing most if a server drove every backchannel.
|
|
66
|
+
*
|
|
67
|
+
* One stroke down and back, because a continuer is "a single small nod" (Kato
|
|
68
|
+
* 2026) and within a cycle the return is as big as the stroke (Mori 2025): no
|
|
69
|
+
* rebound above neutral, which on a head that really rotates reads as a second,
|
|
70
|
+
* upward nod. The stroke is fast and the return takes its time, which is what
|
|
71
|
+
* makes it a beat rather than a bob. 720 ms, inside the 0.5–0.8 s a single
|
|
72
|
+
* small nod lasts.
|
|
73
|
+
*
|
|
74
|
+
* **No preparatory up-beat, and that is a rate constraint rather than taste.**
|
|
75
|
+
* An earlier draft opened with a dip, which put a turning point 308 ms before
|
|
76
|
+
* the down-peak — 1.63 Hz. The corpus lists the swing-up as optional on `short`
|
|
77
|
+
* and mandatory only on `long_p`, so the one that had to go was the one never
|
|
78
|
+
* carrying meaning.
|
|
79
|
+
*
|
|
80
|
+
* The trunk sets forward a fraction and the shoulders with it — about a fifth
|
|
81
|
+
* and a third of the shared `ACK_NOD`'s — because a head that nods on a body
|
|
82
|
+
* that does not move is a head on a stick, and more than that turns "go on"
|
|
83
|
+
* into leaning in.
|
|
84
|
+
*
|
|
85
|
+
* Renders ~4° of chin-down on tara.
|
|
86
|
+
*/
|
|
87
|
+
const NOD_SMALL = {
|
|
88
|
+
id: "NOD_SMALL", label: "nod: continuer", text: "", duration: 720,
|
|
89
|
+
keys: {
|
|
90
|
+
headPitch: [[0, 0], [0.36, 0.34], [1, 0]],
|
|
91
|
+
// The lid dip is what separates a nod from a bob: eyes stay with the user
|
|
92
|
+
// and close a fraction on the beat.
|
|
93
|
+
lidL: [[0, 0], [0.40, 0.045], [1, 0]],
|
|
94
|
+
lidR: [[0, 0], [0.40, 0.045], [1, 0]],
|
|
95
|
+
torsoLean: [[0, 0], [0.40, 0.026], [1, 0]],
|
|
96
|
+
shoulderL: [[0, 0], [0.46, 0.019], [1, 0]],
|
|
97
|
+
shoulderR: [[0, 0], [0.46, 0.019], [1, 0]],
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* The assessment nod — "yes, that's right".
|
|
102
|
+
*
|
|
103
|
+
* Agreement is "single, ample and stressed" (Poggi), larger and faster than
|
|
104
|
+
* feedback (Bauer 2024), so it is one stroke with a hold at the bottom rather
|
|
105
|
+
* than the continuer made bigger: the hold is the stress, and it is what keeps
|
|
106
|
+
* a large nod from reading as a twitch. About twice the continuer's depth.
|
|
107
|
+
*
|
|
108
|
+
* It aliased the shared `ACK_NOD` until 2026-09-14. That clip is two strokes
|
|
109
|
+
* sized for a line face, and on a head that really rotates it rendered 15°,
|
|
110
|
+
* which is past every row of research § 2.3.
|
|
111
|
+
*
|
|
112
|
+
* Renders ~8° of chin-down on tara.
|
|
113
|
+
*/
|
|
114
|
+
const NOD_ASSESS = {
|
|
115
|
+
id: "NOD_ASSESS", label: "nod: assessment", text: "", duration: 1000,
|
|
116
|
+
keys: {
|
|
117
|
+
headPitch: [[0, 0], [0.26, 0.56], [0.50, 0.50], [1, 0]],
|
|
118
|
+
lidL: [[0, 0], [0.28, 0.06], [0.55, 0.04], [1, 0]],
|
|
119
|
+
lidR: [[0, 0], [0.28, 0.06], [0.55, 0.04], [1, 0]],
|
|
120
|
+
torsoLean: [[0, 0], [0.32, 0.04], [0.60, 0.03], [1, 0]],
|
|
121
|
+
shoulderL: [[0, 0], [0.40, 0.025], [1, 0]],
|
|
122
|
+
shoulderR: [[0, 0], [0.40, 0.025], [1, 0]],
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* "Ah — I see." The realisation nod, and the only one that *starts by going
|
|
127
|
+
* up*.
|
|
128
|
+
*
|
|
129
|
+
* The swing-up is the whole gesture, not an ornament: it is what the corpus
|
|
130
|
+
* separates `long_p` from `long` by, and what makes this read as a mind
|
|
131
|
+
* changing rather than a head agreeing (Mori 2022: upward-first marks a change
|
|
132
|
+
* of state). Then two declining beats at 1.30 Hz, the second about 0.65 of the
|
|
133
|
+
* first.
|
|
134
|
+
*
|
|
135
|
+
* Longest of the three at 1.75 s, and that is the corpus mean for this type —
|
|
136
|
+
* a realisation takes longer than an agreement because something happened in
|
|
137
|
+
* between.
|
|
138
|
+
*
|
|
139
|
+
* Renders ~3.5° of chin-up, then ~6° of chin-down, on tara.
|
|
140
|
+
*/
|
|
141
|
+
const NOD_REALIZE = {
|
|
142
|
+
id: "NOD_REALIZE", label: "nod: realisation", text: "", duration: 1750,
|
|
143
|
+
keys: {
|
|
144
|
+
// Same as the assessment nod: no trailing flourish. A −0.08 at 0.95 put two
|
|
145
|
+
// return beats 542 ms apart, 1.85 Hz, which is a twitch on the way out of a
|
|
146
|
+
// gesture whose whole point is the deliberate lift at the start.
|
|
147
|
+
headPitch: [[0, 0], [0.14, -0.30], [0.40, 0.48], [0.64, -0.12], [0.84, 0.30], [1, 0]],
|
|
148
|
+
// Brows up with the swing and down as the nod lands: the face arrives at
|
|
149
|
+
// the understanding before the head finishes agreeing with it.
|
|
150
|
+
browRaiseL: [[0, 0], [0.16, 0.42], [0.46, 0.10], [1, 0]],
|
|
151
|
+
browRaiseR: [[0, 0], [0.16, 0.38], [0.46, 0.10], [1, 0]],
|
|
152
|
+
lidL: [[0, 0], [0.14, -0.08], [0.42, 0.06], [1, 0]],
|
|
153
|
+
lidR: [[0, 0], [0.14, -0.08], [0.42, 0.06], [1, 0]],
|
|
154
|
+
// The corners come up late, on the second beat. Warmth that arrives *with*
|
|
155
|
+
// the realisation reads as having known already.
|
|
156
|
+
mouthCornerL: [[0, 0], [0.55, 0.10], [0.84, 0.26], [1, 0.12]],
|
|
157
|
+
mouthCornerR: [[0, 0], [0.55, 0.10], [0.84, 0.26], [1, 0.12]],
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* "No." The head shake, and it had to be authored for this rig rather than
|
|
162
|
+
* borrowed.
|
|
163
|
+
*
|
|
164
|
+
* `INTERNAL_CLIPS.HEAD_SHAKE` is written in pose units that mean pixels on a
|
|
165
|
+
* line face. On tara a pose unit is a degree, and that clip's +-0.55 lands at
|
|
166
|
+
* +-3.5 deg authored and about +-2 deg rendered — ambient drift, not a refusal.
|
|
167
|
+
* Two things had to change and only one of them is amplitude.
|
|
168
|
+
*
|
|
169
|
+
* **Yaw is the axis this rig is weakest on**, because the albedo is a front
|
|
170
|
+
* projection of a shallow shell: a turn parallaxes rather than re-silhouettes.
|
|
171
|
+
* Measured against the tile, though, it is not as weak as it looks — 8.7 deg
|
|
172
|
+
* moves 13% of the pixels past a 16/255 delta and carries the silhouette 6 px,
|
|
173
|
+
* which is comparable to what 5.7 deg of roll does. So a shake reads here; it
|
|
174
|
+
* just has to actually reach those angles.
|
|
175
|
+
*
|
|
176
|
+
* **And it has to be slow enough to survive the smoothing.** The borrowed clip
|
|
177
|
+
* swings at 1.42 Hz where the head returns about 0.57 of what it is asked for.
|
|
178
|
+
* At 1.05 Hz it returns ~0.71, which buys a quarter more amplitude for nothing
|
|
179
|
+
* and sits further from the impatience line a *refusal* can least afford to
|
|
180
|
+
* cross.
|
|
181
|
+
*
|
|
182
|
+
* Renders about 11 deg peak-to-peak of yaw. § 3.4's laws again: first swing
|
|
183
|
+
* biggest, every one after it smaller.
|
|
184
|
+
*/
|
|
185
|
+
const NOD_NO = {
|
|
186
|
+
id: "NOD_NO", label: "no (head shake)", text: "", duration: 1900,
|
|
187
|
+
keys: {
|
|
188
|
+
headYaw: [[0, 0], [0.14, -1.35], [0.39, 1.15], [0.64, -0.62], [0.85, 0.24], [1, 0]],
|
|
189
|
+
// A small roll in phase with the turn, because a head that swings on one
|
|
190
|
+
// axis alone is a turret. Kept to a fifth of the yaw: more and the refusal
|
|
191
|
+
// starts reading as a wince.
|
|
192
|
+
headRoll: [[0, 0], [0.14, -0.26], [0.39, 0.22], [0.64, -0.12], [1, 0]],
|
|
193
|
+
// The set of the face is what makes it a "no" rather than a look around.
|
|
194
|
+
// A refusal over a resting smile reads as teasing.
|
|
195
|
+
mouthPress: [[0, 0], [0.18, 0.40], [0.82, 0.34], [1, 0]],
|
|
196
|
+
mouthCornerL: [[0, 0], [0.22, -0.22], [1, 0]],
|
|
197
|
+
mouthCornerR: [[0, 0], [0.22, -0.22], [1, 0]],
|
|
198
|
+
browRaiseL: [[0, 0], [0.18, -0.24], [0.86, -0.12], [1, 0]],
|
|
199
|
+
browRaiseR: [[0, 0], [0.18, -0.24], [0.86, -0.12], [1, 0]],
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* What a server may address on a Blender avatar by name, beyond the two every
|
|
204
|
+
* avatar owes it.
|
|
205
|
+
*
|
|
206
|
+
* Shared by every character in this package rather than owned by tara, because
|
|
207
|
+
* they are all driven through the same 30 channels. A character that needs its
|
|
208
|
+
* own shape of one of these overrides that entry; it does not get a second
|
|
209
|
+
* table.
|
|
210
|
+
*/
|
|
211
|
+
export const BLENDER_SEQUENCES = Object.freeze({
|
|
212
|
+
NOD_SMALL, NOD_ASSESS, NOD_REALIZE, NOD_NO,
|
|
213
|
+
});
|
|
214
|
+
/**
|
|
215
|
+
* The Blender avatars' own shape for one of the mixer's own actions, passed to
|
|
216
|
+
* it as `actions`. Same ids, same intent; only the rendering is theirs.
|
|
217
|
+
*
|
|
218
|
+
* **`ACK_NOD` is the continuer here.** It is the nod a server sends while the
|
|
219
|
+
* user is still talking — "mm-hm, go on" — and that is half of all nods and
|
|
220
|
+
* most of what this avatar does, because it listens far more than it speaks.
|
|
221
|
+
* The shared clip is two strokes that render 15° on this head, which is past
|
|
222
|
+
* even agreement (6–10°) and is what the owner read as the head dropping. A
|
|
223
|
+
* server that means agreement or realisation, and knows a Blender avatar is
|
|
224
|
+
* mounted, asks for `NOD_ASSESS` or `NOD_REALIZE`.
|
|
225
|
+
*
|
|
226
|
+
* Aliased rather than restated, so the continuer and the portable nod cannot
|
|
227
|
+
* drift apart.
|
|
228
|
+
*
|
|
229
|
+
* The other shared clips with head keys stay shared, because they already
|
|
230
|
+
* land inside their meaning on tara: `GESTURE_APPROVE` renders 8.8° of
|
|
231
|
+
* chin-down (agreement's band), `GESTURE_GREET` 2.9° of chin-up, and
|
|
232
|
+
* `GESTURE_WAIT` 5.2° of yaw.
|
|
233
|
+
*/
|
|
234
|
+
export const BLENDER_ACTIONS = Object.freeze({
|
|
235
|
+
ACK_NOD: { ...NOD_SMALL, id: "ACK_NOD", label: "acknowledge: nod" },
|
|
236
|
+
});
|
|
237
|
+
// A shape for an action the mixer already has, never a new one: the mixer
|
|
238
|
+
// refuses an id that is not its own, and this keeps the table honest at the type
|
|
239
|
+
// level too. A *new* motion goes in the table above, which is the open door.
|
|
240
|
+
void BLENDER_ACTIONS;
|
|
241
|
+
/**
|
|
242
|
+
* What every character in this package answers to — each one's `supports`, the
|
|
243
|
+
* optional declaration a driving UI reads (`AvatarSupport`).
|
|
244
|
+
*
|
|
245
|
+
* Derived rather than written down, because the three parts already exist: the
|
|
246
|
+
* two ids every avatar owes a server, the mixer's own clip catalogue these
|
|
247
|
+
* characters inherit whole, and this file's own names. A hand-kept fourth copy
|
|
248
|
+
* would only be able to disagree with them. `BLENDER_ACTIONS` adds nothing —
|
|
249
|
+
* it re-shapes an id the mixer already has.
|
|
250
|
+
*
|
|
251
|
+
* It is one list for tara, tushar and tanya for the same reason the tables are:
|
|
252
|
+
* they are one rig driven through one set of channels. A character that stops
|
|
253
|
+
* being able to do one of these owes its own `supports`, not an edit here.
|
|
254
|
+
*/
|
|
255
|
+
export const BLENDER_SUPPORTS = Object.freeze({
|
|
256
|
+
actions: Object.freeze([
|
|
257
|
+
...CORE_ACTION_IDS,
|
|
258
|
+
...ACTION_IDS.filter((id) => !CORE_ACTION_IDS.includes(id)),
|
|
259
|
+
...Object.keys(BLENDER_SEQUENCES),
|
|
260
|
+
]),
|
|
261
|
+
});
|
|
262
|
+
//# sourceMappingURL=sequences.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sequences.js","sourceRoot":"","sources":["../../client/three/sequences.ts"],"names":[],"mappings":"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"}
|