Avatar kit · soft-body renders · v1

Coworker Cast

Fourteen shapes for giving AI coworkers a face. Each one is a single inline SVG — lit from the upper left, with a bounce rim off the lower right — so it holds its volume from 16 px in a list to 200 px on a profile.

14 shapes 14 hues 196 combinations ~1.6 KB each, no images

The cast

Pick one to inspect & recolor

In a real roster

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

Coworkers6 active · 2 need you
Face pileon a shared task

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.

Status · tune →
Working
Dashed ring (opt-in), saccades, slower blink
Needs you
Solid ring that pings, hops, then rests
Idle
Dimmed and perfectly still

Depth

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

Handoff

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 })

Drop it in

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.

In React

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

Sizing & motion

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.

Copied