F Facehash
A L G T N S R M

Deterministic avatars
from any string

A name, an email, an ID — Facehash turns it into the same friendly SVG face every time. No GD, no Imagick, no external services.

Read the docs GitHub
Playground

Try it with your own name

Rendered in your browser by a port of the same renderer the package ships.

Showcase

Every knob, pre-rendered

All of the SVG below was generated at build time by the PHP renderer.

Format

square, squircle or circle

S circle
S square
S squircle

Variant

Radial highlight or flat fill

S gradient
S solid

Initial

First letter of the name, below the eyes

S on
off

Blink

CSS animation embedded in the SVG

S on
S off

Size

Geometry scales with the pixel size

S 24
S 32
S 48
S 64

Palette

Any list of colors you like

S #1
S #2
S #3

Installation

Requires PHP 8.2+ and Laravel 11, 12 or 13.

composer require saade/facehash

The service provider and the Facehash facade are auto-discovered — there is nothing to register.

Quick start

use Saade\Facehash\Facades\Facehash;

// Generate an SVG string
$svg = Facehash::name('Saade')->toSvg();

// Embed as a data URI in an <img> tag
$uri = Facehash::name('Saade')->toUri();

Builder API

Every method returns a new instance, so you can keep a configured builder around and branch off it without side effects.

name(string $name)

Required. The input string. The same string always produces the same face.

Facehash::name('alice@example.com')->toSvg();

size(int $pixels)

Avatar dimensions in pixels. Default: 40.

Facehash::name('Saade')->size(128)->toSvg();

variant(string $variant)

Background style — 'gradient' or 'solid'. Default: 'gradient'.

Facehash::name('Saade')->variant('solid')->toSvg();

format(string $format)

Avatar shape — 'square', 'squircle' or 'circle'. Default: 'circle'.

Facehash::name('Saade')->format('squircle')->toSvg();

blink(bool $enable = true)

Adds a CSS blink animation to the eyes, inlined in the SVG. Default: false.

Facehash::name('Saade')->blink()->toSvg();

initial(bool $show = true)

Show the first letter of the name below the eyes. Default: true.

Facehash::name('Saade')->initial(false)->toSvg();

colors(array $colors)

Override the palette. Each avatar deterministically picks one color from the list.

Facehash::name('Saade')->colors(['#6366f1', '#8b5cf6', '#a78bfa'])->toSvg();

Output methods

MethodReturns
toSvg()Raw SVG string
toBase64()Base64-encoded SVG
toUri()Data URI (data:image/svg+xml;base64,…)

Blade usage

{{-- Inline SVG --}}
{!! Facehash::name($user->name)->size(48)->toSvg() !!}

{{-- As <img> src --}}
<img src="{{ Facehash::name($user->name)->size(48)->toUri() }}" alt="{{ $user->name }}">

{{-- Via the route --}}
<img src="{{ route('facehash', ['name' => $user->name, 'size' => 48]) }}" alt="{{ $user->name }}">

HTTP route

The package ships an optional GET endpoint that returns an image/svg+xml response with long-lived cache headers. It is disabled by default.

// config/facehash.php
'route' => [
    'enabled' => true,
],
GET /facehash?name=Saade

Query parameters

ParameterTypeDefaultDescription
namestringrequiredInput string
sizeint40Size in pixels (16–1024)
variantstringgradientgradient or solid
formatstringcirclecircle, square, squircle
initialbooltrueShow initial letter
blinkboolfalseEnable blink animation
colors[]string[]Custom hex palette
<img src="/facehash?name=Saade" alt="Avatar">
<img src="/facehash?name=Saade&size=128&variant=solid" alt="Avatar">
<img src="/facehash?name=Saade&colors[]=%236366f1&colors[]=%238b5cf6" alt="Avatar">

Configuration

php artisan vendor:publish --tag=facehash-config
<?php

return [
    'defaults' => [
        'size' => 40,
        'variant' => 'gradient',
        'format' => 'circle',
        'initial' => true,
        'blink' => false,
    ],

    'colors' => ['#ec4899', '#f59e0b', '#3b82f6', '#f97316', '#10b981'],

    'route' => [
        'enabled' => false,
        'prefix' => 'facehash',
        'middleware' => ['web'],
        'cache_control' => 'public, max-age=31536000, immutable',
    ],
];
  • defaults — starting values for the builder; any method call overrides them per instance.
  • colors — the palette each avatar picks from. The shipped default uses Tailwind's 500-weight colors.
  • route.enabled — register the HTTP endpoint. Off by default.
  • route.cache_control — the default caches for a year as immutable, which is safe because the same input always produces the same bytes.

How it works

  1. The input string is hashed to a deterministic 32-bit integer.
  2. The hash picks a face type, a color from the palette, and one of nine tilts that offset the face for a subtle 3D look.
  3. The renderer composites the clip path, background, gradient overlay, eye paths and the initial letter into a single SVG.
  4. The same string always produces the exact same SVG — across requests, servers and deploys.

Face types

round
cross
line
curved
The hash is a direct port of the JavaScript original, so a given string yields the same face in PHP as it does in the JS library.

Credits

A PHP/Laravel port of facehash by Cossistant, which provides the face paths, hash algorithm and rendering logic this package reproduces. Released under the MIT license.