ALLPERSONAS / DEVELOPERS
Expressions
Let the face respond to the moment.
Try an expression
Expressions are typed inputs. Pick a cue to see how it changes the face.
Live SDK
@allpersonas/coreMAKE IT YOURS
Use this face in your app
import { createFace } from '@allpersonas/core';
export function mountAssistant(host: HTMLElement) {
Object.assign(host.style, { width: '280px', height: '340px' });
const face = createFace(host, {
avatar: "ruby",
expression: "attentive",
});
// Update when your agent's state changes.
// face.update({ thinking: true });
return () => face.destroy();
}Expression catalog
neutralattentivecuriousuncertainreflectiveguardedanxiousfearfuloverwhelmedsurprisedfrustratedangrysadhurtdisappointedashamedguiltydisgustedsoftenedrelievedhopefulgratefuljoyfulamusedThere are 24 semantic cues. Related emotions can share facial geometry. Everyday warmth and thinking keep the eyes at their normal size.
When to change expression
Set face.update({ expression }) for a text-only response. For spoken segments, subscribe to AvatarSpeech and apply its expression when playback begins.
import { AvatarSpeech, createFace } from '@allpersonas/core';
export function mountTalkingAssistant(container: HTMLElement) {
const root = document.createElement('div');
root.innerHTML = `
<div data-face style="width:280px;height:340px"></div>
<button data-speak type="button">Say hello</button>
<button data-stop type="button">Stop</button>
<p data-error role="alert"></p>
`;
container.append(root);
const face = createFace(root.querySelector<HTMLElement>('[data-face]')!);
const speakButton = root.querySelector<HTMLButtonElement>('[data-speak]')!;
const stopButton = root.querySelector<HTMLButtonElement>('[data-stop]')!;
const error = root.querySelector<HTMLElement>('[data-error]')!;
const speech = new AvatarSpeech();
let disposed = false;
const unsubscribe = speech.subscribe(() => {
const state = speech.getSnapshot();
face.update({
expression: state.expression,
speaking: state.speaking,
boundary: speech.boundary,
});
error.textContent = state.error ?? '';
});
const sayHello = () => {
void speech.speak([
{ expression: 'joyful', text: 'It is good to meet you.' },
{ expression: 'curious', text: 'What is on your mind?' },
]).catch((cause: unknown) => {
if (!disposed) error.textContent = cause instanceof Error
? cause.message : 'Speech could not start.';
});
};
speakButton.addEventListener('click', sayHello);
stopButton.addEventListener('click', speech.stop);
return () => {
disposed = true;
speakButton.removeEventListener('click', sayHello);
stopButton.removeEventListener('click', speech.stop);
unsubscribe();
speech.stop();
face.destroy();
root.remove();
};
}Expressions hold between responses. They are independent of idle blinks and mouth motion. Clear thinking when the response is ready so the selected expression becomes visible.