@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
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Peep control-plane study.
3
+ *
4
+ * This is intentionally not a character and is not registered in faces.js.
5
+ * It retains only SVG elements whose geometry is written from apply(params):
6
+ * brows, eyes, mouth interior/lips, teeth and tongue. The other pose-layer
7
+ * groups remain empty because poseTransforms writes their transforms; keeping
8
+ * the groups lets this file exercise the exact same animation contract without
9
+ * silently changing the engine.
10
+ */
11
+
12
+ import { clamp, lerp } from './params.js';
13
+ import { f, createFaceShell, faceApi, poseTransforms, pairedTeeth } from './face-core.js';
14
+ import { taper, taperRing, region } from './line-art.js';
15
+
16
+ export const THEME = {
17
+ ink: '#1b1b1b', paper: '#ffffff', accent: '#f97415',
18
+ mouthIn: '#1b1b1b', teeth: '#ffffff', tongue: '#8d7f79',
19
+ };
20
+
21
+ const VB = { x: 92, y: 76, w: 576, h: 800 };
22
+ export const META = {
23
+ viewBox: { ...VB },
24
+ mouthCrop: { x: 296, y: 434, w: 168, h: 98 },
25
+ };
26
+
27
+ // These are geometry anchors for paths regenerated by apply(), not drawn art.
28
+ const CX = 380;
29
+ const BROW_L = [[CX - 20, 347], [CX - 40, 340], [CX - 60, 336], [CX - 76, 337],
30
+ [CX - 86, 339], [CX - 94, 343], [CX - 99, 348]];
31
+ const BROW_R = [[CX + 22, 344], [CX + 40, 337], [CX + 58, 333], [CX + 73, 335],
32
+ [CX + 83, 337], [CX + 90, 341], [CX + 95, 346]];
33
+ const EYE = { y: 386, dx: 55, rx: 14, ry: 16.5 };
34
+ const MOUTH = { cx: CX, cy: 488 };
35
+ const MOUTH_APERTURE = 38;
36
+
37
+ // The original pose specification is retained verbatim: this study is for
38
+ // observing control planes, not for creating a second motion model.
39
+ const PIVOT = { x: CX, y: 700 };
40
+ const POSE = {
41
+ leanTravel: 23, leanPivot: { x: PIVOT.x, y: 560 },
42
+ shrugLift: 30, shrugTiltDeg: 1.6, shrugPivot: { x: PIVOT.x, y: 800 },
43
+ yawPx: 28, pitchPx: 17, pivot: PIVOT,
44
+ pitch: {
45
+ headLayers: ['skull', 'features', 'hair'], neckLayer: 'neck',
46
+ hinge: { x: CX, y: 620 }, neckBase: { x: CX, y: 720 },
47
+ headTravel: 1.0, neckTravel: 0.22, foreshorten: 0.040, neckCompress: 0.034,
48
+ },
49
+ breathSwell: 0.008, swellPivot: { x: CX, y: 950 }, turnPx: 16,
50
+ layers: ['neck', 'skull', 'body', 'features', 'hair'],
51
+ parallax: { neck: 1.0, skull: 1.0, body: 0.1, features: 1.22, hair: 1.12 },
52
+ torsoLayers: ['body'], units: 1,
53
+ };
54
+
55
+ function mouthGeometry(p) {
56
+ const cx = MOUTH.cx, cy = MOUTH.cy;
57
+ const open = clamp(p.mouthOpen), round = clamp(p.mouthRound), tuck = clamp(p.mouthTuck);
58
+ const w = (26 + clamp(p.mouthWidth) * 32) * (1 - 0.36 * round);
59
+ const t = 1 - 0.4 * clamp(p.mouthPress);
60
+ const profile = [2.5 * t, 10.5 * t, 3 * t, 11.5 * t * (1 + 0.35 * tuck), 2.5 * t];
61
+ const halfUp = profile[1] / 2, halfLo = profile[3] / 2;
62
+ const h = open * MOUTH_APERTURE, k = clamp(open / 0.18);
63
+ const yL = cy - 1.5 - p.mouthCornerL * 24;
64
+ const yR = cy - 1.5 - p.mouthCornerR * 24;
65
+ const apTop = cy - h * 0.25;
66
+ let apBot = cy + h * 0.75;
67
+ if (tuck > 0) apBot = Math.max(apTop + 6, apBot - tuck * (h * 0.6 + 4));
68
+ const cornerMid = (yL + yR) / 8;
69
+ const topY = (apTop - k * halfUp - cornerMid) / 0.75;
70
+ const botY = (apBot + k * halfLo - cornerMid) / 0.75;
71
+ const contour = [
72
+ [cx - w, yL], [cx - w * 0.55, topY], [cx + w * 0.55, topY], [cx + w, yR],
73
+ [cx + w * 0.55, botY], [cx - w * 0.55, botY], [cx - w, yL],
74
+ ];
75
+ return {
76
+ contour, profile, cx, w, open, tuck,
77
+ innerTop: cornerMid + 0.75 * topY + halfUp,
78
+ innerBot: cornerMid + 0.75 * botY - halfLo,
79
+ };
80
+ }
81
+
82
+ function teethPath(m, amt, lower) {
83
+ if (amt < 0.01) return '';
84
+ const gap = m.innerBot - m.innerTop;
85
+ if (gap < 2) return '';
86
+ const tw = m.w * (lower ? 0.6 : 0.76);
87
+ const cap = lower ? 0.5 : 0.5 + 0.35 * m.tuck;
88
+ const th = Math.min(amt * (lower ? 13 : 20), gap * cap);
89
+ if (lower) {
90
+ const base = m.innerBot + 8, edge = m.innerBot - th, end = m.innerBot - th * 0.35;
91
+ return `M${f(m.cx - tw)} ${f(base)}L${f(m.cx + tw)} ${f(base)}`
92
+ + `L${f(m.cx + tw * 0.92)} ${f(end)}Q${f(m.cx)} ${f(2 * edge - end)} ${f(m.cx - tw * 0.92)} ${f(end)}Z`;
93
+ }
94
+ const top = m.innerTop - 8, edge = m.innerTop + th, end = m.innerTop + th * 0.35;
95
+ return `M${f(m.cx - tw)} ${f(top)}L${f(m.cx + tw)} ${f(top)}`
96
+ + `L${f(m.cx + tw * 0.92)} ${f(end)}Q${f(m.cx)} ${f(2 * edge - end)} ${f(m.cx - tw * 0.92)} ${f(end)}Z`;
97
+ }
98
+
99
+ function eyePath(cx, cy, lid, squint, tiltDeg) {
100
+ const L = clamp(lid);
101
+ const topY = lerp(cy - EYE.ry * 1.05, cy - EYE.ry * 0.42, L);
102
+ const botY = lerp(cy + EYE.ry * 1.05, cy - EYE.ry * 0.05, L) - clamp(squint) * EYE.ry * 0.7;
103
+ const a = (tiltDeg * Math.PI) / 180, ca = Math.cos(a), sa = Math.sin(a);
104
+ const R = (x, y) => {
105
+ const dx = x - cx, dy = y - cy;
106
+ return `${f(cx + dx * ca - dy * sa)} ${f(cy + dx * sa + dy * ca)}`;
107
+ };
108
+ return `M${R(cx - EYE.rx, cy)}C${R(cx - EYE.rx * 0.5, topY)} ${R(cx + EYE.rx * 0.5, topY)} ${R(cx + EYE.rx, cy)}`
109
+ + `C${R(cx + EYE.rx * 0.5, botY)} ${R(cx - EYE.rx * 0.5, botY)} ${R(cx - EYE.rx, cy)}Z`;
110
+ }
111
+
112
+ function browPath(pts, raise, angle, inner) {
113
+ const n = pts.length - 1;
114
+ return taper(pts.map(([x, y], i) => {
115
+ const u = i / n;
116
+ return [x, y - raise * 15 - inner * 11 * (1 - u) - angle * 12 * u];
117
+ }), [3.5, 17, 8], 6);
118
+ }
119
+
120
+ function markup(id, t) {
121
+ return `<svg id="${id}" viewBox="${VB.x} ${VB.y} ${VB.w} ${VB.h}" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" style="display:block;width:100%;height:100%">
122
+ <defs><clipPath id="${id}-clipMouth"><path id="${id}-clipMouthP" d=""/></clipPath></defs>
123
+ <g id="${id}-neck"/>
124
+ <g id="${id}-skull"/>
125
+ <g id="${id}-body"/>
126
+ <g id="${id}-features">
127
+ <path id="${id}-browL" fill="${t.ink}"/><path id="${id}-browR" fill="${t.ink}"/>
128
+ <g id="${id}-eyes"><path id="${id}-eyeL" fill="${t.ink}"/><path id="${id}-eyeR" fill="${t.ink}"/></g>
129
+ <g id="${id}-mouth"><path id="${id}-mouthIn" fill="${t.mouthIn}"/>
130
+ <g clip-path="url(#${id}-clipMouth)"><ellipse id="${id}-tongue" fill="${t.tongue}"/><path id="${id}-teeth" fill="${t.teeth}"/><path id="${id}-teethLo" fill="${t.teeth}" opacity=".85"/></g>
131
+ <path id="${id}-lips" fill="${t.ink}"/></g>
132
+ </g>
133
+ <g id="${id}-hair"/>
134
+ </svg>`;
135
+ }
136
+
137
+ let uid = 0;
138
+ export function createFace(mount, theme = {}) {
139
+ const t = Object.assign({}, THEME, theme);
140
+ const id = `peepControlPlane${++uid}`;
141
+ const { svg, $, set } = createFaceShell(mount, id, markup(id, t));
142
+ const el = {
143
+ neck: $('neck'), skull: $('skull'), body: $('body'), features: $('features'), hair: $('hair'),
144
+ browL: $('browL'), browR: $('browR'), eyes: $('eyes'), eyeL: $('eyeL'), eyeR: $('eyeR'),
145
+ mouthIn: $('mouthIn'), lips: $('lips'), clipMouth: $('clipMouthP'),
146
+ teeth: $('teeth'), teethLo: $('teethLo'), tongue: $('tongue'),
147
+ };
148
+ function apply(p) {
149
+ poseTransforms(p, set, el, POSE);
150
+ set(el.eyes, 'transform', `translate(${f(p.pupilX * 11)} ${f(p.pupilY * 8)})`);
151
+ const lidFollow = Math.max(0, p.pupilY) * 0.22;
152
+ set(el.eyeL, 'd', eyePath(CX - EYE.dx, EYE.y + 1, p.lidL + lidFollow, p.squintL, -9));
153
+ set(el.eyeR, 'd', eyePath(CX + EYE.dx, EYE.y - 1, p.lidR + lidFollow, p.squintR, 8));
154
+ set(el.browL, 'd', browPath(BROW_L, p.browRaiseL, p.browAngleL, p.browInnerL));
155
+ set(el.browR, 'd', browPath(BROW_R, p.browRaiseR, p.browAngleR, p.browInnerR));
156
+ const m = mouthGeometry(p), contour = region(m.contour);
157
+ set(el.mouthIn, 'd', contour); set(el.clipMouth, 'd', contour); set(el.lips, 'd', taperRing(m.contour, m.profile, 12));
158
+ set(el.mouthIn, 'opacity', f(clamp((m.innerBot - m.innerTop) / 3)));
159
+ pairedTeeth(p, set, el, teethPath, m);
160
+ const tg = clamp(p.tongue);
161
+ set(el.tongue, 'cx', f(m.cx)); set(el.tongue, 'cy', f(m.innerBot + 6 - tg * ((m.innerBot - m.innerTop) * 0.8 + 6)));
162
+ set(el.tongue, 'rx', f(m.w * 0.58)); set(el.tongue, 'ry', '8'); set(el.tongue, 'opacity', tg > 0.02 ? '1' : '0');
163
+ }
164
+ return faceApi(mount, svg, apply, t);
165
+ }
166
+
167
+ export const peepControlPlane = { create: createFace, meta: META };
@@ -0,0 +1,7 @@
1
+ import type { AvatarMeta, Face, FaceFactory } from "./avatar.js";
2
+
3
+ export const createFace: FaceFactory;
4
+ export const META: AvatarMeta;
5
+ /** Default palette. Passed as `createAvatar({ theme })`; see authoring-a-face.md. */
6
+ export const THEME: Readonly<Record<string, string>>;
7
+ export const peep: Face;