@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.
Files changed (265) hide show
  1. package/LICENSE +21 -661
  2. package/LICENSE-CC-BY-4.0 +396 -0
  3. package/README.md +191 -662
  4. package/assets/README.md +48 -0
  5. package/assets/tanya.glb +0 -0
  6. package/assets/tara.glb +0 -0
  7. package/assets/tushar.glb +0 -0
  8. package/client/Avatar.tsx +57 -0
  9. package/client/AvatarClient.ts +818 -0
  10. package/client/arjun.ts +26 -0
  11. package/client/createAvatar.ts +177 -0
  12. package/client/createCanvasAvatar.ts +72 -0
  13. package/client/index.ts +44 -0
  14. package/client/internal.ts +108 -0
  15. package/client/interviewer-female.ts +4 -0
  16. package/client/interviewer-male.ts +4 -0
  17. package/client/ishita.ts +26 -0
  18. package/client/kabir.ts +26 -0
  19. package/client/meera.ts +26 -0
  20. package/client/naina.ts +26 -0
  21. package/client/playout.ts +95 -0
  22. package/client/professional-female-a.ts +4 -0
  23. package/client/professional-female-b.ts +4 -0
  24. package/client/professional-male-a.ts +4 -0
  25. package/client/professional-male-b.ts +4 -0
  26. package/client/react.ts +13 -0
  27. package/client/supports.ts +28 -0
  28. package/client/three/assets.ts +24 -0
  29. package/client/three/budgets.ts +27 -0
  30. package/client/three/holds.ts +64 -0
  31. package/client/three/internal.ts +54 -0
  32. package/client/three/motion-limits.json +116 -0
  33. package/client/three/sequences.ts +281 -0
  34. package/client/three/tanya.ts +69 -0
  35. package/client/three/tara-rig.ts +1562 -0
  36. package/client/three/tara.ts +76 -0
  37. package/client/three/tushar.ts +65 -0
  38. package/client/types.ts +235 -0
  39. package/client/useAvatar.ts +74 -0
  40. package/client/vikram.ts +26 -0
  41. package/dist/Avatar.d.ts +44 -0
  42. package/dist/Avatar.d.ts.map +1 -0
  43. package/{client/dist → dist}/Avatar.js +2 -2
  44. package/dist/Avatar.js.map +1 -0
  45. package/dist/AvatarClient.d.ts +274 -0
  46. package/dist/AvatarClient.d.ts.map +1 -0
  47. package/dist/AvatarClient.js +712 -0
  48. package/dist/AvatarClient.js.map +1 -0
  49. package/dist/arjun.d.ts +7 -0
  50. package/dist/arjun.d.ts.map +1 -0
  51. package/dist/arjun.js +20 -0
  52. package/dist/arjun.js.map +1 -0
  53. package/dist/createAvatar.d.ts +135 -0
  54. package/dist/createAvatar.d.ts.map +1 -0
  55. package/dist/createAvatar.js +75 -0
  56. package/dist/createAvatar.js.map +1 -0
  57. package/dist/createCanvasAvatar.d.ts +22 -0
  58. package/dist/createCanvasAvatar.d.ts.map +1 -0
  59. package/dist/createCanvasAvatar.js +47 -0
  60. package/dist/createCanvasAvatar.js.map +1 -0
  61. package/dist/index.d.ts +34 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +33 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/internal.d.ts +34 -0
  66. package/dist/internal.d.ts.map +1 -0
  67. package/dist/internal.js +41 -0
  68. package/dist/internal.js.map +1 -0
  69. package/dist/interviewer-female.d.ts +4 -0
  70. package/dist/interviewer-female.d.ts.map +1 -0
  71. package/dist/interviewer-female.js +3 -0
  72. package/dist/interviewer-female.js.map +1 -0
  73. package/dist/interviewer-male.d.ts +4 -0
  74. package/dist/interviewer-male.d.ts.map +1 -0
  75. package/dist/interviewer-male.js +3 -0
  76. package/dist/interviewer-male.js.map +1 -0
  77. package/dist/ishita.d.ts +7 -0
  78. package/dist/ishita.d.ts.map +1 -0
  79. package/dist/ishita.js +20 -0
  80. package/dist/ishita.js.map +1 -0
  81. package/dist/kabir.d.ts +7 -0
  82. package/dist/kabir.d.ts.map +1 -0
  83. package/dist/kabir.js +20 -0
  84. package/dist/kabir.js.map +1 -0
  85. package/dist/meera.d.ts +7 -0
  86. package/dist/meera.d.ts.map +1 -0
  87. package/dist/meera.js +20 -0
  88. package/dist/meera.js.map +1 -0
  89. package/dist/naina.d.ts +7 -0
  90. package/dist/naina.d.ts.map +1 -0
  91. package/dist/naina.js +20 -0
  92. package/dist/naina.js.map +1 -0
  93. package/dist/playout.d.ts +42 -0
  94. package/dist/playout.d.ts.map +1 -0
  95. package/dist/playout.js +85 -0
  96. package/dist/playout.js.map +1 -0
  97. package/dist/professional-female-a.d.ts +4 -0
  98. package/dist/professional-female-a.d.ts.map +1 -0
  99. package/dist/professional-female-a.js +3 -0
  100. package/dist/professional-female-a.js.map +1 -0
  101. package/dist/professional-female-b.d.ts +4 -0
  102. package/dist/professional-female-b.d.ts.map +1 -0
  103. package/dist/professional-female-b.js +3 -0
  104. package/dist/professional-female-b.js.map +1 -0
  105. package/dist/professional-male-a.d.ts +4 -0
  106. package/dist/professional-male-a.d.ts.map +1 -0
  107. package/dist/professional-male-a.js +3 -0
  108. package/dist/professional-male-a.js.map +1 -0
  109. package/dist/professional-male-b.d.ts +4 -0
  110. package/dist/professional-male-b.d.ts.map +1 -0
  111. package/dist/professional-male-b.js +3 -0
  112. package/dist/professional-male-b.js.map +1 -0
  113. package/dist/react.d.ts +13 -0
  114. package/dist/react.d.ts.map +1 -0
  115. package/dist/react.js +13 -0
  116. package/dist/react.js.map +1 -0
  117. package/dist/supports.d.ts +20 -0
  118. package/dist/supports.d.ts.map +1 -0
  119. package/dist/supports.js +26 -0
  120. package/dist/supports.js.map +1 -0
  121. package/dist/three/assets.d.ts +24 -0
  122. package/dist/three/assets.d.ts.map +1 -0
  123. package/dist/three/assets.js +22 -0
  124. package/dist/three/assets.js.map +1 -0
  125. package/dist/three/budgets.d.ts +17 -0
  126. package/dist/three/budgets.d.ts.map +1 -0
  127. package/dist/three/budgets.js +21 -0
  128. package/dist/three/budgets.js.map +1 -0
  129. package/dist/three/holds.d.ts +33 -0
  130. package/dist/three/holds.d.ts.map +1 -0
  131. package/dist/three/holds.js +56 -0
  132. package/dist/three/holds.js.map +1 -0
  133. package/dist/three/internal.d.ts +52 -0
  134. package/dist/three/internal.d.ts.map +1 -0
  135. package/dist/three/internal.js +49 -0
  136. package/dist/three/internal.js.map +1 -0
  137. package/dist/three/motion-limits.json +116 -0
  138. package/dist/three/sequences.d.ts +71 -0
  139. package/dist/three/sequences.d.ts.map +1 -0
  140. package/dist/three/sequences.js +262 -0
  141. package/dist/three/sequences.js.map +1 -0
  142. package/dist/three/tanya.d.ts +35 -0
  143. package/dist/three/tanya.d.ts.map +1 -0
  144. package/dist/three/tanya.js +51 -0
  145. package/dist/three/tanya.js.map +1 -0
  146. package/dist/three/tara-rig.d.ts +403 -0
  147. package/dist/three/tara-rig.d.ts.map +1 -0
  148. package/dist/three/tara-rig.js +1500 -0
  149. package/dist/three/tara-rig.js.map +1 -0
  150. package/dist/three/tara.d.ts +35 -0
  151. package/dist/three/tara.d.ts.map +1 -0
  152. package/dist/three/tara.js +58 -0
  153. package/dist/three/tara.js.map +1 -0
  154. package/dist/three/tushar.d.ts +31 -0
  155. package/dist/three/tushar.d.ts.map +1 -0
  156. package/dist/three/tushar.js +47 -0
  157. package/dist/three/tushar.js.map +1 -0
  158. package/dist/types.d.ts +149 -0
  159. package/dist/types.d.ts.map +1 -0
  160. package/dist/types.js +140 -0
  161. package/dist/types.js.map +1 -0
  162. package/dist/useAvatar.d.ts +39 -0
  163. package/dist/useAvatar.d.ts.map +1 -0
  164. package/dist/useAvatar.js +35 -0
  165. package/dist/useAvatar.js.map +1 -0
  166. package/dist/vikram.d.ts +7 -0
  167. package/dist/vikram.d.ts.map +1 -0
  168. package/dist/vikram.js +20 -0
  169. package/dist/vikram.js.map +1 -0
  170. package/package.json +110 -25
  171. package/src/avatar.d.ts +218 -120
  172. package/src/avatar.js +950 -213
  173. package/src/behavior.d.ts +42 -0
  174. package/src/behavior.js +114 -0
  175. package/src/camera.js +29 -0
  176. package/src/canvas/author/parts/eye.mjs +722 -0
  177. package/src/canvas/author/parts/hand.mjs +1156 -0
  178. package/src/canvas/author/parts/mouth.mjs +741 -0
  179. package/src/canvas/author/parts/nose.mjs +100 -0
  180. package/src/canvas/author/parts/skin-detail.mjs +67 -0
  181. package/src/canvas/author/path.mjs +283 -0
  182. package/src/canvas/author/rig.mjs +405 -0
  183. package/src/canvas/avatars/round/face.d.mts +3 -0
  184. package/src/canvas/avatars/round/face.mjs +1307 -0
  185. package/src/canvas/create-rig.d.ts +15 -0
  186. package/src/canvas/create-rig.js +100 -0
  187. package/src/canvas/data/img/professional-female-a-hair-back.webp +0 -0
  188. package/src/canvas/data/img/professional-female-a-hair-front.webp +0 -0
  189. package/src/canvas/data/img/professional-female-a-top-body.webp +0 -0
  190. package/src/canvas/data/img/professional-female-b-hair-back.webp +0 -0
  191. package/src/canvas/data/img/professional-female-b-hair-front.webp +0 -0
  192. package/src/canvas/data/img/professional-female-b-top-body.webp +0 -0
  193. package/src/canvas/data/img/professional-male-a-hair-back.webp +0 -0
  194. package/src/canvas/data/img/professional-male-a-hair-front.webp +0 -0
  195. package/src/canvas/data/img/professional-male-a-top-body.webp +0 -0
  196. package/src/canvas/data/img/professional-male-b-hair-back.webp +0 -0
  197. package/src/canvas/data/img/professional-male-b-hair-front.webp +0 -0
  198. package/src/canvas/data/img/professional-male-b-top-body.webp +0 -0
  199. package/src/canvas/data/img/round-m3-hair-back.webp +0 -0
  200. package/src/canvas/data/img/round-m3-hair-front.webp +0 -0
  201. package/src/canvas/data/img/round-m3-top-body.webp +0 -0
  202. package/src/canvas/data/img/round-w1-hair-back.webp +0 -0
  203. package/src/canvas/data/img/round-w1-hair-front.webp +0 -0
  204. package/src/canvas/data/img/round-w1-top-body.webp +0 -0
  205. package/src/canvas/data/interviewer-female.rig.json +1 -0
  206. package/src/canvas/data/interviewer-male.rig.json +1 -0
  207. package/src/canvas/data/professional-female-a.rig.json +1 -0
  208. package/src/canvas/data/professional-female-b.rig.json +1 -0
  209. package/src/canvas/data/professional-male-a.rig.json +1 -0
  210. package/src/canvas/data/professional-male-b.rig.json +1 -0
  211. package/src/canvas/src/live.js +508 -0
  212. package/src/canvas/src/render2d.js +218 -0
  213. package/src/canvas/src/rig.js +297 -0
  214. package/src/canvas/src/vocab.js +96 -0
  215. package/src/clips.js +18 -7
  216. package/src/conformance.js +119 -0
  217. package/src/emotions.js +8 -5
  218. package/src/face-core.js +27 -1
  219. package/src/face-myna.d.ts +7 -0
  220. package/src/face-myna.js +192 -131
  221. package/src/face-peep-control-plane.js +167 -0
  222. package/src/face-peep.d.ts +7 -0
  223. package/src/face-peep.js +274 -116
  224. package/src/face-wren.d.ts +7 -0
  225. package/src/face-wren.js +17 -19
  226. package/src/faces.d.ts +12 -0
  227. package/src/faces.js +53 -0
  228. package/src/gaze.js +434 -58
  229. package/src/hand.js +120 -91
  230. package/src/head.js +134 -0
  231. package/src/idle.js +227 -119
  232. package/src/interjections.js +200 -31
  233. package/src/params.js +8 -4
  234. package/src/perform.js +7 -9
  235. package/src/prosody.js +647 -0
  236. package/src/rig.d.ts +24 -0
  237. package/src/rig.js +32 -0
  238. package/src/speech-timing.js +23 -0
  239. package/src/visemes.js +110 -24
  240. package/client/dist/Avatar.d.ts +0 -27
  241. package/client/dist/Avatar.d.ts.map +0 -1
  242. package/client/dist/Avatar.js.map +0 -1
  243. package/client/dist/AvatarClient.d.ts +0 -139
  244. package/client/dist/AvatarClient.d.ts.map +0 -1
  245. package/client/dist/AvatarClient.js +0 -223
  246. package/client/dist/AvatarClient.js.map +0 -1
  247. package/client/dist/index.d.ts +0 -22
  248. package/client/dist/index.d.ts.map +0 -1
  249. package/client/dist/index.js +0 -22
  250. package/client/dist/index.js.map +0 -1
  251. package/client/dist/types.d.ts +0 -86
  252. package/client/dist/types.d.ts.map +0 -1
  253. package/client/dist/types.js +0 -31
  254. package/client/dist/types.js.map +0 -1
  255. package/client/dist/useAvatar.d.ts +0 -42
  256. package/client/dist/useAvatar.d.ts.map +0 -1
  257. package/client/dist/useAvatar.js +0 -51
  258. package/client/dist/useAvatar.js.map +0 -1
  259. package/client/src/Avatar.tsx +0 -33
  260. package/client/src/AvatarClient.ts +0 -270
  261. package/client/src/index.ts +0 -22
  262. package/client/src/types.ts +0 -104
  263. package/client/src/useAvatar.ts +0 -85
  264. package/docs/contract-avatar.md +0 -371
  265. package/docs/contract-protocol.md +0 -461
package/src/face-wren.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * Avatar: "wren".
3
3
  *
4
4
  * The second line-art character, and the proof run for the recipe in
5
- * docs/contract-avatar.md: static art + a POSE spec + feature blocks + META,
5
+ * docs/authoring-a-face.md: static art + a POSE spec + feature blocks + META,
6
6
  * with the stroke engine imported from line-art.js rather than carried along.
7
7
  * Character: female, thirties, a big natural-curl mass, round glasses, a
8
8
  * crew-neck tee. Same idiom as peep — no strokes anywhere, ink and paper and
@@ -30,10 +30,9 @@ import {
30
30
  f, createFaceShell, faceApi, poseTransforms, pairedTeeth,
31
31
  } from './face-core.js';
32
32
  import { taper, taperRing, region } from './line-art.js';
33
+ import { viewBoxForHead } from './camera.js';
33
34
 
34
35
  export const THEME = {
35
- bg0: '#f6f3ee',
36
- bg1: '#e8e2d8',
37
36
  ink: '#1b1b1b',
38
37
  paper: '#ffffff',
39
38
  accent: '#f97415',
@@ -42,10 +41,9 @@ export const THEME = {
42
41
  tongue: '#8d7f79',
43
42
  };
44
43
 
45
- // Frame: same native 760x950 art space as peep — not a requirement, just no
46
- // reason to differ — with the window shifted up because the hair cloud crowns
47
- // ~40 units higher than peep's fade.
48
- const VB = { x: 92, y: 50, w: 576, h: 800 };
44
+ // Wren's hair cloud is her visible crown; the skull begins well below it.
45
+ const FRAME = { centerX: 380, crownY: 102, chinY: 575 };
46
+ const VB = viewBoxForHead(FRAME);
49
47
 
50
48
  export const META = {
51
49
  viewBox: { x: VB.x, y: VB.y, w: VB.w, h: VB.h },
@@ -53,7 +51,7 @@ export const META = {
53
51
  };
54
52
 
55
53
  // --- landmarks --------------------------------------------------------------
56
- const CX = 380;
54
+ const CX = FRAME.centerX;
57
55
  const HEAD_TOP = 148;
58
56
  const CHIN_Y = 572;
59
57
 
@@ -224,7 +222,7 @@ const POSE = {
224
222
  // peep's breath and trunk numbers; same construction, same art units, and
225
223
  // the two characters should breathe alike. See face-peep.js for the
226
224
  // derivation.
227
- breathSwell: 0.012, swellPivot: { x: CX, y: 950 },
225
+ breathSwell: 0.008, swellPivot: { x: CX, y: 950 },
228
226
  turnPx: 16,
229
227
  layers: LAYERS, parallax: PARALLAX,
230
228
  torsoLayers: ['body'],
@@ -254,8 +252,8 @@ function mouthGeometry(p) {
254
252
  const h = open * MOUTH_APERTURE;
255
253
  const k = clamp(open / 0.18);
256
254
 
257
- const yL = cy - 6 - p.mouthCornerL * 22;
258
- const yR = cy - 6 - p.mouthCornerR * 22;
255
+ const yL = cy - 1.5 - p.mouthCornerL * 22;
256
+ const yR = cy - 1.5 - p.mouthCornerR * 22;
259
257
 
260
258
  const apTop = cy - h * 0.25;
261
259
  let apBot = cy + h * 0.75;
@@ -348,14 +346,7 @@ function markup(id, t) {
348
346
  return `
349
347
  <svg id="${id}" viewBox="${VB.x} ${VB.y} ${VB.w} ${VB.h}" xmlns="http://www.w3.org/2000/svg"
350
348
  preserveAspectRatio="xMidYMid meet" style="display:block;width:100%;height:100%">
351
- <defs>
352
- <radialGradient id="${id}-gBg" cx="50%" cy="36%" r="76%">
353
- <stop offset="0%" stop-color="${t.bg0}"/><stop offset="100%" stop-color="${t.bg1}"/>
354
- </radialGradient>
355
- <clipPath id="${id}-clipMouth"><path id="${id}-clipMouthP" d=""/></clipPath>
356
- </defs>
357
-
358
- <rect x="${VB.x}" y="${VB.y}" width="${VB.w}" height="${VB.h}" fill="url(#${id}-gBg)"/>
349
+ <defs><clipPath id="${id}-clipMouth"><path id="${id}-clipMouthP" d=""/></clipPath></defs>
359
350
 
360
351
  <!-- head and neck. No ears: the hair band covers them (see the hair note).
361
352
  Hair underlay at head parallax, same insurance as peep's — the cloud
@@ -468,3 +459,10 @@ export function createFace(mount, theme = {}) {
468
459
 
469
460
  return faceApi(mount, svg, apply, t);
470
461
  }
462
+
463
+ /**
464
+ * This face as a **Face** record — `{ create, meta }`, the shape
465
+ * `createAvatar({ face })` takes. Importing it costs this drawing and nothing
466
+ * else; `src/faces.js` is the all-three table, for tooling.
467
+ */
468
+ export const wren = { create: createFace, meta: META };
package/src/faces.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { Face } from "./avatar.js";
2
+
3
+ export const peep: Face;
4
+ export const wren: Face;
5
+ export const myna: Face;
6
+
7
+ /** The faces we ship. Not an open vocabulary — a third face is a code change. */
8
+ export type FaceName = "peep" | "wren" | "myna";
9
+
10
+ export const FACES: Readonly<Record<FaceName, Face>>;
11
+ export const FACE_NAMES: readonly FaceName[];
12
+ export const DEFAULT_FACE: FaceName;
package/src/faces.js ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The faces we ship, as a table — for tooling that wants every one of them.
3
+ *
4
+ * **Importing this costs all three drawings** (~2k lines of path data). That is
5
+ * the right trade for `rig-check`, the contact sheets, the sweep and Studio,
6
+ * which exist to compare faces against each other. It is the wrong trade for an
7
+ * application, which renders one: those import a single face module and hand
8
+ * the record to `createAvatar` directly.
9
+ *
10
+ * import { peep } from '@voqalize/avatar/faces/peep';
11
+ * createAvatar({ mount, client, face: peep });
12
+ *
13
+ * A **Face** is `{ create, meta }` and nothing else.
14
+ *
15
+ * `create` is `createFace(mount, theme) -> { svg, apply, theme, destroy }`,
16
+ * callable standalone — the rig tooling drives faces with no mixer attached.
17
+ * That behavioural contract is the whole of what the *rig* needs: everything
18
+ * else — visemes, emotions, gaze, idle, clips, the mixer — works in parameter
19
+ * space and never learns which face it is driving.
20
+ *
21
+ * `meta` is the descriptor (viewBox, mouthCrop — see META in any face module):
22
+ * the things a HOST or a TOOL needs to frame a face without opening it. A face
23
+ * was once a bare factory, on the argument that a schema guessed from two of
24
+ * them would be wrong; the third settled it. Every rig needed exactly a framing
25
+ * rect and a mouth rect to stop the tooling hard-coding per-face tables, and
26
+ * nothing else — so that is all meta carries.
27
+ *
28
+ * The key is the face's name, not its rank. It used to be possible to read rank
29
+ * into it — the original rig was keyed `default`, which became a lie the moment
30
+ * it stopped being the one we ship. `DEFAULT_FACE` is the only place the choice
31
+ * is made, and `packages/avatar/client/createAvatar.ts` is the only place it is consulted.
32
+ *
33
+ * Two earlier rigs, `classic` and `blue-shirt`, were removed on 2026-08-06:
34
+ * stakeholders accepted the line-art pair and rejected both of the others, so
35
+ * carrying them was maintenance against art nobody wanted. What they taught the
36
+ * abstraction survives them — `face-core.js` exists because all three of the
37
+ * first rigs wrote the same apply(), and META exists because all three needed
38
+ * the same two rects. Their code is in git history if a lesson ever needs
39
+ * re-reading.
40
+ */
41
+
42
+ import { peep } from './face-peep.js';
43
+ import { wren } from './face-wren.js';
44
+ import { myna } from './face-myna.js';
45
+
46
+ export { peep, wren, myna };
47
+
48
+ export const FACES = { peep, wren, myna };
49
+
50
+ export const FACE_NAMES = Object.keys(FACES);
51
+
52
+ /** The face a host gets when it does not name one. */
53
+ export const DEFAULT_FACE = 'peep';