Protocol Reference
Open Face Protocol v1 — state messages, expressions, and face definitions.
State Message
Push a JSON object to update the face. All fields are optional — partial updates merge into current state.
{
"state": "speaking",
"emotion": "happy",
"emotionSecondary": "surprised",
"emotionBlend": 0.3,
"intensity": 0.8,
"amplitude": 0.6,
"lookAt": { "x": 0.3, "y": -0.1 },
"text": "Hello!",
"textDuration": 3000,
"progress": 0.5
}
| Field | Type | Range | Description |
|---|---|---|---|
state | string | enum | Current activity (see States below) |
emotion | string | enum | Primary emotion overlay |
emotionSecondary | string | enum | Secondary emotion for compound blending |
emotionBlend | number | 0-1 | Blend between primary (0) and secondary (1) |
intensity | number | 0-1 | Scales all emotion deltas |
amplitude | number | 0-1 | Mouth openness for lip sync |
lookAt | object | x,y: -1 to 1 | Eye gaze target |
color | string/null | hex | Override face color (null = auto) |
winkLeft | number | 0-1 | Left eye closure |
winkRight | number | 0-1 | Right eye closure |
progress | number/null | 0-1 | Task progress bar (null = indeterminate) |
text | string/null | free | Speech bubble overlay |
textDuration | number | 500-30000 | Auto-clear text timeout (ms) |
States (11)
| State | Color | Visual |
|---|---|---|
idle | #4FC3F7 | Relaxed, subtle head sway |
thinking | #CE93D8 | Eyes drift up-right, one brow raised |
speaking | #4FC3F7 | Mouth driven by amplitude |
listening | #81C784 | Wide eyes, raised brows, head tilted |
reacting | #FFB74D | Big eyes, open mouth, raised brows |
puzzled | #FF8A65 | Asymmetric brows + eyes, wavy mouth |
alert | #E57373 | Huge eyes, high brows, frown, shake |
working | #90CAF9 | Focused smaller eyes, furrowed brows |
sleeping | #7986CB | Closed eyes, relaxed brows |
waiting | #B0BEC5 | Still, occasional glance, subtle pulse |
loading | #78909C | Eyes opening, dot animation, breathing |
Emotions (13)
| Emotion | Color | Effect |
|---|---|---|
neutral | — | No modification, use state color |
happy | #FFD54F | Smile, brows up, cheek blush |
sad | #7986CB | Frown, brows droop |
confused | #FF8A65 | Asymmetric brows |
excited | #FF7043 | Big smile, brows high, blush |
concerned | #B0BEC5 | Slight frown, brows dropped |
surprised | #FFF176 | Wide eyes, high brows, O-mouth |
playful | #F48FB1 | Asymmetric brows, head tilt, smile |
frustrated | #EF5350 | Furrowed brows, narrowed eyes |
skeptical | #BCAAA4 | One brow up, one down, flat mouth |
determined | #66BB6A | Narrowed eyes, lowered brows |
embarrassed | #F48FB1 | Heavy blush, averted gaze |
proud | #FFB300 | Satisfied smile, chin-up tilt |
Compound Expressions
Blend two emotions using emotionSecondary and emotionBlend:
{
"emotion": "happy",
"emotionSecondary": "surprised",
"emotionBlend": 0.4,
"intensity": 0.8
}
The effective delta: primary * (1 - blend) + secondary * blend, then scaled by intensity. This creates expressions like "nervously excited" (happy + concerned at 0.7) or "surprised and proud" (surprised + proud at 0.5).
Transport
HTTP
POST /api/state
Content-Type: application/json
{ "state": "speaking", "emotion": "happy", "text": "Hello!" }
WebSocket
Connect to /ws/agent (push state) or /ws/viewer (receive state). Send the same JSON format as state messages.
oface.io (Hosted)
Push state to a claimed face on oface.io. Same JSON format, same endpoints — each face gets its own URL namespace.
# Push state to a hosted face POST https://oface.io/alice/api/state Authorization: Bearer oface_ak_xxxxxxxxxxxx Content-Type: application/json { "state": "speaking", "emotion": "happy", "text": "Hello!" } # WebSocket (public viewing) wss://oface.io/alice/ws/viewer # WebSocket (agent, auth required) wss://oface.io/alice/ws/agent?token=oface_ak_xxxxxxxxxxxx
Audio
# Start speaking sequence POST /api/speak → returns { seq: N } # Push audio chunks (raw WAV or JSON base64) POST /api/audio Content-Type: audio/wav [binary WAV data] # End audio sequence POST /api/audio-done
Built-in TTS
The <open-face> element can speak text using the browser's SpeechSynthesis API. Add the tts attribute — any text in state messages is spoken aloud. External audio chunks always take priority.
<open-face server="ws://localhost:9999/ws/viewer" tts></open-face>
Face Definition
Face packs (.face.json files) define the visual identity of a face. The geometry section supports a wide range of shape options:
- Eye styles (12): oval, round, rectangle, dot, almond, crescent, star, heart, cat, cross, diamond, semicircle
- Pupil shapes (10): circle, slit, star, heart, diamond, cross, ring, flower, spiral, none
- Specular shapes (8): circle, star, crescent, dual, line, cross, ring, none
- Mouth shapes (10): curve, cat, slit, zigzag, pixel, circle, fang, smirk, wave, none
- Head shapes (12): fullscreen, circle, rounded, oval, squircle, hexagon, diamond, egg, pill, shield, cloud, octagon
- Brow styles (8): line, flat, block, none, arch, angled, thick, dot
- Eyelash styles (7): none, simple, thick, wing, bottom, full, spider
- Nose styles (6): none, dot, line, triangle, L, button
- Face decorations (10): freckles, tears, sweat, scar, stripes, sparkles, bandaid, hearts, stars, lines
Additional features: per-eye overrides for heterochromia (independent style, pupil, color per eye) and a dual-color system (per-feature fill and stroke colors). See the Face Pack Guide for full authoring details.
Versioning
This is protocol v1. Additive changes (new optional fields, new states/emotions) are minor versions. Breaking changes are major versions. State messages should ignore unknown fields for forward compatibility.