Free avatar generator
Avatar generator with color you can defend
Free, no signup: paste up to 100 names, addresses or user ids and each line becomes an initials tile or a mirrored identicon, drawn from a 32-bit FNV-1a hash of the normalized string. The twelve background plates are chosen by a walk through LCH that rejects any color landing within ΔE76 12 of another after protanopia, deuteranopia and tritanopia are simulated, and the letters are black or white by measured contrast — 4.58:1 in the worst case, AA everywhere. Every tile downloads as a roughly 400-byte SVG or as a PNG at 32 to 1024 px.
- 100% free
- No signup
- 100 names at once
- 12 CVD-safe plates
- SVG and PNG to 1024px
One per line, up to 100. 10 in the grid.
Press Ctrl+V anywhere on the page to drop in a column of names straight out of a spreadsheet — no need to click the field first.
Picture
Color rules
Export size
10 avatars
Lowest contrast in this set 4.61:1
How far apart the plates stay
6 distinct plates across 15 pairs. Closest pair, as ΔE76: 22.5 in normal vision, 12.4 protanopia, 14.9 deuteranopia, 20.2 tritanopia.
No pair falls under the ΔE 2.3 just-noticeable difference in any of the three dichromacies.
Ada Lovelace
- Hashed key
- ada lovelace
- FNV-1a 32
- 0x9814377e · plate 3 of 12
- Plate
- #00874d
- Ink
- #ffffff · white chosen
- Contrast
- 4.61:1 · AAA at 49px bold
- SVG
- 398 bytes at 128×128
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 100 100" role="img" aria-label="Ada Lovelace"><rect width="100" height="100" rx="50" ry="50" fill="#00874d"/><text x="50" y="50" dy=".35em" text-anchor="middle" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif" font-size="38" font-weight="600" fill="#ffffff">AL</text></svg>
How to generate deterministic avatars
Names in, the same pictures out on every machine that runs the same three steps.
Paste the names exactly as your database holds them
Each line is normalized before it is hashed: NFC first, then trimmed, inner whitespace collapsed to single spaces, then lowercased. That is why “ Ada Lovelace ” and “ada lovelace” land on the same avatar, and why a name typed with a combining acute matches the same name typed with a precomposed é. An address is recognized by its @ and only the local part feeds the initials, so grace.hopper@example.com becomes GH rather than GE. The key that actually got hashed is printed under the selected avatar so you can compare it with what your backend is passing in.
Choose the picture and the color rules
Initials give a name something legible at 32 px; the identicon gives an anonymous id a shape, which is what you want for accounts that have no human name yet. Deep plates take white initials and pale plates take black ones — the choice is aesthetic, because the ink is picked by contrast either way. Raise the floor to 7:1 and the palette drops from 12 plates to 10, since AAA rules out every lightness between L* 37.8 and L* 61.7. Turning the color-vision filter off widens the palette to the full 16 by only spacing hues in normal vision.
Export at the size the service asks for, or take the map
SVG is the file to store when your own front end renders the avatar: it is around 400 bytes for a two-letter tile and scales from a comment row to a profile header without a second export. PNG is what to send anywhere the size is fixed and the renderer is not yours — 80 px is Gravatar's default, 128 px is a Discord upload, 512 px is a Slack workspace icon. The Copy-as-JSON button hands you name, key, hash, background, foreground and contrast for every row at once, which is enough to store a color column instead of recomputing it on every page render.
Technical specifications
| Hash | FNV-1a 32-bit over the UTF-8 bytes of the key, offset basis 0x811c9dc5 and prime 0x01000193. The key is NFC-normalized, trimmed, whitespace-collapsed and lowercased; both key and hash are shown for the selected avatar |
|---|---|
| Palette | 12 plates at the defaults: a greedy LCH walk at chroma 52 over four lightness levels 7 L* apart, keeping only candidates at ΔE76 12 or more from every accepted plate in normal vision and after each of three dichromacies. 16 plates with the filter off, 11 for pale plates, 10 at a 7:1 floor |
| Ink | Black or white, chosen per plate by contrast. The floor across the whole plate space is 4.58:1, measured at the L* 49.4 crossover where black and white score alike; most plates sit between 4.6:1 and 10.0:1 |
| Identicon | 5×5 grid mirrored about the center column, 15 independent bits from a mulberry32 stream seeded with the hash — 32,768 patterns, 393,216 pattern-and-plate combinations. All-empty and all-filled grids are corrected deterministically |
| Initials | 1 to 3 graphemes segmented with Intl.Segmenter, taken from the first and last surviving token. Email local parts split on . _ + and -, 16 name particles dropped, Han/Kana/Hangul reduced to one character, emoji kept whole |
| SVG output | 398 bytes for a two-letter avatar at 128 px, 307 to 1,428 bytes for an identicon depending on how many cells are filled. viewBox 0 0 100 100, text positioned with dy=".35em" rather than dominant-baseline |
| PNG output | canvas.toBlob at 32, 48, 80, 128, 256 and 512 px presets or any size from 16 to 1024. Drawn directly on the canvas, so the initials use the fonts this machine actually has rather than an SVG renderer's substitute |
| Batch | 100 names per grid, lines over 240 characters hashed from the first 240, and Download all sends the first 20 files at 250 ms apart — past that browsers cancel the run. Nothing is uploaded; the names stay in this tab |
Frequently asked questions
Will my backend produce the same avatar as this page?
Yes, if it repeats the same three steps: normalize to NFC, trim and collapse whitespace, lowercase, then FNV-1a 32 over the UTF-8 bytes. The byte encoding is where implementations usually part company — hashing UTF-16 code units instead of UTF-8 gives a different number for any name outside ASCII, which is why one account can end up green in the browser and blue in a generated email. Each avatar here shows its hash as 0x-prefixed hex, so you can print the same value from Python, Go or Postgres and check the two agree before you ship.
Two people in my list came out the same color.
That is arithmetic rather than a bug: twelve plates over five names collide 62% of the time, and over ten names it is a near certainty. Color is a recognition aid — it makes your own row findable in a list you scroll every day — and the initials are what actually distinguish two accounts. If you need the picture itself to differ, switch to the identicon: 15 independent bits give 32,768 patterns, or 393,216 combinations once the plate is counted.
Why are the initials always pure black or pure white?
Because that is the only choice that cannot fail. Black or white on any sRGB color never drops below 4.58:1 — the worst case is the crossover at L* 49.4, where black and white score the same — so picking whichever is better with bestTextColor guarantees WCAG AA for the initials on every plate the palette can produce. A tinted ink taken from the plate's own hue looks more designed and drops under 4.5:1 on the light half of the wheel, which is how avatar initials end up illegible on exactly the pale mint tile someone screenshots for the bug report.
Does the color still tell people apart if they are color blind?
For the three dichromacies, yes, and the page proves it rather than claiming it: the palette is built by a greedy walk that rejects any candidate plate landing within ΔE76 12 of an accepted one after protanopia, deuteranopia and tritanopia have been simulated, and the panel under the grid reports the closest surviving pair for each. Achromatopsia is the honest exception. Once hue carries nothing, only lightness is left, and at the same spacing exactly 2 of the 12 plates survive — no palette of a dozen colors can be safe there, which is the argument for the identicon pattern as a second channel.
My downloaded SVG renders with the initials sitting on the bottom edge.
That is a renderer ignoring dominant-baseline, and the file here avoids it. librsvg — what ImageMagick, GTK apps and several server-side thumbnailers use — does not implement dominant-baseline at all, so an avatar centered with dominant-baseline="central" comes out with the letters resting on the vertical midline instead of straddling it. These files position the text with dy=".35em" from a y of 50 instead, which every SVG renderer honors because it is plain text positioning rather than a baseline hint.
The initials are wrong for names that are not two Western words.
Four rules cover the cases that break a naive first-letter-of-each-word split. Sixteen nobiliary particles — van, von, de, della, ibn and the rest — are dropped when two other tokens remain, so Ludwig van Beethoven is LB and not LV. A name whose first character is Han, Kana or Hangul returns that one character, because a two-character initial reads as a different word in those scripts. Letters are cut by grapheme with Intl.Segmenter, so an é built from a combining mark or a flag emoji stays whole instead of splitting into halves. And a line with no letter, digit or emoji at all falls back to the identicon and says so, rather than drawing an empty tile.
Should I hash the display name or the user id?
The id, in almost every case. A display name is editable, and the day someone adds a middle initial their avatar changes color and their colleagues stop finding them in a list — the same failure as rehashing on every sign-in. Hash the immutable primary key and pass the display name separately for the initials; this page keeps them separate for that reason, showing the hashed key beside the letters it drew. Locale is the other trap: use toLowerCase and not toLocaleLowerCase, because the locale-aware form maps the Turkish dotted capital İ differently and a Turkish browser would then compute a different hash than your server.
About deterministic avatars
A default avatar exists because a product cannot show an empty square next to a name. Gravatar has served hash-derived identicons since 2007, GitHub has drawn one for every account without a photo since 2013, and the pattern that spread from them is always the same shape: take a stable string, hash it, and turn the number into a picture. The part that spread badly is the color. Practically every snippet in circulation reaches for hsl(hash % 360, 65%, 50%) and then paints white initials on top, and that combination is measurably broken — across twelve evenly spaced hues at that saturation and lightness, white text clears 4.5:1 on only four of them, and on the yellow it scores 1.61:1. The initials do not become hard to read; they become invisible. Picking the ink per plate instead is the whole fix, and it costs nothing, because black or white on any sRGB color is never worse than 4.58:1.
The second thing the hash-to-hue recipe cannot do is survive color-vision deficiency. Around 8% of men of northern European descent have some form of it, and under deuteranopia the hue circle collapses toward a single blue-to-yellow axis: two plates that look a third of the wheel apart can simulate to nearly the same color. Spacing hues evenly is therefore not enough, and the palette here is built by testing candidates after simulation rather than before — chroma held at 52, four lightness levels seven L* apart, and every accepted plate at least ΔE76 12 from the others in normal vision and under all three dichromacies. Twelve survive at the default 4.5:1 floor, ten at 7:1. Lightness has to do that much of the work because it is the only channel a deficiency leaves intact — which also sets the limit honestly: under achromatopsia only 2 of the 12 plates stay apart, so if a full range of vision has to be covered, the identicon pattern, not the color, is what carries the identity. If you want to see the collapse on your own brand colors rather than on these plates, that is the same simulation the color blindness simulator runs.
What you ship depends on who rasterizes it. Store the SVG when your own front end paints the avatar — it is around 400 bytes, it scales from a 24 px comment row to a profile header without a second export, and SVG optimizer has nothing left to strip from a file this small. Send PNG anywhere the receiving service re-encodes what you give it: server-side renderers substitute fonts freely, so initials laid out with a system stack shift width on the way through, and SVG to PNG is the same rasterizing step for artwork that did not come from this page. Going the other way — an existing raster mark you want as a tile — is PNG to SVG. And when the same generated mark has to double as a site icon, a 32 px avatar is already a favicon: the multi-size container is built by the favicon generator, a single frame by image to ICO, and ICO converter shows what ended up inside the container.
Where the names you paste go
Every number on this page is worked out by JavaScript running in the tab you are reading it in. Nothing you type, paste or open is uploaded, logged or kept, which is also why the tools carry on working after you disconnect from the network.
A list of user names is personal data in a way a hex code is not, so it is worth being precise: the textarea contents are held in React state for as long as the tab is open and nowhere else. Nothing is written to local storage, no name appears in a URL, and reloading the page clears the list back to the ten examples.