@maxnth/gestalt

Deterministic generative avatar components for Vue 3. Render unique avatars from any seed without stored images or network requests.
Install
npm install @maxnth/gestalt
Latest Version:0.1.0
Vue:3
License:MIT
Last Updated:Jul 17, 2026
Links: GitHub  ·  npm
Maintainer: maxnth

@maxnth/gestalt

l

Give @maxnth/gestalt a string or number — a user id, email, handle, or anything else — and it renders a unique inline SVG avatar. The same seed always produces the same result, so you get consistent, good-looking avatars entirely from data.

Documentation · Storybook

Why use it?

  • No assets to ship. Every avatar is generated on the fly, so there is no image folder, no CDN, and no broken links.
  • Stable by design. A seed like ada@example.com always produces the exact same avatar.
  • Server-rendered. Built-in Vue components emit complete inline SVG during SSR, with no client-side drawing pass.
  • Flexible core. Use a component, generate a framework-independent SVG document, or keep using the canvas helpers for raster export and custom algorithms.
  • Easy to extend. Bring your own rendering algorithm via the generic <Avatar> component.
  • Fully typed. Written in TypeScript with declarations included.

Install

pnpm add @maxnth/gestalt
# or: npm i / yarn add / bun add

Requires vue >= 3.5.

Usage

<GradientAvatar>

The quickest way to start is the mesh-gradient avatar component.

<script setup>
import { GradientAvatar } from '@maxnth/gestalt'
</script>

<template>
  <GradientAvatar seed="jane@example.com" :size="96" />
</template>

Props

Prop Type Default Description
seed string | number — Any value; each unique seed yields a unique avatar.
size number 32 Rendered size in pixels.
radius number | string "9999px" Corner radius. Number is pixels; string is CSS.
variant "mesh" | "bloom" | "flare" | "silk" | "nova" | "void" | "jade" | "auto" "mesh" Gradient composition. auto selects one deterministically from the seed.
mode "smooth" | "dither" "smooth" Smooth gradient or palette-quantized square cells.
style Record<string, string | number> — Extra inline styles merged onto the wrapper.

class is forwarded to the wrapper <span> like any standard Vue attribute.

<!-- Palette-quantized pixel treatment -->
<GradientAvatar seed="jane@example.com" :size="96" mode="dither" />

Ring / border

All avatar components support a ring prop that draws an outline around the avatar using box-shadow, so it naturally follows the chosen radius.

<GradientAvatar seed="jane@example.com" :size="96" ring />

<GradientAvatar seed="jane@example.com" :size="96" :ring="4" />

<GradientAvatar seed="jane@example.com" :size="96" ring="0 0 0 3px #10b981" />
ring value Result
true Default white ring (2px).
number White ring with the given thickness in pixels.
string Any CSS box-shadow value for full control.
omitted No ring.
<!-- Circle -->
<GradientAvatar seed="jane@example.com" :size="96" />

<!-- Rounded square -->
<GradientAvatar seed="jane@example.com" :size="96" :radius="16" />

<!-- Square -->
<GradientAvatar seed="jane@example.com" :size="96" :radius="0" />

<IdenticonAvatar>

For a GitHub-style geometric avatar, render a symmetric grid of cells with a deterministic color pair.

<script setup>
import { IdenticonAvatar } from '@maxnth/gestalt'
</script>

<template>
  <IdenticonAvatar seed="jane@example.com" :size="96" />
  <IdenticonAvatar seed="jane@example.com" :size="96" mirror="vertical" />
</template>
Prop Type Default Description
seed string | number — Any value; each unique seed yields a unique pattern.
size number 32 Rendered size in pixels.
radius number | string "9999px" Corner radius. Number is pixels; string is CSS.
mirror "horizontal" | "vertical" | "both" | "none" "horizontal" Which axis to mirror.
foreground string — Cell color as #RGB or #RRGGBB. Invalid values use the generated color.
background string — SVG background as #RGB or #RRGGBB. Invalid values use the generated color.
style Record<string, string | number> — Extra inline styles merged onto the wrapper.

<FlowFieldAvatar>

For a plotter-style generative avatar, render streamlines through a deterministic noise field.

<script setup>
import { FlowFieldAvatar } from '@maxnth/gestalt'
</script>

<template>
  <FlowFieldAvatar seed="jane@example.com" :size="96" />
  <FlowFieldAvatar seed="jane@example.com" :size="96" :columns="9" :rows="9" :iterations="56" />
</template>
Prop Type Default Description
seed string | number — Any value; each unique seed yields a unique flow field.
size number 32 Rendered size in pixels.
radius number | string "9999px" Corner radius. Number is pixels; string is CSS.
columns number 14 Number of seed columns.
rows number 14 Number of seed rows.
iterations number 28 Steps traced in each direction from every seed.
stepSize number — Step size in internal SVG user-space units.
background string — SVG background as #RGB or #RRGGBB.
colors string[] — #RGB or #RRGGBB stroke colors; invalid entries are ignored.
strokeWidth number — Stroke width in internal SVG user-space units.
opacity number 0.72 Stroke opacity from 0 to 1.
style Record<string, string | number> — Extra inline styles merged onto the wrapper.

<InitialsAvatar>

For a more traditional placeholder avatar, render one or two initials on a solid background.

<script setup>
import { InitialsAvatar } from '@maxnth/gestalt'
</script>

<template>
  <InitialsAvatar seed="Maximilian Nöth" :size="96" mode="single" />
  <InitialsAvatar seed="Maximilian Nöth" :size="96" mode="double" />
</template>

Double initials split the seed by spaces, dashes, underscores, and dots — so Ada Lovelace becomes AL.

Prop Type Default Description
seed string | number — The name or value used to derive the initials.
size number 32 Rendered size in pixels.
radius number | string "9999px" Corner radius. Number is pixels; string is CSS.
mode "single" | "double" "single" Whether to show one or two initials.
background string — Background as #RGB or #RRGGBB; invalid values use the generated color.
color string — Text as #RGB or #RRGGBB; invalid values use automatic contrast.
style Record<string, string | number> — Extra inline styles merged onto the wrapper.

Generic <Avatar>

When you want to experiment with a custom Canvas2D generator, use the lower-level <Avatar> component. The built-in components above use inline SVG; this generic compatibility component remains canvas-based.

<script setup>
import { Avatar, gradientAvatarAlgorithm } from '@maxnth/gestalt'
</script>

<template>
  <Avatar seed="user-123" :size="80" :algorithm="gradientAvatarAlgorithm" />
</template>

An algorithm is just an object with a name and a render function:

import type { AlgorithmRenderContext, AvatarAlgorithm } from '@maxnth/gestalt'

const stripeAlgorithm: AvatarAlgorithm = {
  name: 'stripe',
  render({ ctx, size, seed }: AlgorithmRenderContext, options) {
    ctx.fillStyle = '#3b82f6'
    ctx.fillRect(0, 0, size, size / 2)
  },
}

Engine helpers

The same gradient engine is exposed as plain functions, which is handy for downloads, server renderers, or anywhere you need an <img> src.

import {
  generatePalette,
  gradientToDataURL,
  seedFromString,
} from '@maxnth/gestalt'

// 512×512 PNG data URL
const src = gradientToDataURL('jane@example.com', { size: 512 })

// Inspect the palette behind a seed
const { seed, colors, harmony } = generatePalette('jane@example.com')

// Convert a string to its numeric seed
const numericSeed = seedFromString('jane@example.com')
Helper Description
drawMeshGradient(ctx, seed, size) Paint the raw mesh into a 2D canvas context.
drawFlowField(ctx, seed, size, opts?) Paint a flow field into a 2D canvas context.
generateFlowFieldLines(seed, size, opts?) Generate deterministic flow-field streamlines.
renderGradient(canvas, seed, opts?) Render a seed into a canvas with the soft blur.
gradientToDataURL(seed, opts?) Render and return a data URL.
gradientToBlob(seed, opts?) Render and resolve a Blob.
generatePalette(seed) Get the deterministic colors and harmony for a seed.
generateDitherGradient(seed, size, variant?) Generate palette-quantized dither cells.
drawDitherGradient(ctx, seed, size, variant?) Paint the dither treatment into a 2D canvas.
seedFromString(input) / toSeed(seed) Hash any value into a numeric seed.
generateGradientSvg(seed, size?, idPrefix?, variant?, mode?) Generate a framework-independent gradient SVG document.
generateInitialsSvg(seed, size?, opts?) Generate an initials SVG document.
generateIdenticonSvg(seed, size?, opts?) Generate an identicon SVG document.
generateFlowFieldSvg(seed, size?, opts?) Generate a flow-field SVG document.

Generator dimensions are rounded and clamped from 1 through 4096; identicon gridSize is clamped from 1 through 64. Built-in color options accept #RGB and #RRGGBB only and normalize them to uppercase #RRGGBB, keeping SVG and Canvas output consistent across runtimes.

SSR

All built-in avatar components render complete inline SVG markup on the server. Their output is deterministic and hydrates without a client-side drawing pass. The lower-level <Avatar> component remains canvas-based for custom Canvas2D algorithms and therefore renders an empty canvas until it mounts in the browser.

License

MIT © Maximilian Nöth

Related Packages

ditherdance

Dithering for the web. Dither any image with Floyd-Steinberg, Atkinson or Bayer,...

864 1
holiday-avatar

Vue library for generating nice user avatar. (Inspired by react-nice-avatar)

1,550 60
vue-avatar-gradient

Generate beautiful gradient avatars for your Vue application.

833 1
web3-avatar-vue

Vue component for generating beautiful Web3 gradient avatars

8,679 18
mochikao

Deterministic avatars: any string becomes a cute, unique SVG character. Zero dep...

1,142 2

Version History

Version Released Vue License
0.1.0 ^3.5.0 MIT
0.0.0 ^3.5.0 MIT