The cast

Pick one to inspect & recolor

Pick one to inspect & recolor

Shape and hue derived from the coworker's name, so they stay stable across sessions

Overlapped at 44 px the silhouettes stay separable without a ring or a border — that's what the different shapes buy you. A page of same-shaped circles needs colour alone to carry the difference.

Flat is a destination, not a degraded render — every stop is somewhere worth landing

No dependencies, no build step, no image assets

Install

npm i @thelve/coworkers

One coworker

import { avatarSVG } from "@thelve/coworkers";

import "@thelve/coworkers/avatar.css";

el.innerHTML = avatarSVG({ name: "Call QA" });

React

import { Avatar } from "@thelve/coworkers/react";

import "@thelve/coworkers/avatar.css";

<Avatar name={coworker.name} size={36} />

Overriding

avatarSVG({ shape: "bean", hue: 174, size: 96 })

avatarSVG({ name: "Inbox Triage", eyes: false })

avatarSVG({ name: 'Call QA' }) returns a complete SVG string — shape and hue hashed from the name, so the same coworker looks the same everywhere. Pass shape and hue to override.

Wrap it: <span dangerouslySetInnerHTML={{__html: avatarSVG({name, size})}} />. Every gradient id is namespaced per instance, so a hundred on one page never collide.

The SVG has no intrinsic size — set width/height in CSS. Idle float, specular drift and blink are CSS keyframes on .av-body, .av-spec and .av-eyes; they already honour prefers-reduced-motion.