smirks
v0.0.2
Published
Deterministic pixel-face avatars for the modern web
Maintainers
Readme
smirks
Deterministic pixel-face avatars for the modern web.
pnpm add smirksimport { Smirk } from 'smirks/react';
<Smirk seed={user.id} />That's it. Same seed → same smirk, forever.
Features
- Deterministic. Same seed produces the exact same SVG bytes on every runtime, every version.
- Tiny. Under 2 KB gzipped. Zero runtime dependencies.
- Themeable. Built-in palettes, custom palettes, fixed colors, or
currentColorfor full Tailwind control. - Accessible. Default and bold palette pairs meet WCAG 2.1 non-text contrast (3:1) and APCA Lc ≥ 50 — accessible for decorative content at small sizes without sacrificing the soft-pastel aesthetic.
- Universal. Works in React, vanilla JS, Node, Bun, Deno, Cloudflare Workers, Vercel Edge — anywhere.
- Type-safe. Strict TypeScript, discriminated unions for color modes, autocomplete on every option.
Usage
React
import { Smirk } from 'smirks/react';
import { palettes } from 'smirks';
// Default palette (soft pastel pairs)
<Smirk seed={user.id} />
// Bold palette (white on saturated)
<Smirk seed={user.id} palette={palettes.bold} />
// Override one color, let the other vary by seed
<Smirk seed={user.id} fg="#ffffff" />
<Smirk seed={user.id} bg="#000000" />
// Fully fixed colors (shape still varies by seed)
<Smirk seed={user.id} fg="#ffffff" bg="#000000" />
// Tailwind-native: currentColor follows your CSS
<Smirk
seed={user.id}
mode="currentColor"
className="text-white bg-black rounded-full"
/>
// Accessible label
<Smirk seed={user.id} title={user.displayName} />
// Sizing is CSS — no size prop
<Smirk seed={user.id} className="w-12 h-12 rounded-full" />Vanilla / SSR / Workers
import { generateSvg } from 'smirks';
const svg = generateSvg('alice'); // string starting with <svg…>
const svg = generateSvg('alice', { palette: MY }); // custom paletteBuilt-in palettes
import { palettes } from 'smirks';
palettes.default; // soft: Tailwind *-600/700 on *-50, 12 pairs
palettes.bold; // white on the soft palette's foregrounds, 12 pairs
palettes.monochrome; // one black-on-white pair (every smirk identical color)
palettes.duotone; // black-on-white + white-on-blackCustom palettes
import type { Palette } from 'smirks';
// Pre-paired combinations (recommended — every pair is hand-curated)
const BRAND: Palette = {
pairs: [
{ fg: '#0066ff', bg: '#f0f7ff' },
{ fg: '#ff3366', bg: '#fff0f3' },
],
};
// Independent fg/bg picks (more variety, less control)
const MIXED: Palette = {
fg: ['#000000', '#1f2937', '#374151'],
bg: ['#ffffff', '#f9fafb', '#f3f4f6'],
};Determinism contract
| Input | Guaranteed |
|--------------------------------------------------|----------------------------------------------------|
| (seed, palette) | identical SVG bytes forever |
| (seed, palette, fg?, bg?) — partial overrides | identical SVG bytes forever; provided colors win |
| (seed) with mode: 'currentColor' | identical color-free SVG bytes; visuals via CSS |
Same seed today, same smirk in 2030. No silent visual drift across versions.
License
MIT
