notyourface deterministically generates pseudo-random but stable avatar images from any input seed. Like a configurable hash function that produces funky little graphics. Your face is beautiful! But sometimes you need the next best thing.
For more examples, see the π² DEMO PLAYGROUND!
Well, and the Configuration section.
- π©βπ» Simple but efficient API, typed with TypeScript
- π¨ Fixed, custom color palettes or colorful randomness
- 𧬠Deterministic (same seed == same image)
- π¦ Only ~1.3kb gzipped
- β‘ Works client-side (in the browser) and caches up to
ngenerated avatar images (1024by default) - π Configurable complexity, size, shape types, ...
- π¦ No runtime dependencies (as in zero, none, ...wait, why is there a parrot?!)
- πΌ Returns encoded image data as a data URI, e.g. for direct use as
<img src="...">or CSSbackground-image: url(...)or returns a ready-to-useimgHTML element β so no DOM manipulations by the library, it's all up to you! - π€ no AI involved nor required (in case you were concerned)
I wasn't satisfied with any of the comparable existing libraries. They were either too complicated and heavy, too focused on a specific technological context (a framework or library), or just didn't produce the aesthetics I was looking for. So I built this.
You got this. Something like...
npm install notyourfaceUse it in browser-facing code! The library needs access to a document object and the Canvas API to generate the images.
You have the choice between two function calls. That's it.
dataURI(options?)gives you a data URI containing encoded PNG image data. You can use it as<img src="...">in HTML orbackground-image: url(...)in CSS.imgEl(options?, attributes?)gives you a ready-to-use<img>element with optional attributes set. It has the same encoded PNG data set assrc, so this second function is just a convenience wrapper around the first one.
It's that easy:
import nyf from 'notyourface';
// To get a PNG data URI string, call `dataURI`.
// Optionally, pass some options (see below!).
const dataUri = nyf.dataURI({ seed: 'my.email@example.com' });
// ...so you can do something like this:
someImgElement.src = dataUri;
// ...or this:
someElement.style.backgroundImage = `url(${dataUri})`;
// ...OR, to get an <img> element right away, call `imgEl`.
// Optionally, pass some options (see below!) and/or
// attributes you want to be set on the element.
const imgEl = nyf.imgEl({ seed: 'my.email@example.com' }, { class: 'my-avatar' });
// ...so you can do this:
someElement.appendChild(imgEl);All options are, as the name suggests, optional.
- Type:
unknown(optional) - Default: A random seed.
An optional (but recommended) seed. This can be anything: A string, a number, an object, etc. The output will be stable as long as the same seed is used with the same set of other options.
Use something that is unique about what the avatar is going to represent, like a username. Also, whatever you use as a seed input should be JSON-serializable or at least produce a meaningful string representation. Internally, the seed is converted to a string (using JSON.stringify or String(seed) as a fallback) and then hashed to a number.
- Type:
number(optional) - Default:
128
The size of the generated avatar image in pixels. As they are square-shaped, this will be both the width and height.
β Be very careful with the size of the generated images. The larger the size, the longer it will take to generate the images. Also, as the cache will store the images in memory, larger images will take up more memory when cached. A maximum size value of more or less 256 is recommended. Of course, this greatly depends on where and how you are using this.
Avatar images with size values of 64, 128 and 256:
- Type:
string[](optional) - Default:
undefined - Example:
['#F00', 'lime', 'rgba(0, 0, 255, 1.0)']
A custom color palette to use. The string values can be any valid CSS color string. Using less than two colors here won't make much sense (think about it!).
If no custom color palette is set or the provided color palette contains less than two colors, a pseudo-random color palette will be generated and used instead.
β If a seed is given, a pseudo-random color palette will be stable a.k.a. the same for each call using this seed! Not so random after all!
Two different custom color palettes in action. In this case :
['#134686', '#ED3F27', '#FEB21A', '#FDF4E3']and['#004030', '#4A9782', '#DCD0A8', '#FFF9E5']
- Type:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10(optional) - Default:
4
The number of shapes that will be drawn. This makes for the overall perceived complexity of the avatar image.
Complexity values from 1 to 10:
As you can see, we should've realized we're making a huge mistake at around 6. Maybe 7 and beyond should have never happened. As the shapes are overlapping, it just gets worse at some point.
- Type:
Array<'square' | 'circle' | 'line'>(optional) - Default:
undefined(one pseudo-random shape type will be used)
The types of shapes that will be drawn onto the avatar image. This is a way to e.g. reduce the shapes used to only specific types. This greatly changes the overall style and distinguishability of the avatar image.
- If not set, a single pseudo-random shape type will be used (default).
- If set to
[](an empty array), all available shape types will be used. - If set to a specific combination of shape types, only those will be used.
π‘ No, this does not determine the shape of the generated image. There are no circular digital images. But you can always style your <img> element to be circular with border-radius: 50% or make it blurry using filter: blur(2px), or whatever you like.
undefined (default) |
![]() |
|---|---|
[] |
![]() |
['circle'] |
![]() |
['square'] |
![]() |
['line'] |
![]() |
- Type:
number(optional) - Default:
1024
The number of avatar images to cache in memory. If this is set to a positive number and the cache already contains >= cache images, the cache will still be read from, but not written to.
As this library was developed with an optimistic attitude, negative values will simply be turned into their positive counterparts (so the absolute value is used).
β A value of 0 will completely disable the cache for this call, so it will neither be read from nor written to.
Important
We're sticking to semantic versioning here, so major version bumps will happen whenever the API changes in a way that breaks backwards compatibility.
But what does that mean?
In the context of this project, API compatibility means that as long as calling code uses the same major version of this library, the calls will not break. However, the generated graphics resulting from certain calls might change with minor version bumps! This is because even the smallest fix might change the output of the library.
Contributions are welcome! Please see the contributing guidelines.
Use the following npm scripts in development:
npm run fix: Runs ESLint with--fixflag and Prettier with--writeflag.npm run dev: Starts the development server. Visithttp://localhost:5173afterwards to see the development page that hot-reloads and reflects the current state of the source live.npm test(ornpm run test): Runs the test suite.npm run build: Runs thefixscript,tsc, andvite buildin sequence.npm run bump <major|minor|patch>: Bumps the version number and creates a new commit and tag.














































