npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cast-avatar

v1.9.0

Published

Dependency-free deterministic SVG avatar generator for browsers.

Readme

Cast Avatar

npm version tests license

Live demo → — try every style and trait in the browser.

Cast Avatar is a tiny, dependency-free JavaScript library for creating deterministic SVG avatars without network access. It is inspired by DiceBear and similar avatar systems that turn a stable seed into repeatable faces, initials, or geometric shapes.

Goals

  • Offline-first: no remote images, fonts, APIs, or package dependencies are required.
  • Deterministic: the same seed and options always generate the same SVG.
  • Persistable: avatarHash() creates a compact lookup key, while encodeAvatar() stores the exact resolved avatar configuration.
  • Framework-free: use it with plain HTML, CSS, and JavaScript.
  • Inclusive traits: apps can choose or auto-generate skin tone, face shape, hair, eyebrows, eye shape, nose, mouth, gender presentation, facial hair, freckles, blush, headwear, earrings, accessories, and clothing color.

Install

npm install cast-avatar
import { createAvatar } from 'cast-avatar';

const svg = createAvatar('[email protected]', { style: 'face' });

The package ships as ES module source with no build step, and includes TypeScript declarations (avatar.d.ts) so every option and trait is typed.

Use from a CDN

No build or install needed — cast-avatar is served from npm CDNs. Use jsDelivr's auto-bundled, minified single file:

<script type="module">
  import { createAvatar } from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';
  document.body.innerHTML = createAvatar('[email protected]', { style: 'face' });
</script>

Or import the raw ES module source (also works on unpkg):

<script type="module">
  import { createAvatar } from 'https://cdn.jsdelivr.net/npm/[email protected]/src/avatar.js';
</script>

The <cast-avatar> element works the same way — importing it registers the tag:

<script type="module">
  import 'https://cdn.jsdelivr.net/npm/[email protected]/element/+esm';
</script>
<cast-avatar seed="[email protected]" variant="face" size="96"></cast-avatar>

Pin the version (@0.1.0) in production: an unpinned URL serves the latest release, which can change an existing seed's avatar — see Stability and versioning.

Quick start

The snippets below import from ./src/avatar.js so they run directly from a clone (open index.html with no build); when installed from npm, import from cast-avatar instead.

<div id="avatar"></div>
<script type="module">
  import { avatarHash, encodeAvatar, mountAvatar } from './src/avatar.js';

  const options = {
    seed: '[email protected]',
    style: 'face',
    traits: {
      gender: 'feminine',
      skinTone: 'medium',
      hairStyle: 'curly',
      hairColor: 'black',
      eyes: 'round',
      accessories: 'glasses'
    }
  };

  mountAvatar('#avatar', options);
  console.log(avatarHash(options));
  console.log(encodeAvatar(options));
</script>

API

createAvatar(options) or createAvatar(seed, options)

Returns an SVG string. Use either an options object or a seed with options as the second argument.

import { createAvatar } from './src/avatar.js';

const svg = createAvatar('user-123', { style: 'shapes', size: 96 });

mountAvatar(target, options) or mountAvatar(target, seed, options)

Renders the SVG into a DOM element or selector and returns the generated SVG string.

mountAvatar(document.querySelector('[data-avatar]'), 'Lin Chen', { style: 'face' });

avatarHash(options)

Returns a deterministic base-36 hash for a resolved avatar configuration. Use this as a compact lookup key when you also store the seed/options somewhere else.

const hash = avatarHash({ seed: 'user-123', traits: { skinTone: 'dark', hairStyle: 'coily' } });

encodeAvatar(options) and decodeAvatar(encoded)

Use these helpers when your app needs to persist the exact avatar that was generated, including all auto choices after they resolve.

const encoded = encodeAvatar({ seed: 'user-123', traits: { skinTone: 'dark' } });
const config = decodeAvatar(encoded);
const svg = createAvatar(config);

Encoded strings include a version prefix and an integrity hash so tampered payloads are rejected.

toDataUri(svg) and createAvatarDataUri(options)

Use these helpers for img tags.

const uri = createAvatarDataUri({ seed: 'user-123' });
document.querySelector('img').src = uri;

createAvatarElement(options)

Creates a browser SVGElement without mounting it.

const element = createAvatarElement({ seed: 'user-123' });
document.body.append(element);

resolveAvatarOptions(options)

Returns the deterministic, fully-resolved option set used by the renderer. This is useful for debugging or storing the final values that auto produced.

avatarOptions

The exported table of every allowed value for each style and trait — the canonical source for building pickers or validating input.

import { avatarOptions } from 'cast-avatar';

avatarOptions.style;     // ['portrait', 'cartoon', 'minimal', 'line', ...]
avatarOptions.hairStyle; // ['none', 'stubble', 'short', 'long', ...]

createAvatars(items, sharedOptions) and createAvatarSprite(items, options)

Render a roster in one call. createAvatars returns an array of SVG strings; createAvatarSprite packs them into a single SVG grid (handy for previewing a fleet of agents). Each item is a seed or an options object.

import { createAvatars, createAvatarSprite } from 'cast-avatar';

const avatars = createAvatars(['agent-1', 'agent-2'], { style: 'line' });
const sheet = createAvatarSprite(agentIds, { columns: 8, cell: 64, style: 'bot' });

createAvatarGroup(seeds, options) and mergeSeeds(...seeds)

createAvatarGroup composes several member seeds into one cohesive mark — a clipped mosaic (1–4 tiles), with extra members collapsing into a +N chip. Great for a team channel, an agent squad, or a group DM icon. mergeSeeds combines seeds into a single deterministic, order-independent seed for a stable "pair"/relationship avatar.

import { createAvatarGroup, mergeSeeds, createAvatar } from 'cast-avatar';

const team = createAvatarGroup(['ada', 'grace', 'lin', 'noor', 'kai'], { style: 'portrait' });
// '+1' chip for the 5th member; pass { max: 4 } to tune the cap.

// Members can also be objects with per-member overrides:
const squad = createAvatarGroup([
  'ada',
  { seed: 'grace', style: 'bot' },
  { seed: 'lin', traits: { skinTone: 'dark' } },
], { style: 'portrait' });

const pair = createAvatar(mergeSeeds('alice', 'bob')); // same avatar regardless of order

Custom palettes

Pass a palette to theme avatars to your own colors. Tone maps (skinTones/hairColors) merge over the defaults; color lists (backgrounds, shapeColors, clothingColors, inks) replace them. The result stays fully deterministic, and the palette is preserved through encodeAvatar/decodeAvatar.

const brand = {
  backgrounds: ['#0f172a', '#1e293b'],
  shapeColors: ['#22d3ee', '#a78bfa', '#f472b6'],
  clothingColors: ['#0ea5e9', '#6366f1'],
};

createAvatar('agent-7', { style: 'shapes', palette: brand });

For a built-in colorblind-safe option, pass the preset name instead of an object. It uses the Okabe–Ito palette (distinguishable across common color-vision deficiencies) for the abstract styles, clothing, and inks, while leaving skin and hair tones natural:

createAvatar('agent-7', { style: 'shapes', palette: 'accessible' });

The preset is also exported (COLORBLIND_SAFE_PALETTE, PALETTE_PRESETS) if you want to extend or compose it, and resolvePalette(override) resolves an object or preset name into a full color set.

Accessibility

Every avatar renders as an accessible image: role="img" with an aria-label and a native <title> (defaulting to `${seed} avatar`). Set a meaningful title when the seed isn't human-friendly:

createAvatar('u_8f3a1', { title: 'Ada Lovelace' });

When an avatar sits next to text that already names the person, mark it decorative so assistive tech skips it (it renders aria-hidden="true" with no role, label, or title):

createAvatar('u_8f3a1', { decorative: true });

For color-vision accessibility, use palette: 'accessible' (see Custom palettes). The status badge otherwise conveys state through color and corner position alone — add status: { state, icon: true } for a shape glyph so it's distinguishable without color, and pair it with visible text where presence is important.

Expressions

expression is a shorthand that presets the expressive traits (eyes + mouth + eyebrows) while leaving identity traits seed-derived — so the same avatar can change mood without becoming a different person. It's ideal for reflecting user or agent state (idle, thinking, done, error). Explicit traits still take precedence over an expression, and it applies to the face styles (portrait, studio, cartoon, minimal, line).

createAvatar('agent-7', { expression: 'thinking' });  // same agent, pensive
createAvatar('agent-7', { expression: 'happy' });      // same agent, pleased
// per-trait overrides still win:
createAvatar('agent-7', { expression: 'happy', traits: { eyes: 'wink' } });

Values: neutral, happy, sad, surprised, thinking, wink.

Web component

A zero-dependency <cast-avatar> custom element is available from the cast-avatar/element entry point. Importing the module registers the element.

<script type="module">
  import 'cast-avatar/element';
</script>

<cast-avatar seed="[email protected]" variant="face" size="96"></cast-avatar>

Attributes: seed, variant (the style name — style is reserved by HTML), size, background, and animate. The element re-renders when any of these change. For full trait control, render with the JavaScript API instead.

Talking avatars

An avatar rendered with animate: 'talk' (face styles portrait, studio, cartoon) can speak text aloud with its mouth moving in time, via the browser's native speech engine — no dependency. Import the opt-in cast-avatar/speak helper:

import { createAvatar } from 'cast-avatar';
import { speak } from 'cast-avatar/speak';

document.body.innerHTML = createAvatar('ada', { style: 'studio', animate: 'talk' });
const avatar = document.body.querySelector('svg');

await speak(avatar, 'Hello, I am Ada.', { rate: 1.1 });

speak(target, text, opts?) accepts the avatar <svg>, a <cast-avatar>, or any container of one. It returns a Promise that resolves when speech ends. opts (voice, rate, pitch, volume, lang) pass through to the utterance. stopSpeaking(target?) cancels and rests the mouth.

The <cast-avatar> element exposes the same thing as a method:

<cast-avatar seed="ada" variant="studio" animate="talk"></cast-avatar>
<script type="module">
  import 'cast-avatar/element';
  document.querySelector('cast-avatar').speak('Hi there!');
</script>

Notes: requires animate: 'talk' (that's what emits the mouth rig). Respects prefers-reduced-motion — it still speaks, but skips mouth motion. Importing the module is SSR-safe; with no speech engine speak() resolves as a no-op. Speech support and available voices vary by browser/OS.

Options

| Option | Values | | --- | --- | | seed | Any stable string, such as a user ID, email, or username. name and id are accepted as aliases. | | style | portrait (default), studio, cartoon, minimal, line, pixel, initials, bot, shapes, mesh; or auto for a seed-random style. face is a legacy alias for cartoon. | | expression | neutral, happy, sad, surprised, thinking, wink — presets the expressive traits while keeping identity stable. See Expressions. | | size | Pixel size from 24 to 1024; defaults to 128. | | background | Any CSS color, transparent, a seeded gradient, a seeded pattern (dots, rings, grid), or auto. | | radius | SVG corner radius — a number (px) or CSS length; defaults to 50% (circle). | | title | Accessible label (and <title> tooltip) for the SVG; defaults to "<seed> avatar". | | decorative | When true, hide the SVG from assistive tech (aria-hidden, no role/label/title). Defaults to false. See Accessibility. | | initials | Optional text override for the initials style. | | status | Presence badge. A state string (online/busy/away/offline) for a corner dot, or an object { state, shape: 'dot'\|'ring', position, pulse, icon } for a ring border, custom placement/animation, or a colorblind-safe shape glyph (icon: true). Omitted = none. Applies to every style. | | animate | A subtle looping animation: breathe, bounce, blink (eye-blink), or talk (mouth flap). blink/talk are face styles only. Respects prefers-reduced-motion. Works on every style. | | palette | Override the default color sets (object), or a preset name ('accessible' / 'colorblind-safe') — see Custom palettes. | | fontWeight | Monogram font weight for the initials style (default 800). | | fontFamily | Monogram font family for the initials style. | | traits | Object of per-feature traits; see below. |

For the initials style, set radius: 0 for a square monogram tile or keep the default 50% for a circle, and use fontWeight/fontFamily to restyle the text.

The styles are deterministic from the seed. portrait (the default), studio, cartoon, minimal, line, and pixel use the trait set below — portrait is a refined illustrative face, studio a semi-realistic, sculpted portrait of the same person (a faceShape-driven head, multi-layer skin modelling, a sculpted nose, volumetric lips, and lidded eyes), cartoon a playful one (formerly face), minimal a flat geometric one, and line a monochrome thin-line one. initials renders a monogram, and bot/shapes/mesh derive their colors and composition from the seed alone (mesh is an abstract gradient-blob style).

Not every trait applies to every style: the illustrative faces (portrait, studio, cartoon) honour the full set; minimal and line render a style-appropriate subset (and line, being monochrome, ignores colour traits); and pixel/initials/bot/shapes/mesh derive everything from the seed and ignore face traits. The playground only shows the controls a given style uses.

Trait options

Traits live under the traits key. Every trait also accepts auto (the default), which deterministically chooses a value from the seed. Each trait is drawn from its own seed-derived stream, so setting one trait never changes the auto-generated value of another.

| Trait | Values | | --- | --- | | gender | neutral, feminine, masculine. | | skinTone | light, mediumLight, medium, mediumDark, dark. | | faceShape | round, oval, soft. | | hairStyle | none, stubble, short, long, curly, coily, bun, afro, mohawk, spiky, hijab. | | hairColor | black, brown, blonde, red, gray, white. | | eyebrows | flat, raised, angled. | | eyes | round, smile, sleepy, wink. | | nose | soft, button, wide. | | mouth | smile, neutral, open. | | facialHair | none, stubble, mustache, goatee, beard, fullBeard, sideburns. | | freckles | none, light, heavy. | | blush | none, soft. | | headwear | none, beanie, cap, turban, bucket, hijab. | | earrings | none, studs, hoops. | | accessories | none, glasses, sunglasses. | | clothing | Any CSS color or auto; colors the shoulders/collar in the face styles. The one free-color trait. |

The face style uses every trait. The pixel style derives a comparable character (skin, hair, hat, glasses, beard) from the seed. A hijab hairstyle implies hijab headwear unless you set a different headwear explicitly.

The legacy top-level hair and clothing options are still accepted as aliases for traits.hairStyle and traits.clothing.

The complete, machine-readable list of every allowed value lives in the exported avatarOptions table — see below.

Edge & server rendering

createAvatar — and createAvatars, createAvatarSprite, createAvatarDataUri, avatarHash, encodeAvatar — are pure string functions with no DOM or Node APIs, so they run anywhere: Node, Deno, Bun, Cloudflare Workers, and Vercel / Netlify Edge. And because Cast is dependency-free, there's nothing to bundle.

// Cloudflare Workers / any fetch handler
import { createAvatar } from 'cast-avatar';

export default {
  fetch(request) {
    const seed = new URL(request.url).searchParams.get('seed') || 'cast';
    const svg = createAvatar(seed, { style: 'portrait' });
    return new Response(svg, {
      headers: {
        'content-type': 'image/svg+xml; charset=utf-8',
        'cache-control': 'public, max-age=31536000, immutable',
      },
    });
  },
};

For Open Graph / social images, use the avatar SVG (or its data-URI from createAvatarDataUri) directly as og:image, or rasterize it to PNG at the edge. The output is deterministic, so a CDN can cache it forever.

(createAvatarElement and mountAvatar are the only DOM-bound helpers — not needed for edge/SSR.)

Stability and versioning

Avatars are deterministic: the same seed and options always produce the same SVG for a given version of cast-avatar. Because each trait is drawn from its own seed-derived stream, rendering at any size yields the same character — just scaled.

Across versions, the visual output for a given seed can change — adding a hairstyle, adjusting a palette, or refining how a feature is drawn all shift what auto resolves to or how it is rendered. This project treats a visual change to an existing seed as a breaking change (a major version bump). If you need an avatar to stay identical over time, pick a guarantee level:

| Need | Persist | Render with | | --- | --- | --- | | Stable while you control the version | the seed (e.g. an agent/user id) | createAvatar(seed) — pin the exact version | | Survive library upgrades | encodeAvatar(seed, options) | createAvatar(decodeAvatar(stored)) | | Pixel-locked forever | the rendered SVG string | use it directly |

avatarHash() is a one-way lookup/cache key. It cannot regenerate an avatar and it changes whenever any option (including size or background) changes, so don't use it as your identity anchor — persist the seed (or one of the artifacts above) instead.

Demo

Try the hosted demo at go4cas.github.io/cast, or run it locally: open index.html in a browser (serve it over HTTP so the ES module imports resolve — e.g. npx serve or python3 -m http.server). It needs no build step.

The demo includes:

  • A large live preview with controls for every face trait plus size, background, and clothing.
  • A Randomize button, Copy SVG / Copy data-URI / Download PNG buttons, and a Copy link button.
  • A shareable URL: the current avatar is encoded into the page's URL hash, so any link reproduces the exact avatar.
  • A fixed-seed variation gallery for the face, portrait, minimal, line, initials, shapes, pixel, bot, and mesh styles.

Team Builder

The Team Builder (team.html) turns a pasted list of identifiers — names, emails, or IDs, with optional labels — into a whole set of avatars at once. Style the team, customize individuals (style, expression, status, and full identity traits), reorder or remove tiles, and import a roster from CSV. Export the result as a ZIP of SVGs or PNGs, a sprite sheet, a group mark, a createAvatars snippet, or a shareable link. Like the rest of the demo it's a single static file with no build step.

Development

Run the test suite with:

npm test

Credits

Cast Avatar was inspired by DiceBear — its seed-driven, multi-style approach to avatars shaped this project's design, and the pixel and bot styles in particular take cues from DiceBear's catalog. All of Cast Avatar's artwork is original and procedurally generated; no DiceBear assets are bundled or copied.