Skip to content

Repository files navigation

expovatar

npm version license

Deterministic avatars from any string — for React Native + Expo. Wallet address, username, UUID → the same avatar every time. Two modes: gradient (diffuse blurred blends) and dither (Bayer halftone). Skia‑rendered, crisp at any size.

expovatar is a React Native port of hashvatar: the same FNV‑1a → mulberry32 seeding, OKLCH palette, and generation logic, with the canvas renderers rebuilt on @shopify/react-native-skia.

import { Expovatar } from 'expovatar'

<Expovatar hash="favourafula.bnb" size={48} />
<Expovatar hash="chidinma" size={64} mode="dither" />
<Expovatar hash="0x742d…f44e" size={64} tones={['hotpink', '#00ff99']} animated />

Install

Skia is a native module — expovatar runs on an Expo dev client / prebuild / EAS build, not Expo Go.

npm install expovatar
npx expo install @shopify/react-native-skia

@shopify/react-native-skia (≥1.5) is the only peer. No Reanimated / Gesture Handler needed — animation uses a plain requestAnimationFrame loop.


Usage

import { Expovatar } from 'expovatar'

function Row() {
  return (
    <>
      <Expovatar hash="favourafula.bnb" size={64} />
      <Expovatar hash="adaeze" size={40} mode="dither" />
      <Expovatar hash="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" size={40} tones={['#6366f1']} />
    </>
  )
}

The component renders a circle by default (rounded); pass rounded={false} for a square.

Props

Prop Type Default Description
hash string Any string. Same string → same avatar.
size number 64 Square size in px.
mode 'gradient' | 'dither' 'gradient' Render style.
animated boolean false Animate (drifting blends / swirling dither).
dotScale number auto Dither cell size; scales with size if omitted.
tones string[] Restrict the palette — hex, oklch(l c h), or common CSS names.
rounded boolean true Clip to a circle.
style ViewStyle Style on the wrapping view.

Modes

Gradient — six irregular polygons, each blurred (MaskFilter) and composited with a blend mode (SrcOver / Overlay / SoftLight) over a base color, for a soft diffuse blob. Monotone from the hash by default.

Dither — an 8×8 Bayer‑matrix halftone: a directional gradient thresholded into crisp cells of one color over another. Great for a retro / pixelated identity.

<Expovatar hash="emeka.bnb" mode="gradient" />
<Expovatar hash="emeka.bnb" mode="dither" dotScale={3} />

Tones

Restrict the palette to a hue family. Without tones, the avatar is monotone from the hash.

<Expovatar hash="ngozi" tones={['hotpink']} />                 // one family
<Expovatar hash="ngozi" tones={['#ff6b6b', '#4ecdc4']} />      // multiple
<Expovatar hash="ngozi" tones={['oklch(0.65 0.25 310)']} />    // oklch

Accepts hex (#ff69b4 / ff69b4), oklch(l c h), and common CSS color names (red, hotpink, teal, …). Unknown names fall back to the monotone palette; hex and oklch() always work.


Utilities

Everything deterministic is exported for custom rendering or theming — none of it touches Skia:

import { hashToColors, hashToSeeds, oklchToHex } from 'expovatar'

const colors = hashToColors('favourafula.bnb', undefined, 4)  // OKLCH[]
const hexes = colors.map(oklchToHex)                          // ['#…', …]
const seeds = hashToSeeds('favourafula.bnb', 8)               // 8 numbers in [0,1)
  • hashToColors(hash, tones?, count?) → the generated OKLCH palette.
  • hashToSeeds(hash, count)count deterministic numbers in [0, 1).
  • oklchToHex / oklchToCss / rgbToOklch / parseTone → color helpers.
  • drawGradient / drawDither → low‑level Skia painters (draw into any SkCanvas / PictureRecorder) if you want to composite avatars yourself.

How it works

hashFNV‑1amulberry32 seeds → an OKLCH palette → a Skia picture. The picture is recorded once and memoized; animated re‑records on a requestAnimationFrame loop. Same string always yields the same seeds, palette, and picture.

The hash / color / generation logic ports near‑verbatim from hashvatar. The web renderers (<canvas> 2D, ctx.filter, globalCompositeOperation, ImageData) become Skia: MaskFilter blur, BlendMode, and crisp drawRect cells.


Development

npm install
npm test          # vitest — pure-core determinism
npm run typecheck
npm run build     # tsup → dist (ESM + CJS + d.ts)

License

MIT. Ported from hashvatar (MIT, © Médhy Chabour) — see LICENSE.

About

Deterministic avatars from any string for React Native + Expo — gradient & dither, Skia-rendered. A port of hashvatar.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages