Rendering
Charivo's rendering layer is usually built from @charivo/render and
@charivo/render-live2d.
Recommended Stack
Use:
@charivo/render-live2das the concrete renderer@charivo/renderas the stateful manager
This is the default rendering path in the repo.
What Each Package Does
@charivo/render-live2ddraws the Live2D model and exposes renderer methods@charivo/renderconnects the renderer to Charivo events, mouse tracking, canonical avatar actions, and lip-sync updates
Most apps use both together.
Basic Setup
import { createLive2DRenderer } from "@charivo/render-live2d";
import { createRenderManager } from "@charivo/render";
const renderer = createLive2DRenderer({ canvas });
const renderManager = createRenderManager(renderer, {
canvas,
mouseTracking: "document",
});
await renderManager.initialize();
await renderManager.loadModel("/live2d/Hiyori/Hiyori.model3.json");
Attach the manager to Charivo after initialization:
charivo.attachRenderer(renderManager);
What @charivo/render Adds
- character text rendering
tts:audio:startandtts:audio:endtts:lipsync:updaterealtime:expressionrealtime:motionrealtime:gaze- optional mouse tracking
In normal app code, wire the manager to Charivo rather than handling these
events yourself.
Event Wiring
RenderManager intentionally uses setEventBus(...), not
setEventEmitter(...).
Rendering subscribes to upstream events, so it needs the full event bus
contract. This split is part of the public design. Detaching or replacing the
renderer tears down its bus subscriptions via disconnect(), so a detached
manager stops reacting to events without being destroyed.
Model Loading
The usual flow is:
- create the canvas
- create the renderer
- create the render manager
- call
initialize() - call
loadModel(...) - attach the manager to
Charivo
If the renderer exposes optional methods such as playExpression,
playMotionByGroup, lookAt, or model catalog getters, @charivo/render will use
them automatically.
Gaze Drivers
The render manager arbitrates between three gaze drivers:
- AI gaze — driven by the
realtime:gazeevent from the realtime model's look intent. Owns the avatar's gaze while the AI suspend window is active. - Local-presence gaze — driven by calling
renderManager.setLocalGaze(coords)from the app layer (e.g. webcam face tracking). Suspends mouse cursor tracking through a separate local-gaze window while active. - Mouse cursor — the default continuous mouse-tracking path.
Priority for cursor-follow: AI (realtime:gaze) > local-presence (setLocalGaze) > mouse cursor
Deliberate taps yield only to the AI window — local-presence does not suppress them.
setLocalGaze returns false (no-op) while AI gaze owns the avatar or when
the renderer has no lookAt.
Alternatives
- Use
@charivo/render/stubfor tests or demos that do not need real rendering. - If you already have a custom renderer, keep using
@charivo/renderand provide aRendererimplementation from@charivo/core.