@convai/embody 1.0.0 → 1.0.1-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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @convai/embody
2
2
 
3
+ ## 1.0.1-beta.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Fix: `ConvaiCharacter` and `CharacterModel` call `onReady` (and `onError`) once per character. An inline `onReady={(c) => …}` used to run again on every parent re-render, repeating whatever setup the app did there, such as adding a `speakingChange` listener.
8
+
9
+ Docs: two new guides, "Add your own animations to a character" (the `animations` option, `idleClip`, `crossfadeTo`, a talking clip on `speakingChange`, `register` at runtime) and "Use your own 3D model" (a resolver for a MetaHuman GLB you host, the rig requirements, Full and Lite files, `connect: false` previews). The `createCharacter` reference gains `modelVariant`, `character.model`, and sections for `AnimationController` and the `CharacterBundle` manifest; the React reference says which props reload the character. The README's Lite count no longer says 113.
10
+
3
11
  ## 1.0.0
4
12
 
5
13
  ### Major Changes
package/README.md CHANGED
@@ -217,7 +217,8 @@ profile, so a new rig is a value rather than a code change.
217
217
  ### Full and Lite bodies
218
218
 
219
219
  A body can ship two GLBs of the same rig: **Full**, with all 251 MetaHuman
220
- blendshapes, and **Lite**, with 113. Phones need Lite. three.js spends one
220
+ blendshapes, and **Lite**, with a reduced set (the art team's Lite exports
221
+ carry 103; keep it at 192 or fewer). Phones need Lite. three.js spends one
221
222
  vertex-shader uniform per blendshape, many mobile GPUs allow 256 in all, and
222
223
  past that the head fails to compile and is not drawn.
223
224
 
@@ -229,6 +230,35 @@ gets Full. Pass `modelVariant: 'full'` or `'lite'` to force one;
229
230
  file everywhere. Blendshapes Lite drops are skipped by lipsync, blink and
230
231
  eye gaze rather than erroring.
231
232
 
233
+ ## Your own animations and models
234
+
235
+ **Animations.** `animations` maps a clip name to a GLB holding an animation of
236
+ that name, merged over the body's clips by name (the key must equal the
237
+ animation's name inside the file). `character.animations` then plays them:
238
+
239
+ ```ts
240
+ const character = await createCharacter({
241
+ token, characterId,
242
+ animations: { Wave: '/animations/gestures.glb' },
243
+ })
244
+ character.animations.crossfadeTo('Wave', { once: true, thenBackTo: 'Idle' })
245
+
246
+ // embody moves the mouth while the character speaks, never the body clip:
247
+ character.client?.on('speakingChange', (s) => character.animations.crossfadeTo(s ? 'Talk' : 'Idle'))
248
+ ```
249
+
250
+ Clips must be authored on the MetaHuman skeleton; nothing is retargeted, and
251
+ tracks for bones the model lacks are dropped with a console warning.
252
+
253
+ **Models.** A `resolver` returning a `CharacterBundle` for files you host
254
+ replaces the body while the conversation still comes from the character's
255
+ Convai session. The model must be on `convai-mha-1`: MetaHuman bone names
256
+ (`head`, `neck_01`, `neck_02`, `spine_02`, `spine_04`, …) and `CTRL_expressions_*`
257
+ blendshapes. Other rigs load with a still head and face.
258
+
259
+ Step-by-step guides: [Add your own animations](./docs/site/convai-embody/add-your-own-animations.md),
260
+ [Use your own 3D model](./docs/site/convai-embody/use-your-own-3d-model.md).
261
+
232
262
  ## Escape hatches
233
263
 
234
264
  The defaults cover the normal case; each of these exists for a specific one.
@@ -272,6 +302,8 @@ Convai Embody*. Its source is [`docs/site/`](./docs/site) in this repository:
272
302
  | [Add a 3D character to a React app](./docs/site/convai-embody/add-a-3d-character-to-a-react-app.md) | install, render, verify, troubleshoot |
273
303
  | [Add a 3D character to a three.js scene](./docs/site/convai-embody/add-a-3d-character-to-a-three-js-scene.md) | the framework-free API |
274
304
  | [Add a chat widget to a character](./docs/site/convai-embody/add-a-chat-widget-to-a-character.md) | one connection for body and chat |
305
+ | [Add your own animations to a character](./docs/site/convai-embody/add-your-own-animations.md) | load, crossfade, talking clip, runtime clips |
306
+ | [Use your own 3D model](./docs/site/convai-embody/use-your-own-3d-model.md) | a MetaHuman GLB you host, Full and Lite, rig requirements |
275
307
  | [React API reference](./docs/site/convai-embody/react-api-reference.md) | every prop and default |
276
308
  | [createCharacter reference](./docs/site/convai-embody/createcharacter-reference.md) | every option, the handle, the errors |
277
309
  | [How Convai Embody works](./docs/site/convai-embody/how-convai-embody-works.md) | resolution, the frame pipeline, environments |
@@ -19,20 +19,27 @@ import { jsx as _jsx } from "react/jsx-runtime";
19
19
  * (which delegates cancellation to `../character/lifecycle`). This adds
20
20
  * nothing but the `<primitive>` render and the onReady/onError plumbing.
21
21
  */
22
- import { useEffect } from 'react';
22
+ import { useEffect, useRef } from 'react';
23
23
  import { useCharacter } from './useCharacter.js';
24
24
  export function CharacterModel({ onReady, onError, ...opts }) {
25
25
  const { character, error } = useCharacter(opts);
26
+ // The callbacks are read through refs so that announcing is keyed on the
27
+ // character (or error) alone. Apps pass them inline, `onReady={(c) => …}`,
28
+ // which is a new function on every render; with the callback as an effect
29
+ // dependency, each parent re-render re-announced the same character and
30
+ // re-ran whatever setup the app did there.
31
+ const onReadyRef = useRef(onReady);
32
+ const onErrorRef = useRef(onError);
33
+ onReadyRef.current = onReady;
34
+ onErrorRef.current = onError;
26
35
  useEffect(() => {
27
- if (character && onReady)
28
- onReady(character);
29
- // eslint-disable-next-line react-hooks/exhaustive-deps
30
- }, [character, onReady]);
36
+ if (character)
37
+ onReadyRef.current?.(character);
38
+ }, [character]);
31
39
  useEffect(() => {
32
- if (error && onError)
33
- onError(error);
34
- // eslint-disable-next-line react-hooks/exhaustive-deps
35
- }, [error, onError]);
40
+ if (error)
41
+ onErrorRef.current?.(error);
42
+ }, [error]);
36
43
  if (!character)
37
44
  return null;
38
45
  return _jsx("primitive", { object: character.root });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@convai/embody",
3
- "version": "1.0.0",
3
+ "version": "1.0.1-beta.0",
4
4
  "description": "Give a Convai character a body: resolve 3D characters by characterId and drive them with lipsync and animation. Layered on @convai/web-sdk.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Convai <support@convai.com>",