Open source by Inlaylab · v1.0.0

Friendly avatars,
from any string.

Pass a user ID, email or name. Get the same delightful avatar every time, as clean SVG that themes with CSS variables, in every framework.

morph
gradient
aura
clay
$ npm i @inlaylab/opaline

One seed in. The same face out, everywhere.

  • DeterministicSame seed, same avatar: on the server, in every browser, in every framework.
  • Zero dependenciesA tiny core plus native wrappers. Import only the styles you ship.
  • ThemeableColors are CSS variables, so avatars follow your brand and dark mode.
  • Every frameworkReact, Vue, Svelte, Angular, Web Components, or plain SVG strings.
Playground

Make it yours.

Every option, live. What you see is the library's own output; copy the code for your framework or download the SVG.

Docs

Install

One core with zero dependencies, and a thin native component for each framework. Styles are separate imports, so you ship only what you use.

Core
pnpm add @inlaylab/opaline
import { createAvatar } from '@inlaylab/opaline'
import { morph } from '@inlaylab/opaline/morph'

createAvatar(morph, { seed: 'ada@inlay.dev' }).svg
Web Component
pnpm add @inlaylab/opaline-element
<script type="module">import '@inlaylab/opaline-element'</script>
<opaline-avatar seed="ada@inlay.dev" look="morph"></opaline-avatar>
React
pnpm add @inlaylab/opaline-react
import { Avatar } from '@inlaylab/opaline-react'
import { morph } from '@inlaylab/opaline/morph'

<Avatar seed="ada@inlay.dev" look={morph} src={user.photo} alt="Ada" />
Angular
pnpm add @inlaylab/opaline-angular
import { OpalineAvatar } from '@inlaylab/opaline-angular'
import { morph } from '@inlaylab/opaline/morph'

<op-avatar seed="ada@inlay.dev" [look]="morph" [src]="user.photo" alt="Ada" />
Vue
pnpm add @inlaylab/opaline-vue
import { Avatar } from '@inlaylab/opaline-vue'
import { morph } from '@inlaylab/opaline/morph'

<Avatar seed="ada@inlay.dev" :look="morph" :src="user.photo" alt="Ada" />
Svelte
pnpm add @inlaylab/opaline-svelte
import { Avatar } from '@inlaylab/opaline-svelte'
import { morph } from '@inlaylab/opaline/morph'

<Avatar seed="ada@inlay.dev" look={morph} src={user.photo} alt="Ada" />

Options

Any option you set fixes that part; the seed fills in the rest.

OptionValuesWhat it does
seedstring | number | nullAny string: user ID, email, name. Emails are lower-cased; whitespace is trimmed.
sizenumberPixel size. Default 64.
palettevivid · pastel · electric · muted · warm · cool · monoColor family. Default vivid.
finishflat · soft · glossLight and shade. Morph and Gradient default to flat, Clay to soft.
expressionbeam · content · … · giggleFix the face. Or set mood: happy · calm · surprised · playful.
facebooleanMorph, Gradient and Clay show a face unless false.
familyegg · duo · tri · cushion · clover · petalBlob shape family.
bodyjelly · hoodClay only. With ears: cat · bear · bunny.
shapecircle · squircleAura only.
backdropnone · tintA soft circle behind the body.
src · altstringWrappers only: a photo shown once it loads, and an accessible name.

Theming

Colors come out as var(--avatar-c1, #hex). Set the variables on any parent to follow your brand or dark mode. --avatar-c1 is always the body.

Same seed, same avatar

The seed is normalized (trimmed, NFC, emails lower-cased) and hashed into a seeded generator; no Math.random, no dates. The same seed and options give the same picture on the server, in every browser and in every framework. Gradient IDs are scoped per seed and options, and each component instance adds its own suffix, so two avatars on one page never clash.