Deterministic pixel art avatars from any string.
~2.9 million unique characters. Zero dependencies. 4 KB gzipped.
Install · Quick Start · React · Next.js · Headless · API · Demo
Pass any string — an email, username, wallet address — and get back a cute, deterministic blob character. Same input always produces the same lil guy.
Works everywhere: React component with 3D hover + blink animation, headless SVG/PNG generation, Next.js image API route, or plain <script> tag.
npm install lil_guyimport { LilGuy } from "lil_guy";
function UserAvatar({ email }: { email: string }) {
return <LilGuy name={email} size={48} />;
}import { toSvgString } from "lil_guy";
const svg = toSvgString("alice@example.com");
// → complete SVG string, use anywhere<script src="https://unpkg.com/lil_guy/dist/lil-guy.js"></script>
<script>
const svg = LilGuy.toSvgString("alice@example.com");
document.getElementById("avatar").textContent = svg;
</script>The <LilGuy> component renders an interactive pixel art avatar with 3D tilt and blink animation.
<LilGuy
name="alice@example.com"
size={64}
shape="circle" // "circle" | "square"
variant="gradient" // "gradient" | "solid" | "transparent"
interactive // 3D hover effect (default: true)
enableBlink // blink animation
intensity3d="dramatic" // "none" | "subtle" | "medium" | "dramatic"
/>Override individual features while keeping the rest deterministic:
<LilGuy name="alice" parts={{ hair: 2, eyes: 0 }} />import { Avatar, AvatarImage, AvatarFallback } from "lil_guy";
<Avatar>
<AvatarImage src="/photos/alice.jpg" alt="Alice" />
<AvatarFallback name="alice@example.com" size={48} />
</Avatar>Two-line API route that serves avatar PNGs. Caches forever since the output is deterministic.
// app/api/avatar/route.ts
import { toLilGuyHandler } from "lil_guy/next";
export const { GET } = toLilGuyHandler();Then use it anywhere:
<img src="/api/avatar?name=alice@example.com&size=128" />Generate SVG strings or PNG data URLs without React or a DOM.
import { toSvgString, toPng } from "lil_guy";
// SVG string — works in Node, Deno, Bun, browsers
const svg = toSvgString("alice", { size: 256 });
// PNG data URL — browser only (needs canvas)
const png = await toPng("alice", { size: 256 });For full control, use the pipeline directly:
import { hash, resolve, compose, getPalette, resolveColor } from "lil_guy";
const config = resolve("alice"); // → { head: 3, eyes: 1, mouth: 2, ... }
const grid = compose(config); // → 16×16 number[][] of color tokens
const palette = getPalette(config.palette);
const color = resolveColor(palette, grid[8][8]); // → "#FFB347"| Prop | Type | Default | Description |
|---|---|---|---|
name |
string |
— | Input string to generate avatar from |
size |
number | string |
40 |
Size in px or CSS units |
shape |
"circle" | "square" |
"circle" |
Avatar shape |
variant |
"gradient" | "solid" | "transparent" |
"transparent" |
Background style |
interactive |
boolean |
true |
Enable 3D hover effect |
enableBlink |
boolean |
false |
Enable blink animation |
intensity3d |
"none" | "subtle" | "medium" | "dramatic" |
"dramatic" |
3D rotation intensity |
parts |
object |
— | Pin specific features by index |
palette |
Palette |
— | Override color palette |
showInitial |
boolean |
false |
Show first letter overlay |
Returns a complete SVG string. No DOM or React needed.
Returns a PNG data URL. Browser only.
Creates a Next.js route handler. Returns { GET }.
- Hash — FNV-1a hash of the input string, with independent per-slot hashing for each feature
- Resolve — Hash selects head shape, eyes, mouth, hair, body pattern, accessory, palette, and rotation from the part library
- Compose — Layers parts onto a 16×16 grid using a token system (body, feature, pattern, accent, eyes, mouth)
- Render — Tokens map to palette colors and render as SVG rects
8 heads × 8 eyes × 5 mouths × 8 hair × 8 bodies × 6 accessories × 12 palettes = ~2.9 million unique characters.
MIT