A viseme is the visual shape of the mouth for a sound — the visual counterpart of a phoneme. The SDK emits one of 22 viseme ids (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.
0–21).
Internally, ready-made Rive mascots map those onto number inputs 100–118
via the exported VISEMES_MAP; you rarely touch the raw ids directly.
The model output
Inference produces one viseme id per 10 ms frame.client.processAudio()
returns that as a VisemeTimeline, not a raw array:
processAudio() returns the timeline directly. It is run-length-encoded,
~10× smaller than a per-frame array, and is exactly the change-event model the
playback engine consumes, so there is no second representation to keep in sync.
The VisemeTimeline shape
localStorage, your database, a CDN,
a file — and replay it later without touching the model, the network, or a
license refresh.
Helpers
All three are pure functions on the package root.| Helper | Signature | Purpose |
|---|---|---|
framesToTimeline | (argmax: readonly number[], opts: { speechMs: number; frameMs?: number }) → VisemeTimeline | Build a timeline from a per-frame viseme array (if you assemble visemes yourself). |
timelineToCues | (tl: VisemeTimeline) → { offset: number; visemeId: number }[] | Expand a timeline into the cue list MascotPlayback consumes. The inverse of the change-event encoding. |
parseTimeline | (input: unknown) → VisemeTimeline | Validate untrusted/persisted JSON and return a typed timeline, or throw. |
parseTimeline is the trust boundary
Persisted JSON outlives SDK versions. parseTimeline is the single gate for
loading a timeline back: it validates version, frameMs, monotonic cue
offsets, the leading t: 0, and viseme-id ranges. On any mismatch it throws a
LipsyncError whose .code === "bad_timeline":
VISEME_TIMELINE_VERSION is bumped on any breaking shape or semantics change,
so an old stored timeline fails loudly instead of animating garbage. Treat
bad_timeline as “regenerate”, never as a license or network condition. It is
documented in the error-code reference.
Next
Offline lip sync
Generate → persist → replay in practice.
Rive co-existence
How visemes reach the avatar.
Core client
processAudio, streaming sessions.