Avatars

A deterministic mesh-gradient avatar for any seed, rendered on a <canvas>, or a crisp ordered dither of the same palette via pattern. The same seed always yields the same avatar, with no stored images and no network. Self-contained: the engine is bundled in.

Installation

Install with your package manager of choice. React 18 or newer is the only peer dependency.

pnpm add @outpacelabs/avatars

Usage

Import the component and give it a seed. That's it: the same seed always renders the same gradient, so a user id or email is a stable avatar with nothing to store.

import { GradientAvatar } from "@outpacelabs/avatars";

export function Avatar({ user }) {
  return <GradientAvatar seed={user.id} size={96} />;
}

Props

seedstring | numberAny value; each unique seed is a unique gradient.
sizenumberRendered size in pixels. Default 32.
pattern"mesh" | "dither"Render engine. mesh is the soft gradient; dither is an ordered dither of the same palette. Default "mesh".
radiusnumber | stringCorner radius. Number = pixels, string = any CSS length. Pass 0 for a square. Default "9999px".
colorsstring[]Your own hex palette instead of the seed-derived harmony. The seed still drives the layout, so each seed stays unique but on-brand.
p3booleanRender in the Display P3 wide-gamut color space, more vivid on capable screens, unchanged on the rest. Default false.
classNamestringExtra classes on the wrapper span.
styleCSSPropertiesExtra inline styles merged onto the wrapper.

Sizes & shapes

size scales the avatar; radius reshapes it. It defaults to a full circle. Pass a number for a rounded square or 0 for a hard square.

circle
radius={18}
radius={0}
<GradientAvatar seed="studio" size={84} />            // circle
<GradientAvatar seed="studio" size={84} radius={18} /> // rounded square
<GradientAvatar seed="studio" size={84} radius={0} />  // square

Patterns

pattern switches the render engine. mesh (the default) is the signature soft gradient; dither is an ordered dither of the same palette, a crisp retro look with no blur. Both are deterministic from the seed.

mesh
dither
<GradientAvatar seed="studio" size={84} />                  // mesh (default)
<GradientAvatar seed="studio" size={84} pattern="dither" /> // dither

Colors & P3

By default the palette is derived from the seed via color-harmony rules. Pass colors to use your own palette instead, brand colors, a product theme, anything. The seed still drives the layout (and rotates which color leads), so every seed stays unique while staying on-brand. Hex in, # optional.

// Your brand palette instead of the seed-derived harmony.
<GradientAvatar seed={user.id} colors={["#4f46e5", "#06b6d4", "#ec4899"]} />

Set p3 to render in the wide-gamut Display P3 color space. On capable screens the palette reads noticeably more vivid; everywhere else it maps back to the same sRGB color, so it's safe to leave on.

// Wide-gamut Display P3, more vivid on capable screens.
<GradientAvatar seed="studio" size={84} p3 />

Engine helpers

The bundled engine is re-exported so you can render gradients outside React: to a data URL for an <img>, a Blob for the clipboard, or a full-resolution download.

drawMeshGradient(ctx, seed, size, options?)Paint the raw mesh into a 2D canvas context. The lowest-level primitive.
drawDither(ctx, seed, size, options?)Paint the ordered dither into a 2D canvas context.
renderGradient(canvas, seed, options?)Render a seed into a canvas with the signature soft blur baked in.
gradientToDataURL(seed, options?) → stringRender and return a data URL. Handy for <img src>, downloads, or copy.
gradientToBlob(seed, options?) → Promise<Blob | null>Render and resolve a Blob, e.g. to write to the clipboard.
generatePalette(seed, options?) → GradientPaletteThe colors and harmony rule behind a seed. Pass colors for your own palette.
seedFromString(input) → number / toSeed(seed) → numberThe deterministic hashing used to turn any value into a numeric seed.
import { gradientToDataURL, generatePalette } from "@outpacelabs/avatars";

// A 512×512 PNG data URL, no React required.
const src = gradientToDataURL("jane@example.com", { size: 512 });

// Just the colors behind a seed.
const { colors, harmony } = generatePalette("jane@example.com");

Types are exported too: GradientPalette, Harmony, RenderOptions, and ExportOptions.

License

Free to use under the MIT license. Use it anywhere, commercial or not, no attribution required.

By Outpace Studios

Brands, interfaces, and motion for
venture-backed companies