Emotion scripting API
Reference for the emotion scripting surface — ConvaiEmotionController, EmotionReading, override and lock methods, C# events, and IEmotionStateSource.
The Emotion system exposes two distinct paths for reacting to and controlling emotional state at runtime. The Inspector path uses ConvaiCharacterEventRelay — a component that surfaces emotion change callbacks as standard Unity Events, requiring no code. The scripting path uses ConvaiEmotionController directly, exposing a full C# API for reading live state, injecting overrides, and locking expressions. Both paths can be used simultaneously.
Inspector path — ConvaiCharacterEventRelay
ConvaiCharacterEventRelay is a MonoBehaviour that bridges character callbacks to Unity Events, allowing designers to wire emotion reactions entirely in the Inspector without writing any code.
Add Component: Convai → Events → Convai Character Event Relay
Place it on any GameObject in the scene. It automatically finds the ConvaiCharacter on the same GameObject, or you can assign a character from a different GameObject via the Character field.
Inspector fields
Character
(none)
Optional explicit reference to a ConvaiCharacter. Leave empty to use auto-resolve.
Auto Resolve Character
true
When enabled, the relay finds a ConvaiCharacter on the same GameObject automatically.
OnEmotionChanged event
The relay exposes an On Emotion Changed Unity Event that fires whenever the character's emotion signal changes. The event delivers a CharacterEmotionRelayData payload:
CharacterId
string
Unique identifier of the character.
CharacterName
string
Display name of the character (falls back to the GameObject name).
Emotion
string
The raw server label (e.g. "happy").
Intensity
int
Integer scale 1–3 as sent by the backend.
Example wiring: Add a ConvaiCharacterEventRelay to your NPC's GameObject. In the On Emotion Changed list, click +, drag a UI Text component into the object field, and select Text.text — the label will update automatically on every emotion change.
ConvaiCharacterEventRelay fires on the raw server label before taxonomy resolution or smoothing. Use it for UI display, audio cues, or simple branching logic. For smoothed, post-resolution state with scores and hold time, use ConvaiEmotionController.Current from script instead.
Accessing the controller from script
The ConvaiEmotionController component can be retrieved by its concrete type or through the IEmotionStateSource interface. Use the interface when you want to decouple your code from the specific component implementation:
Reading current emotion state
ConvaiEmotionController.Current returns an EmotionReading — an immutable snapshot rebuilt every frame from the accumulator's output. Poll it in Update or react to it on any event.
EmotionReading properties and methods
DominantLabel
string
Canonical label of the highest-scoring emotion (e.g. "joy", "anger").
DominantScore
float
Normalised score [0–1] for the dominant emotion after smoothing and burst.
AllScores
IReadOnlyDictionary<string, float>
Full score table keyed by canonical label. Every emotion in the taxonomy has an entry. Emotions with no contribution this frame have a score of 0.
MouthInfluence
float
[0–1] hint consumed by the LipSync compositor to blend mouth shapes during non-speaking frames.
DominantHoldSeconds
float
Wall-clock seconds the current dominant label has been held continuously.
IsNeutral
bool
true when the dominant label is "neutral" or when DominantScore ≤ 0.
NeutralLabel
const string
The string constant "neutral".
GetScore(string canonicalLabel)
float
Returns the smoothed score for the given canonical label, or 0 when absent.
CopyScoresTo(IDictionary<string, float> destination)
void
Copies the full score table into a caller-owned dictionary. Clears the destination before copying.
Authoring-time lock
The controller has three serialised fields that fix the expression to a specific emotion directly from the Inspector — useful during authoring and debugging, or to preview blendshape slot results in the Scene view without entering Play Mode.
lockEmotion
bool
false
When enabled, all incoming server emotion events are ignored and the character holds the locked emotion.
lockedEmotionLabel
string
"neutral"
Canonical taxonomy label to hold while lockEmotion is active.
lockedIntensity
float
1.0
Intensity [0–1] of the locked emotion.
lockEmotion is a serialised field — its value is saved with the scene or prefab. If you leave it enabled and forget to reset it, the character will silently ignore all live emotion signals in your production build with no runtime error or warning. Always disable it before building.
ConvaiEmotionController inherits [ExecuteAlways] from its base class. Setting lockEmotion = true in the Inspector updates blendshapes in the Scene view immediately, without entering Play Mode. This makes it a practical tool for verifying that slot mappings produce the correct visual result on your character mesh.
SetEmotionOverride and ClearEmotionOverride
SetEmotionOverride injects an additional score into the accumulator on top of whatever the server is sending. The override is still subject to smoothing — it blends in at lerpSpeed, not instantly. Use this when your application logic needs to amplify or steer emotion in response to in-scene events.
ClearEmotionOverride removes the override and returns the accumulator to server-driven state. The transition back is smoothed.
LockEmotion and UnlockEmotion
LockEmotion bypasses the accumulator entirely, snapping the character to a specific expression and holding it there regardless of what the server sends. Use this when you need a guaranteed, stable expression during scripted sequences.
UnlockEmotion releases the lock. The accumulator resumes from neutral and begins responding to server events again.
API signatures:
Subscribing to emotion change events
To react to each new emotion the backend sends — for logging, analytics, or adaptive scenario logic — subscribe to OnCharacterEmotionChanged on ConvaiManager.Events. This is a standard C# event; subscribe in OnEnable and unsubscribe in OnDisable.
CharacterEmotionChanged properties
CharacterId
string
Unique identifier of the character whose emotion changed.
Emotion
string
The raw server label (e.g. "happy", not the canonical "joy").
Intensity
int
Integer scale 1–3 as sent by the backend (clamped).
NormalizedIntensity
float
(Intensity - 1) / 2f — maps the 1–3 range to [0, 1].
IsNeutral
bool
true if the emotion string is "neutral".
IsHighIntensity
bool
true if Intensity >= 3.
IsLowIntensity
bool
true if Intensity <= 1.
Timestamp
DateTime
UTC timestamp of when the event was created.
CharacterEmotionChanged.Emotion contains the raw server label (e.g. "happy"), not the canonical taxonomy label ("joy"). If you need the canonical label — for example, to look up a score in AllScores — resolve it through the taxonomy: taxonomy.TryResolve(e.Emotion, out EmotionDescriptor descriptor).
IEmotionStateSource interface
Code that only needs to read emotion state — without controlling overrides or locks — should depend on IEmotionStateSource rather than the concrete ConvaiEmotionController. This keeps the dependency minimal and makes the consuming class easier to test.
Next steps
For complete worked examples that combine profile configuration with these API calls, see Emotion examples. If something is not behaving as expected at runtime, see Troubleshoot emotion.
Emotion examplesTroubleshoot emotionLast updated
Was this helpful?