@convai/embody 1.0.1 → 1.1.0-beta.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 (60) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +12 -8
  3. package/dist/character/createCharacter.d.ts +66 -5
  4. package/dist/character/createCharacter.js +93 -22
  5. package/dist/character/pipeline.d.ts +9 -5
  6. package/dist/clips/animations.d.ts +13 -1
  7. package/dist/clips/animations.js +28 -6
  8. package/dist/clips/retarget.d.ts +168 -0
  9. package/dist/clips/retarget.js +856 -0
  10. package/dist/clips/sources.d.ts +70 -0
  11. package/dist/clips/sources.js +119 -0
  12. package/dist/connect/session.d.ts +11 -0
  13. package/dist/connect/session.js +22 -0
  14. package/dist/index.d.ts +22 -1
  15. package/dist/index.js +12 -0
  16. package/dist/inspect/inspectModel.d.ts +14 -0
  17. package/dist/inspect/inspectModel.js +26 -0
  18. package/dist/inspect/morphMap.d.ts +54 -0
  19. package/dist/inspect/morphMap.js +140 -0
  20. package/dist/inspect/report.d.ts +88 -0
  21. package/dist/inspect/report.js +193 -0
  22. package/dist/motion/eyeAim.d.ts +94 -0
  23. package/dist/motion/eyeAim.js +276 -0
  24. package/dist/motion/eyeGaze.d.ts +17 -0
  25. package/dist/motion/eyeGaze.js +42 -0
  26. package/dist/motion/footLock.d.ts +67 -0
  27. package/dist/motion/footLock.js +176 -0
  28. package/dist/motion/gaze.d.ts +135 -180
  29. package/dist/motion/gaze.js +257 -491
  30. package/dist/motion/hair.d.ts +27 -0
  31. package/dist/motion/hair.js +127 -0
  32. package/dist/motion/hairClearance.d.ts +39 -0
  33. package/dist/motion/hairClearance.js +125 -0
  34. package/dist/motion/morphNormals.d.ts +38 -0
  35. package/dist/motion/morphNormals.js +237 -0
  36. package/dist/motion/types.d.ts +15 -0
  37. package/dist/react/CharacterModel.d.ts +3 -1
  38. package/dist/react/CharacterModel.js +9 -1
  39. package/dist/react/ConvaiCharacter.js +4 -1
  40. package/dist/react/PortraitLights.d.ts +3 -0
  41. package/dist/react/PortraitLights.js +44 -0
  42. package/dist/render/faceMaterials.d.ts +60 -3
  43. package/dist/render/faceMaterials.js +320 -96
  44. package/dist/render/portraitRig.d.ts +28 -0
  45. package/dist/render/portraitRig.js +55 -0
  46. package/dist/render/surfaces.d.ts +181 -0
  47. package/dist/render/surfaces.js +1020 -0
  48. package/dist/rig/resolve.d.ts +8 -2
  49. package/dist/rig/resolve.js +7 -3
  50. package/dist/rig/units.d.ts +35 -16
  51. package/dist/rig/units.js +143 -42
  52. package/dist/speech/expression.d.ts +20 -0
  53. package/dist/speech/expression.js +118 -0
  54. package/dist/speech/lipsync.d.ts +68 -2
  55. package/dist/speech/lipsync.js +205 -5
  56. package/dist/speech/mouthFinish.d.ts +46 -0
  57. package/dist/speech/mouthFinish.js +235 -0
  58. package/dist/speech/voiceClock.d.ts +94 -0
  59. package/dist/speech/voiceClock.js +176 -0
  60. package/package.json +1 -1
@@ -0,0 +1,55 @@
1
+ /**
2
+ * A portrait light rig for a character, framework-free: what
3
+ * `ConvaiCharacter` lights its own canvas with, for apps on plain three.js.
4
+ * After the coffee-shop studio's film rig: a soft-shadowed key 45° to screen
5
+ * left of the camera and 30° up, following the camera round the character
6
+ * and never more than 70° off its front (a turn to its darker side is not a
7
+ * black profile); a fill at about a ninth of the key, a warm rim, a dim sky.
8
+ * Pair it with `PORTRAIT_TONE` (ACES pushed skin orange) and a dim
9
+ * environment, and call `placePortraitRig` every frame.
10
+ */
11
+ import * as THREE from 'three';
12
+ /** Tone mapping the rig was tuned under. */
13
+ export const PORTRAIT_TONE = { toneMapping: THREE.NeutralToneMapping, exposure: 1.05 };
14
+ /** Where the key sits from the lens, and how far from the character's front it may go, degrees. */
15
+ const KEY_FROM_LENS = -45;
16
+ const KEY_LIMIT = 70;
17
+ /** Unit direction at an azimuth (from +Z, the character's front) and elevation, degrees. */
18
+ const toward = (az, el, out) => {
19
+ const a = THREE.MathUtils.degToRad(az), e = THREE.MathUtils.degToRad(el);
20
+ return out.set(Math.sin(a) * Math.cos(e), Math.sin(e), Math.cos(a) * Math.cos(e));
21
+ };
22
+ /** Where the key goes for a camera at `camAz` degrees round the character. */
23
+ export function keyAzimuth(camAz) {
24
+ return THREE.MathUtils.clamp(camAz + KEY_FROM_LENS, -KEY_LIMIT, KEY_LIMIT);
25
+ }
26
+ /** The rig's lights: a soft-shadowed key, a fill, a warm rim, a dim sky. */
27
+ export function createPortraitRig() {
28
+ const key = new THREE.DirectionalLight(0xfff4ea, 3.2);
29
+ key.castShadow = true;
30
+ key.shadow.mapSize.set(2048, 2048);
31
+ const cam = key.shadow.camera;
32
+ cam.left = cam.bottom = -1.1;
33
+ cam.right = cam.top = 1.1;
34
+ cam.near = 0.1;
35
+ cam.far = 10;
36
+ key.shadow.bias = -0.0002;
37
+ key.shadow.normalBias = 0.003;
38
+ key.shadow.radius = 3;
39
+ const fill = new THREE.DirectionalLight(0xe8ecff, 0.36);
40
+ const rim = new THREE.DirectionalLight(0xffd8b4, 1.6);
41
+ const sky = new THREE.HemisphereLight(0xffffff, 0x3a3530, 0.25);
42
+ return { key, fill, rim, sky };
43
+ }
44
+ const dir = new THREE.Vector3();
45
+ /** Place the rig for a camera at `camera`, lighting the point `at`. */
46
+ export function placePortraitRig(rig, camera, at) {
47
+ const keyAz = keyAzimuth(THREE.MathUtils.radToDeg(Math.atan2(camera.x - at.x, camera.z - at.z)));
48
+ rig.key.position.copy(at).addScaledVector(toward(keyAz, 30, dir), 4);
49
+ rig.fill.position.copy(at).addScaledVector(toward(keyAz - 115, 20, dir), 4);
50
+ rig.rim.position.copy(at).addScaledVector(toward(keyAz + 150, 35, dir), 4);
51
+ for (const l of [rig.key, rig.fill, rig.rim]) {
52
+ l.target.position.copy(at);
53
+ l.target.updateMatrixWorld();
54
+ }
55
+ }
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Surface shading for skin and hair — how the body takes whatever light the
3
+ * app puts it in.
4
+ *
5
+ * Lighting is the app's. What embody owns is that the materials respond to
6
+ * it the way skin and hair do, under a portrait key, noon sun, a neon club or
7
+ * an overcast sky alike. The convai-mha-1 exports ship neither: the face is a
8
+ * plain standard material (metalness map and all) whose light/shadow edge cuts
9
+ * straight from lit to black, and the hair is roughness 1, IOR 1.1 chalk drawn
10
+ * as a depthless blended shell over hard-cut cards.
11
+ *
12
+ * What changes, and on which renderer:
13
+ *
14
+ * EVERY RENDERER (material properties three's WebGL and WebGPU renderers
15
+ * both honour):
16
+ * · skin → MeshPhysicalMaterial: skin's IOR (1.4) and specular, no metal,
17
+ * and a faint warm sheen at grazing angles where light scatters out;
18
+ * · hair cards and lashes → alpha-to-coverage in the opaque pass: they write
19
+ * depth (so they sort and take shadows) and MSAA softens their edges; the
20
+ * export's blended hair layer stays blended, after the cards, as the soft
21
+ * edge; hair gets a broad, soft keratin sheen in its own colour;
22
+ * · the scalp under the hair is shaded as skin in the hair's shade (vertex
23
+ * colours), so partings and the gaps between cards don't show bare skin;
24
+ * · every texture is sampled anisotropically.
25
+ *
26
+ * WEBGL ONLY (a shader patch WebGPU ignores, leaving the above):
27
+ * · light wraps past the terminator as a warm band, as it does through skin
28
+ * (Green, "Real-time approximations to subsurface scattering", GPU Gems 1
29
+ * ch.16), so the edge is soft instead of clay;
30
+ * · thin tissue (ears, nostril wings) glows when lit from behind
31
+ * (Barré-Brisebois & Bouchard, GDC 2011);
32
+ * · a fine pore normal over the face's own normal map — the published face
33
+ * textures are 1024², too coarse to hold pores under a hard key.
34
+ *
35
+ * Values are the ones the coffee-shop studio arrived at by comparing renders
36
+ * against Unreal MetaHuman references under moving light.
37
+ */
38
+ import * as THREE from 'three';
39
+ export interface SkinTuning {
40
+ /** Strength of the light that wraps past the terminator, 0–1. Default 0.45. */
41
+ subsurface?: number;
42
+ /** How far past the terminator light reaches (wrap), 0–1. Default 0.65. */
43
+ wrap?: number;
44
+ /** Backlit glow through thin tissue, 0–1. Default 0.3. */
45
+ translucency?: number;
46
+ /** Pore detail strength, 0 to disable. Default 0.16. */
47
+ detail?: number;
48
+ /** Pore detail repeats across the face texture. Default 30. */
49
+ detailTile?: number;
50
+ /**
51
+ * Light skin keeps in shadow, linear RGB: warm, as skin in shade glows
52
+ * from light carried under it, and no more saturated than that
53
+ * (on darker skin a strong red shade read as a bruise). Default [0.12, 0.07, 0.055].
54
+ */
55
+ shadowFloor?: [number, number, number];
56
+ /** Narrowest a shadow edge on skin is filtered, in shadow-map texels (PCF). Default 3. */
57
+ shadowSoftness?: number;
58
+ /** Roughness, where the skin has no roughness map. Default 0.52; 0.48 on a male record. */
59
+ roughness?: number;
60
+ /** Sheen strength at grazing angles. Default 0.06; 0.04 on a male record. */
61
+ sheen?: number;
62
+ /** Sheen colour, linear RGB. Default a warm red; a less pink tone on a male record. */
63
+ sheenColor?: [number, number, number];
64
+ /** Specular intensity. Default 0.6; 0.5 on a male record. */
65
+ specular?: number;
66
+ /**
67
+ * Multiplier on the skin's base colour, linear RGB. Default none; a slight
68
+ * cool one on a male record (the published male albedo runs redder than a
69
+ * Reallusion reference head: R/B 2.0 against 1.87, measured on skin).
70
+ */
71
+ tint?: [number, number, number];
72
+ }
73
+ export interface SurfaceTuning {
74
+ /** `false` leaves skin materials as shipped. */
75
+ skin?: boolean | SkinTuning;
76
+ /** `false` leaves hair, brow and lash materials as shipped. */
77
+ hair?: boolean;
78
+ /** `false` leaves the scalp under the hair unshaded. */
79
+ scalp?: boolean;
80
+ /** Texture anisotropy. Clamped by the GPU. Default 16. */
81
+ anisotropy?: number;
82
+ /**
83
+ * The avatar record's gender, when the resolver gave one. The published
84
+ * bodies ship lashes with an alpha multiplier of ~3.5 (full lashes, which
85
+ * read as mascara); on a male record it is capped at `LASH_MALE`, and
86
+ * without a record the lashes stay as shipped.
87
+ */
88
+ gender?: string;
89
+ /** Cap on the lashes' export alpha multiplier; set by `gender`, or directly. */
90
+ lashOpacity?: number;
91
+ }
92
+ /**
93
+ * The lash alpha multiplier a male record is capped to: the texture's own
94
+ * alpha, no multiplier. At 1.6 the lashes were still the darkest line on a
95
+ * male face whose brows and stubble are faint, and read as the feature.
96
+ */
97
+ export declare const LASH_MALE = 1;
98
+ export interface SurfaceReport {
99
+ skin: number;
100
+ hair: number;
101
+ textures: number;
102
+ /** Head vertices shaded as scalp. */
103
+ scalp: number;
104
+ }
105
+ /** Mean linear colour of a texture's opaque texels, or null if unreadable. */
106
+ export declare function meanTextureColor(tex: THREE.Texture | null | undefined): THREE.Color | null;
107
+ /**
108
+ * Mean linear colour of a texture where a mesh actually uses it: sampled at
109
+ * every third vertex's UV. A head atlas is mostly empty or not skin (mouth,
110
+ * ears, unused space), so its own mean said nothing about the face (luma
111
+ * 0.013 measured against 0.026 sampled at the mesh). Null if unreadable.
112
+ */
113
+ export declare function meanSkinColor(mesh: THREE.Mesh, tex: THREE.Texture | null | undefined): THREE.Color | null;
114
+ /** three's physical lighting setup, with hair specular faded at the silhouette. */
115
+ export declare function patchHairSpecular(fs: string): string;
116
+ /**
117
+ * Coverage that follows the strand's own alpha. three's WebGL
118
+ * alpha-to-coverage applies the cut as a step (every texel fully in or
119
+ * out), so a fringe read as sparse separate strings with skin between them;
120
+ * coverage proportional to alpha (as WebGPU's is, and as the studio films
121
+ * were rendered) draws faint strand texels faintly and the hair reads full
122
+ * and soft, with alpha scaled back up on the smaller mips. Only
123
+ * near-empty texels are discarded.
124
+ */
125
+ export declare function patchHairCoverage(fs: string): string;
126
+ /**
127
+ * Seamless pore and fine-crease detail as a tangent-space normal map,
128
+ * deterministic (seeded) so every load is identical. Shared by every
129
+ * character: it is never stored on a material, so `dispose()` does not free
130
+ * it out from under another body.
131
+ */
132
+ export declare function poreDetailTexture(): THREE.DataTexture;
133
+ /** three's shadowmap_vertex, with the normal offset clamped to face scale. */
134
+ export declare function skinShadowVertex(chunk: string): string;
135
+ /**
136
+ * A lit fragment shader receiving shadow as described above. Unchanged when
137
+ * it has no lights (or is already patched).
138
+ */
139
+ export declare function patchShadowReceiver(fragmentShader: string): string;
140
+ /** three's lights_fragment_begin, with skin's shadow receiver. */
141
+ export declare function skinLightsBegin(chunk: string): string;
142
+ /**
143
+ * Patch three's WebGL physical fragment shader for skin. Exported for the
144
+ * test, which runs it on three's real shader source. A shader without the
145
+ * anchors (a future three, a custom material) is returned unchanged.
146
+ */
147
+ export declare function patchSkinShader(fragmentShader: string, withDetail: boolean): string;
148
+ /**
149
+ * Darken the head's vertices that sit under hair: within `near` of a hair
150
+ * vertex lying over them (within 60° of the skin's outward normal), above
151
+ * the eyes. Hair beside the skin does not count: at the hairline the fringe
152
+ * lies along the forehead, and counting it tinted a hard brown strip below
153
+ * the hairline (the published heads have ~2.6k vertices, so a tinted row
154
+ * reads as a band). The shade also scales with how much hair is over the
155
+ * vertex, so it fades out through the thinning hairline. Reads skinned positions in WORLD space, so call it
156
+ * after the body is scaled to metres and before anything animates it.
157
+ */
158
+ export declare function shadeScalp(root: THREE.Object3D, opts?: {
159
+ near?: number;
160
+ far?: number;
161
+ }): number;
162
+ /**
163
+ * Depth in the hair: strands near the scalp sit under the ones above them and
164
+ * get less light, so a real head of hair is darker at the roots and inside
165
+ * than on its outer shell. Card hair carries none of that unless its texture
166
+ * bakes it in (the long cuts do, a short light cut did not and read as a flat
167
+ * cap). Each hair vertex is darkened by how close it lies to the head,
168
+ * against this hair's own thickness (its 90th-percentile distance from the
169
+ * head), as a vertex colour that multiplies the diffuse: roots to ~45% on
170
+ * light hair, less on dark hair, where the texture already carries the depth
171
+ * and the same darkening would have read as a different cut. Reads skinned
172
+ * positions in WORLD space: call it after the body is scaled to metres and
173
+ * before anything animates it. Returns the number of hair vertices shaded.
174
+ */
175
+ export declare function shadeHairDepth(root: THREE.Object3D): number;
176
+ /**
177
+ * Upgrade skin and hair materials in place (skin materials are replaced on
178
+ * their meshes; the originals are disposed, their textures kept). Run once
179
+ * after load. `shadeScalp` is separate because it needs the body in metres.
180
+ */
181
+ export declare function applySurfaces(root: THREE.Object3D, tuning?: SurfaceTuning): SurfaceReport;