Emotions

Inline emotion markers in LLM output with automatic expression mapping.

AvatarLayer can parse inline emotion markers from LLM output, strip them from TTS text, and apply expression changes to the avatar renderer automatically.

Setup

Enable emotions in the session config:

import {
  AvatarSession,
  OpenAIAdapter,
  ElevenLabsAdapter,
  VRMLocalRenderer,
  getEmotionSystemPromptSuffix,
} from "avatarlayer";

const session = new AvatarSession({
  llm: new OpenAIAdapter({ apiKey: "sk-..." }),
  tts: new ElevenLabsAdapter({ apiKey: "..." }),
  renderer: new VRMLocalRenderer({ modelUrl: "/models/avatar.vrm" }),
  systemPrompt: "You are a friendly avatar assistant.\n\n" + getEmotionSystemPromptSuffix(),
  emotions: true,
});

The getEmotionSystemPromptSuffix() function returns instruction text that tells the LLM how to emit emotion markers.

How it works

  1. The LLM outputs text with inline markers like <|ACT {"emotion":"happy","intensity":0.8}|>
  2. The session's marker parser detects and extracts these markers from the stream
  3. Markers are stripped from the text before it reaches TTS
  4. The parsed emotion is applied to the renderer via update() with the appropriate expression preset
  5. The emotion event fires on the session

Marker format

Emotion markers

<|ACT {"emotion":"happy","intensity":0.8}|>

The JSON payload contains:

FieldTypeDescription
emotionstringEmotion name (see values below)
intensitynumberIntensity from 0 to 1

Delay markers

<|DELAY:500|>

Inserts a pause (in milliseconds) in the speech output.

Emotion values

The Emotion enum defines the supported emotion labels:

ValueVRM presetLive2D expression
happyhappyhappy
sadsadsad
angryangryangry
surprisedsurprisedsurprised
relaxedrelaxedrelaxed
neutralneutralneutral

The EMOTION_VRM_MAP and EMOTION_LIVE2D_MAP exports provide the full mapping from emotion labels to renderer-specific expression names.

Events

EventPayloadDescription
emotion{ name: string, intensity: number }Fired each time an emotion marker is parsed from the LLM stream
session.on("emotion", ({ name, intensity }) => {
  console.log(`Emotion: ${name} at ${intensity}`);
});

Utilities

ExportDescription
getEmotionSystemPromptSuffix()Returns the instruction text for the LLM
EmotionEnum of supported emotion labels
EMOTION_VALUESArray of all emotion label strings
EMOTION_VRM_MAPMap from emotion label to VRM expression preset
EMOTION_LIVE2D_MAPMap from emotion label to Live2D expression name
parseEmotionMarker(text)Parse an emotion marker string into an EmotionPayload
parseDelayMarker(text)Parse a delay marker string into milliseconds
createMarkerParser()Create a stateful parser for streaming marker extraction