Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mascot.bot/llms.txt

Use this file to discover all available pages before exploring further.

Two migrations live here:
  1. 0.2.x → 0.3.0 — current pre-release cutover. Package scope rename
    • symbol consolidation (single Provider, single mount component). Most readers want this.
  2. Legacy → 0.2.x — older architectural migration (server-side visemes → on-device WebAssembly). Kept for integrators on the pre-0.2 SDK.

0.2.x → 0.3.0

The 0.3.0 release unifies SDK naming across the package scope and the React component surface. Hard cutover — no deprecated aliases. The bytes computing visemes are unchanged; only names and the mount shape moved.

Package scope

.npmrc
# 0.2.x
@mascotbot-sdk:registry=https://npm.mascot.bot/

# 0.3.0
@mascotbot:registry=https://npm.mascot.bot/
# package.json
- "@mascotbot-sdk/lipsync-core":         "^0.2.9",
- "@mascotbot-sdk/lipsync-react":        "^0.2.9",
+ "@mascotbot/core":         "^0.3.0",
+ "@mascotbot/react":        "^0.3.0",
The same renaming applies to lipsync-native@mascotbot/native and lipsync-react-native@mascotbot/react-native for RN integrators.

React mount — one Provider, one component

- import { LipsyncProvider, useLipsync } from "@mascotbot-sdk/lipsync-react";
- import {
-   MascotProvider, MascotClient, MascotRive,
-   useMascotPlayback, useMascotInputs,
- } from "@mascotbot-sdk/lipsync-react/rive";
+ import { MascotProvider, useMascot } from "@mascotbot/react";
+ import {
+   Mascot, MascotRive,
+   useMascotPlayback, useMascotInputs,
+ } from "@mascotbot/react/rive";

- <LipsyncProvider apiKey="mascot_pub_…">
-   <MascotProvider>
-     <MascotClient src="/avatar.riv">
-       <MascotRive />
-     </MascotClient>
-   </MascotProvider>
- </LipsyncProvider>
+ <MascotProvider apiKey="mascot_pub_…">
+   <Mascot src="/avatar.riv" />
+ </MascotProvider>
If you previously wrapped <MascotRive /> (or a loading slot) inside <MascotClient>, pass those as children of <Mascot> instead — they take over from the default canvas:
<MascotProvider apiKey="mascot_pub_…">
  <Mascot src="/avatar.riv" inputs={["wave"]}>
    <div className="my-layout-wrapper">
      <MascotRive />
      <MyCustomOverlay />
    </div>
  </Mascot>
</MascotProvider>

Symbol rename — quick reference

0.2.x0.3.0Notes
<LipsyncProvider><MascotProvider>Top-level provider; takes apiKey
<MascotProvider> (empty Rive marker)goneMerged into the top-level
<MascotClient> + <MascotRive /><Mascot>Single component; renders canvas by default. <MascotRive /> stays as an escape hatch
useLipsync()useMascot()Same return shape
MascotLipsyncClientLipsyncClientClass — package scope provides brand
MascotLipsyncConfigLipsyncConfigType
LipsyncContextValueMascotContextValueType returned by useMascot()
MascotClientContext / MascotClientContextType / MascotClientPropsMascotContext / MascotContextType / MascotPropsComponent renamed → matching types
Unchanged on purpose (feature-descriptive — lipsync here names what the thing is, not who ships it):
  • useProcessAudio(url)
  • useLipsyncStream({ source })
  • useMascotRive() / useMascotInputs() / useMascotPlayback()
  • LipsyncError / LipsyncStatus / LipsyncLogger
  • LipsyncStreamSource / LipsyncStreamFrame
  • LicenseError / NetworkError / EngineError / RefusedError
  • VisemeTimeline / VisemeCue / MascotPlayback (the class) / NaturalLipSync*

Migration steps (0.2.x → 0.3.0)

1

Update .npmrc + package.json

Change @mascotbot-sdk:registry=… to @mascotbot:registry=…, then rewrite the four dep names. pnpm install --force after — pnpm caches tarballs by hash, the new scope needs a fresh resolve.
2

Run the rename grep

git grep -nE '\b(LipsyncProvider|MascotClient|useLipsync|MascotLipsyncClient|MascotLipsyncConfig|LipsyncProviderProps|LipsyncContextValue|MascotClientContext|MascotClientContextType|MascotClientProps)\b'
Every hit needs the substitution in the table above. useLipsyncStream, LipsyncError, etc. are intentionally preserved — they survive because the word lipsync precisely describes what they are.
3

Collapse the Provider + Mascot mount

<LipsyncProvider><MascotProvider>… → single <MascotProvider apiKey>. <MascotClient src><MascotRive /></MascotClient><Mascot src /> if you don’t need a custom layout slot. If you do, change the tag name from MascotClient to Mascot and keep the children.
4

Typecheck + smoke

npx tsc --noEmit is the gate. Runtime behavior is identical — if types pass, runtime almost always passes too.

Legacy → 0.2.x

The 0.2.x SDK was a new architecture, not a renamed release. If you integrated a pre-0.2 build, the changes below still apply (cascade 0.2.x → 0.3.0 from the section above on top).

What changed, conceptually

Then (legacy)Now (0.2.x+)
One legacy @mascotbot/react package (pre-0.2)@mascotbot/core + @mascotbot/react, each with a /rive subpath
Visemes computed server-side and streamed to the client (REST /v1/visemes, SSE, a Mascot Bot WebSocket proxy, “viseme injection”)Visemes computed by the SDK on-device. No proxy, no REST viseme API, no SSE viseme protocol
Provider-specific hooks (useMascotElevenlabs, useMascotLiveAPI, useMascotOpenAI) and a TTS hook (useMascotSpeech)One realtime contract: tap the assistant’s audio into useLipsyncStream({ source: { kind: "mediaStream", stream } }). TTS server returns audio only; the SDK does the lip sync
getSignedUrl proxy that injected visemesProvider wired with its own official SDK; server mints only a short-lived provider credential
result.argmax per-frame arrayresult.timeline — a serializable, versioned VisemeTimeline
Private-registry .tgz installPrivate npm registry npm.mascot.bot with an .npmrc token
The dedicated provider guides (ElevenLabs, Gemini Live, OpenAI Realtime) and Realtime overview show the new wiring end to end.

Symbol map (legacy → 0.2.x — then add the 0.3.0 column above)

Legacy0.2.x replacement
Legacy @mascotbot/react (pre-0.2)@mascotbot/react + @mascotbot/react/rive (0.3.0 names)
useMascot()useMascotRive() + useMascotInputs() (split the grab-bag — rive/render from the first, custom/has/riveInputs from the second)
useMascotClient()useMascotRive() + useMascotInputs()
useRiveInputs()useMascotInputs()
useMascotSpeech()Server route returns audio → createPCMStreamPlayer + useLipsyncStream. See Realtime overview
useMascotElevenlabs()ElevenLabs guide — own SDK + audio tap
useMascotLiveAPI()Gemini Live guide
useMascotOpenAI()OpenAI Realtime guide
gesture: true (auto-fire at utterance start)The auto-fire is gone — the SDK never drives the gesture input. The built-in stress emphasis is useMascotPlayback().stress([{ offset, stress }]). A separate custom gesture trigger input is consumer-fired via useMascotInputs().custom.gesture.fire() — declare it on <Mascot inputs={["gesture", ...]}> first
useMicLipsync()useLipsyncStream({ source: { kind: "mic" } })
useStreamingLipsync()useLipsyncStream({ source: { kind: "manual" } })
useMediaStreamLipsync()useLipsyncStream({ source: { kind: "mediaStream", stream } })
playback.add(visemes)playback.pushVisemes(cues) (streaming) or playback.setTimeline(tl) (offline)
loadPrefetchedData(...)Persist a VisemeTimeline JSON; replay via parseTimeline + setTimeline. See Offline lip sync
result.argmaxresult.timeline (a VisemeTimeline)
rive.stateMachineInputs(...) introspection for presenceuseMascotInputs().has(name) / hasRiveInput(rive, name)
Mascot Bot proxy / get-signed-url / /v1/visemesRemoved — hybrid architecture; license init + refresh against license.mascot.bot.

Hooks are not reference-stable

Legacy useMascot() returned a memoised, stable object; useMascotRive() / useMascotInputs() return a fresh wrapper every render.
  • Putting their return (custom, has, the whole handle) in a useEffect / useCallback dependency array re-runs it every render — e.g. a Rive event listener that re-binds ~60×/s. Capture what you need in a useRef and depend only on the stable rive instance (stable once loaded). riveInputs identity is stable, but the wrapper object and has are fresh per render — so this rule applies to them.
The one consumer responsibility that is real is full per-call teardown on a shared clientstop() + close() + null the stream state on every call-end path; see the Troubleshooting guide. A lingering pipeline on the shared client corrupts other widgets that use the same <MascotProvider>.

Next

Quickstart

The current happy path.

Realtime overview

Provider wiring.

Troubleshooting

Post-migration issues.