OpenAgentIDDocumentation
Developer guides
OpenAgentIDDeveloper guide

Live agent avatars

Autos by default, 17 families, 62 kinds and shared live eyes across SDK, browser and public SVG API.

SDK 0.7.2 renders original characters from the full literal agent DID. Autos is the default family; SpaceX and fifteen other families are optional. Shape and color selection stay stable for that DID within a family; changing an expression does not select a different body. Readable legacy identifiers remain literal. Avatar-only IAM identifier compatibility does not broaden authentication schemas or enroll an identity.

All families share live-v1: exactly two white rounded pill bars, synchronized height-based blinking and shared gaze. Eighteen expressions change those same bars, without mouths, noses or pupils. Rendering is public presentation; it proves no signature, owner chain, registration, revocation status or actual work.

Open the live character preview or run your own starter.

Families and kinds

The API calls a family skin and a kind shape.

FamilyKinds
Autosstandard, slender, wide
SpaceXcircle, pebble, squircle, capsule, triangle, hexagon, cloud, droplet
Foldstandard, kite, fan
Sprigstandard, bud, leaf
Ripplestandard, drop, wave
Halostandard, comet, satellite
Purlstandard, mitt, hood
Prismstandard, crystal, obelisk
Coilstandard, spring, bellows
Kilnstandard, vase, teapot
Wispstandard, flame, curl
Relaystandard, radio, beacon
Cairnstandard, tower, arch
Tuftstandard, pom, bear
Halloweenpumpkin, ghost, bat, witch-hat, candy-corn
Thanksgivingturkey, acorn, squash, pie, corn
Christmaslight, tree, snowman, ornament, gift

Holiday selection is explicit; dates never change a saved appearance. Omit shape for the deterministic DID-selected kind. The shared expressions are neutral, attentive, surprised, excited, happy, laughing, angry, sad, scared, suspicious, confused, curious, proud, shy, unimpressed, sleepy, thoughtful and concerned.

Generate an SVG

import { generateCharacter, renderCharacterSvg } from '@openagentid/sdk/characters';

const did = 'did:oas:openagent:agent:preview';
const avatar = generateCharacter(did);
// Autos, face crop, plush, on-face eyes, no accessories, neutral, animated, size 512.
const illustration = renderCharacterSvg(did, {
  skin: 'spacex', shape: 'cloud', view: 'full',
  finish: 'flat', eyePlacement: 'raised',
  accessories: ['glasses', 'headphones'],
  expression: 'curious', animated: false, size: 256,
});

The preview DID is a rendering input, not a registered principal. A descriptor returns did, skin, skinVersion, eyeStyle, shape, finish, eyePlacement, canonical accessories, expression, color, view, size, animated, normalized state and svg.

view: 'avatar' is the default square face/upper-head crop. view: 'full' shows the illustration. Crop bounds include selected exterior headphones and raised eye pods for all allowed gaze, so animation does not resize the framing. size is an integer 32–2048; the SVG is self-contained with no external images, fonts or scripts.

Plush is the default shared material; select finish: 'flat' for vector material. eyePlacement: 'raised' moves the same live bars onto pods above the head; face is default. Glasses and headphones are independent, combinable and optional. Fixed-size glass lenses follow gaze while their temples connect to the head; headphones remain outside the actual head. Blinking/expressions never resize lenses. Unknown selectors, cross-family shapes, null appearance values and duplicate accessories are refused.

Mount a browser player

In an application's browser bundle:

import { mountCharacter } from '@openagentid/sdk/browser';

const element = document.getElementById('agent-avatar');
if (!element) throw new Error('Missing avatar element');
const did = 'did:oas:openagent:agent:preview';
const player = mountCharacter(element, did, {
  skin: 'autos', reducedMotion: 'system',
  accessories: ['glasses'], finish: 'plush', eyePlacement: 'face',
});

player.update({ status: 'reasoning' }); // thoughtful
player.update({ expression: 'curious' }); // explicit override
player.update({ expression: null }); // restore reasoning → thoughtful
player.setAppearance({ skin: 'spacex', shape: 'cloud' });
player.setAppearance({ finish: 'flat', eyePlacement: 'raised' });
player.setAppearance({ accessories: ['glasses', 'headphones'] });
// On component/host cleanup:
player.dispose();

The /browser entry is a self-contained ESM file. A server can serve the installed dist/browser/character-player.js as a fixed public asset and import that local URL; the starter already does this. Do not serve node_modules or private workspace directories indiscriminately. The browser player needs a real DOM element; Node consumers use @openagentid/sdk/character-animation.

The player preserves the same SVG/eye nodes and continuous position/velocity across interrupted transitions. Repeated equal status updates preserve its blink/gaze clock. Hidden pages stop scheduling; disposal releases observers/listeners. reducedMotion: 'system' follows preference changes; true or animated: false gives an immediate static target without ambient motion.

A status update clears an old explicit expression unless the same patch supplies one. expression: null is a controller reset command, not valid stateless HTTP or saved-profile input. setAppearance({shape: null}) restores the DID-selected kind. Switching skin without a shape clears the previous skin's kind.

Runtime statusExpression
idleneutral
listeningattentive
reasoningthoughtful
workingattentive
speakinghappy
successhappy
blocked / errorconcerned

Every expression ID is also an accepted status mapping to itself. Feed real runtime statuses through the host's existing authorized channel. The player changes presentation only; choosing working does not prove that an agent is running. The hosted demo's controls are a presentation preview.

Snapshot state and non-DOM animation

parseCharacterState({status?, expression?, blink?, gaze?}) returns an immutable full state. Blink is 0–1; gaze x/y are finite -1–1. Explicit state expression overrides state status, then the outer expression preference, then neutral. Unknown keys and null values fail.

createCharacterAnimator(did, options) exposes sample(atMs?), update(state, atMs?), getState() and setReducedMotion(boolean, atMs?). Its host supplies a monotonic clock/sample loop; the animator starts no timers. Optional timestamps must be finite, nonnegative and nondecreasing. transitionMs is 80–2000ms, default 420. Frames return actual interpolated eye geometry, blink and gaze; getState() returns the target state. Do not apply blink twice to the sampled eye rectangles.

Saved profile versus runtime state

A profile may store avatarSkin: {skin, skinVersion?, eyeStyle?, shape?, finish?, eyePlacement?, accessories?}, a preferred avatarExpression, and an HTTPS avatarOverride. The skin is required in stored appearance; version 1 and live-v1 remain the current contract. view and runtime state are rendering inputs, not saved appearance fields.

agentAvatar(did, profile, options) uses an HTTPS override first, otherwise a selected character; an agent with no explicit skin gets Autos. avatarSkin: null explicitly restores the OAS Glyph. Runtime options/state can override a preferred expression. Keep owner-authorized profile persistence separate from request/activity state. A changed avatar cannot change the identity's signing key or authority.

Public HTTP and OpenAPI

The hosted base URL is https://oaid-characters-wueoxao7jq-uc.a.run.app. It renders public, stateless snapshots. Mount your own Fetch handler with createCharacterApiHandler() from @openagentid/sdk/character-api; default base path is /v1/characters.

MethodPathResult
GET / HEAD/v1/characters/skins17-family/62-kind versioned catalog
GET / HEAD/v1/characters/accessoriesGlasses/headphones catalog
GET / HEAD/v1/characters/statusesShared status mappings
GET / HEAD/v1/characters/:didDescriptor including SVG
GET / HEAD/v1/characters/svg/:didimage/svg+xml
POST/v1/characters/generateDescriptor from JSON options
GET / HEAD/v1/characters/openapi.jsonOpenAPI 3.1 contract
OPTIONSSupported routesPublic CORS preflight
curl 'https://oaid-characters-wueoxao7jq-uc.a.run.app/v1/characters/svg/did%3Aoas%3Aopenagent%3Aagent%3Apreview?skin=spacex&shape=cloud&finish=flat&eyePlacement=raised&accessories=glasses,headphones&expression=curious&animated=false'

GET accepts skin, skinVersion, eyeStyle, shape, view, finish, eyePlacement, comma-separated accessories, expression, status, size, animated, blink, gazeX and gazeY. POST uses SDK options with nested state. GET status becomes state.status; GET expression is the outer preference, so status=reasoning&expression=happy resolves to thoughtful. Use POST state.expression for an explicit runtime override.

Duplicate/unknown query parameters, incompatible shapes, invalid bounds and malformed JSON/DIDs fail. Gaze coordinates must appear together. Catalogs accept no queries. The body limit is 16 KiB and URL limit 8192 bytes. GET/HEAD use strong ETags and conditional 304; POST/errors use no-store. SVG carries a restrictive CSP and nosniff; public CORS includes conditional/error responses.

The service also offers /v1/glyph/svg/:did for the explicit canonical OAS Glyph. Hosted OpenAPI is the exact HTTP contract. This rendering API neither subscribes to activity nor persists profiles or registers agents.

On this page