@voqalize/avatar 0.4.1 → 0.4.2
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/README.md +46 -28
- package/assets/README.md +4 -3
- package/assets/tanya.glb +0 -0
- package/assets/tara.glb +0 -0
- package/assets/tess.glb +0 -0
- package/assets/tushar.glb +0 -0
- package/client/internal.ts +20 -0
- package/client/three/assets.ts +5 -3
- package/client/three/holds.ts +7 -2
- package/client/three/internal.ts +5 -5
- package/client/three/motion-limits.json +5 -1
- package/client/three/sequences.ts +5 -5
- package/client/three/tara-rig.ts +22 -8
- package/client/three/tess-asset.ts +6 -0
- package/client/three/tess.ts +72 -0
- package/dist/internal.d.ts +2 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +12 -1
- package/dist/internal.js.map +1 -1
- package/dist/three/assets.d.ts +1 -0
- package/dist/three/assets.d.ts.map +1 -1
- package/dist/three/assets.js +5 -3
- package/dist/three/assets.js.map +1 -1
- package/dist/three/holds.d.ts +7 -2
- package/dist/three/holds.d.ts.map +1 -1
- package/dist/three/holds.js +7 -2
- package/dist/three/holds.js.map +1 -1
- package/dist/three/internal.d.ts +5 -5
- package/dist/three/internal.js +5 -5
- package/dist/three/motion-limits.json +5 -1
- package/dist/three/sequences.d.ts +5 -5
- package/dist/three/sequences.js +5 -5
- package/dist/three/tara-rig.d.ts +18 -4
- package/dist/three/tara-rig.d.ts.map +1 -1
- package/dist/three/tara-rig.js +9 -8
- package/dist/three/tara-rig.js.map +1 -1
- package/dist/three/tess-asset.d.ts +7 -0
- package/dist/three/tess-asset.d.ts.map +1 -0
- package/dist/three/tess-asset.js +7 -0
- package/dist/three/tess-asset.js.map +1 -0
- package/dist/three/tess.d.ts +38 -0
- package/dist/three/tess.d.ts.map +1 -0
- package/dist/three/tess.js +54 -0
- package/dist/three/tess.js.map +1 -0
- package/package.json +5 -1
- package/src/avatar.d.ts +65 -2
- package/src/avatar.js +68 -63
- package/src/faces.js +1 -1
- package/src/gaze.js +19 -44
- package/src/idle.js +60 -26
- package/src/prosody.js +104 -14
- package/src/rig.d.ts +7 -0
package/README.md
CHANGED
|
@@ -5,10 +5,11 @@ avatars are lip-synced to the audio and they are state aware: they know when
|
|
|
5
5
|
they have been interrupted, when the user is talking versus idle, when a tool
|
|
6
6
|
call has started and stopped.
|
|
7
7
|
|
|
8
|
-
No video track, no per-minute avatar vendor, no second media path.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
No video track, no per-minute avatar vendor, no second media path. SVG faces
|
|
9
|
+
and 2.5-D characters ship with it, one per entry point, so you pay for the one
|
|
10
|
+
you import, and you can author your own. Canvas2D identities also ship and are
|
|
11
|
+
frozen: they still work, they get no further work,
|
|
12
|
+
and they come out in 0.5.0 (below).
|
|
12
13
|
|
|
13
14
|
This is the browser half. The pipeline half is
|
|
14
15
|
[`voqalize-avatar`](https://pypi.org/project/voqalize-avatar/) on PyPI; they are
|
|
@@ -16,10 +17,10 @@ two ends of one wire format and release independently, kept compatible by the
|
|
|
16
17
|
wire contract rather than a shared version number
|
|
17
18
|
([RELEASING.md § Compatibility](https://github.com/voqalize/avatar/blob/main/RELEASING.md#compatibility)).
|
|
18
19
|
|
|
19
|
-
**Licence: MIT for the code, CC-BY 4.0 for the
|
|
20
|
-
(`assets/*.glb
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
**Licence: MIT for the code and the SVG and Canvas2D avatars, CC-BY 4.0 for the
|
|
21
|
+
2.5-D character binaries** (`assets/*.glb` — see `assets/README.md` for the
|
|
22
|
+
credit line). Which applies is decided by the kind of avatar, so adding a
|
|
23
|
+
character never moves the line. The manifest declares the pair as
|
|
23
24
|
`MIT AND CC-BY-4.0`.
|
|
24
25
|
|
|
25
26
|
## Install
|
|
@@ -85,14 +86,14 @@ always the renderer's.
|
|
|
85
86
|
|
|
86
87
|
What is left over is small, specific, and each item is a case the library
|
|
87
88
|
refuses to guess at — a deliberate nod or greeting, a tool whose calls never
|
|
88
|
-
enter your pipeline, a pose richer than the
|
|
89
|
+
enter your pipeline, a pose richer than the core states, a backend that is not
|
|
89
90
|
ours. [The architecture
|
|
90
91
|
page](https://github.com/voqalize/avatar/blob/main/docs/architecture.md) is the
|
|
91
92
|
canonical reference for all of it.
|
|
92
93
|
|
|
93
94
|
## The wire protocol
|
|
94
95
|
|
|
95
|
-
|
|
96
|
+
`state`, `action` and `cues`, one envelope
|
|
96
97
|
([contract-wire.md](https://github.com/voqalize/avatar/blob/main/docs/contract-wire.md)):
|
|
97
98
|
|
|
98
99
|
```json
|
|
@@ -113,16 +114,16 @@ Emission is overwrite, never merge: a `cues` message says "discard everything
|
|
|
113
114
|
queued at or after `from_ms`, then append these". The server decides; the client
|
|
114
115
|
has no say and no way to refuse.
|
|
115
116
|
|
|
116
|
-
**Not using our backend?** Any server can produce cues
|
|
117
|
+
**Not using our backend?** Any server can produce cues; the ways, best first:
|
|
117
118
|
If your TTS emits native viseme events, map the integer ids through
|
|
118
119
|
`AZURE_VISEME_TO_LETTER` and ship `{t, v}` as they stream. Otherwise force-align
|
|
119
120
|
the text against the audio and map ARPAbet through `ARPABET_TO_VISEME`. With no
|
|
120
121
|
server work at all, `textToCues(text)` is a crude grapheme guesser, fit for
|
|
121
|
-
previews only.
|
|
122
|
+
previews only. Each is exported from `@voqalize/avatar/internal`.
|
|
122
123
|
|
|
123
124
|
## The faces
|
|
124
125
|
|
|
125
|
-
|
|
126
|
+
All hand-authored line art: **`peep`** (the default),
|
|
126
127
|
**`wren`**, **`myna`**. Each is its own entry point, and you pass the value
|
|
127
128
|
rather than a name:
|
|
128
129
|
|
|
@@ -133,11 +134,18 @@ createAvatar({ mount, client, face: myna });
|
|
|
133
134
|
```
|
|
134
135
|
|
|
135
136
|
A name would need a table, and a table is a dynamic index no bundler can shake —
|
|
136
|
-
|
|
137
|
+
every drawing in every consumer's bundle to render one.
|
|
137
138
|
|
|
138
|
-
## Professional avatars
|
|
139
|
+
## Professional avatars — frozen, removed in 0.5.0
|
|
139
140
|
|
|
140
|
-
|
|
141
|
+
**Do not start here.** These are a Canvas2D renderer that ended up in the
|
|
142
|
+
wrong place: more expensive to author than an SVG drawing and less expressive
|
|
143
|
+
than the 2.5-D characters, which is the whole range it was meant to sit between.
|
|
144
|
+
They still work and they are still tested, but they get no further work, and
|
|
145
|
+
their entry points come out in 0.5.0. Pick an SVG face or a 2.5-D character
|
|
146
|
+
instead; both are below.
|
|
147
|
+
|
|
148
|
+
Complete, code-authored avatars, each its own `createAvatar` module:
|
|
141
149
|
|
|
142
150
|
```js
|
|
143
151
|
import { createAvatar } from '@voqalize/avatar/avatars/arjun';
|
|
@@ -151,15 +159,15 @@ const avatar = createAvatar({ mount, client: pipecatClient });
|
|
|
151
159
|
```
|
|
152
160
|
|
|
153
161
|
`arjun`/`meera` are the original interviewer pair; `vikram`/`ishita` and
|
|
154
|
-
`kabir`/`naina` are
|
|
162
|
+
`kabir`/`naina` are further wardrobe/hair directions on the same rig. The
|
|
155
163
|
entry points `interviewer-male`, `interviewer-female`, `professional-male-a`,
|
|
156
164
|
`professional-female-a`, `professional-male-b` and `professional-female-b`
|
|
157
165
|
still work — they are `@deprecated` aliases for the names above, kept so
|
|
158
166
|
existing imports do not break, and should not be used in new code.
|
|
159
167
|
|
|
160
|
-
|
|
168
|
+
They depict Indian professionals in their late twenties, without caricature
|
|
161
169
|
or regional costume cues. They are calibrated at call-tile size and preserve
|
|
162
|
-
|
|
170
|
+
every expression target, continuous visemes, gaze, blink, head motion, and
|
|
163
171
|
the frame-edge gesture hand. Each module is a complete identity, not a face
|
|
164
172
|
value: import one instead of the default module and do not pass a `face`
|
|
165
173
|
option.
|
|
@@ -171,23 +179,25 @@ only in low-motion upper-cheek areas; none are used as demographic cues.
|
|
|
171
179
|
They use the same public contract and the same Pipecat lifecycle/viseme driver
|
|
172
180
|
as the SVG avatars. Their private renderer is Canvas2D; its rig data and bitmap
|
|
173
181
|
wardrobe assets are implementation details and no Canvas or pose API is added
|
|
174
|
-
to the package surface.
|
|
182
|
+
to the package surface. Like the SVG faces they are code, MIT, and ask for no
|
|
183
|
+
attribution.
|
|
175
184
|
|
|
176
185
|
## The 2.5-D characters
|
|
177
186
|
|
|
178
|
-
|
|
187
|
+
The characters ship as compiled binaries, each its own `createAvatar` module:
|
|
179
188
|
|
|
180
189
|
```js
|
|
181
190
|
import { createAvatar } from '@voqalize/avatar/avatars/tara';
|
|
182
191
|
// or: @voqalize/avatar/avatars/tushar
|
|
183
192
|
// @voqalize/avatar/avatars/tanya
|
|
193
|
+
// @voqalize/avatar/avatars/tess
|
|
184
194
|
|
|
185
195
|
const avatar = createAvatar({ mount, client: pipecatClient });
|
|
186
196
|
```
|
|
187
197
|
|
|
188
198
|
A photograph of a face projected onto shallow geometry, with the parts that have
|
|
189
199
|
to move — eyes, teeth, the lip line — built as geometry rather than painted.
|
|
190
|
-
Three.js is an *optional* peer (`three`, `>=0.180 <0.187`) behind
|
|
200
|
+
Three.js is an *optional* peer (`three`, `>=0.180 <0.187`) behind those
|
|
191
201
|
entry points only, so an SVG or Canvas consumer never downloads it, and the `.glb`
|
|
192
202
|
is fetched when the avatar mounts.
|
|
193
203
|
|
|
@@ -196,7 +206,7 @@ cue-synced mouth, and a server that has never heard of these characters drives o
|
|
|
196
206
|
correctly. The head turns 15° of yaw and 24° of pitch, which is a measured limit
|
|
197
207
|
rather than an option.
|
|
198
208
|
|
|
199
|
-
**The
|
|
209
|
+
**The binaries are artwork under CC-BY 4.0**, separately from the MIT code
|
|
200
210
|
around them; the credit line is in `assets/README.md`. Mounting, sizing, the asset
|
|
201
211
|
budget and what the characters can be asked to do:
|
|
202
212
|
[characters.md](https://github.com/voqalize/avatar/blob/main/docs/characters.md).
|
|
@@ -234,7 +244,7 @@ React binding. `src/` is the widget itself: the mixer, the SVG rig and drawings,
|
|
|
234
244
|
plus the private Canvas2D interviewer rigs and their assets, as dependency-free
|
|
235
245
|
ES modules with no build step, imported by `dist/` through ordinary relative
|
|
236
246
|
paths. `client/` is the TypeScript those `dist/` files were compiled from, so
|
|
237
|
-
the source maps resolve. `assets/` is the
|
|
247
|
+
the source maps resolve. `assets/` is the compiled characters and their
|
|
238
248
|
licence note — the only non-JavaScript thing here, fetched at runtime by URL.
|
|
239
249
|
|
|
240
250
|
The contract documents do not ship here. They live in the repository, which is
|
|
@@ -244,10 +254,18 @@ where they are kept current:
|
|
|
244
254
|
## License
|
|
245
255
|
|
|
246
256
|
**MIT for the code, CC-BY 4.0 for the artwork**, and Voqalize holds the
|
|
247
|
-
copyright on all of it. The
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
257
|
+
copyright on all of it. The licence follows the kind of avatar, not the roster:
|
|
258
|
+
|
|
259
|
+
- **SVG faces and Canvas2D identities are code** — MIT, no attribution. Each is
|
|
260
|
+
drawn by the function that ships it; a Canvas2D identity's rig data and
|
|
261
|
+
wardrobe bitmaps are implementation details of that function, not artwork you
|
|
262
|
+
are licensing.
|
|
263
|
+
- **2.5-D characters are artwork** — `assets/*.glb`, and nothing else in the
|
|
264
|
+
tarball, under CC-BY 4.0. `assets/README.md` carries the credit line.
|
|
265
|
+
|
|
266
|
+
MIT is usable anywhere, including in closed-source products. The manifest
|
|
267
|
+
declares the package as `MIT AND CC-BY-4.0`, which is what a licence scanner
|
|
268
|
+
reports whether or not you import a 2.5-D character.
|
|
251
269
|
|
|
252
270
|
The drawing idiom `peep` is authored in is
|
|
253
271
|
[Open Peeps](https://www.openpeeps.com/) (CC0) — no artwork is copied. The
|
package/assets/README.md
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# The character binaries
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The 2.5-D characters, one compiled file each:
|
|
4
4
|
|
|
5
5
|
| file | character | what it is |
|
|
6
6
|
|---|---|---|
|
|
7
7
|
| `tara.glb` | tara | the first; shallow geometry under a projected portrait |
|
|
8
8
|
| `tushar.glb` | tushar | the second, her scripts with his landmarks |
|
|
9
9
|
| `tanya.glb` | tanya | the third, built from supplied reference images |
|
|
10
|
+
| `tess.glb` | tess | the fourth, from a single supplied reference sheet |
|
|
10
11
|
|
|
11
12
|
They are loaded for you. `@voqalize/avatar/avatars/tara` resolves the file beside
|
|
12
13
|
itself and hands it to a loader; you never name a path, and the only reason to
|
|
@@ -20,7 +21,7 @@ in this directory to regenerate it from, and the next release overwrites it.
|
|
|
20
21
|
|
|
21
22
|
## Licence: CC-BY 4.0
|
|
22
23
|
|
|
23
|
-
The rest of this package is MIT. These
|
|
24
|
+
The rest of this package is MIT. These files are artwork, not code, so they
|
|
24
25
|
carry an artwork licence: **Creative Commons Attribution 4.0 International**, the
|
|
25
26
|
full text in `LICENSE-CC-BY-4.0` at the package root. Use them in a product,
|
|
26
27
|
commercially, modified or retextured, and credit us:
|
|
@@ -41,7 +42,7 @@ file is the only way terms travel with it.
|
|
|
41
42
|
Every character began as an image from a generative model — OpenAI's and
|
|
42
43
|
Google's — and **none of them depicts a real person**. Any resemblance to one is
|
|
43
44
|
coincidence, not a likeness, and there are no personality rights attached to any
|
|
44
|
-
of
|
|
45
|
+
of them. What we did with that image is ours: the geometry, the measured
|
|
45
46
|
landmarks, the projection, the relighting and the authored morph targets are all
|
|
46
47
|
human work, and they are the substance of what is licensed here.
|
|
47
48
|
|
package/assets/tanya.glb
CHANGED
|
Binary file
|
package/assets/tara.glb
CHANGED
|
Binary file
|
package/assets/tess.glb
ADDED
|
Binary file
|
package/assets/tushar.glb
CHANGED
|
Binary file
|
package/client/internal.ts
CHANGED
|
@@ -47,6 +47,24 @@ export {
|
|
|
47
47
|
LEAD_MS,
|
|
48
48
|
// The body's share of a held tilt, for a page driving a rig by hand.
|
|
49
49
|
SHOULDER_TILT,
|
|
50
|
+
// Stepping a gesture by hand: the catalogue, the player, and the smoothing
|
|
51
|
+
// law the mixer puts between a clip's keyframes and the face. A filmstrip
|
|
52
|
+
// instrument needs all three, and the one thing it must not do is fork the
|
|
53
|
+
// smoothing — that is the part a keyframe is authored against
|
|
54
|
+
// (docs/internal-mixer.md § Smoothing).
|
|
55
|
+
INTERNAL_CLIPS,
|
|
56
|
+
ClipPlayer,
|
|
57
|
+
TAU,
|
|
58
|
+
clamp,
|
|
59
|
+
approach,
|
|
60
|
+
// Posing a face directly, with no mixer, no clock and no client above it —
|
|
61
|
+
// what a pose sheet or a rig-conformance page does. `makeParams` fills the
|
|
62
|
+
// rests around a handful of overrides, `emotionPose` names a familiar set of
|
|
63
|
+
// them, `avatarFrame` wraps the result and `createSvgRig(face)` draws it.
|
|
64
|
+
makeParams,
|
|
65
|
+
emotionPose,
|
|
66
|
+
avatarFrame,
|
|
67
|
+
createSvgRig,
|
|
50
68
|
shapeFor,
|
|
51
69
|
normalizeCues,
|
|
52
70
|
textToCues,
|
|
@@ -55,6 +73,8 @@ export {
|
|
|
55
73
|
} from "../src/avatar.js";
|
|
56
74
|
|
|
57
75
|
export type {
|
|
76
|
+
Clip,
|
|
77
|
+
ClipSample,
|
|
58
78
|
AvatarApi,
|
|
59
79
|
AvatarStateName,
|
|
60
80
|
AvatarActionId,
|
package/client/three/assets.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Every compiled character as one table — for a page that enumerates them.
|
|
3
3
|
*
|
|
4
4
|
* Each URL lives in its own module (`tara-asset.ts` and its siblings) and this
|
|
5
5
|
* file only gathers them, because a bundler emits assets per module: anything
|
|
6
|
-
* importing *this* ships
|
|
7
|
-
*
|
|
6
|
+
* importing *this* ships every GLB, which is right for a rig instrument that
|
|
7
|
+
* switches between characters and wrong for a consumer who mounted one.
|
|
8
8
|
* So the character modules never import this — they import their own — and the
|
|
9
9
|
* only reader is `/internal/three`, a separate entry point that ships nothing.
|
|
10
10
|
*/
|
|
11
11
|
import { TANYA_GLB } from "./tanya-asset.js";
|
|
12
|
+
import { TESS_GLB } from "./tess-asset.js";
|
|
12
13
|
import { TARA_GLB } from "./tara-asset.js";
|
|
13
14
|
import { TUSHAR_GLB } from "./tushar-asset.js";
|
|
14
15
|
|
|
@@ -16,6 +17,7 @@ export const ASSETS = Object.freeze({
|
|
|
16
17
|
tara: TARA_GLB,
|
|
17
18
|
tushar: TUSHAR_GLB,
|
|
18
19
|
tanya: TANYA_GLB,
|
|
20
|
+
tess: TESS_GLB,
|
|
19
21
|
});
|
|
20
22
|
|
|
21
23
|
/** Every compiled character, in build order. */
|
package/client/three/holds.ts
CHANGED
|
@@ -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
|
|
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
|
|
@@ -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
|
|
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)[]) {
|
package/client/three/internal.ts
CHANGED
|
@@ -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
|
|
5
|
-
* `createAvatar` each, the mixer behind it, nothing to
|
|
6
|
-
* other door, for a page whose subject is the *rig*
|
|
7
|
-
* renderer with no mixer in front of it,
|
|
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` — 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,
|
|
@@ -110,7 +110,11 @@
|
|
|
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": []
|
|
113
117
|
}
|
|
114
118
|
},
|
|
115
|
-
"remeasure": "An axis carrying `remeasure` was measured on an asset that has since changed. It stays as written
|
|
119
|
+
"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
120
|
}
|
|
@@ -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
|
|
266
|
-
*
|
|
267
|
-
* characters inherit whole, and this file's own names. A hand-kept
|
|
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
|
|
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
|
*/
|
package/client/three/tara-rig.ts
CHANGED
|
@@ -69,10 +69,11 @@ const FRAME_CENTRE = (FRAME.top + FRAME.bottom) / 2;
|
|
|
69
69
|
* shell, and a large turn is where that reads as a cardboard cutout rather than
|
|
70
70
|
* a head. **It opened from 9° to 15° on 2026-09-18.** The cutout was measured
|
|
71
71
|
* rather than assumed — a ladder rendered at 9/12/15/18/21/25/30 and read at
|
|
72
|
-
* crop on
|
|
73
|
-
* tushar. 9° was therefore set at half of where the artefact
|
|
74
|
-
* and the stiffness the owner reported on tanya's turns was
|
|
75
|
-
* her asset. 15° keeps 3° of headroom
|
|
72
|
+
* crop on the characters that existed then is clean to 21° on tara and to 18°
|
|
73
|
+
* on tanya and tushar. 9° was therefore set at half of where the artefact
|
|
74
|
+
* actually begins, and the stiffness the owner reported on tanya's turns was
|
|
75
|
+
* that margin, not her asset. 15° keeps 3° of headroom under the 18° the
|
|
76
|
+
* tightest of them read.
|
|
76
77
|
*
|
|
77
78
|
* This is not for speech: Busso wants ±1.15° of yaw in neutral conversation and
|
|
78
79
|
* always did. It is for a head that turns to *look* at something, which is what
|
|
@@ -931,6 +932,19 @@ export interface TaraRigOptions {
|
|
|
931
932
|
/** `false` leaves an asset's expression maps unread, for a capture tool
|
|
932
933
|
* comparing the face with and without them. */
|
|
933
934
|
readonly expression?: boolean;
|
|
935
|
+
/** Keeps the drawing buffer readable after the browser has composited it, so
|
|
936
|
+
* a caller can copy the canvas out at any moment rather than only from
|
|
937
|
+
* inside the frame that drew it.
|
|
938
|
+
*
|
|
939
|
+
* A pose sheet needs this and a consumer must not have it. WebGL contexts are
|
|
940
|
+
* a handful per page, so a sheet of thirty poses cannot be thirty canvases —
|
|
941
|
+
* it holds one pose still, copies the canvas into a tile, and moves on. Copy
|
|
942
|
+
* outside the drawing frame and the buffer has already been cleared, which is
|
|
943
|
+
* a blank tile and not an error. The cost is that the buffer cannot be
|
|
944
|
+
* discarded, which on some drivers means a second copy of every frame; the
|
|
945
|
+
* consumer renders thirty frames a second forever and pays nothing for a
|
|
946
|
+
* readback it never performs. */
|
|
947
|
+
readonly readback?: boolean;
|
|
934
948
|
}
|
|
935
949
|
|
|
936
950
|
const radians = (deg: number) => (deg * Math.PI) / 180;
|
|
@@ -940,9 +954,9 @@ const radians = (deg: number) => (deg * Math.PI) / 180;
|
|
|
940
954
|
* Three.js throws out of the constructor rather than returning anything, and it
|
|
941
955
|
* has already written its own line to the console by then; that line is kept
|
|
942
956
|
* because it names the underlying reason, which this one does not. */
|
|
943
|
-
function webglRenderer(): THREE.WebGLRenderer | null {
|
|
957
|
+
function webglRenderer(readback = false): THREE.WebGLRenderer | null {
|
|
944
958
|
try {
|
|
945
|
-
return new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
|
959
|
+
return new THREE.WebGLRenderer({ antialias: true, alpha: true, preserveDrawingBuffer: readback });
|
|
946
960
|
} catch {
|
|
947
961
|
return null;
|
|
948
962
|
}
|
|
@@ -1153,7 +1167,7 @@ const expressionWeights = (pose: RigPose, side: "L" | "R", expression: Expressio
|
|
|
1153
1167
|
// `options` is `unknown` in the contract, and stays `unknown` here: the mixer
|
|
1154
1168
|
// passes `rigOptions` through verbatim and has no way to know any rig's shape.
|
|
1155
1169
|
export function createTaraRig(mount: HTMLElement, options?: unknown): AvatarRig {
|
|
1156
|
-
const { onReady, url, expression: readExpression = true } =
|
|
1170
|
+
const { onReady, url, expression: readExpression = true, readback = false } =
|
|
1157
1171
|
(options ?? {}) as TaraRigOptions;
|
|
1158
1172
|
// A missing `url` is a caller's defect, not a browser condition — the WebGL
|
|
1159
1173
|
// path below degrades because a driver is nobody's fault, whereas this would
|
|
@@ -1164,7 +1178,7 @@ export function createTaraRig(mount: HTMLElement, options?: unknown): AvatarRig
|
|
|
1164
1178
|
camera.position.set(0, FRAME_CENTRE, 6);
|
|
1165
1179
|
camera.lookAt(0, FRAME_CENTRE, 0);
|
|
1166
1180
|
|
|
1167
|
-
const renderer = webglRenderer();
|
|
1181
|
+
const renderer = webglRenderer(readback);
|
|
1168
1182
|
// No context, no face — and that has to be the whole of it. `createAvatar` is
|
|
1169
1183
|
// synchronous and returns `{ destroy }`, so a consumer has nothing to catch:
|
|
1170
1184
|
// anything thrown here lands in *their* window and takes the call page with
|
|
@@ -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,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tess — American, and like `tushar.ts` and `tanya.ts` a copy of `tara.ts`.
|
|
3
|
+
*
|
|
4
|
+
* Her GLB is tara's scripts run with her landmarks in place of tara's
|
|
5
|
+
* (`characters/tess/`, whose README has the provenance and the commands), so
|
|
6
|
+
* the rig, the mixer, the sequences and her tuning are all hers, unmodified;
|
|
7
|
+
* the one seam is `TaraRigOptions.url`.
|
|
8
|
+
*
|
|
9
|
+
* She is back inside tara's atlas window — her hair is drawn into a low tail
|
|
10
|
+
* that clears both ears and reaches |u| 0.492 against a window that stops at
|
|
11
|
+
* 0.64 — so unlike tanya she needs no `face_texture.py` of her own, and her
|
|
12
|
+
* `Hair` shell gives up no roll: nothing of hers hangs past the jaw to lag.
|
|
13
|
+
*
|
|
14
|
+
* Her head angles have not been read off her yet. `motion-limits.json` says so
|
|
15
|
+
* rather than guessing, and `headHold` gives her the tightest budget any face
|
|
16
|
+
* is still vouched for until the owner drives her.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { PipecatClient } from "@pipecat-ai/client-js";
|
|
20
|
+
import { AvatarClient, createSvgAvatar } from "../internal.js";
|
|
21
|
+
import { TESS_GLB } from "./tess-asset.js";
|
|
22
|
+
import { BLENDER_ACTIONS, BLENDER_SEQUENCES, BLENDER_SUPPORTS } from "./sequences.js";
|
|
23
|
+
import { headHold } from "./holds.js";
|
|
24
|
+
import { createTaraRig, TARA_TUNING } from "./tara-rig.js";
|
|
25
|
+
import type { TaraRigOptions } from "./tara-rig.js";
|
|
26
|
+
|
|
27
|
+
export interface AvatarOptions {
|
|
28
|
+
readonly mount: HTMLElement;
|
|
29
|
+
readonly client: PipecatClient;
|
|
30
|
+
/** Viseme amplitude, 0..2. `1` is as authored. */
|
|
31
|
+
readonly mouthGain?: number;
|
|
32
|
+
/** Gesture-clip amplitude, 0..2. */
|
|
33
|
+
readonly gestureGain?: number;
|
|
34
|
+
/** Idle/liveness amplitude, 0..2. */
|
|
35
|
+
readonly motionGain?: number;
|
|
36
|
+
/** Fires when the GLB is in the scene — for a capture tool, not a consumer. */
|
|
37
|
+
readonly onReady?: () => void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface AvatarInstance { destroy(): void; }
|
|
41
|
+
|
|
42
|
+
/** The optional driving-UI declaration; one list for every character built on
|
|
43
|
+
* this rig (`sequences.ts`), because they are one rig. */
|
|
44
|
+
export const supports = BLENDER_SUPPORTS;
|
|
45
|
+
|
|
46
|
+
export function createAvatar(options: AvatarOptions): AvatarInstance {
|
|
47
|
+
const { mount, client, onReady, ...gains } = options;
|
|
48
|
+
if (!mount) throw new TypeError("createAvatar: `mount` is required");
|
|
49
|
+
if (!client) throw new TypeError("createAvatar: `client` is required");
|
|
50
|
+
|
|
51
|
+
const rigOptions: TaraRigOptions = { onReady, url: TESS_GLB };
|
|
52
|
+
// TARA-SPECIFIC, kept on purpose: `TARA_TUNING` (her mouth and motion gains)
|
|
53
|
+
// is the first thing to question if she reads wrong in a call.
|
|
54
|
+
const widget = createSvgAvatar({
|
|
55
|
+
mount, rig: createTaraRig, rigOptions, hand: false,
|
|
56
|
+
sequences: BLENDER_SEQUENCES, actions: BLENDER_ACTIONS, ...TARA_TUNING,
|
|
57
|
+
headHold: headHold("tess"), ...gains,
|
|
58
|
+
});
|
|
59
|
+
const driver = new AvatarClient(widget);
|
|
60
|
+
const detach = driver.attach(client);
|
|
61
|
+
|
|
62
|
+
let destroyed = false;
|
|
63
|
+
return {
|
|
64
|
+
destroy() {
|
|
65
|
+
if (destroyed) return;
|
|
66
|
+
destroyed = true;
|
|
67
|
+
detach();
|
|
68
|
+
driver.destroy();
|
|
69
|
+
widget.destroy();
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
package/dist/internal.d.ts
CHANGED
|
@@ -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, 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";
|
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,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,
|
|
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,EACR,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,18 @@ 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,
|
|
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, normalizeCues, textToCues, ARPABET_TO_VISEME, AZURE_VISEME_TO_LETTER, } from "../src/avatar.js";
|
|
36
47
|
export { BEHAVIOR_STATE_IDS, BEHAVIOR_ACTIONS, BEHAVIOR_ACTION_IDS, WIRE_ACTION_TO_BEHAVIOR, } from "../src/behavior.js";
|
|
37
48
|
export { isAvatarMessage, CORE_ACTION_IDS } from "./types.js";
|
|
38
49
|
// A renderer may reuse the one lifecycle/precedence ladder without gaining a
|
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;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,
|
|
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,EACR,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"}
|
package/dist/three/assets.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../client/three/assets.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../client/three/assets.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,MAAM;;;;;EAKjB,CAAC;AAEH,gDAAgD;AAChD,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,MAAM,CAAC"}
|
package/dist/three/assets.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Every compiled character as one table — for a page that enumerates them.
|
|
3
3
|
*
|
|
4
4
|
* Each URL lives in its own module (`tara-asset.ts` and its siblings) and this
|
|
5
5
|
* file only gathers them, because a bundler emits assets per module: anything
|
|
6
|
-
* importing *this* ships
|
|
7
|
-
*
|
|
6
|
+
* importing *this* ships every GLB, which is right for a rig instrument that
|
|
7
|
+
* switches between characters and wrong for a consumer who mounted one.
|
|
8
8
|
* So the character modules never import this — they import their own — and the
|
|
9
9
|
* only reader is `/internal/three`, a separate entry point that ships nothing.
|
|
10
10
|
*/
|
|
11
11
|
import { TANYA_GLB } from "./tanya-asset.js";
|
|
12
|
+
import { TESS_GLB } from "./tess-asset.js";
|
|
12
13
|
import { TARA_GLB } from "./tara-asset.js";
|
|
13
14
|
import { TUSHAR_GLB } from "./tushar-asset.js";
|
|
14
15
|
export const ASSETS = Object.freeze({
|
|
15
16
|
tara: TARA_GLB,
|
|
16
17
|
tushar: TUSHAR_GLB,
|
|
17
18
|
tanya: TANYA_GLB,
|
|
19
|
+
tess: TESS_GLB,
|
|
18
20
|
});
|
|
19
21
|
//# sourceMappingURL=assets.js.map
|
package/dist/three/assets.js.map
CHANGED
|
@@ -1 +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;
|
|
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,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;IAChB,IAAI,EAAE,QAAQ;CACf,CAAC,CAAC"}
|