MIT · zero dependencies · runs offline
Deterministic avatars from anything.
Give Avaroid a string. Get a unique avatar. Give it the same string tomorrow and get the exact same one.
npm install avaroid
- normalized
- hash
- variant
- bot
- output
- network
- 0 requests
02 — Playground
Try any seed.
Every control maps 1:1 to an option. What you see here is what
avatar() returns.
- seed
- hash
- size
- format
- bytes
03 — Determinism
Same seed. Same avatar. Always.
| input | normalized | avatar | vs. run 1 |
|---|
Strings are trimmed, lowercased and Unicode-normalized before hashing, so cosmetic differences don't fork an identity. One character of real difference does.
different seeds → different avatars
04 — Quick start
One function. That's the API.
Import avatar, pass a seed, get an SVG string back.
Synchronous, pure, no setup. Prefer components? Each framework gets a native one.
index.tsimport { avatar } from 'avaroid'
const svg: string = avatar('david@example.com')
// options are optional
avatar('david@example.com', {
size: 128,
background: 'auto',
radius: 24,
})
index.jsimport { avatar } from 'avaroid'
const el = document.querySelector('#me')
el.innerHTML = avatar(user.email, { size: 128 })
// or as an <img> source
img.src = avatar(user.id, {
radius: 24,
format: 'data-url',
})
UserChip.tsximport { Avatar } from 'avaroid/react'
export function UserChip({ user }) {
return (
<Avatar
seed={user.email}
size={128}
radius={24}
alt={user.name}
/>
)
}
UserChip.vue<script setup lang="ts">
import { Avatar } from 'avaroid/vue'
defineProps<{ email: string }>()
</script>
<template>
<Avatar :seed="email" :size="128" :radius="24" />
</template>
UserChip.svelte<script lang="ts">
import { Avatar } from 'avaroid/svelte'
let { email }: { email: string } = $props()
</script>
<Avatar seed={email} size={128} radius={24} />
user-chip.component.tsimport { Component, input } from '@angular/core'
import { AvatarComponent } from 'avaroid/angular'
@Component({
selector: 'app-user-chip',
imports: [AvatarComponent],
template: `<avaroid-avatar [seed]="email()" [size]="128" [radius]="24" />`,
})
export class UserChip {
readonly email = input.required<string>()
}
05 — Properties
Small on purpose.
Avaroid does one thing. Everything it doesn't do is a dependency, a request, or a database you don't have to think about.
-
01
f(x) = f(x)
Deterministic
The same seed always generates the same avatar — across machines, runtimes and releases.
-
02
offline
Zero network calls
Avatars are generated locally. No CDN, no API key, no trackers in your UI.
-
03
0 deps
Tiny
No dependencies and side-effect free, so bundlers keep only what you import.
-
04
64-unit → ∞
SVG-first
Smooth curves on a seed-derived dark field, drawn on a 64-unit canvas and rendered with geometricPrecision. One asset scales from a favicon to a profile photo.
-
05
esm · types
Framework agnostic
Works anywhere JavaScript runs — browser, Node, Bun, Deno, workers. React, Vue, Svelte and Angular components included.
-
06
6 options
Customizable
Control design, variant, size, background and shape. Six options, sensible defaults, nothing else.
06 — Examples
One system. Endless faces.
07 — How it works
Input to avatar, in four steps.
Avaroid converts your input into a stable seed and uses it to drive the avatar generator. No database or stored identity mapping required.
- 01 input string or image bytes
- 02 normalize trim · lowercase · NFC
- 03 hash fast, non-cryptographic
- 04 seeded generator PRNG picks every trait
-
→ output
avatar(seed, options?) → string
Parameters
| name | type | description |
|---|---|---|
| seed | string | ArrayBuffer | Uint8Array | Any identity. Strings are normalized; bytes are hashed as-is — pass await file.arrayBuffer(). |
| options | AvatarOptions | Optional. Every field has a default. |
AvatarOptions
| option | type | default | description |
|---|---|---|---|
| design | 'modern' | 'classic' | 'modern' | Rendering style. classic keeps the original 16-unit pixel look. |
| variant | 'bot' | 'grid' | 'glyph' | 'bot' | Generator family. Same seed, different family, different look. |
| size | number | 64 | Width and height in px. The art is drawn once on a 64-unit canvas, so every size renders smooth. |
| background | 'auto' | 'transparent' | string | 'auto' | Seed-derived color, none, or any CSS color. |
| radius | number | 0 | Corner radius in px. Use size / 2 for a circle. |
| format | 'svg' | 'data-url' | 'svg' | Raw SVG markup, or a data URL ready for img.src. |
Returns
string — SVG markup, or a data URL when format: 'data-url'.
Errors
TypeError for a value of the wrong type, RangeError for an out-of-range or unknown option.
Components
<Avatar seed … /> from /react,
/vue and /svelte, and
<avaroid-avatar> from /angular
take the same options plus alt, and render an <img>.