@voqalize/avatar 0.2.2 → 0.3.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/README.md +144 -663
- package/client/Avatar.tsx +57 -0
- package/client/AvatarClient.ts +523 -0
- package/client/arjun.ts +24 -0
- package/client/createAvatar.ts +139 -0
- package/client/createCanvasAvatar.ts +72 -0
- package/client/index.ts +39 -0
- package/client/internal.ts +80 -0
- package/client/interviewer-female.ts +4 -0
- package/client/interviewer-male.ts +4 -0
- package/client/ishita.ts +24 -0
- package/client/kabir.ts +24 -0
- package/client/meera.ts +24 -0
- package/client/naina.ts +24 -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/types.ts +146 -0
- package/client/useAvatar.ts +74 -0
- package/client/vikram.ts +24 -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 +196 -0
- package/dist/AvatarClient.d.ts.map +1 -0
- package/dist/AvatarClient.js +450 -0
- package/dist/AvatarClient.js.map +1 -0
- package/dist/arjun.d.ts +6 -0
- package/dist/arjun.d.ts.map +1 -0
- package/dist/arjun.js +18 -0
- package/dist/arjun.js.map +1 -0
- package/dist/createAvatar.d.ts +99 -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 +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/internal.d.ts +30 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +33 -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 +6 -0
- package/dist/ishita.d.ts.map +1 -0
- package/dist/ishita.js +18 -0
- package/dist/ishita.js.map +1 -0
- package/dist/kabir.d.ts +6 -0
- package/dist/kabir.d.ts.map +1 -0
- package/dist/kabir.js +18 -0
- package/dist/kabir.js.map +1 -0
- package/dist/meera.d.ts +6 -0
- package/dist/meera.d.ts.map +1 -0
- package/dist/meera.js +18 -0
- package/dist/meera.js.map +1 -0
- package/dist/naina.d.ts +6 -0
- package/dist/naina.d.ts.map +1 -0
- package/dist/naina.js +18 -0
- package/dist/naina.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/types.d.ts +94 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +93 -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 +6 -0
- package/dist/vikram.d.ts.map +1 -0
- package/dist/vikram.js +18 -0
- package/dist/vikram.js.map +1 -0
- package/package.json +81 -24
- package/src/avatar.d.ts +161 -120
- package/src/avatar.js +234 -146
- package/src/behavior.d.ts +26 -0
- package/src/behavior.js +102 -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 +4 -3
- 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 +119 -4
- package/src/hand.js +120 -91
- package/src/idle.js +18 -101
- package/src/interjections.js +156 -31
- package/src/params.js +8 -4
- package/src/perform.js +7 -9
- package/src/rig.d.ts +24 -0
- package/src/rig.js +32 -0
- package/src/speech-timing.js +23 -0
- package/src/visemes.js +28 -12
- 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,26 @@
|
|
|
1
|
+
import type { AvatarApi, AvatarActionId, AvatarStateName } from "./avatar.js";
|
|
2
|
+
|
|
3
|
+
/** The whole behaviour vocabulary — the nine. Not an alias list; see behavior.js. */
|
|
4
|
+
export type BehaviorStateId =
|
|
5
|
+
| "IDLE" | "LISTENING" | "STRAINING" | "THINKING" | "WORKING"
|
|
6
|
+
| "MUTED" | "SPEAKING" | "DEGRADED" | "OFFLINE";
|
|
7
|
+
|
|
8
|
+
export type BehaviorActionId =
|
|
9
|
+
| "ack.receive" | "ack.nod"
|
|
10
|
+
| "turn.interrupted"
|
|
11
|
+
| "gesture.greet" | "gesture.farewell" | "gesture.approve" | "gesture.wait";
|
|
12
|
+
|
|
13
|
+
export const BEHAVIOR_STATES: Readonly<Record<BehaviorStateId, { renderState: AvatarStateName }>>;
|
|
14
|
+
export const BEHAVIOR_STATE_IDS: readonly BehaviorStateId[];
|
|
15
|
+
export const BEHAVIOR_ACTIONS: Readonly<Record<BehaviorActionId, { renderAction: AvatarActionId }>>;
|
|
16
|
+
export const BEHAVIOR_ACTION_IDS: readonly BehaviorActionId[];
|
|
17
|
+
export const WIRE_ACTION_TO_BEHAVIOR: Readonly<Record<AvatarActionId, BehaviorActionId>>;
|
|
18
|
+
|
|
19
|
+
export class BehaviorController {
|
|
20
|
+
constructor(avatar: AvatarApi);
|
|
21
|
+
state: BehaviorStateId | null;
|
|
22
|
+
setState(id: BehaviorStateId, options?: { force?: boolean }): this;
|
|
23
|
+
action(id: BehaviorActionId): this;
|
|
24
|
+
wireAction(id: AvatarActionId): this;
|
|
25
|
+
destroy(): void;
|
|
26
|
+
}
|
package/src/behavior.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Behavior catalog and controller.
|
|
3
|
+
*
|
|
4
|
+
* This is the layer between factual/wire inputs and the bundled SVG renderer.
|
|
5
|
+
* It is not a seam any avatar implementation sees: an implementation receives
|
|
6
|
+
* a PipecatClient and decides for itself what a state means.
|
|
7
|
+
*
|
|
8
|
+
* The vocabulary is the nine core states. It used to be seventeen — the core
|
|
9
|
+
* set plus every SVG render state (TYPING, CANT_HEAR, SEARCHING_SCREEN, …)
|
|
10
|
+
* passed straight through, so that tooling could drive one of *those* from
|
|
11
|
+
* here. That made the mixer's private state list look like part of the
|
|
12
|
+
* behaviour vocabulary. Tooling that wants a render state calls
|
|
13
|
+
* `avatar.setState` on the mixer, which is whose state it is.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Durable states the behavior layer resolves, and the render state each one
|
|
18
|
+
* asks the bundled SVG mixer for. The right-hand column belongs to a renderer:
|
|
19
|
+
* `WORKING` may draw as anything, and this is where a divergence lands rather
|
|
20
|
+
* than leaks. `STRAINING` is the first row to actually use that — the two
|
|
21
|
+
* columns were written out for years while the mapping stayed 1:1.
|
|
22
|
+
*/
|
|
23
|
+
export const BEHAVIOR_STATES = Object.freeze({
|
|
24
|
+
IDLE: { renderState: 'IDLE' },
|
|
25
|
+
LISTENING: { renderState: 'LISTENING' },
|
|
26
|
+
// What the server calls straining, this renderer draws as CANT_HEAR: the
|
|
27
|
+
// behavior name claims only that the avatar is trying harder to hear, while
|
|
28
|
+
// the pose is one particular drawing of that. A renderer with no such pose
|
|
29
|
+
// may legitimately point this at LISTENING.
|
|
30
|
+
STRAINING: { renderState: 'CANT_HEAR' },
|
|
31
|
+
THINKING: { renderState: 'THINKING' },
|
|
32
|
+
WORKING: { renderState: 'WORKING' },
|
|
33
|
+
MUTED: { renderState: 'MUTED' },
|
|
34
|
+
SPEAKING: { renderState: 'SPEAKING' },
|
|
35
|
+
DEGRADED: { renderState: 'DEGRADED' },
|
|
36
|
+
OFFLINE: { renderState: 'OFFLINE' },
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const BEHAVIOR_STATE_IDS = Object.freeze(Object.keys(BEHAVIOR_STATES));
|
|
40
|
+
|
|
41
|
+
/** Library action IDs. These are broader and more readable than the wire. */
|
|
42
|
+
export const BEHAVIOR_ACTIONS = Object.freeze({
|
|
43
|
+
'ack.receive': { renderAction: 'ACK_RECEIVE' },
|
|
44
|
+
'ack.nod': { renderAction: 'ACK_NOD' },
|
|
45
|
+
'turn.interrupted': { renderAction: 'RESPONSE_INTERRUPTED' },
|
|
46
|
+
'gesture.greet': { renderAction: 'GESTURE_GREET' },
|
|
47
|
+
'gesture.farewell': { renderAction: 'GESTURE_GOODBYE' },
|
|
48
|
+
'gesture.approve': { renderAction: 'GESTURE_APPROVE' },
|
|
49
|
+
'gesture.wait': { renderAction: 'GESTURE_WAIT' },
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export const BEHAVIOR_ACTION_IDS = Object.freeze(Object.keys(BEHAVIOR_ACTIONS));
|
|
53
|
+
|
|
54
|
+
/** Stable, promoted wire names map into the behavior catalog here and nowhere else. */
|
|
55
|
+
export const WIRE_ACTION_TO_BEHAVIOR = Object.freeze({
|
|
56
|
+
ACK_RECEIVE: 'ack.receive',
|
|
57
|
+
ACK_NOD: 'ack.nod',
|
|
58
|
+
RESPONSE_INTERRUPTED: 'turn.interrupted',
|
|
59
|
+
GESTURE_GREET: 'gesture.greet',
|
|
60
|
+
GESTURE_GOODBYE: 'gesture.farewell',
|
|
61
|
+
GESTURE_APPROVE: 'gesture.approve',
|
|
62
|
+
GESTURE_WAIT: 'gesture.wait',
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Turns behavior intent into the legacy SVG mixer's calls. A future renderer
|
|
67
|
+
* receives the same intent through its own adapter; it does not need to know
|
|
68
|
+
* the legacy state/action names used below.
|
|
69
|
+
*/
|
|
70
|
+
export class BehaviorController {
|
|
71
|
+
constructor(avatar) {
|
|
72
|
+
if (!avatar || typeof avatar.setState !== 'function' || typeof avatar.action !== 'function') {
|
|
73
|
+
throw new TypeError('BehaviorController requires an avatar implementation');
|
|
74
|
+
}
|
|
75
|
+
this.avatar = avatar;
|
|
76
|
+
this.state = null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
setState(id, { force = false } = {}) {
|
|
80
|
+
const def = BEHAVIOR_STATES[id];
|
|
81
|
+
if (!def) throw new Error(`unknown behavior state: ${id}`);
|
|
82
|
+
if (!force && this.state === id) return this;
|
|
83
|
+
this.state = id;
|
|
84
|
+
this.avatar.setState(def.renderState);
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
destroy() {}
|
|
89
|
+
|
|
90
|
+
action(id) {
|
|
91
|
+
const def = BEHAVIOR_ACTIONS[id];
|
|
92
|
+
if (!def) throw new Error(`unknown behavior action: ${id}`);
|
|
93
|
+
this.avatar.action(def.renderAction);
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
wireAction(id) {
|
|
98
|
+
const behaviorId = WIRE_ACTION_TO_BEHAVIOR[id];
|
|
99
|
+
if (!behaviorId) throw new Error(`unknown wire action: ${id}`);
|
|
100
|
+
return this.action(behaviorId);
|
|
101
|
+
}
|
|
102
|
+
}
|
package/src/camera.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The close webcam crop shared by every avatar renderer.
|
|
3
|
+
*
|
|
4
|
+
* The head gets most of the tile because lip sync and listening expressions
|
|
5
|
+
* are the information the avatar is there to carry. The remaining lower band
|
|
6
|
+
* leaves enough neck and shoulder for posture to read without turning the
|
|
7
|
+
* call tile into a half-body portrait.
|
|
8
|
+
*/
|
|
9
|
+
export const CALL_CAMERA = Object.freeze({
|
|
10
|
+
aspect: 4 / 3,
|
|
11
|
+
headroom: 0.06,
|
|
12
|
+
head: 0.70,
|
|
13
|
+
body: 0.24,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
/** Derive a camera rectangle from three landmarks in the drawing's own units. */
|
|
17
|
+
export function viewBoxForHead({ centerX, crownY, chinY }) {
|
|
18
|
+
if (![centerX, crownY, chinY].every(Number.isFinite) || chinY <= crownY) {
|
|
19
|
+
throw new TypeError('viewBoxForHead: expected a finite centre and crown above chin');
|
|
20
|
+
}
|
|
21
|
+
const h = (chinY - crownY) / CALL_CAMERA.head;
|
|
22
|
+
const w = h * CALL_CAMERA.aspect;
|
|
23
|
+
return {
|
|
24
|
+
x: centerX - w / 2,
|
|
25
|
+
y: crownY - h * CALL_CAMERA.headroom,
|
|
26
|
+
w,
|
|
27
|
+
h,
|
|
28
|
+
};
|
|
29
|
+
}
|