• English
  • AgentAvatar

    The avatar you actually drop into a list.

    Ada
    Grace
    Alan
    +1Platform
    import { MarkStageProvider, AgentAvatar } from '@aora-bot/react';
    
    const people = [
      { id: 'ada@example.com', name: 'Ada' },
      { id: 'grace@example.com', name: 'Grace' },
      { id: 'alan@example.com', name: 'Alan' },
      { id: 'team', name: 'Platform', members: [{ id: 'a' }, { id: 'b' }, { id: 'c' }, { id: 'd' }] },
    ];
    
    export default function Demo() {
      return (
        <MarkStageProvider>
          <div className="site-demo">
            {people.map((agent) => (
              <div className="site-demo__cell" key={agent.id}>
                <AgentAvatar agent={agent} sizePx={52} />
                <span className="site-demo__label">{agent.name}</span>
              </div>
            ))}
          </div>
        </MarkStageProvider>
      );
    }

    What it chooses between

    In order:

    1. A picture, if pictureUrl is set
    2. A group cluster, if members is non-empty
    3. A character, derived from id

    Which means an application can pass whatever it has and get something sensible, rather than branching at every call site.

    Identity without storage

    Shape and ink are hashed from id when not given explicitly, so every user has a consistent character and you store nothing. Two clients, two sessions and a server render all agree.

    import { AgentAvatar } from '@aora-bot/react';
    
    export default function Demo() {
      return (
        <div className="site-demo">
          {['u-1', 'u-2', 'u-3', 'u-4', 'u-5', 'u-6', 'u-7', 'u-8'].map((id) => (
            <AgentAvatar key={id} agent={{ id }} sizePx={44} still />
          ))}
        </div>
      );
    }

    Pass shape or color on the agent to override either independently.

    Face style

    Put face: 'line' on the agent for the line face. The nose is hashed from id like the shape and ink, so it is as stable as they are; set nose to choose one or null for none.

    import { AgentAvatar } from '@aora-bot/react';
    
    export default function Demo() {
      return (
        <div className="site-demo">
          {['u-1', 'u-2', 'u-3', 'u-4', 'u-5', 'u-6', 'u-7', 'u-8'].map((id) => (
            <AgentAvatar key={id} agent={{ id, face: 'line' }} sizePx={44} still />
          ))}
        </div>
      );
    }

    A cast preset can carry a face and nose too; an explicit value on the agent wins over the preset, and the preset over the hash.

    Sizes

    xs, 16px
    sm, 22px
    md, 28px
    lg, 36px
    xl, 72px
    import { AgentAvatar, AVATAR_SIZES } from '@aora-bot/react';
    
    export default function Demo() {
      return (
        <div className="site-demo" style={{ alignItems: 'flex-end' }}>
          {Object.entries(AVATAR_SIZES).map(([size, px]) => (
            <div className="site-demo__cell" key={size}>
              <AgentAvatar agent={{ id: 'nova' }} size={size as never} />
              <span className="site-demo__label">
                {size}, {px}px
              </span>
            </div>
          ))}
        </div>
      );
    }

    Still and halo

    still renders an image instead of an animation — the right choice in long lists. halo adds a soft colour wash derived from the character's own hue.

    import { AgentAvatar } from '@aora-bot/react';
    
    export default function Demo() {
      return (
        <div className="site-demo">
          <AgentAvatar agent={{ id: 'halo-1' }} sizePx={64} halo still />
          <AgentAvatar agent={{ id: 'halo-2' }} sizePx={64} halo still />
          <AgentAvatar agent={{ id: 'halo-3' }} sizePx={64} halo still />
        </div>
      );
    }

    Fill

    fillPx sets the size of the character inside the circle. The circle keeps its size; only what is drawn inside it changes, so smaller than the circle leaves a margin and larger crops it. The default fills the circle exactly. It is a custom property rather than a width on the child, because the child is an img in two of the three branches and the stylesheet already sizes those.

    fillPx 44
    fillPx 64
    fillPx 80
    import { AgentAvatar } from '@aora-bot/react';
    
    export default function Demo() {
      return (
        <div className="site-demo">
          {[44, 64, 80].map((fill) => (
            <div className="site-demo__cell" key={fill}>
              <AgentAvatar agent={{ id: 'fill', shape: 'hex', color: 'blue' }} sizePx={64} fillPx={fill} halo />
              <span className="site-demo__label">fillPx {fill}</span>
            </div>
          ))}
        </div>
      );
    }

    While the shape is changing

    isMorphingShape says the shape is being changed under the character right now — the editor is open and someone is clicking through the grid. While it is true the avatar holds its last settled state for the settle window (SETTLE_MS, through useMarkSettle), so a morph is one change rather than two. A body that changes shape and expression in the same frame does not read as the same character with a new outline; it reads as a different character appearing.

    Accessibility

    The avatar is aria-hidden unless it has a picture with a name. When an avatar stands alone with no adjacent text, give it a name yourself — see accessibility.

    API

    PropTypeDefaultDescription
    agent*AgentLike——
    classNamestring——
    emotionIdstring—Protocol id, for hosts that speak the wire format. Ignored when `state` is given.
    face"cute" | "eyes" | "line"—Face style, overriding whatever the agent identity resolves to.
    fillPxnumber—Size of the character inside the circle. Smaller than the circle leaves a margin; larger crops it. Defaults to filling the circle exactly.
    halobooleanfalseSoft colour wash behind the character.
    isMorphingShapebooleanfalseThe shape is being changed under the character right now. Holds the last settled state for the settle window, so a morph is one change rather than two. A body that changes shape and expression in the same frame does not read as the same character having a new outline; it reads as a different character appearing.
    lineWeightnumber—Stroke width multiplier. Not part of an identity, so always explicit.
    nose"slant" | "angular" | "hook" | "long" | "curve" | "bow" | null—Nose, overriding the identity. `null` draws no nose.
    size"xs" | "sm" | "md" | "lg" | "xl"'md'—
    sizePxnumber—Exact pixel size, overriding `size`.
    state"idle" | "sleeping" | "drowsy" | "bored" | "waking" | "powering-down" | "listening" | "thinking" | "searching" | "reading" | "writing" | "working" | "loading" | "progress" | "radar" | "orbit" | "dictating" | "uploading" | "sending" | "receiving" | "messaging" | "waiting" | "spawning" | "composing" | "dragging" | "happy" | "excited" | "laughing" | "playful" | "proud" | "celebrate" | "bouncing" | "shy" | "sad" | "angry" | "confused" | "suspicious" | "surprised" | "scared" | "curious" | "humming" | "alerting" | "notifying" | "refusing"——
    stillbooleanfalseRender a still image instead of an animation.
    styleCSSProperties——

    Next