Kaspicondeterministic pixel identicons
v1.1.0
SHA-256 keystream · zero dependencies · reproducible forever

One address.
One face. Forever.

Kaspicon hashes any string — a Kaspa wallet address, a handle, a whispered secret — into a unique pixel avatar as a portable, self-contained SVG. Same input ⇒ same pixels, on any machine, in any browser, in any year. Determinism isn't a feature here; it's the whole contract.

Bech32 is case-insensitive — so KASPA:QY… and kaspa:qy… paint the exact same face. Any other string is hashed byte-for-byte, case and all.
seed · sha-256
svg source

The determinism contract

Kaspicon is a pure function of (input, options). To prove it, we render your current input three independent times and compare the SVG byte streams:

render #1
=
render #2
=
render #3
  • No randomnessMath.random never touches a pixel. There is no nonce, no salt, no luck.
  • No environmentNo clock, no network, no locale, no stored state. Pure IEEE-754 arithmetic.
  • Standard hashIdentity = SHA-256 of the normalized input. Nothing proprietary to drift.
  • Fixed consumptionThe keystream bytes are consumed in a documented, versioned order.
  • Self-contained SVGNo scripts, fonts, or external refs — it renders identically everywhere.
  • VersionedKaspicon.VERSION is embedded in every file's <desc> tag.

Built for real list sizes

The big preview above is the best case. Wallets and explorers actually render avatars small — 24–32px, inline in a transaction or address list. Here's the same 14 addresses at that size, once with the default kaspa palette and once with spectrum — same grid: 7, halo and backplate off (the { preset: "list" } bundle), palette is the only thing that changes.

palette: kaspa (default)narrow hue range

palette: spectrumrecommended for lists

Use it anywhere

// 1 · render an avatar (returns an SVG string)
const svg = Kaspicon.svg("kaspa:qpauqsvk7yf9unex…");

// 2 · drop it straight into an <img>
img.src = Kaspicon.toDataURL(addr, { palette: "spectrum" });

// 3 · every knob is part of the deterministic input
Kaspicon.svg(addr, {
  grid: 9,           // 7 · 9 · 11
  shape: "auto",     // auto · square · round · circle · diamond
  palette: "kaspa",  // kaspa · spectrum · ember · mono
  halo: true,        // 32-bit hash-trace ring
  background: true   // rounded backplate
});

// small inline avatar (list rows, 20-32px)? use the preset:
Kaspicon.svg(addr, { preset: "list" });
// same as: { grid: 7, palette: "spectrum", halo: false, background: false }

// extras
Kaspicon.seed(addr)     // → 256-bit fingerprint hex
Kaspicon.epithet(addr)  // → deterministic creature name
Kaspicon.element(addr)  // → live SVG DOM node
optionvalueseffect
grid7 · 9 · 11mirrored pixel matrix resolution — use 7 for ≤32px, 9 for 48–96px, 11 for ≥96px
shapeauto · square · round · circle · diamondpixel glyph (auto is hash-chosen)
palettekaspa · spectrum · ember · monohue family — spectrum for lists, kaspa for single large-format use
halotrue · false32-bit fingerprint trace around the grid
backgroundtrue · falserounded backplate & inner rim
preset"list"tuned bundle for small inline avatars; explicit options still override it

How a face is born

  1. Normalize. Trim whitespace. Inputs starting with kaspa: are case-folded (bech32 rule); everything else stays byte-exact.
  2. Seed. seed = SHA-256(utf8(input)) — your 256-bit identity.
  3. Expand. A keystream of blocks: SHA-256(seed ‖ counter), counter = 0, 1, 2…
  4. Paint. Hue, pixel shape, occupancy, growth, the eye glint, accent sprinkles and the 32-bit halo — each reads the next stream bytes in a fixed, documented order.
  5. Emit. A compact plain SVG. Mirror-symmetric grid, hash-trace halo, deterministic epithet. Done — forever.
The hash-trace halo is not decoration: its 32 little pads literally encode the first 32 bits of the address's SHA-256 seed. Two avatars with identical halos share a fingerprint prefix.