@voqalize/avatar 0.3.0 → 0.4.1
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-CC-BY-4.0 +396 -0
- package/README.md +65 -17
- package/assets/README.md +48 -0
- package/assets/tanya.glb +0 -0
- package/assets/tara.glb +0 -0
- package/assets/tushar.glb +0 -0
- package/client/AvatarClient.ts +337 -42
- package/client/arjun.ts +2 -0
- package/client/createAvatar.ts +38 -0
- package/client/index.ts +6 -1
- package/client/internal.ts +31 -3
- package/client/ishita.ts +2 -0
- package/client/kabir.ts +2 -0
- package/client/meera.ts +2 -0
- package/client/naina.ts +2 -0
- package/client/playout.ts +95 -0
- package/client/supports.ts +28 -0
- package/client/three/assets.ts +22 -0
- package/client/three/budgets.ts +27 -0
- package/client/three/holds.ts +64 -0
- package/client/three/internal.ts +54 -0
- package/client/three/motion-limits.json +116 -0
- package/client/three/sequences.ts +281 -0
- package/client/three/tanya-asset.ts +6 -0
- package/client/three/tanya.ts +69 -0
- package/client/three/tara-asset.ts +25 -0
- package/client/three/tara-rig.ts +1571 -0
- package/client/three/tara.ts +77 -0
- package/client/three/tushar-asset.ts +6 -0
- package/client/three/tushar.ts +65 -0
- package/client/types.ts +109 -20
- package/client/vikram.ts +2 -0
- package/dist/AvatarClient.d.ts +89 -11
- package/dist/AvatarClient.d.ts.map +1 -1
- package/dist/AvatarClient.js +297 -35
- package/dist/AvatarClient.js.map +1 -1
- package/dist/arjun.d.ts +1 -0
- package/dist/arjun.d.ts.map +1 -1
- package/dist/arjun.js +2 -0
- package/dist/arjun.js.map +1 -1
- package/dist/createAvatar.d.ts +36 -0
- package/dist/createAvatar.d.ts.map +1 -1
- package/dist/createAvatar.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +9 -5
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +13 -5
- package/dist/internal.js.map +1 -1
- package/dist/ishita.d.ts +1 -0
- package/dist/ishita.d.ts.map +1 -1
- package/dist/ishita.js +2 -0
- package/dist/ishita.js.map +1 -1
- package/dist/kabir.d.ts +1 -0
- package/dist/kabir.d.ts.map +1 -1
- package/dist/kabir.js +2 -0
- package/dist/kabir.js.map +1 -1
- package/dist/meera.d.ts +1 -0
- package/dist/meera.d.ts.map +1 -1
- package/dist/meera.js +2 -0
- package/dist/meera.js.map +1 -1
- package/dist/naina.d.ts +1 -0
- package/dist/naina.d.ts.map +1 -1
- package/dist/naina.js +2 -0
- package/dist/naina.js.map +1 -1
- package/dist/playout.d.ts +42 -0
- package/dist/playout.d.ts.map +1 -0
- package/dist/playout.js +85 -0
- package/dist/playout.js.map +1 -0
- package/dist/supports.d.ts +20 -0
- package/dist/supports.d.ts.map +1 -0
- package/dist/supports.js +26 -0
- package/dist/supports.js.map +1 -0
- package/dist/three/assets.d.ts +8 -0
- package/dist/three/assets.d.ts.map +1 -0
- package/dist/three/assets.js +19 -0
- package/dist/three/assets.js.map +1 -0
- package/dist/three/budgets.d.ts +17 -0
- package/dist/three/budgets.d.ts.map +1 -0
- package/dist/three/budgets.js +21 -0
- package/dist/three/budgets.js.map +1 -0
- package/dist/three/holds.d.ts +33 -0
- package/dist/three/holds.d.ts.map +1 -0
- package/dist/three/holds.js +56 -0
- package/dist/three/holds.js.map +1 -0
- package/dist/three/internal.d.ts +52 -0
- package/dist/three/internal.d.ts.map +1 -0
- package/dist/three/internal.js +49 -0
- package/dist/three/internal.js.map +1 -0
- package/dist/three/motion-limits.json +116 -0
- package/dist/three/sequences.d.ts +71 -0
- package/dist/three/sequences.d.ts.map +1 -0
- package/dist/three/sequences.js +262 -0
- package/dist/three/sequences.js.map +1 -0
- package/dist/three/tanya-asset.d.ts +7 -0
- package/dist/three/tanya-asset.d.ts.map +1 -0
- package/dist/three/tanya-asset.js +7 -0
- package/dist/three/tanya-asset.js.map +1 -0
- package/dist/three/tanya.d.ts +35 -0
- package/dist/three/tanya.d.ts.map +1 -0
- package/dist/three/tanya.js +51 -0
- package/dist/three/tanya.js.map +1 -0
- package/dist/three/tara-asset.d.ts +26 -0
- package/dist/three/tara-asset.d.ts.map +1 -0
- package/dist/three/tara-asset.js +26 -0
- package/dist/three/tara-asset.js.map +1 -0
- package/dist/three/tara-rig.d.ts +409 -0
- package/dist/three/tara-rig.d.ts.map +1 -0
- package/dist/three/tara-rig.js +1504 -0
- package/dist/three/tara-rig.js.map +1 -0
- package/dist/three/tara.d.ts +35 -0
- package/dist/three/tara.d.ts.map +1 -0
- package/dist/three/tara.js +59 -0
- package/dist/three/tara.js.map +1 -0
- package/dist/three/tushar-asset.d.ts +7 -0
- package/dist/three/tushar-asset.d.ts.map +1 -0
- package/dist/three/tushar-asset.js +7 -0
- package/dist/three/tushar-asset.js.map +1 -0
- package/dist/three/tushar.d.ts +31 -0
- package/dist/three/tushar.d.ts.map +1 -0
- package/dist/three/tushar.js +47 -0
- package/dist/three/tushar.js.map +1 -0
- package/dist/types.d.ts +65 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +58 -11
- package/dist/types.js.map +1 -1
- package/dist/vikram.d.ts +1 -0
- package/dist/vikram.d.ts.map +1 -1
- package/dist/vikram.js +2 -0
- package/dist/vikram.js.map +1 -1
- package/package.json +34 -6
- package/src/avatar.d.ts +59 -2
- package/src/avatar.js +743 -94
- package/src/behavior.d.ts +28 -12
- package/src/behavior.js +54 -42
- package/src/canvas/create-rig.js +1 -1
- package/src/canvas/src/live.js +2 -2
- package/src/conformance.js +1 -1
- package/src/emotions.js +4 -2
- package/src/gaze.js +334 -73
- package/src/head.js +134 -0
- package/src/idle.js +210 -19
- package/src/interjections.js +70 -26
- package/src/prosody.js +647 -0
- package/src/visemes.js +85 -15
package/dist/index.d.ts
CHANGED
|
@@ -23,8 +23,12 @@
|
|
|
23
23
|
* because they are an interface.
|
|
24
24
|
*
|
|
25
25
|
* To ship your own avatar, publish a module exporting `createAvatar` and import
|
|
26
|
-
* that instead — see `createAvatar.ts` and docs/design-avatar-interface.md.
|
|
26
|
+
* that instead — see `createAvatar.ts` and docs/design-avatar-interface.md. A
|
|
27
|
+
* module may also export `supports`, which is how a page that *drives* an
|
|
28
|
+
* avatar learns which action ids this one answers to; every consumer that only
|
|
29
|
+
* mounts a face can ignore it.
|
|
27
30
|
*/
|
|
28
31
|
export { createAvatar } from "./createAvatar.js";
|
|
29
|
-
export
|
|
32
|
+
export { supports } from "./supports.js";
|
|
33
|
+
export type { AvatarOptions, AvatarInstance, AvatarFactory, AvatarSupport, SvgAvatarOptions, Face, FaceTheme, Gain, HandSide, } from "./createAvatar.js";
|
|
30
34
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EACV,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,IAAI,EACJ,SAAS,EACT,IAAI,EACJ,QAAQ,GACT,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,11 @@
|
|
|
23
23
|
* because they are an interface.
|
|
24
24
|
*
|
|
25
25
|
* To ship your own avatar, publish a module exporting `createAvatar` and import
|
|
26
|
-
* that instead — see `createAvatar.ts` and docs/design-avatar-interface.md.
|
|
26
|
+
* that instead — see `createAvatar.ts` and docs/design-avatar-interface.md. A
|
|
27
|
+
* module may also export `supports`, which is how a page that *drives* an
|
|
28
|
+
* avatar learns which action ids this one answers to; every consumer that only
|
|
29
|
+
* mounts a face can ignore it.
|
|
27
30
|
*/
|
|
28
31
|
export { createAvatar } from "./createAvatar.js";
|
|
32
|
+
export { supports } from "./supports.js";
|
|
29
33
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/internal.d.ts
CHANGED
|
@@ -15,16 +15,20 @@
|
|
|
15
15
|
* const track = new VisemeTrack();
|
|
16
16
|
* track.start(cues, () => performance.now() - t0);
|
|
17
17
|
* // per frame:
|
|
18
|
-
* const s = track.sample(); // { letter: "D", intensity: 1 } | null
|
|
18
|
+
* const s = track.sample(); // { letter: "D", intensity: 1, phone: "OW" } | null
|
|
19
19
|
*
|
|
20
20
|
* `docs/internal-rig.md` describes the pose-channel model the bundled SVG
|
|
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, STATES, STATE_NAMES, ACTIONS, ACTION_IDS, GAZE_NAMES, GAZE_TARGETS, EMOTION_NAMES, VisemeTrack, VISEME_LETTERS, VISEME_SHAPES, SILENT, LEAD_MS, shapeFor, normalizeCues, textToCues, ARPABET_TO_VISEME, AZURE_VISEME_TO_LETTER, } 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, shapeFor, normalizeCues, textToCues, ARPABET_TO_VISEME, AZURE_VISEME_TO_LETTER, } from "../src/avatar.js";
|
|
25
25
|
export type { AvatarApi, AvatarStateName, AvatarActionId, AvatarGazeName, AvatarEmotionName, AvatarAction, AvatarMeta, VisemeLetter, Cue, PoseChannel, PoseOverrides, CreateAvatarOptions as CreateSvgAvatarOptions, } from "../src/avatar.js";
|
|
26
|
-
export {
|
|
26
|
+
export type { AvatarFrame, AvatarRig, AvatarRigFactory, HandFrame, RigPose, } from "../src/rig.js";
|
|
27
|
+
export { BEHAVIOR_STATE_IDS, BEHAVIOR_ACTIONS, BEHAVIOR_ACTION_IDS, WIRE_ACTION_TO_BEHAVIOR, } from "../src/behavior.js";
|
|
27
28
|
export type { BehaviorStateId, BehaviorActionId } from "../src/behavior.js";
|
|
28
|
-
export { isAvatarMessage } from "./types.js";
|
|
29
|
-
export type {
|
|
29
|
+
export { isAvatarMessage, CORE_ACTION_IDS } from "./types.js";
|
|
30
|
+
export type { AvatarSupport } from "./createAvatar.js";
|
|
31
|
+
export { AvatarClient } from "./AvatarClient.js";
|
|
32
|
+
export type { AvatarCommand, AvatarCue, AvatarCuesCmd, CoreActionId, } from "./types.js";
|
|
33
|
+
export type { AvatarClientOptions, AvatarDriver, AvatarPresenceState } from "./AvatarClient.js";
|
|
30
34
|
//# sourceMappingURL=internal.d.ts.map
|
package/dist/internal.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../client/internal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAIL,YAAY,IAAI,eAAe,
|
|
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"}
|
package/dist/internal.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* const track = new VisemeTrack();
|
|
16
16
|
* track.start(cues, () => performance.now() - t0);
|
|
17
17
|
* // per frame:
|
|
18
|
-
* const s = track.sample(); // { letter: "D", intensity: 1 } | null
|
|
18
|
+
* const s = track.sample(); // { letter: "D", intensity: 1, phone: "OW" } | null
|
|
19
19
|
*
|
|
20
20
|
* `docs/internal-rig.md` describes the pose-channel model the bundled SVG
|
|
21
21
|
* renderer uses internally. It is *not* the seam to implement — see
|
|
@@ -25,9 +25,17 @@ export {
|
|
|
25
25
|
// The bundled SVG widget. Not the faces: importing one from here would put
|
|
26
26
|
// all three in every bundle that wanted the viseme clock.
|
|
27
27
|
// `@voqalize/avatar/faces/<name>` is where a face comes from.
|
|
28
|
-
createAvatar as createSvgAvatar,
|
|
28
|
+
createAvatar as createSvgAvatar,
|
|
29
|
+
// The pose space a custom `rig` is handed on every frame, and the rests it is
|
|
30
|
+
// measured against.
|
|
31
|
+
REST, CHANNELS, RANGE, STATES, STATE_NAMES, ACTIONS, ACTION_IDS, GAZE_NAMES, GAZE_TARGETS, EMOTION_NAMES,
|
|
29
32
|
// The viseme clock and its tables.
|
|
30
|
-
VisemeTrack, VISEME_LETTERS, VISEME_SHAPES, SILENT, LEAD_MS,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
VisemeTrack, VISEME_LETTERS, VISEME_SHAPES, SILENT, LEAD_MS,
|
|
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";
|
|
36
|
+
export { BEHAVIOR_STATE_IDS, BEHAVIOR_ACTIONS, BEHAVIOR_ACTION_IDS, WIRE_ACTION_TO_BEHAVIOR, } from "../src/behavior.js";
|
|
37
|
+
export { isAvatarMessage, CORE_ACTION_IDS } from "./types.js";
|
|
38
|
+
// A renderer may reuse the one lifecycle/precedence ladder without gaining a
|
|
39
|
+
// second public avatar interface.
|
|
40
|
+
export { AvatarClient } from "./AvatarClient.js";
|
|
33
41
|
//# sourceMappingURL=internal.js.map
|
package/dist/internal.js.map
CHANGED
|
@@ -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
|
|
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"}
|
package/dist/ishita.d.ts
CHANGED
|
@@ -2,5 +2,6 @@
|
|
|
2
2
|
import type { CanvasAvatarOptions } from './createCanvasAvatar.js';
|
|
3
3
|
import type { AvatarInstance } from './createAvatar.js';
|
|
4
4
|
export type { CanvasAvatarOptions };
|
|
5
|
+
export { supports } from './supports.js';
|
|
5
6
|
export declare function createAvatar(options: CanvasAvatarOptions): AvatarInstance;
|
|
6
7
|
//# sourceMappingURL=ishita.d.ts.map
|
package/dist/ishita.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ishita.d.ts","sourceRoot":"","sources":["../client/ishita.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAG/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAUxD,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,cAAc,CAOzE"}
|
|
1
|
+
{"version":3,"file":"ishita.d.ts","sourceRoot":"","sources":["../client/ishita.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAG/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAUxD,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,cAAc,CAOzE"}
|
package/dist/ishita.js
CHANGED
|
@@ -7,6 +7,8 @@ const IMAGES = {
|
|
|
7
7
|
'professional-female-a-hair-front.webp': new URL('../src/canvas/data/img/professional-female-a-hair-front.webp', import.meta.url),
|
|
8
8
|
};
|
|
9
9
|
const FACE = () => import('../src/canvas/avatars/round/face.mjs');
|
|
10
|
+
// Same mixer, same clip library, so the same declaration (`supports.ts`).
|
|
11
|
+
export { supports } from './supports.js';
|
|
10
12
|
export function createAvatar(options) {
|
|
11
13
|
return createCanvasAvatar(options, {
|
|
12
14
|
rigUrl: RIG_URL,
|
package/dist/ishita.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ishita.js","sourceRoot":"","sources":["../client/ishita.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAE/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAI7D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,mDAAmD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC9F,MAAM,MAAM,GAAG;IACb,qCAAqC,EAAE,IAAI,GAAG,CAAC,4DAA4D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IAC7H,sCAAsC,EAAE,IAAI,GAAG,CAAC,6DAA6D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IAC/H,uCAAuC,EAAE,IAAI,GAAG,CAAC,8DAA8D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;CACzH,CAAC;AACX,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,sCAAsC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"ishita.js","sourceRoot":"","sources":["../client/ishita.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAE/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAI7D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,mDAAmD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC9F,MAAM,MAAM,GAAG;IACb,qCAAqC,EAAE,IAAI,GAAG,CAAC,4DAA4D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IAC7H,sCAAsC,EAAE,IAAI,GAAG,CAAC,6DAA6D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IAC/H,uCAAuC,EAAE,IAAI,GAAG,CAAC,8DAA8D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;CACzH,CAAC;AACX,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,sCAAsC,CAAC,CAAC;AAGlE,0EAA0E;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,UAAU,YAAY,CAAC,OAA4B;IACvD,OAAO,kBAAkB,CAAC,OAAO,EAAE;QACjC,MAAM,EAAE,OAAO;QACf,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,8CAA8C;KACtD,CAAC,CAAC;AACL,CAAC"}
|
package/dist/kabir.d.ts
CHANGED
|
@@ -2,5 +2,6 @@
|
|
|
2
2
|
import type { CanvasAvatarOptions } from './createCanvasAvatar.js';
|
|
3
3
|
import type { AvatarInstance } from './createAvatar.js';
|
|
4
4
|
export type { CanvasAvatarOptions };
|
|
5
|
+
export { supports } from './supports.js';
|
|
5
6
|
export declare function createAvatar(options: CanvasAvatarOptions): AvatarInstance;
|
|
6
7
|
//# sourceMappingURL=kabir.d.ts.map
|
package/dist/kabir.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kabir.d.ts","sourceRoot":"","sources":["../client/kabir.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAG5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAUxD,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,cAAc,CAOzE"}
|
|
1
|
+
{"version":3,"file":"kabir.d.ts","sourceRoot":"","sources":["../client/kabir.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAG5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAUxD,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,cAAc,CAOzE"}
|
package/dist/kabir.js
CHANGED
|
@@ -7,6 +7,8 @@ const IMAGES = {
|
|
|
7
7
|
'professional-male-b-hair-front.webp': new URL('../src/canvas/data/img/professional-male-b-hair-front.webp', import.meta.url),
|
|
8
8
|
};
|
|
9
9
|
const FACE = () => import('../src/canvas/avatars/round/face.mjs');
|
|
10
|
+
// Same mixer, same clip library, so the same declaration (`supports.ts`).
|
|
11
|
+
export { supports } from './supports.js';
|
|
10
12
|
export function createAvatar(options) {
|
|
11
13
|
return createCanvasAvatar(options, {
|
|
12
14
|
rigUrl: RIG_URL,
|
package/dist/kabir.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kabir.js","sourceRoot":"","sources":["../client/kabir.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAE5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAI7D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,iDAAiD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5F,MAAM,MAAM,GAAG;IACb,mCAAmC,EAAE,IAAI,GAAG,CAAC,0DAA0D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IACzH,oCAAoC,EAAE,IAAI,GAAG,CAAC,2DAA2D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IAC3H,qCAAqC,EAAE,IAAI,GAAG,CAAC,4DAA4D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;CACrH,CAAC;AACX,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,sCAAsC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"kabir.js","sourceRoot":"","sources":["../client/kabir.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAE5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAI7D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,iDAAiD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5F,MAAM,MAAM,GAAG;IACb,mCAAmC,EAAE,IAAI,GAAG,CAAC,0DAA0D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IACzH,oCAAoC,EAAE,IAAI,GAAG,CAAC,2DAA2D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IAC3H,qCAAqC,EAAE,IAAI,GAAG,CAAC,4DAA4D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;CACrH,CAAC;AACX,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,sCAAsC,CAAC,CAAC;AAGlE,0EAA0E;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,UAAU,YAAY,CAAC,OAA4B;IACvD,OAAO,kBAAkB,CAAC,OAAO,EAAE;QACjC,MAAM,EAAE,OAAO;QACf,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,0CAA0C;KAClD,CAAC,CAAC;AACL,CAAC"}
|
package/dist/meera.d.ts
CHANGED
|
@@ -2,5 +2,6 @@
|
|
|
2
2
|
import type { CanvasAvatarOptions } from './createCanvasAvatar.js';
|
|
3
3
|
import type { AvatarInstance } from './createAvatar.js';
|
|
4
4
|
export type { CanvasAvatarOptions };
|
|
5
|
+
export { supports } from './supports.js';
|
|
5
6
|
export declare function createAvatar(options: CanvasAvatarOptions): AvatarInstance;
|
|
6
7
|
//# sourceMappingURL=meera.d.ts.map
|
package/dist/meera.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meera.d.ts","sourceRoot":"","sources":["../client/meera.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAGlF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAUxD,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,cAAc,CAOzE"}
|
|
1
|
+
{"version":3,"file":"meera.d.ts","sourceRoot":"","sources":["../client/meera.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAGlF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAUxD,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,cAAc,CAOzE"}
|
package/dist/meera.js
CHANGED
|
@@ -7,6 +7,8 @@ const IMAGES = {
|
|
|
7
7
|
'round-w1-hair-front.webp': new URL('../src/canvas/data/img/round-w1-hair-front.webp', import.meta.url),
|
|
8
8
|
};
|
|
9
9
|
const FACE = () => import('../src/canvas/avatars/round/face.mjs');
|
|
10
|
+
// Same mixer, same clip library, so the same declaration (`supports.ts`).
|
|
11
|
+
export { supports } from './supports.js';
|
|
10
12
|
export function createAvatar(options) {
|
|
11
13
|
return createCanvasAvatar(options, {
|
|
12
14
|
rigUrl: RIG_URL,
|
package/dist/meera.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meera.js","sourceRoot":"","sources":["../client/meera.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAI7D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,gDAAgD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3F,MAAM,MAAM,GAAG;IACb,yBAAyB,EAAE,IAAI,GAAG,CAAC,gDAAgD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IACrG,wBAAwB,EAAE,IAAI,GAAG,CAAC,+CAA+C,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IACnG,0BAA0B,EAAE,IAAI,GAAG,CAAC,iDAAiD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;CAC/F,CAAC;AACX,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,sCAAsC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"meera.js","sourceRoot":"","sources":["../client/meera.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAI7D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,gDAAgD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3F,MAAM,MAAM,GAAG;IACb,yBAAyB,EAAE,IAAI,GAAG,CAAC,gDAAgD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IACrG,wBAAwB,EAAE,IAAI,GAAG,CAAC,+CAA+C,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IACnG,0BAA0B,EAAE,IAAI,GAAG,CAAC,iDAAiD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;CAC/F,CAAC;AACX,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,sCAAsC,CAAC,CAAC;AAGlE,0EAA0E;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,UAAU,YAAY,CAAC,OAA4B;IACvD,OAAO,kBAAkB,CAAC,OAAO,EAAE;QACjC,MAAM,EAAE,OAAO;QACf,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,gDAAgD;KACxD,CAAC,CAAC;AACL,CAAC"}
|
package/dist/naina.d.ts
CHANGED
|
@@ -2,5 +2,6 @@
|
|
|
2
2
|
import type { CanvasAvatarOptions } from './createCanvasAvatar.js';
|
|
3
3
|
import type { AvatarInstance } from './createAvatar.js';
|
|
4
4
|
export type { CanvasAvatarOptions };
|
|
5
|
+
export { supports } from './supports.js';
|
|
5
6
|
export declare function createAvatar(options: CanvasAvatarOptions): AvatarInstance;
|
|
6
7
|
//# sourceMappingURL=naina.d.ts.map
|
package/dist/naina.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"naina.d.ts","sourceRoot":"","sources":["../client/naina.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAG9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAUxD,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,cAAc,CAOzE"}
|
|
1
|
+
{"version":3,"file":"naina.d.ts","sourceRoot":"","sources":["../client/naina.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAG9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAUxD,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,cAAc,CAOzE"}
|
package/dist/naina.js
CHANGED
|
@@ -7,6 +7,8 @@ const IMAGES = {
|
|
|
7
7
|
'professional-female-b-hair-front.webp': new URL('../src/canvas/data/img/professional-female-b-hair-front.webp', import.meta.url),
|
|
8
8
|
};
|
|
9
9
|
const FACE = () => import('../src/canvas/avatars/round/face.mjs');
|
|
10
|
+
// Same mixer, same clip library, so the same declaration (`supports.ts`).
|
|
11
|
+
export { supports } from './supports.js';
|
|
10
12
|
export function createAvatar(options) {
|
|
11
13
|
return createCanvasAvatar(options, {
|
|
12
14
|
rigUrl: RIG_URL,
|
package/dist/naina.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"naina.js","sourceRoot":"","sources":["../client/naina.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAE9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAI7D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,mDAAmD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC9F,MAAM,MAAM,GAAG;IACb,qCAAqC,EAAE,IAAI,GAAG,CAAC,4DAA4D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IAC7H,sCAAsC,EAAE,IAAI,GAAG,CAAC,6DAA6D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IAC/H,uCAAuC,EAAE,IAAI,GAAG,CAAC,8DAA8D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;CACzH,CAAC;AACX,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,sCAAsC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"naina.js","sourceRoot":"","sources":["../client/naina.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAE9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAI7D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,mDAAmD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC9F,MAAM,MAAM,GAAG;IACb,qCAAqC,EAAE,IAAI,GAAG,CAAC,4DAA4D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IAC7H,sCAAsC,EAAE,IAAI,GAAG,CAAC,6DAA6D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IAC/H,uCAAuC,EAAE,IAAI,GAAG,CAAC,8DAA8D,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;CACzH,CAAC;AACX,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,sCAAsC,CAAC,CAAC;AAGlE,0EAA0E;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,UAAU,YAAY,CAAC,OAA4B;IACvD,OAAO,kBAAkB,CAAC,OAAO,EAAE;QACjC,MAAM,EAAE,OAAO;QACf,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,4CAA4C;KACpD,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When the bot's audio actually begins, heard on the track the browser plays.
|
|
3
|
+
*
|
|
4
|
+
* `BotStartedSpeaking` and the audio reach the browser by different roads —
|
|
5
|
+
* the event on the data channel, the sound over RTP and through a jitter
|
|
6
|
+
* buffer — so the event is a statement about *which* audio is starting and
|
|
7
|
+
* not about when anyone hears it. Measured on two stacks, the event arrived
|
|
8
|
+
* 57 ms after the first sample on one and 160 ms before it on the other: the
|
|
9
|
+
* mouth lagged the voice on the first and ran ahead of it on the second, and
|
|
10
|
+
* no constant corrects both. So the turn clock is anchored to the sound.
|
|
11
|
+
*
|
|
12
|
+
* What makes "the sound began" observable is that between turns the decoded
|
|
13
|
+
* track is exact digital zero — Opus decodes silence to silence — so onset is
|
|
14
|
+
* the first sample off zero, not a speech detector's guess at a threshold. That
|
|
15
|
+
* matters: cue `t: 0` is the first sample the TTS produced, lead-in included,
|
|
16
|
+
* and a detector keyed to *speech* would anchor 20-50 ms into the lead-in.
|
|
17
|
+
*
|
|
18
|
+
* What this probe hears is the sound entering the page's audio graph, not
|
|
19
|
+
* leaving the speaker. For a wired speaker the difference is about what the
|
|
20
|
+
* compositor and display add to the picture, and the two cancel. A Bluetooth
|
|
21
|
+
* headset adds 150-250 ms that nothing on the picture side matches, so the
|
|
22
|
+
* probe also reports the device latency the browser admits to, and the
|
|
23
|
+
* client delays the mouth by the excess (`AvatarClient.ts`).
|
|
24
|
+
*/
|
|
25
|
+
export interface PlayoutProbe {
|
|
26
|
+
/**
|
|
27
|
+
* Where the bot's current sound began, on the caller's `now()` clock.
|
|
28
|
+
* `null`: the track is silent right now. `undefined`: this probe cannot say —
|
|
29
|
+
* the track has been sounding for longer than it can look back, or the
|
|
30
|
+
* audio graph is not running.
|
|
31
|
+
*/
|
|
32
|
+
onset(): number | null | undefined;
|
|
33
|
+
/** The output device's latency as this context reports it, in ms; 0 when it
|
|
34
|
+
* will not say. The probe shares the device the call's audio plays on. */
|
|
35
|
+
outputLatencyMs?(): number;
|
|
36
|
+
/** Ask a suspended graph to run. A browser that needs a gesture for it
|
|
37
|
+
* ignores the request outside one, so this is safe to call at any time. */
|
|
38
|
+
resume?(): void;
|
|
39
|
+
dispose(): void;
|
|
40
|
+
}
|
|
41
|
+
export declare function createPlayoutProbe(track: MediaStreamTrack, now: () => number): PlayoutProbe | null;
|
|
42
|
+
//# sourceMappingURL=playout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playout.d.ts","sourceRoot":"","sources":["../client/playout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,KAAK,IAAI,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnC;8EAC0E;IAC1E,eAAe,CAAC,IAAI,MAAM,CAAC;IAC3B;+EAC2E;IAC3E,MAAM,CAAC,IAAI,IAAI,CAAC;IAChB,OAAO,IAAI,IAAI,CAAC;CACjB;AASD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,MAAM,GAAG,YAAY,GAAG,IAAI,CA6ClG"}
|
package/dist/playout.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When the bot's audio actually begins, heard on the track the browser plays.
|
|
3
|
+
*
|
|
4
|
+
* `BotStartedSpeaking` and the audio reach the browser by different roads —
|
|
5
|
+
* the event on the data channel, the sound over RTP and through a jitter
|
|
6
|
+
* buffer — so the event is a statement about *which* audio is starting and
|
|
7
|
+
* not about when anyone hears it. Measured on two stacks, the event arrived
|
|
8
|
+
* 57 ms after the first sample on one and 160 ms before it on the other: the
|
|
9
|
+
* mouth lagged the voice on the first and ran ahead of it on the second, and
|
|
10
|
+
* no constant corrects both. So the turn clock is anchored to the sound.
|
|
11
|
+
*
|
|
12
|
+
* What makes "the sound began" observable is that between turns the decoded
|
|
13
|
+
* track is exact digital zero — Opus decodes silence to silence — so onset is
|
|
14
|
+
* the first sample off zero, not a speech detector's guess at a threshold. That
|
|
15
|
+
* matters: cue `t: 0` is the first sample the TTS produced, lead-in included,
|
|
16
|
+
* and a detector keyed to *speech* would anchor 20-50 ms into the lead-in.
|
|
17
|
+
*
|
|
18
|
+
* What this probe hears is the sound entering the page's audio graph, not
|
|
19
|
+
* leaving the speaker. For a wired speaker the difference is about what the
|
|
20
|
+
* compositor and display add to the picture, and the two cancel. A Bluetooth
|
|
21
|
+
* headset adds 150-250 ms that nothing on the picture side matches, so the
|
|
22
|
+
* probe also reports the device latency the browser admits to, and the
|
|
23
|
+
* client delays the mouth by the excess (`AvatarClient.ts`).
|
|
24
|
+
*/
|
|
25
|
+
/** 8192 samples is 170 ms at 48 kHz: past the 57 ms the sound has been seen to
|
|
26
|
+
* lead the event by, with room for a slower network. */
|
|
27
|
+
const WINDOW = 8192;
|
|
28
|
+
/** -80 dBFS. The gaps between turns are exact zero; this only keeps a
|
|
29
|
+
* denormal from reading as speech. */
|
|
30
|
+
const FLOOR = 1e-4;
|
|
31
|
+
export function createPlayoutProbe(track, now) {
|
|
32
|
+
const Ctx = globalThis.AudioContext;
|
|
33
|
+
if (!Ctx)
|
|
34
|
+
return null;
|
|
35
|
+
let ctx;
|
|
36
|
+
let source;
|
|
37
|
+
let analyser;
|
|
38
|
+
try {
|
|
39
|
+
ctx = new Ctx();
|
|
40
|
+
source = ctx.createMediaStreamSource(new MediaStream([track]));
|
|
41
|
+
analyser = ctx.createAnalyser();
|
|
42
|
+
analyser.fftSize = WINDOW;
|
|
43
|
+
source.connect(analyser);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
// A context made after the user's connect click is allowed to run; one that
|
|
49
|
+
// is not simply answers `undefined`, and the event anchors the turn.
|
|
50
|
+
ctx.resume().catch(() => { });
|
|
51
|
+
const buf = new Float32Array(WINDOW);
|
|
52
|
+
return {
|
|
53
|
+
onset() {
|
|
54
|
+
if (ctx.state !== "running")
|
|
55
|
+
return undefined;
|
|
56
|
+
analyser.getFloatTimeDomainData(buf);
|
|
57
|
+
const t = now();
|
|
58
|
+
let first = -1;
|
|
59
|
+
for (let i = 0; i < buf.length; i++) {
|
|
60
|
+
if (Math.abs(buf[i]) > FLOOR) {
|
|
61
|
+
first = i;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (first < 0)
|
|
66
|
+
return null;
|
|
67
|
+
if (first === 0)
|
|
68
|
+
return undefined;
|
|
69
|
+
return t - ((buf.length - first) / ctx.sampleRate) * 1000;
|
|
70
|
+
},
|
|
71
|
+
outputLatencyMs() {
|
|
72
|
+
const s = ctx.outputLatency;
|
|
73
|
+
return typeof s === "number" && Number.isFinite(s) ? s * 1000 : 0;
|
|
74
|
+
},
|
|
75
|
+
resume() {
|
|
76
|
+
if (ctx.state === "suspended")
|
|
77
|
+
ctx.resume().catch(() => { });
|
|
78
|
+
},
|
|
79
|
+
dispose() {
|
|
80
|
+
source.disconnect();
|
|
81
|
+
ctx.close().catch(() => { });
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=playout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playout.js","sourceRoot":"","sources":["../client/playout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAmBH;wDACwD;AACxD,MAAM,MAAM,GAAG,IAAI,CAAC;AACpB;sCACsC;AACtC,MAAM,KAAK,GAAG,IAAI,CAAC;AAEnB,MAAM,UAAU,kBAAkB,CAAC,KAAuB,EAAE,GAAiB;IAC3E,MAAM,GAAG,GAAG,UAAU,CAAC,YAAY,CAAC;IACpC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,GAAiB,CAAC;IACtB,IAAI,MAAkC,CAAC;IACvC,IAAI,QAAsB,CAAC;IAC3B,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,CAAC,uBAAuB,CAAC,IAAI,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/D,QAAQ,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;QAChC,QAAQ,CAAC,OAAO,GAAG,MAAM,CAAC;QAC1B,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,4EAA4E;IAC5E,qEAAqE;IACrE,GAAG,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC7B,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IAErC,OAAO;QACL,KAAK;YACH,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAC;YAC9C,QAAQ,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC;YACrC,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC;YAChB,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;YACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACpC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,GAAG,KAAK,EAAE,CAAC;oBAAC,KAAK,GAAG,CAAC,CAAC;oBAAC,MAAM;gBAAC,CAAC;YACtD,CAAC;YACD,IAAI,KAAK,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC3B,IAAI,KAAK,KAAK,CAAC;gBAAE,OAAO,SAAS,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;QAC5D,CAAC;QACD,eAAe;YACb,MAAM,CAAC,GAAG,GAAG,CAAC,aAAa,CAAC;YAC5B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,CAAC;QACD,MAAM;YACJ,IAAI,GAAG,CAAC,KAAK,KAAK,WAAW;gBAAE,GAAG,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO;YACL,MAAM,CAAC,UAAU,EAAE,CAAC;YACpB,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC9B,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `supports` for every avatar this package ships — the SVG faces and the six
|
|
3
|
+
* canvas identities alike.
|
|
4
|
+
*
|
|
5
|
+
* It is one constant and one file because they are one renderer: the canvas
|
|
6
|
+
* avatars mount the same mixer with the same clip library, so a second list
|
|
7
|
+
* would be the same list with a second chance to be wrong. It is not in
|
|
8
|
+
* `createAvatar.ts`, where the type is documented, because a value is imported
|
|
9
|
+
* for real — reading it from there would pull `peep`'s drawing into a canvas
|
|
10
|
+
* avatar's bundle.
|
|
11
|
+
*
|
|
12
|
+
* The two required ids first, then this renderer's own catalogue. `ACTION_IDS`
|
|
13
|
+
* already carries `RESPONSE_INTERRUPTED` as this renderer's shape for it, so
|
|
14
|
+
* the join dedupes rather than concatenating, and `ACKNOWLEDGE` is the one name
|
|
15
|
+
* here with no clip behind it because `action()` resolves it on the floor
|
|
16
|
+
* (docs/internal-mixer.md § Actions).
|
|
17
|
+
*/
|
|
18
|
+
import type { AvatarSupport } from "./createAvatar.js";
|
|
19
|
+
export declare const supports: AvatarSupport;
|
|
20
|
+
//# sourceMappingURL=supports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supports.d.ts","sourceRoot":"","sources":["../client/supports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,eAAO,MAAM,QAAQ,EAAE,aAKrB,CAAC"}
|
package/dist/supports.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `supports` for every avatar this package ships — the SVG faces and the six
|
|
3
|
+
* canvas identities alike.
|
|
4
|
+
*
|
|
5
|
+
* It is one constant and one file because they are one renderer: the canvas
|
|
6
|
+
* avatars mount the same mixer with the same clip library, so a second list
|
|
7
|
+
* would be the same list with a second chance to be wrong. It is not in
|
|
8
|
+
* `createAvatar.ts`, where the type is documented, because a value is imported
|
|
9
|
+
* for real — reading it from there would pull `peep`'s drawing into a canvas
|
|
10
|
+
* avatar's bundle.
|
|
11
|
+
*
|
|
12
|
+
* The two required ids first, then this renderer's own catalogue. `ACTION_IDS`
|
|
13
|
+
* already carries `RESPONSE_INTERRUPTED` as this renderer's shape for it, so
|
|
14
|
+
* the join dedupes rather than concatenating, and `ACKNOWLEDGE` is the one name
|
|
15
|
+
* here with no clip behind it because `action()` resolves it on the floor
|
|
16
|
+
* (docs/internal-mixer.md § Actions).
|
|
17
|
+
*/
|
|
18
|
+
import { ACTION_IDS } from "../src/avatar.js";
|
|
19
|
+
import { CORE_ACTION_IDS } from "./types.js";
|
|
20
|
+
export const supports = Object.freeze({
|
|
21
|
+
actions: Object.freeze([
|
|
22
|
+
...CORE_ACTION_IDS,
|
|
23
|
+
...ACTION_IDS.filter((id) => !CORE_ACTION_IDS.includes(id)),
|
|
24
|
+
]),
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=supports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supports.js","sourceRoot":"","sources":["../client/supports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,CAAC,MAAM,QAAQ,GAAkB,MAAM,CAAC,MAAM,CAAC;IACnD,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC;QACrB,GAAG,eAAe;QAClB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAE,eAAqC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;KACnF,CAAC;CACH,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../client/three/assets.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,MAAM;;;;EAIjB,CAAC;AAEH,gDAAgD;AAChD,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,MAAM,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The three compiled characters as one table — for a page that enumerates them.
|
|
3
|
+
*
|
|
4
|
+
* Each URL lives in its own module (`tara-asset.ts` and its siblings) and this
|
|
5
|
+
* file only gathers them, because a bundler emits assets per module: anything
|
|
6
|
+
* importing *this* ships all three GLBs, which is right for a rig instrument
|
|
7
|
+
* that switches between characters and wrong for a consumer who mounted one.
|
|
8
|
+
* So the character modules never import this — they import their own — and the
|
|
9
|
+
* only reader is `/internal/three`, a separate entry point that ships nothing.
|
|
10
|
+
*/
|
|
11
|
+
import { TANYA_GLB } from "./tanya-asset.js";
|
|
12
|
+
import { TARA_GLB } from "./tara-asset.js";
|
|
13
|
+
import { TUSHAR_GLB } from "./tushar-asset.js";
|
|
14
|
+
export const ASSETS = Object.freeze({
|
|
15
|
+
tara: TARA_GLB,
|
|
16
|
+
tushar: TUSHAR_GLB,
|
|
17
|
+
tanya: TANYA_GLB,
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=assets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.js","sourceRoot":"","sources":["../../client/three/assets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,QAAQ;IACd,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE,SAAS;CACjB,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Measurable limits for one 3-D avatar at its shipping surface. */
|
|
2
|
+
export declare const SHIPPING_SURFACE: Readonly<{
|
|
3
|
+
cssWidth: 400;
|
|
4
|
+
cssHeight: 300;
|
|
5
|
+
maxDevicePixelRatio: 2;
|
|
6
|
+
}>;
|
|
7
|
+
/** Keep the physical drawing buffer inside the shipping ceiling at any mount size. */
|
|
8
|
+
export declare function pixelRatioFor(width: number, height: number, devicePixelRatio: number): number;
|
|
9
|
+
/** Crossing one of these is a failed asset/runtime review, not a suggestion. */
|
|
10
|
+
export declare const HARD_BUDGET: Readonly<{
|
|
11
|
+
assetBytes: number;
|
|
12
|
+
triangles: 60000;
|
|
13
|
+
drawCalls: 30;
|
|
14
|
+
bones: 40;
|
|
15
|
+
morphTargets: 40;
|
|
16
|
+
}>;
|
|
17
|
+
//# sourceMappingURL=budgets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budgets.d.ts","sourceRoot":"","sources":["../../client/three/budgets.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,eAAO,MAAM,gBAAgB;;;;EAI3B,CAAC;AAEH,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAS7F;AAED,gFAAgF;AAChF,eAAO,MAAM,WAAW;;;;;;EAMtB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Measurable limits for one 3-D avatar at its shipping surface. */
|
|
2
|
+
export const SHIPPING_SURFACE = Object.freeze({
|
|
3
|
+
cssWidth: 400,
|
|
4
|
+
cssHeight: 300,
|
|
5
|
+
maxDevicePixelRatio: 2,
|
|
6
|
+
});
|
|
7
|
+
/** Keep the physical drawing buffer inside the shipping ceiling at any mount size. */
|
|
8
|
+
export function pixelRatioFor(width, height, devicePixelRatio) {
|
|
9
|
+
const maxWidth = SHIPPING_SURFACE.cssWidth * SHIPPING_SURFACE.maxDevicePixelRatio;
|
|
10
|
+
const maxHeight = SHIPPING_SURFACE.cssHeight * SHIPPING_SURFACE.maxDevicePixelRatio;
|
|
11
|
+
return Math.max(0.1, Math.min(SHIPPING_SURFACE.maxDevicePixelRatio, devicePixelRatio, maxWidth / Math.max(1, width), maxHeight / Math.max(1, height)));
|
|
12
|
+
}
|
|
13
|
+
/** Crossing one of these is a failed asset/runtime review, not a suggestion. */
|
|
14
|
+
export const HARD_BUDGET = Object.freeze({
|
|
15
|
+
assetBytes: 6 * 1024 * 1024,
|
|
16
|
+
triangles: 60_000,
|
|
17
|
+
drawCalls: 30,
|
|
18
|
+
bones: 40,
|
|
19
|
+
morphTargets: 40,
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=budgets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budgets.js","sourceRoot":"","sources":["../../client/three/budgets.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC5C,QAAQ,EAAE,GAAG;IACb,SAAS,EAAE,GAAG;IACd,mBAAmB,EAAE,CAAC;CACvB,CAAC,CAAC;AAEH,sFAAsF;AACtF,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,MAAc,EAAE,gBAAwB;IACnF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,GAAG,gBAAgB,CAAC,mBAAmB,CAAC;IAClF,MAAM,SAAS,GAAG,gBAAgB,CAAC,SAAS,GAAG,gBAAgB,CAAC,mBAAmB,CAAC;IACpF,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAC3B,gBAAgB,CAAC,mBAAmB,EACpC,gBAAgB,EAChB,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAC7B,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAChC,CAAC,CAAC;AACL,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC;IACvC,UAAU,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI;IAC3B,SAAS,EAAE,MAAM;IACjB,SAAS,EAAE,EAAE;IACb,KAAK,EAAE,EAAE;IACT,YAAY,EAAE,EAAE;CACjB,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How far each character may hold its head off centre, as the mixer wants it:
|
|
3
|
+
* pose units per axis, ready to hand to `createSvgAvatar` as `headHold`.
|
|
4
|
+
*
|
|
5
|
+
* The angles themselves are in `motion-limits.json` and are only
|
|
6
|
+
* there. They were read off the three faces by the person who owns how they
|
|
7
|
+
* look, one axis at a time, at the surface a call actually shows — which is
|
|
8
|
+
* the only way this kind of number can be got, and the reason nothing here
|
|
9
|
+
* recomputes, adjusts or second-guesses one. This file is the unit change and
|
|
10
|
+
* nothing else.
|
|
11
|
+
*
|
|
12
|
+
* An axis the file marks for re-measurement is not enforced: it was read off an
|
|
13
|
+
* asset that has since been fixed, and holding the driver to a defect that no
|
|
14
|
+
* longer exists is worse than the defect. It falls back to the tightest angle
|
|
15
|
+
* still live on that axis across the other characters instead of falling out of
|
|
16
|
+
* the budget altogether, which is what it used to do. That is not a way of
|
|
17
|
+
* believing the stale number by the back door — it is the same budget the
|
|
18
|
+
* faces nobody has any doubt about are already held to. Dropping the axis made
|
|
19
|
+
* the one face nobody can currently vouch for the only one driven with no
|
|
20
|
+
* budget at all, and speech asks for about nine degrees of yaw before a budget
|
|
21
|
+
* trims it.
|
|
22
|
+
*/
|
|
23
|
+
import LIMITS from "./motion-limits.json";
|
|
24
|
+
declare const AXIS: {
|
|
25
|
+
readonly headYaw: "yaw";
|
|
26
|
+
readonly headPitch: "pitch";
|
|
27
|
+
readonly headRoll: "roll";
|
|
28
|
+
};
|
|
29
|
+
export type HeadHold = Partial<Record<keyof typeof AXIS, number>>;
|
|
30
|
+
/** `name` as the limits file spells it: tara, tushar, tanya. */
|
|
31
|
+
export declare function headHold(name: keyof typeof LIMITS.characters): HeadHold;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=holds.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"holds.d.ts","sourceRoot":"","sources":["../../client/three/holds.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,MAAM,MAAM,sBAAsB,CAAuB;AAUhE,QAAA,MAAM,IAAI;;;;CAAoE,CAAC;AAE/E,MAAM,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,OAAO,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;AAmBlE,gEAAgE;AAChE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,MAAM,CAAC,UAAU,GAAG,QAAQ,CAQvE"}
|