@voqalize/avatar 0.4.1 → 0.4.3

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.
Files changed (203) hide show
  1. package/LICENSE-APACHE-2.0 +201 -0
  2. package/README.md +26 -95
  3. package/assets/README.md +30 -18
  4. package/assets/tanvi.glb +0 -0
  5. package/assets/tanya.glb +0 -0
  6. package/assets/tara.glb +0 -0
  7. package/assets/tess.glb +0 -0
  8. package/assets/tushar.glb +0 -0
  9. package/client/internal.ts +24 -0
  10. package/client/supports.ts +6 -7
  11. package/client/three/assets.ts +7 -3
  12. package/client/three/budgets.ts +1 -1
  13. package/client/three/{tara-rig.ts → character-rig.ts} +682 -540
  14. package/client/three/createCharacter.ts +109 -0
  15. package/client/three/holds.ts +8 -3
  16. package/client/three/internal.ts +8 -7
  17. package/client/three/motion-limits.json +10 -2
  18. package/client/three/sequences.ts +5 -5
  19. package/client/three/tanvi-asset.ts +6 -0
  20. package/client/three/tanvi.ts +30 -0
  21. package/client/three/tanya.ts +18 -58
  22. package/client/three/tara.ts +19 -60
  23. package/client/three/tess-asset.ts +6 -0
  24. package/client/three/tess.ts +30 -0
  25. package/client/three/tushar.ts +18 -55
  26. package/dist/internal.d.ts +2 -2
  27. package/dist/internal.d.ts.map +1 -1
  28. package/dist/internal.js +16 -1
  29. package/dist/internal.js.map +1 -1
  30. package/dist/supports.d.ts +6 -7
  31. package/dist/supports.d.ts.map +1 -1
  32. package/dist/supports.js +6 -7
  33. package/dist/supports.js.map +1 -1
  34. package/dist/three/assets.d.ts +2 -0
  35. package/dist/three/assets.d.ts.map +1 -1
  36. package/dist/three/assets.js +7 -3
  37. package/dist/three/assets.js.map +1 -1
  38. package/dist/three/budgets.d.ts +1 -1
  39. package/dist/three/budgets.js +1 -1
  40. package/dist/three/character-rig.d.ts +366 -0
  41. package/dist/three/character-rig.d.ts.map +1 -0
  42. package/dist/three/{tara-rig.js → character-rig.js} +633 -526
  43. package/dist/three/character-rig.js.map +1 -0
  44. package/dist/three/createCharacter.d.ts +60 -0
  45. package/dist/three/createCharacter.d.ts.map +1 -0
  46. package/dist/three/createCharacter.js +84 -0
  47. package/dist/three/createCharacter.js.map +1 -0
  48. package/dist/three/holds.d.ts +7 -2
  49. package/dist/three/holds.d.ts.map +1 -1
  50. package/dist/three/holds.js +8 -3
  51. package/dist/three/holds.js.map +1 -1
  52. package/dist/three/internal.d.ts +7 -7
  53. package/dist/three/internal.d.ts.map +1 -1
  54. package/dist/three/internal.js +6 -6
  55. package/dist/three/internal.js.map +1 -1
  56. package/dist/three/motion-limits.json +10 -2
  57. package/dist/three/sequences.d.ts +5 -5
  58. package/dist/three/sequences.js +5 -5
  59. package/dist/three/tanvi-asset.d.ts +7 -0
  60. package/dist/three/tanvi-asset.d.ts.map +1 -0
  61. package/dist/three/tanvi-asset.js +7 -0
  62. package/dist/three/tanvi-asset.js.map +1 -0
  63. package/dist/three/tanvi.d.ts +24 -0
  64. package/dist/three/tanvi.d.ts.map +1 -0
  65. package/dist/three/tanvi.js +24 -0
  66. package/dist/three/tanvi.js.map +1 -0
  67. package/dist/three/tanya.d.ts +16 -28
  68. package/dist/three/tanya.d.ts.map +1 -1
  69. package/dist/three/tanya.js +15 -43
  70. package/dist/three/tanya.js.map +1 -1
  71. package/dist/three/tara.d.ts +17 -22
  72. package/dist/three/tara.d.ts.map +1 -1
  73. package/dist/three/tara.js +16 -45
  74. package/dist/three/tara.js.map +1 -1
  75. package/dist/three/tess-asset.d.ts +7 -0
  76. package/dist/three/tess-asset.d.ts.map +1 -0
  77. package/dist/three/tess-asset.js +7 -0
  78. package/dist/three/tess-asset.js.map +1 -0
  79. package/dist/three/tess.d.ts +24 -0
  80. package/dist/three/tess.d.ts.map +1 -0
  81. package/dist/three/tess.js +24 -0
  82. package/dist/three/tess.js.map +1 -0
  83. package/dist/three/tushar.d.ts +16 -25
  84. package/dist/three/tushar.d.ts.map +1 -1
  85. package/dist/three/tushar.js +15 -40
  86. package/dist/three/tushar.js.map +1 -1
  87. package/package.json +10 -49
  88. package/src/avatar.d.ts +67 -2
  89. package/src/avatar.js +131 -255
  90. package/src/faces.js +1 -1
  91. package/src/gaze.js +20 -47
  92. package/src/idle.js +69 -27
  93. package/src/prosody.js +109 -15
  94. package/src/rig.d.ts +7 -0
  95. package/src/speech-timing.js +9 -0
  96. package/src/visemes.js +107 -13
  97. package/client/arjun.ts +0 -26
  98. package/client/createCanvasAvatar.ts +0 -72
  99. package/client/interviewer-female.ts +0 -4
  100. package/client/interviewer-male.ts +0 -4
  101. package/client/ishita.ts +0 -26
  102. package/client/kabir.ts +0 -26
  103. package/client/meera.ts +0 -26
  104. package/client/naina.ts +0 -26
  105. package/client/professional-female-a.ts +0 -4
  106. package/client/professional-female-b.ts +0 -4
  107. package/client/professional-male-a.ts +0 -4
  108. package/client/professional-male-b.ts +0 -4
  109. package/client/vikram.ts +0 -26
  110. package/dist/arjun.d.ts +0 -7
  111. package/dist/arjun.d.ts.map +0 -1
  112. package/dist/arjun.js +0 -20
  113. package/dist/arjun.js.map +0 -1
  114. package/dist/createCanvasAvatar.d.ts +0 -22
  115. package/dist/createCanvasAvatar.d.ts.map +0 -1
  116. package/dist/createCanvasAvatar.js +0 -47
  117. package/dist/createCanvasAvatar.js.map +0 -1
  118. package/dist/interviewer-female.d.ts +0 -4
  119. package/dist/interviewer-female.d.ts.map +0 -1
  120. package/dist/interviewer-female.js +0 -3
  121. package/dist/interviewer-female.js.map +0 -1
  122. package/dist/interviewer-male.d.ts +0 -4
  123. package/dist/interviewer-male.d.ts.map +0 -1
  124. package/dist/interviewer-male.js +0 -3
  125. package/dist/interviewer-male.js.map +0 -1
  126. package/dist/ishita.d.ts +0 -7
  127. package/dist/ishita.d.ts.map +0 -1
  128. package/dist/ishita.js +0 -20
  129. package/dist/ishita.js.map +0 -1
  130. package/dist/kabir.d.ts +0 -7
  131. package/dist/kabir.d.ts.map +0 -1
  132. package/dist/kabir.js +0 -20
  133. package/dist/kabir.js.map +0 -1
  134. package/dist/meera.d.ts +0 -7
  135. package/dist/meera.d.ts.map +0 -1
  136. package/dist/meera.js +0 -20
  137. package/dist/meera.js.map +0 -1
  138. package/dist/naina.d.ts +0 -7
  139. package/dist/naina.d.ts.map +0 -1
  140. package/dist/naina.js +0 -20
  141. package/dist/naina.js.map +0 -1
  142. package/dist/professional-female-a.d.ts +0 -4
  143. package/dist/professional-female-a.d.ts.map +0 -1
  144. package/dist/professional-female-a.js +0 -3
  145. package/dist/professional-female-a.js.map +0 -1
  146. package/dist/professional-female-b.d.ts +0 -4
  147. package/dist/professional-female-b.d.ts.map +0 -1
  148. package/dist/professional-female-b.js +0 -3
  149. package/dist/professional-female-b.js.map +0 -1
  150. package/dist/professional-male-a.d.ts +0 -4
  151. package/dist/professional-male-a.d.ts.map +0 -1
  152. package/dist/professional-male-a.js +0 -3
  153. package/dist/professional-male-a.js.map +0 -1
  154. package/dist/professional-male-b.d.ts +0 -4
  155. package/dist/professional-male-b.d.ts.map +0 -1
  156. package/dist/professional-male-b.js +0 -3
  157. package/dist/professional-male-b.js.map +0 -1
  158. package/dist/three/tara-rig.d.ts +0 -409
  159. package/dist/three/tara-rig.d.ts.map +0 -1
  160. package/dist/three/tara-rig.js.map +0 -1
  161. package/dist/vikram.d.ts +0 -7
  162. package/dist/vikram.d.ts.map +0 -1
  163. package/dist/vikram.js +0 -20
  164. package/dist/vikram.js.map +0 -1
  165. package/src/canvas/author/parts/eye.mjs +0 -722
  166. package/src/canvas/author/parts/hand.mjs +0 -1156
  167. package/src/canvas/author/parts/mouth.mjs +0 -741
  168. package/src/canvas/author/parts/nose.mjs +0 -100
  169. package/src/canvas/author/parts/skin-detail.mjs +0 -67
  170. package/src/canvas/author/path.mjs +0 -283
  171. package/src/canvas/author/rig.mjs +0 -405
  172. package/src/canvas/avatars/round/face.d.mts +0 -3
  173. package/src/canvas/avatars/round/face.mjs +0 -1307
  174. package/src/canvas/create-rig.d.ts +0 -15
  175. package/src/canvas/create-rig.js +0 -100
  176. package/src/canvas/data/img/professional-female-a-hair-back.webp +0 -0
  177. package/src/canvas/data/img/professional-female-a-hair-front.webp +0 -0
  178. package/src/canvas/data/img/professional-female-a-top-body.webp +0 -0
  179. package/src/canvas/data/img/professional-female-b-hair-back.webp +0 -0
  180. package/src/canvas/data/img/professional-female-b-hair-front.webp +0 -0
  181. package/src/canvas/data/img/professional-female-b-top-body.webp +0 -0
  182. package/src/canvas/data/img/professional-male-a-hair-back.webp +0 -0
  183. package/src/canvas/data/img/professional-male-a-hair-front.webp +0 -0
  184. package/src/canvas/data/img/professional-male-a-top-body.webp +0 -0
  185. package/src/canvas/data/img/professional-male-b-hair-back.webp +0 -0
  186. package/src/canvas/data/img/professional-male-b-hair-front.webp +0 -0
  187. package/src/canvas/data/img/professional-male-b-top-body.webp +0 -0
  188. package/src/canvas/data/img/round-m3-hair-back.webp +0 -0
  189. package/src/canvas/data/img/round-m3-hair-front.webp +0 -0
  190. package/src/canvas/data/img/round-m3-top-body.webp +0 -0
  191. package/src/canvas/data/img/round-w1-hair-back.webp +0 -0
  192. package/src/canvas/data/img/round-w1-hair-front.webp +0 -0
  193. package/src/canvas/data/img/round-w1-top-body.webp +0 -0
  194. package/src/canvas/data/interviewer-female.rig.json +0 -1
  195. package/src/canvas/data/interviewer-male.rig.json +0 -1
  196. package/src/canvas/data/professional-female-a.rig.json +0 -1
  197. package/src/canvas/data/professional-female-b.rig.json +0 -1
  198. package/src/canvas/data/professional-male-a.rig.json +0 -1
  199. package/src/canvas/data/professional-male-b.rig.json +0 -1
  200. package/src/canvas/src/live.js +0 -508
  201. package/src/canvas/src/render2d.js +0 -218
  202. package/src/canvas/src/rig.js +0 -297
  203. package/src/canvas/src/vocab.js +0 -96
@@ -0,0 +1,109 @@
1
+ /**
2
+ * `createCharacter` — the Blender characters' entry point, and the other end of
3
+ * the fork agreed on 2026-09-17 (*"Aligned that we fork"*).
4
+ *
5
+ * There are two `createAvatar` implementations in this package now, not one
6
+ * with a branch in it. `client/createAvatar.ts` mounts a drawing: a `Face`
7
+ * record, a theme, the frame-edge hand. This one mounts a compiled head: a GLB
8
+ * url, the shared rig, the house performance. They are separate because almost
9
+ * every option the second one passes exists to *undo* something the first one
10
+ * assumes — no hand, no theme, clips whose keys are degrees rather than ink —
11
+ * and threading one more per-avatar option through a shared entry point is the
12
+ * smell rather than the fix.
13
+ *
14
+ * **What is not forked is the mixer.** Both entry points resolve their options
15
+ * and hand them to the same `createSvgAvatar`, which still does states, layers,
16
+ * gaze, idle, blinks, clips and per-channel smoothing for every face in the
17
+ * package. Forking *that* would give two copies of the smoothing law, and the
18
+ * smoothing law is the thing a clip's keyframes are authored against
19
+ * (docs/internal-mixer.md § Smoothing) — two copies of it drift, and the drift
20
+ * is invisible until a nod reads wrong on one character only.
21
+ *
22
+ * A character module is therefore its GLB and its name:
23
+ *
24
+ * export const supports = BLENDER_SUPPORTS;
25
+ * export const createAvatar = character("tara", TARA_GLB);
26
+ *
27
+ * and everything else about how a Blender character is driven is here, once.
28
+ */
29
+
30
+ import type { PipecatClient } from "@pipecat-ai/client-js";
31
+ import { AvatarClient, createSvgAvatar } from "../internal.js";
32
+ import type { AvatarFactory, AvatarInstance, AvatarOptions } from "../createAvatar.js";
33
+ import { BLENDER_ACTIONS, BLENDER_SEQUENCES } from "./sequences.js";
34
+ import { headHold } from "./holds.js";
35
+ import { createCharacterRig, CHARACTER_TUNING } from "./character-rig.js";
36
+ import type { CharacterRigOptions } from "./character-rig.js";
37
+
38
+ /**
39
+ * What every Blender character takes — the two options every avatar shares,
40
+ * plus the three gains.
41
+ *
42
+ * There is no `face`, no `theme` and no `hand`: a compiled character is one
43
+ * drawing with one palette baked into its atlas, and it has no arms. There is
44
+ * no `url` either, because the character *is* the module you imported.
45
+ */
46
+ export interface CharacterAvatarOptions extends AvatarOptions {
47
+ /** Viseme amplitude, 0..2. `1` is as authored. */
48
+ readonly mouthGain?: number;
49
+ /** Gesture-clip amplitude, 0..2. */
50
+ readonly gestureGain?: number;
51
+ /** Idle/liveness amplitude, 0..2. */
52
+ readonly motionGain?: number;
53
+ /** Fires when the GLB is in the scene — for a capture tool, not a consumer. */
54
+ readonly onReady?: () => void;
55
+ }
56
+
57
+ export type { AvatarInstance };
58
+
59
+ /**
60
+ * One Blender character's `createAvatar`, bound to its name and its mesh.
61
+ *
62
+ * `name` is not a lookup key — nothing resolves a character by it and there is
63
+ * no table to miss. It selects this face's row in `motion-limits.json`, which
64
+ * is the one per-character fact that is neither in the GLB nor in the rig:
65
+ * the angles a person read off the face by eye, which no build can derive
66
+ * (`holds.ts`).
67
+ */
68
+ export function character(name: Parameters<typeof headHold>[0], url: string):
69
+ AvatarFactory<CharacterAvatarOptions> {
70
+ const hold = headHold(name);
71
+ return function createAvatar(options: CharacterAvatarOptions): AvatarInstance {
72
+ const { mount, client, onReady, ...gains } = options;
73
+ if (!mount) throw new TypeError("createAvatar: `mount` is required");
74
+ if (!client) throw new TypeError("createAvatar: `client` is required");
75
+
76
+ const rigOptions: CharacterRigOptions = { onReady, url };
77
+ // `hand: false` disables the bundled SVG hand renderer only; the semantic
78
+ // hand frame still reaches the rig, which ignores it — these characters
79
+ // have no arms, and that is the library's oldest standing constraint
80
+ // rather than an omission.
81
+ //
82
+ // `sequences` is what a server can address on a Blender character beyond
83
+ // the two ids every avatar owes it — the three nod types the listening
84
+ // research separates, and a head shake sized for a rig whose pose unit is
85
+ // a degree. The wire's action id is open, so nothing here needed
86
+ // promoting: a server that does not know which face is mounted sends
87
+ // `ACKNOWLEDGE` and is never wrong. `actions` is the other half, the
88
+ // Blender shape for an id the mixer already has, whose shared keys land
89
+ // outside what they mean on a head that turns in degrees.
90
+ const widget = createSvgAvatar({
91
+ mount, rig: createCharacterRig, rigOptions, hand: false,
92
+ sequences: BLENDER_SEQUENCES, actions: BLENDER_ACTIONS, ...CHARACTER_TUNING,
93
+ headHold: hold, ...gains,
94
+ });
95
+ const driver = new AvatarClient(widget);
96
+ const detach = driver.attach(client);
97
+
98
+ let destroyed = false;
99
+ return {
100
+ destroy() {
101
+ if (destroyed) return;
102
+ destroyed = true;
103
+ detach();
104
+ driver.destroy();
105
+ widget.destroy();
106
+ },
107
+ };
108
+ };
109
+ }
@@ -3,12 +3,16 @@
3
3
  * pose units per axis, ready to hand to `createSvgAvatar` as `headHold`.
4
4
  *
5
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
6
+ * there. They were read off the faces by the person who owns how they
7
7
  * look, one axis at a time, at the surface a call actually shows — which is
8
8
  * the only way this kind of number can be got, and the reason nothing here
9
9
  * recomputes, adjusts or second-guesses one. This file is the unit change and
10
10
  * nothing else.
11
11
  *
12
+ * An axis the file never carried is the same case, and a character built but
13
+ * not yet driven by the owner has none of them: the file says so instead of
14
+ * carrying a number nobody read, and the fallback below is what holds her.
15
+ *
12
16
  * An axis the file marks for re-measurement is not enforced: it was read off an
13
17
  * asset that has since been fixed, and holding the driver to a defect that no
14
18
  * longer exists is worse than the defect. It falls back to the tightest angle
@@ -22,7 +26,7 @@
22
26
  */
23
27
 
24
28
  import LIMITS from "./motion-limits.json" with { type: "json" };
25
- import { HEAD_CLAMP, HEAD_DEG } from "./tara-rig.js";
29
+ import { HEAD_CLAMP, HEAD_DEG } from "./character-rig.js";
26
30
 
27
31
  /** Degrees of each axis per pose unit, which is `HEAD_DEG` at the clamp. */
28
32
  const PER_UNIT = {
@@ -52,7 +56,8 @@ function safest(axis: string): number | undefined {
52
56
  return angles.length ? Math.min(...angles) : undefined;
53
57
  }
54
58
 
55
- /** `name` as the limits file spells it: tara, tushar, tanya. */
59
+ /** `name` as the limits file spells it — a character with no live axis there
60
+ * is held to the tightest budget any other is still vouched for. */
56
61
  export function headHold(name: keyof typeof LIMITS.characters): HeadHold {
57
62
  const out: HeadHold = {};
58
63
  for (const channel of Object.keys(AXIS) as (keyof typeof AXIS)[]) {
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * The 2.5-D rig, below the `createAvatar` modules — `/internal`, no semver promise.
3
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
4
+ * A character's own module — `tara.ts`, `tushar.ts`, `tanya.ts`, `tess.ts`, `tanvi.ts` — is
5
+ * what a consumer gets: one `createAvatar` each, the mixer behind it, nothing to
6
+ * configure. This is the other door, for a page whose subject is the *rig*
7
+ * rather than the call — the renderer with no mixer in front of it, every
8
+ * compiled character, and the head envelope their channels are scaled by. Its readers are the rig instruments
9
9
  * in the working tree, and nothing that ships.
10
10
  *
11
11
  * It exists because those instruments were reaching around the package instead,
@@ -18,8 +18,9 @@
18
18
  export { ASSETS as CHARACTERS } from "./assets.js";
19
19
  export type { CharacterName } from "./assets.js";
20
20
 
21
- export { createTaraRig, EYE_DEG, HEAD_CLAMP, HEAD_DEG, TARA_TUNING } from "./tara-rig.js";
22
- export type { TaraRigOptions } from "./tara-rig.js";
21
+ export { createCharacterRig, EYE_DEG, HEAD_CLAMP, HEAD_DEG, CHARACTER_TUNING,
22
+ HEAD_PARTS, PIVOT, ROLL_PIVOT } from "./character-rig.js";
23
+ export type { CharacterRigOptions } from "./character-rig.js";
23
24
  export { HARD_BUDGET, pixelRatioFor, SHIPPING_SURFACE } from "./budgets.js";
24
25
 
25
26
  /**
@@ -1,6 +1,6 @@
1
1
  {
2
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.",
3
+ "versus": "This is not `HEAD_DEG` and is much smaller than it. `HEAD_DEG` (character-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
4
  "units": "degrees from rest, either side, per axis driven alone from rest",
5
5
  "surface": {
6
6
  "cssWidth": 400,
@@ -110,7 +110,15 @@
110
110
  "fixed": "2026-09-19"
111
111
  }
112
112
  ]
113
+ },
114
+ "tess": {
115
+ "unmeasured": "Nothing here has been read off her. She was built on 2026-09-20 and the owner has not driven her yet, so this entry carries no angle at all rather than a plausible one: `holds.ts` falls back to the tightest angle still live on each axis, which is the budget the faces nobody doubts are already held to. Drive her with the hold-and-move instrument and this becomes the same shape as the entries above.",
116
+ "defects": []
117
+ },
118
+ "tanvi": {
119
+ "unmeasured": "Nothing here has been read off her. She was built on 2026-09-23 and the owner has not driven her yet, so this entry carries no angle at all rather than a plausible one: `holds.ts` falls back to the tightest angle still live on each axis. Drive her with the hold-and-move instrument and this becomes the same shape as the entries above.",
120
+ "defects": []
113
121
  }
114
122
  },
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."
123
+ "remeasure": "An axis carrying `remeasure` was measured on an asset that has since changed. It stays as written — a measurement is not edited by someone who did not make it — and a gate skips it and says so."
116
124
  }
@@ -262,13 +262,13 @@ void (BLENDER_ACTIONS satisfies Partial<Record<keyof typeof ACTIONS, Sequence>>)
262
262
  * What every character in this package answers to — each one's `supports`, the
263
263
  * optional declaration a driving UI reads (`AvatarSupport`).
264
264
  *
265
- * Derived rather than written down, because the three parts already exist: the
266
- * two ids every avatar owes a server, the mixer's own clip catalogue these
267
- * characters inherit whole, and this file's own names. A hand-kept fourth copy
268
- * would only be able to disagree with them. `BLENDER_ACTIONS` adds nothing —
265
+ * Derived rather than written down, because every part of it already exists: the
266
+ * ids every avatar owes a server, the mixer's own clip catalogue these
267
+ * characters inherit whole, and this file's own names. A hand-kept copy beside
268
+ * them would only be able to disagree with them. `BLENDER_ACTIONS` adds nothing —
269
269
  * it re-shapes an id the mixer already has.
270
270
  *
271
- * It is one list for tara, tushar and tanya for the same reason the tables are:
271
+ * It is one list for every 2.5-D character for the same reason the tables are:
272
272
  * they are one rig driven through one set of channels. A character that stops
273
273
  * being able to do one of these owes its own `supports`, not an edit here.
274
274
  */
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Where tanvi's compiled GLB is. One character, one module — see
3
+ * [tara-asset.ts](./tara-asset.ts) for why that separation is load-bearing and
4
+ * why the `new URL` literal is spelled exactly this way.
5
+ */
6
+ export const TANVI_GLB = new URL("../../assets/tanvi.glb", import.meta.url).href;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * tanvi — Indian, and the first character whose hair is not part of her head.
3
+ *
4
+ * Her GLB is the shared scripts run with her landmarks (`characters/tanvi/`).
5
+ * Her long waves fall past both shoulders onto her chest, which a `Hair` shell
6
+ * painted into the head's atlas cannot carry: it can only be where the head is.
7
+ * So her photograph is split into her with the hair pulled back, which is what
8
+ * every other script reads, and the hair alone, which becomes a `HairLayer`
9
+ * mesh of its own — turning with the skull, holding back its share of a roll
10
+ * like tanya's hanging hair, lifting with the shoulders below the chin, and
11
+ * drawn over everything behind it (`character-rig.ts`).
12
+ *
13
+ * Her head angles have not been read off her yet. `motion-limits.json` says so
14
+ * rather than guessing, and `headHold` gives her the tightest budget any face
15
+ * is still vouched for until the owner drives her.
16
+ */
17
+
18
+ import { character } from "./createCharacter.js";
19
+ import type { CharacterAvatarOptions } from "./createCharacter.js";
20
+ import { BLENDER_SUPPORTS } from "./sequences.js";
21
+ import { TANVI_GLB } from "./tanvi-asset.js";
22
+
23
+ export type { CharacterAvatarOptions as AvatarOptions };
24
+ export type { AvatarInstance } from "./createCharacter.js";
25
+
26
+ /** The optional driving-UI declaration; one list for every Blender character
27
+ * (`sequences.ts`), because they are one rig. */
28
+ export const supports = BLENDER_SUPPORTS;
29
+
30
+ export const createAvatar = character("tanvi", TANVI_GLB);
@@ -1,69 +1,29 @@
1
1
  /**
2
- * tanya — the third 3-D character, and like `tushar.ts` a copy of `tara.ts`.
2
+ * tanya — the third 3-D character, and the first whose atlas is not tara's
3
+ * window.
3
4
  *
4
- * Her GLB is tara's scripts run with her landmarks and atlas layout in place of
5
- * hers (`characters/tanya/`, whose README has the provenance and the commands),
6
- * so the rig, the mixer, the sequences and her tuning are all hers, unmodified;
7
- * the one seam is `TaraRigOptions.url`.
5
+ * Her GLB is the shared scripts run with her landmarks and atlas layout
6
+ * (`characters/tanya/`, whose README has the provenance and the commands).
7
+ * Her hair is the silhouette down past the jaw, out to |u| 0.761 where tara's
8
+ * window stops at 0.64, so `characters/tanya/face_texture.py` widens it to
9
+ * 1408x1568 at the same 800 pixels per face height. That is a fact about the
10
+ * asset and costs this file nothing — the rig reads the window from the GLB.
8
11
  *
9
- * She is the first character whose atlas is not tara's window. Her hair is the
10
- * silhouette down past the jaw, out to |u| 0.761 where tara's window stops at
11
- * 0.64, so `characters/tanya/face_texture.py` widens it to 1408x1568 at the same
12
- * 800 pixels per face height. That is a fact about the asset and costs this file
13
- * nothing — the rig reads the window from the GLB.
12
+ * Hair that hangs is what else makes her the third rather than a fourth copy:
13
+ * hers is the only `Hair` mesh that carries the roll channels, because it is
14
+ * the only one with anything below the hold line to lag behind a tilt.
14
15
  */
15
16
 
16
- import type { PipecatClient } from "@pipecat-ai/client-js";
17
- import { AvatarClient, createSvgAvatar } from "../internal.js";
17
+ import { character } from "./createCharacter.js";
18
+ import type { CharacterAvatarOptions } from "./createCharacter.js";
19
+ import { BLENDER_SUPPORTS } from "./sequences.js";
18
20
  import { TANYA_GLB } from "./tanya-asset.js";
19
- import { BLENDER_ACTIONS, BLENDER_SEQUENCES, BLENDER_SUPPORTS } from "./sequences.js";
20
- import { headHold } from "./holds.js";
21
- import { createTaraRig, TARA_TUNING } from "./tara-rig.js";
22
- import type { TaraRigOptions } from "./tara-rig.js";
23
21
 
24
- export interface AvatarOptions {
25
- readonly mount: HTMLElement;
26
- readonly client: PipecatClient;
27
- /** Viseme amplitude, 0..2. `1` is as authored. */
28
- readonly mouthGain?: number;
29
- /** Gesture-clip amplitude, 0..2. */
30
- readonly gestureGain?: number;
31
- /** Idle/liveness amplitude, 0..2. */
32
- readonly motionGain?: number;
33
- /** Fires when the GLB is in the scene — for a capture tool, not a consumer. */
34
- readonly onReady?: () => void;
35
- }
22
+ export type { CharacterAvatarOptions as AvatarOptions };
23
+ export type { AvatarInstance } from "./createCharacter.js";
36
24
 
37
- export interface AvatarInstance { destroy(): void; }
38
-
39
- /** The optional driving-UI declaration; one list for all three characters
25
+ /** The optional driving-UI declaration; one list for every Blender character
40
26
  * (`sequences.ts`), because they are one rig. */
41
27
  export const supports = BLENDER_SUPPORTS;
42
28
 
43
- export function createAvatar(options: AvatarOptions): AvatarInstance {
44
- const { mount, client, onReady, ...gains } = options;
45
- if (!mount) throw new TypeError("createAvatar: `mount` is required");
46
- if (!client) throw new TypeError("createAvatar: `client` is required");
47
-
48
- const rigOptions: TaraRigOptions = { onReady, url: TANYA_GLB };
49
- // TARA-SPECIFIC, kept on purpose: `TARA_TUNING` (her mouth and motion gains)
50
- // is the first thing to question if she reads wrong in a call.
51
- const widget = createSvgAvatar({
52
- mount, rig: createTaraRig, rigOptions, hand: false,
53
- sequences: BLENDER_SEQUENCES, actions: BLENDER_ACTIONS, ...TARA_TUNING,
54
- headHold: headHold("tanya"), ...gains,
55
- });
56
- const driver = new AvatarClient(widget);
57
- const detach = driver.attach(client);
58
-
59
- let destroyed = false;
60
- return {
61
- destroy() {
62
- if (destroyed) return;
63
- destroyed = true;
64
- detach();
65
- driver.destroy();
66
- widget.destroy();
67
- },
68
- };
69
- }
29
+ export const createAvatar = character("tanya", TANYA_GLB);
@@ -4,74 +4,33 @@
4
4
  * Structurally this is the canvas avatars' shape, one layer down: the mixer
5
5
  * (`@voqalize/avatar/internal`) does states, layers, gaze, idle, blinks, clips
6
6
  * and per-channel smoothing exactly as it does for every SVG face, and the only
7
- * thing tara replaces is the renderer at the end of it. That is the whole
8
- * argument for authoring her morph targets under the library's pose-channel
9
- * names: nothing above this line knows there is a GPU involved, and every clip,
10
- * viseme and co-articulation rule the SVG faces have works here unmodified.
7
+ * thing a Blender character replaces is the renderer at the end of it. That is
8
+ * the whole argument for authoring her morph targets under the library's pose
9
+ * channel names: nothing above this line knows there is a GPU involved, and
10
+ * every clip, viseme and co-articulation rule the SVG faces have works here
11
+ * unmodified.
12
+ *
13
+ * How a Blender character is driven is `createCharacter.ts`, and it is the same
14
+ * for all of them. What is hers is the mesh — and, until 2026-09-23, rather
15
+ * more than that: this file was the original, the others were copies of it, and
16
+ * the performance every character inherits was measured on her face. It is the
17
+ * house performance now (`CHARACTER_TUNING`), which changes nothing about how
18
+ * she looks and everything about where it is decided.
11
19
  *
12
20
  * The Three.js import lives behind this module rather than in the barrel so an
13
21
  * SVG or Canvas consumer never downloads it.
14
22
  */
15
23
 
16
- import type { PipecatClient } from "@pipecat-ai/client-js";
17
- import { AvatarClient, createSvgAvatar } from "../internal.js";
18
- import { BLENDER_ACTIONS, BLENDER_SEQUENCES, BLENDER_SUPPORTS } from "./sequences.js";
24
+ import { character } from "./createCharacter.js";
25
+ import type { CharacterAvatarOptions } from "./createCharacter.js";
26
+ import { BLENDER_SUPPORTS } from "./sequences.js";
19
27
  import { TARA_GLB } from "./tara-asset.js";
20
- import { headHold } from "./holds.js";
21
- import { createTaraRig, TARA_TUNING } from "./tara-rig.js";
22
- import type { TaraRigOptions } from "./tara-rig.js";
23
-
24
- export interface AvatarOptions {
25
- readonly mount: HTMLElement;
26
- readonly client: PipecatClient;
27
- /** Viseme amplitude, 0..2. `1` is as authored. */
28
- readonly mouthGain?: number;
29
- /** Gesture-clip amplitude, 0..2. */
30
- readonly gestureGain?: number;
31
- /** Idle/liveness amplitude, 0..2. */
32
- readonly motionGain?: number;
33
- /** Fires when the GLB is in the scene — for a capture tool, not a consumer. */
34
- readonly onReady?: () => void;
35
- }
36
28
 
37
- export interface AvatarInstance { destroy(): void; }
29
+ export type { CharacterAvatarOptions as AvatarOptions };
30
+ export type { AvatarInstance } from "./createCharacter.js";
38
31
 
39
- /** The optional driving-UI declaration; one list for all three characters
32
+ /** The optional driving-UI declaration; one list for every Blender character
40
33
  * (`sequences.ts`), because they are one rig. */
41
34
  export const supports = BLENDER_SUPPORTS;
42
35
 
43
- export function createAvatar(options: AvatarOptions): AvatarInstance {
44
- const { mount, client, onReady, ...gains } = options;
45
- if (!mount) throw new TypeError("createAvatar: `mount` is required");
46
- if (!client) throw new TypeError("createAvatar: `client` is required");
47
-
48
- const rigOptions: TaraRigOptions = { onReady, url: TARA_GLB };
49
- // `hand: false` disables the bundled SVG hand renderer only; the semantic
50
- // hand frame still reaches the rig, which ignores it — tara has no arms, and
51
- // that is the library's oldest standing constraint rather than an omission.
52
- // `sequences` is what a server can address on *this* avatar beyond the two
53
- // ids every avatar owes it — the three nod types the listening research
54
- // separates, and a head shake sized for a rig whose pose unit is a degree.
55
- // The wire's action id is open, so nothing here needed promoting; a server
56
- // that does not know tara is mounted sends `ACKNOWLEDGE` and is never wrong.
57
- // `actions` is the other half: her own shape for an id the mixer already has,
58
- // whose shared keys land outside what it means on a head that turns in degrees.
59
- const widget = createSvgAvatar({
60
- mount, rig: createTaraRig, rigOptions, hand: false,
61
- sequences: BLENDER_SEQUENCES, actions: BLENDER_ACTIONS, ...TARA_TUNING,
62
- headHold: headHold("tara"), ...gains,
63
- });
64
- const driver = new AvatarClient(widget);
65
- const detach = driver.attach(client);
66
-
67
- let destroyed = false;
68
- return {
69
- destroy() {
70
- if (destroyed) return;
71
- destroyed = true;
72
- detach();
73
- driver.destroy();
74
- widget.destroy();
75
- },
76
- };
77
- }
36
+ export const createAvatar = character("tara", TARA_GLB);
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Where tess's compiled GLB is. One character, one module — see
3
+ * [tara-asset.ts](./tara-asset.ts) for why that separation is load-bearing and
4
+ * why the `new URL` literal is spelled exactly this way.
5
+ */
6
+ export const TESS_GLB = new URL("../../assets/tess.glb", import.meta.url).href;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * tess — American, and the leanest character in the forge.
3
+ *
4
+ * Her GLB is the shared scripts run with her landmarks (`characters/tess/`,
5
+ * whose README has the provenance and the commands). She is back inside tara's
6
+ * atlas window — her hair is drawn into a low tail that clears both ears and
7
+ * reaches |u| 0.492 against a window that stops at 0.64 — so unlike tanya she
8
+ * needs no `face_texture.py` of her own, and her `Hair` shell gives up no roll:
9
+ * nothing of hers hangs past the jaw to lag. One supplied sheet, no paid edit,
10
+ * no module of her own; she is what a new character costs at the floor, which
11
+ * is why the README builds its template from her.
12
+ *
13
+ * Her head angles have not been read off her yet. `motion-limits.json` says so
14
+ * rather than guessing, and `headHold` gives her the tightest budget any face
15
+ * is still vouched for until the owner drives her.
16
+ */
17
+
18
+ import { character } from "./createCharacter.js";
19
+ import type { CharacterAvatarOptions } from "./createCharacter.js";
20
+ import { BLENDER_SUPPORTS } from "./sequences.js";
21
+ import { TESS_GLB } from "./tess-asset.js";
22
+
23
+ export type { CharacterAvatarOptions as AvatarOptions };
24
+ export type { AvatarInstance } from "./createCharacter.js";
25
+
26
+ /** The optional driving-UI declaration; one list for every Blender character
27
+ * (`sequences.ts`), because they are one rig. */
28
+ export const supports = BLENDER_SUPPORTS;
29
+
30
+ export const createAvatar = character("tess", TESS_GLB);
@@ -1,65 +1,28 @@
1
1
  /**
2
- * tushar — the second 3-D character, and deliberately a copy of `tara.ts`.
2
+ * tushar — the second 3-D character, and the one who proved the factory.
3
3
  *
4
- * His GLB is tara's scripts run with his landmarks and atlas layout in place of
5
- * hers (`characters/tushar/`, whose README has the provenance and the commands),
6
- * so the rig, the mixer, the sequences and her tuning are all hers, unmodified;
7
- * the one seam is `TaraRigOptions.url`. What turns out to be hers rather than
8
- * general is marked TARA-SPECIFIC where it lives, and generalised only once a
9
- * third character agrees.
4
+ * His GLB is the shared scripts run with his landmarks and atlas layout in
5
+ * place of tara's (`characters/tushar/`, whose README has the provenance and
6
+ * the commands). He was a deliberate copy of `tara.ts` for as long as there was
7
+ * a `tara.ts` to copy; since 2026-09-23 there is one Blender entry point and he
8
+ * is its second caller rather than her second draft (`createCharacter.ts`).
9
+ *
10
+ * He is also the face that turned the ledger from a question into a decision.
11
+ * What was marked TARA-SPECIFIC was marked that way because one face cannot
12
+ * tell a convention from a coincidence; he agreed with her, and so did the two
13
+ * after him.
10
14
  */
11
15
 
12
- import type { PipecatClient } from "@pipecat-ai/client-js";
13
- import { AvatarClient, createSvgAvatar } from "../internal.js";
16
+ import { character } from "./createCharacter.js";
17
+ import type { CharacterAvatarOptions } from "./createCharacter.js";
18
+ import { BLENDER_SUPPORTS } from "./sequences.js";
14
19
  import { TUSHAR_GLB } from "./tushar-asset.js";
15
- import { BLENDER_ACTIONS, BLENDER_SEQUENCES, BLENDER_SUPPORTS } from "./sequences.js";
16
- import { headHold } from "./holds.js";
17
- import { createTaraRig, TARA_TUNING } from "./tara-rig.js";
18
- import type { TaraRigOptions } from "./tara-rig.js";
19
-
20
- export interface AvatarOptions {
21
- readonly mount: HTMLElement;
22
- readonly client: PipecatClient;
23
- /** Viseme amplitude, 0..2. `1` is as authored. */
24
- readonly mouthGain?: number;
25
- /** Gesture-clip amplitude, 0..2. */
26
- readonly gestureGain?: number;
27
- /** Idle/liveness amplitude, 0..2. */
28
- readonly motionGain?: number;
29
- /** Fires when the GLB is in the scene — for a capture tool, not a consumer. */
30
- readonly onReady?: () => void;
31
- }
32
20
 
33
- export interface AvatarInstance { destroy(): void; }
21
+ export type { CharacterAvatarOptions as AvatarOptions };
22
+ export type { AvatarInstance } from "./createCharacter.js";
34
23
 
35
- /** The optional driving-UI declaration; one list for all three characters
24
+ /** The optional driving-UI declaration; one list for every Blender character
36
25
  * (`sequences.ts`), because they are one rig. */
37
26
  export const supports = BLENDER_SUPPORTS;
38
27
 
39
- export function createAvatar(options: AvatarOptions): AvatarInstance {
40
- const { mount, client, onReady, ...gains } = options;
41
- if (!mount) throw new TypeError("createAvatar: `mount` is required");
42
- if (!client) throw new TypeError("createAvatar: `client` is required");
43
-
44
- const rigOptions: TaraRigOptions = { onReady, url: TUSHAR_GLB };
45
- // TARA-SPECIFIC, kept on purpose: `TARA_TUNING` (her mouth and motion gains)
46
- // is the first thing to question if he reads wrong in a call.
47
- const widget = createSvgAvatar({
48
- mount, rig: createTaraRig, rigOptions, hand: false,
49
- sequences: BLENDER_SEQUENCES, actions: BLENDER_ACTIONS, ...TARA_TUNING,
50
- headHold: headHold("tushar"), ...gains,
51
- });
52
- const driver = new AvatarClient(widget);
53
- const detach = driver.attach(client);
54
-
55
- let destroyed = false;
56
- return {
57
- destroy() {
58
- if (destroyed) return;
59
- destroyed = true;
60
- detach();
61
- driver.destroy();
62
- widget.destroy();
63
- },
64
- };
65
- }
28
+ export const createAvatar = character("tushar", TUSHAR_GLB);
@@ -21,8 +21,8 @@
21
21
  * renderer uses internally. It is *not* the seam to implement — see
22
22
  * docs/design-avatar-interface.md.
23
23
  */
24
- export { createAvatar as createSvgAvatar, REST, CHANNELS, RANGE, STATES, STATE_NAMES, ACTIONS, ACTION_IDS, GAZE_NAMES, GAZE_TARGETS, EMOTION_NAMES, VisemeTrack, VISEME_LETTERS, VISEME_SHAPES, SILENT, LEAD_MS, SHOULDER_TILT, shapeFor, normalizeCues, textToCues, ARPABET_TO_VISEME, AZURE_VISEME_TO_LETTER, } from "../src/avatar.js";
25
- export type { AvatarApi, AvatarStateName, AvatarActionId, AvatarGazeName, AvatarEmotionName, AvatarAction, AvatarMeta, VisemeLetter, Cue, PoseChannel, PoseOverrides, CreateAvatarOptions as CreateSvgAvatarOptions, } from "../src/avatar.js";
24
+ export { createAvatar as createSvgAvatar, REST, CHANNELS, RANGE, STATES, STATE_NAMES, ACTIONS, ACTION_IDS, GAZE_NAMES, GAZE_TARGETS, EMOTION_NAMES, VisemeTrack, VISEME_LETTERS, VISEME_SHAPES, SILENT, LEAD_MS, SHOULDER_TILT, INTERNAL_CLIPS, ClipPlayer, TAU, clamp, approach, makeParams, emotionPose, avatarFrame, createSvgRig, shapeFor, JAW_OF_OPEN, normalizeCues, textToCues, ARPABET_TO_VISEME, AZURE_VISEME_TO_LETTER, } from "../src/avatar.js";
25
+ export type { Clip, ClipSample, AvatarApi, AvatarStateName, AvatarActionId, AvatarGazeName, AvatarEmotionName, AvatarAction, AvatarMeta, VisemeLetter, Cue, PoseChannel, PoseOverrides, CreateAvatarOptions as CreateSvgAvatarOptions, } from "../src/avatar.js";
26
26
  export type { AvatarFrame, AvatarRig, AvatarRigFactory, HandFrame, RigPose, } from "../src/rig.js";
27
27
  export { BEHAVIOR_STATE_IDS, BEHAVIOR_ACTIONS, BEHAVIOR_ACTION_IDS, WIRE_ACTION_TO_BEHAVIOR, } from "../src/behavior.js";
28
28
  export type { BehaviorStateId, BehaviorActionId } from "../src/behavior.js";
@@ -1 +1 @@
1
- {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../client/internal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAIL,YAAY,IAAI,eAAe,EAG/B,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,MAAM,EACN,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACV,YAAY,EACZ,aAAa,EAEb,WAAW,EACX,cAAc,EACd,aAAa,EACb,MAAM,EACN,OAAO,EAEP,aAAa,EACb,QAAQ,EACR,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACV,SAAS,EACT,eAAe,EACf,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,GAAG,EACH,WAAW,EACX,aAAa,EACb,mBAAmB,IAAI,sBAAsB,GAC9C,MAAM,kBAAkB,CAAC;AAK1B,YAAY,EACV,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,OAAO,GACR,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAM9D,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EACV,aAAa,EACb,SAAS,EACT,aAAa,EACb,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,mBAAmB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../client/internal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAIL,YAAY,IAAI,eAAe,EAG/B,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,MAAM,EACN,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACV,YAAY,EACZ,aAAa,EAEb,WAAW,EACX,cAAc,EACd,aAAa,EACb,MAAM,EACN,OAAO,EAEP,aAAa,EAMb,cAAc,EACd,UAAU,EACV,GAAG,EACH,KAAK,EACL,QAAQ,EAKR,UAAU,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,QAAQ,EAIR,WAAW,EACX,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACV,IAAI,EACJ,UAAU,EACV,SAAS,EACT,eAAe,EACf,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,GAAG,EACH,WAAW,EACX,aAAa,EACb,mBAAmB,IAAI,sBAAsB,GAC9C,MAAM,kBAAkB,CAAC;AAK1B,YAAY,EACV,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,OAAO,GACR,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAM9D,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EACV,aAAa,EACb,SAAS,EACT,aAAa,EACb,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,mBAAmB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/internal.js CHANGED
@@ -32,7 +32,22 @@ REST, CHANNELS, RANGE, STATES, STATE_NAMES, ACTIONS, ACTION_IDS, GAZE_NAMES, GAZ
32
32
  // The viseme clock and its tables.
33
33
  VisemeTrack, VISEME_LETTERS, VISEME_SHAPES, SILENT, LEAD_MS,
34
34
  // The body's share of a held tilt, for a page driving a rig by hand.
35
- SHOULDER_TILT, shapeFor, normalizeCues, textToCues, ARPABET_TO_VISEME, AZURE_VISEME_TO_LETTER, } from "../src/avatar.js";
35
+ SHOULDER_TILT,
36
+ // Stepping a gesture by hand: the catalogue, the player, and the smoothing
37
+ // law the mixer puts between a clip's keyframes and the face. A filmstrip
38
+ // instrument needs all three, and the one thing it must not do is fork the
39
+ // smoothing — that is the part a keyframe is authored against
40
+ // (docs/internal-mixer.md § Smoothing).
41
+ INTERNAL_CLIPS, ClipPlayer, TAU, clamp, approach,
42
+ // Posing a face directly, with no mixer, no clock and no client above it —
43
+ // what a pose sheet or a rig-conformance page does. `makeParams` fills the
44
+ // rests around a handful of overrides, `emotionPose` names a familiar set of
45
+ // them, `avatarFrame` wraps the result and `createSvgRig(face)` draws it.
46
+ makeParams, emotionPose, avatarFrame, createSvgRig, shapeFor,
47
+ // The one number that says how far the mandible falls for a given aperture.
48
+ // Anything composing a mouth pose without `shapeFor` — a retarget, a driver —
49
+ // needs it, and the amplitudes behind the lips are calibrated at it.
50
+ JAW_OF_OPEN, normalizeCues, textToCues, ARPABET_TO_VISEME, AZURE_VISEME_TO_LETTER, } from "../src/avatar.js";
36
51
  export { BEHAVIOR_STATE_IDS, BEHAVIOR_ACTIONS, BEHAVIOR_ACTION_IDS, WIRE_ACTION_TO_BEHAVIOR, } from "../src/behavior.js";
37
52
  export { isAvatarMessage, CORE_ACTION_IDS } from "./types.js";
38
53
  // A renderer may reuse the one lifecycle/precedence ladder without gaining a
@@ -1 +1 @@
1
- {"version":3,"file":"internal.js","sourceRoot":"","sources":["../client/internal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO;AACL,2EAA2E;AAC3E,0DAA0D;AAC1D,8DAA8D;AAC9D,YAAY,IAAI,eAAe;AAC/B,8EAA8E;AAC9E,oBAAoB;AACpB,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,MAAM,EACN,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACV,YAAY,EACZ,aAAa;AACb,mCAAmC;AACnC,WAAW,EACX,cAAc,EACd,aAAa,EACb,MAAM,EACN,OAAO;AACP,qEAAqE;AACrE,aAAa,EACb,QAAQ,EACR,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AA4B1B,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAO9D,6EAA6E;AAC7E,kCAAkC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"internal.js","sourceRoot":"","sources":["../client/internal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO;AACL,2EAA2E;AAC3E,0DAA0D;AAC1D,8DAA8D;AAC9D,YAAY,IAAI,eAAe;AAC/B,8EAA8E;AAC9E,oBAAoB;AACpB,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,MAAM,EACN,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACV,YAAY,EACZ,aAAa;AACb,mCAAmC;AACnC,WAAW,EACX,cAAc,EACd,aAAa,EACb,MAAM,EACN,OAAO;AACP,qEAAqE;AACrE,aAAa;AACb,2EAA2E;AAC3E,0EAA0E;AAC1E,2EAA2E;AAC3E,8DAA8D;AAC9D,wCAAwC;AACxC,cAAc,EACd,UAAU,EACV,GAAG,EACH,KAAK,EACL,QAAQ;AACR,2EAA2E;AAC3E,2EAA2E;AAC3E,6EAA6E;AAC7E,0EAA0E;AAC1E,UAAU,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,QAAQ;AACR,4EAA4E;AAC5E,8EAA8E;AAC9E,qEAAqE;AACrE,WAAW,EACX,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AA8B1B,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAO9D,6EAA6E;AAC7E,kCAAkC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}