Deterministic PNG avatars for your projects. Pick a seed, get an avatar — no API, no server, no network required.
Inspired by DiceBear, but uses hand-crafted PNG illustrations instead of generated SVGs.
npm install quick-avatarimport { createAvatar, doteye } from 'quick-avatar';
const avatar = createAvatar(doteye, { seed: 'user@example.com' });
// Async: lazy-loads only the matching image chunk (~50 KB)
const src = await avatar.toDataUri();
// → "data:image/png;base64,..."Same seed always returns the same avatar.
import { useEffect, useState } from 'react';
import { createAvatar, doteye } from 'quick-avatar';
function Avatar({ userId }: { userId: string }) {
const [src, setSrc] = useState('');
useEffect(() => {
createAvatar(doteye, { seed: userId }).toDataUri().then(setSrc);
}, [userId]);
return <img src={src} width={64} height={64} alt="avatar" />;
}Skip bundling entirely — link directly to the image file via jsDelivr:
const avatar = createAvatar(doteye, { seed: 'user@example.com' });
// Default: jsDelivr pointing to the published npm package
avatar.toUrl();
// → "https://cdn.jsdelivr.net/npm/quick-avatar/dist/sets/doteye/images/39.png"
// Custom CDN or self-hosted
avatar.toUrl('https://assets.example.com');
// → "https://assets.example.com/dist/sets/doteye/images/39.png"<img src={createAvatar(doteye, { seed: userId }).toUrl()} alt="avatar" />import { createAvatar, doteye } from 'quick-avatar';
const avatar = createAvatar(doteye, { seed: 'user@example.com' });
// Read as Buffer (e.g. for HTTP response or sharp processing)
const buffer = avatar.toBuffer();
res.setHeader('Content-Type', 'image/png');
res.end(buffer);
// Or get the absolute file path
const filePath = avatar.toFilePath();
// → "/path/to/node_modules/quick-avatar/dist/sets/doteye/images/39.png"| Parameter | Type | Description |
|---|---|---|
collection |
AvatarCollection |
An imported style set, e.g. doteye |
options.seed |
string |
Any string — user ID, email, username, etc. |
options.cdnBase |
string (optional) |
Default CDN base URL used by toUrl() |
Returns an AvatarResult:
| Method / Property | Returns | Notes |
|---|---|---|
toDataUri() |
Promise<string> |
Lazy-loads the image as a base64 data URI |
toUrl(cdnBase?) |
string |
CDN URL, synchronous, zero bundle cost |
toBuffer() |
Buffer |
Node.js only — reads the PNG file synchronously |
toFilePath() |
string |
Node.js only — absolute path to the PNG file |
index |
number |
Which avatar was selected (0-based) |
set |
string |
Name of the collection, e.g. "doteye" |
| Import | Name | Count | Background |
|---|---|---|---|
doteye |
Doteye | 64 | White |
doteyeAlpha |
Doteye Alpha | 64 | Transparent |
doteyePaper |
Doteye Paper | 64 | Transparent (B&W) |
ol |
OL | 72 | White |
import { createAvatar, doteye, doteyeAlpha, doteyePaper, ol } from 'quick-avatar';
// Solid white background
const avatar = createAvatar(doteye, { seed: 'user@example.com' });
// Transparent background — compose over any color
const avatarAlpha = createAvatar(doteyeAlpha, { seed: 'user@example.com' });
// Black & white, transparent background
const avatarPaper = createAvatar(doteyePaper, { seed: 'user@example.com' });quick-avatar uses code splitting so your bundle only ever includes the image chunks you actually render:
- Core logic (
index.mjs): ~5 KB - Per-image chunk: ~40–100 KB, loaded on demand
- CDN mode: 0 KB — images are fetched at runtime, never bundled
Place your images in avatars/<setName>/. File names can be anything — they will be sorted numerically and assigned 0-based indices.
avatars/
pixel/
pixel-avatar-1.png
pixel-avatar-2.png
...
npm run generate pixel
# or regenerate all sets at once:
npm run generateThis will:
- Convert each PNG to a base64 module in
src/sets/pixel/images/*.ts - Write a
src/sets/pixel/meta.tswith the count and set name - Copy the original PNG files to
dist/sets/pixel/images/for CDN use
Create src/sets/pixel/index.ts:
import { resolve } from 'path';
import { fileURLToPath } from 'url';
import type { AvatarCollection } from '../../core/types.js';
import { count, name } from './meta.js';
const __dirname = fileURLToPath(new URL('.', import.meta.url));
export const pixel: AvatarCollection = {
name,
count,
async getImage(index: number): Promise<string> {
const mod = await import(`./images/${index}.ts`);
return mod.default as string;
},
getFilePath(index: number): string {
return resolve(__dirname, 'sets', name, 'images', `${index}.png`);
},
};Add one line to src/index.ts:
export { createAvatar } from './core/create-avatar.js';
export type { AvatarCollection, AvatarOptions, AvatarResult } from './core/types.js';
export { doteye } from './sets/doteye/index.js';
export { pixel } from './sets/pixel/index.js'; // ← add thisnpm run buildUsers can now import the new set:
import { createAvatar, pixel } from 'quick-avatar';# Install dependencies
npm install
# Regenerate all sets from source PNGs
npm run generate
# Build (clean → generate → compile)
npm run buildMIT