@stricahq/cardano-identicon
v1.0.0
Published
Deterministic SVG identicons for Cardano addresses, stake addresses, stake pools and DReps
Downloads
144
Maintainers
Readme
@stricahq/cardano-identicon
Deterministic SVG identicons for Cardano addresses, stake addresses, stake pools and DReps. No runtime dependencies, and the same code runs in Node and the browser. Light and dark palettes are built in, along with an auto theme that follows the viewer's prefers-color-scheme.
Each icon is a tile of concentric arcs. The arc angles, the colours, the number of rings — all of it is derived from the input's bytes, so a given address always draws the same picture. The entity kind shows up as a small white glyph on the centre medallion:
| Kind | Glyph | Detected from |
| --------- | -------- | --------------------- |
| address | hexagon | addr, addr_test |
| stake | diamond | stake, stake_test |
| pool | ring | pool |
| drep | triangle | drep |
Those are the bech32 prefixes from CIP-5 / CIP-129. Anything without a recognisable kind just gets a plain dot in the middle.
Install
npm install @stricahq/cardano-identiconUsage
import { identicon, identiconDataUri } from "@stricahq/cardano-identicon";
// Pass a bech32 string and the kind is read off the prefix.
const svg = identicon(
"addr1qxqm3nxwzf70ke9jqa2zrtrevjznpv6yykptxnv34perjc8a7zgxmpv5pgk4hhhe0m9kfnlsf5pt7d2ahkxaul2zygrq3nura9",
);
// Hex or raw bytes carry no prefix, so name the kind yourself to get the glyph.
const svg2 = identicon(
"0181b8ccce127cfb64b2075421ac79648530b3442582b34d91a8723960fdf0906d85940a2d5bdef97ecb64cff04d02bf355dbd8dde7d422206",
{ type: "address" },
);
const svg3 = identicon(poolIdBytes, { type: "pool" }); // Buffer or Uint8Array both work
// Options can be mixed and matched:
identicon("pool...", { size: 128 }); // pixel size, default 64
identicon("addr...", { theme: "dark" }); // same hues, dark ground
identicon("addr...", { theme: "auto" }); // follows prefers-color-scheme
identicon("drep...", { borderRadius: 50 }); // 0 = square tile, 50 = circle
// Or grab a data URI for an <img src> or a CSS background.
const uri = identiconDataUri("stake...", { size: 64 });You get back a plain SVG string, so it's up to you where it goes: drop it into innerHTML, write it to a file, or wrap it in a data URI. bech32 and hex are decoded to their raw bytes before anything is drawn, which means both encodings of the same entity land on the same icon. The bech32 checksum isn't verified — drawing an identicon isn't the same as validating an address — and anything that's neither hex nor bech32 is hashed straight from its UTF-8 bytes.
In the browser
No build step required. Pull it from a CDN and set the SVG on an element:
<div id="avatar"></div>
<script type="module">
import { identicon } from "https://esm.sh/@stricahq/cardano-identicon";
document.getElementById("avatar").innerHTML = identicon("addr...", {
size: 96,
});
</script>API
identicon(input, options?): string
Returns a full SVG document as a string. It uses a 100×100 viewBox and rounds its own corners, so it scales to any size cleanly.
input—string | Uint8Array. bech32 (case-insensitive) and hex (with or without a0x) are decoded to bytes; everything else is read as UTF-8. ABufferworks anywhere aUint8Arraydoes.options.size— width and height in px. Default64.options.type—"address" | "stake" | "pool" | "drep". Sets the core glyph and overrides prefix detection. You'll want this for hex and byte inputs, since they don't carry a prefix.options.borderRadius— corner rounding as a percentage of the width.0is a square,50is a circle, and values outside0–50are clamped. Default18.options.theme—"light"(default),"dark", or"auto". A theme only fixes saturation and lightness; the hue always comes from the seed, so an entity keeps its colour across light and dark."auto"embeds both palettes and switches on the viewer'sprefers-color-scheme, which browsers honour even through<img>and data URIs. Its CSS classes are scoped per seed, so you can inline plenty of them on one page without collisions.
identiconDataUri(input, options?): string
The same SVG, encoded as a data:image/svg+xml URI.
One caveat worth stating plainly: an identicon is a visual aid, not a security check. The hash behind it is 32-bit and not cryptographic, so don't rely on it to tell two addresses apart.
Performance
No canvas, no rasterization — it just decodes the input, hashes it, and builds an SVG string. That's all synchronous, so you can generate icons on the fly instead of caching them.
We ran it over 5,000 different bech32 inputs (a mix of addresses, stake addresses, pools and DReps) and timed the full identicon() call:
| Call | Throughput | Per icon |
| -------------------------- | -------------- | -------- |
| identicon (light / dark) | ~137,000 / sec | ~7 µs |
| identicon (auto theme) | ~94,000 / sec | ~11 µs |
| identiconDataUri (light) | ~92,000 / sec | ~11 µs |
That's on an Apple M1 Pro (16 GB) running Node v24.13.0, single-threaded. auto is a bit slower since it has to emit both palettes and a small stylesheet. Different hardware will give different numbers, but it works out to roughly 100k icons a second from a single core.
Development
npm install
npm run typecheck
npm run build # ESM + CJS + .d.ts into dist/License
Licensed under the Apache License, Version 2.0.
Copyright 2026 Strica
