# Avatar

A generative avatar: a mirrored dither face drawn from a name, with a group that overlaps and counts the rest.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available by appending `.md` to any URL or sending an `Accept: text/markdown` header. The dithercn agent skill, for building any dither on the engine, is at [/.well-known/agent-skills/dithercn/SKILL.md](/.well-known/agent-skills/dithercn/SKILL.md).

<ComponentPreview src="examples/avatar-demo.tsx" size="md" controls="avatarControls">
  <AvatarDemo />
</ComponentPreview>

## Installation [#installation]

<InstallBlock name="avatar" />

## Usage [#usage]

```tsx
import { Avatar, AvatarGroup } from "@/components/dithercn/avatar";

export function Owner() {
  return <Avatar name="ada@acme.dev" label="Ada Lovelace" status="online" />;
}

export function Viewers({ names }: { names: string[] }) {
  return (
    <AvatarGroup max={4}>
      {names.map((name) => (
        <Avatar key={name} name={name} />
      ))}
    </AvatarGroup>
  );
}
```

`name` seeds a small random generator that fills half of a 5 by 5 grid of blocks, and the other half mirrors it. A block is more likely to be on near the centre, so every face is a compact mark rather than noise, and the middle column always has at least two blocks. Each block is full or half tone, and the fill decides how half tone is drawn. Behind the face sits a disc of sparse dither in the same colour, densest at the top left as if lit, and kept one cell clear of the face so the mark stays crisp. The same string always gives the same face and colour, on the server and in the browser, so you can use an email or a user id and get a stable avatar for free.

Without `color`, the avatar picks one of six palette hues from the string. Pass a palette name or any CSS colour to set it yourself.

## Examples [#examples]

### Group with a count [#group-with-a-count]

`AvatarGroup` overlaps its avatars, cuts a gap around each in the surface colour, and replaces the rest with a "+N" chip. Set `outline` to the colour behind the group so the gaps disappear into it.

<ComponentPreview src="examples/avatar-group.tsx" size="md">
  <AvatarGroupExample />
</ComponentPreview>

### Members with presence [#members-with-presence]

A member list seeded by email, labelled by name. `status` adds a dot and appends the state to the accessible name, as in "Alan Turing, busy". The owner gets a `ring`; the bot gets a grey hatched face.

<ComponentPreview src="examples/avatar-members.tsx" size="md">
  <AvatarMembers />
</ComponentPreview>

### Fills [#fills]

The same six names in every fill. Gradient draws half tone as a Bayer checker; dotted and hatched texture it instead; solid uses a lighter opacity. Full blocks are solid in every fill.

<ComponentPreview src="examples/avatar-fills.tsx" size="md">
  <AvatarFills />
</ComponentPreview>

## Props [#props]

### Avatar [#avatar]

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `name` (required) | `string` |  | The string the face and colour come from, such as a name, email or id. Also the accessible name. |
| `label` | `string` |  | Accessible name to use instead of name, when name is an id. |
| `size` | `number` | `40` | Diameter in pixels. Inside a group, the group's size. |
| `color` | `DitherColor` |  | A palette name or any CSS colour. Without it, one of six hues picked from name. |
| `fill` | `"gradient" \| "dotted" \| "hatched" \| "solid"` | `"gradient"` | How each block's tone is drawn. |
| `shape` | `"circle" \| "square"` | `"circle"` | A circle or a rounded square. |
| `ring` | `boolean` | `false` | A ring in the avatar's colour, for the current user or a selection. |
| `status` | `"online" \| "away" \| "busy" \| "offline"` |  | A presence dot in the corner, added to the accessible name. |
| `bloom` | `"off" \| "low" \| "high"` | `"off"` | A soft glow in the avatar's colour. |

### AvatarGroup [#avatargroup]

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `max` | `number` |  | Show at most this many avatars, then a +N chip. |
| `size` | `number` | `32` | Diameter of every avatar in pixels. |
| `outline` | `string` | `"var(--background)"` | Colour of the gap around each avatar. Match the surface behind the group. |
| `moreLabel` | `(count: number) => string` | `"N more"` | What the +N chip announces to screen readers. |

`avatarFace(name)` and `avatarColor(name)` are exported too, if you want the same face elsewhere, such as an Open Graph image.

## Notes [#notes]

* The avatar is a `role="img"` element named by `label` or `name`, plus the status when there is one. The group is a `role="group"`; give it an `aria-label` such as "Viewers" when the context does not say.
* The face is one or a few SVG paths, cached per name and fill. No canvas, no client JavaScript.
* Avatars in a group lift by 2 pixels on hover on devices that can hover. With reduced motion they stay put.