Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Core Laravel Package

dicebear/core

DiceBear core is the PHP engine behind DiceBear avatars. Pass any seed string and it returns a deterministic, customizable SVG avatar, so the same input always yields the same image. Multiple styles and a flexible API make it easy to add consistent profile pictures to Laravel apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require dicebear/core

Confirm the major version you get — the namespace and constructor shape changed between the v1 (DiceBear\Avatars\Initials, etc.) and v2 (DiceBear\Avatar) lines. The README on the tagged version is the only reliable reference; there is no Laravel-facing documentation.

Minimum viable call

use DiceBear\Avatar;

$avatar = new Avatar('initials', [
    'seed'            => '[email protected]',
    'backgroundColor' => ['b6e3f4', 'c0aede', 'ffd5dc'],
    'radius'          => 50,
]);

$svg = $avatar->toString();   // "<svg ...>"

The output is a plain SVG string. No filesystem writes, no HTTP calls, no config file, no service provider — it is a pure function of (style, options).

Where to look first

  1. The style list in the README (initials, avataaars, bottts, identicon, shapes, thumbs, …) — pick two or three, not thirty.
  2. The option schema per style. Options are not uniform: initials takes chars, fontSize, fontWeight, textColor, backgroundType; avataaars takes accessories, top, clothing, etc. Dump $avatar->toJson() (or the equivalent in your version) to see the resolved option set — this is the fastest way to discover what actually got applied versus silently ignored.
  3. src/ for the style definitions if you need to know exactly which options are hashed into the seed.

First use case

Give every user a deterministic, zero-storage avatar derived from something stable — their ID or a normalised email — and serve it from a route with a long-lived cache header. This replaces a Gravatar lookup or a "default grey silhouette" with one line of code and no upload pipeline.

Route::get('/avatar/{user}', function (User $user) {
    $svg = (new Avatar('initials', [
        'seed' => (string) $user->id,
    ]))->toString();

    return response($svg, 200, [
        'Content-Type'  => 'image/svg+xml',
        'Cache-Control' => 'public, max-age=31536000, immutable',
    ]);
})->name('avatar');

Implementation Patterns

Wrap it, don't sprinkle it. Even at this adoption level, isolate the library behind one class so a version bump or a swap to a hosted DiceBear endpoint touches a single file.

namespace App\Support;

use DiceBear\Avatar;

class AvatarFactory
{
    public function svg(string $seed, string $style = 'initials', array $options = []): string
    {
        return (new Avatar($style, array_merge([
            'seed'            => $this->normalizeSeed($seed),
            'backgroundColor' => ['b6e3f4', 'c0aede', 'ffd5dc', 'd1d4f9'],
        ], $options)))->toString();
    }

    public function dataUri(string $seed, string $style = 'initials', array $options = []): string
    {
        return 'data:image/svg+xml;base64,' . base64_encode($this->svg($seed, $style, $options));
    }

    protected function normalizeSeed(string $seed): string
    {
        return mb_strtolower(trim($seed));
    }
}

Bind it as a singleton and inject where needed. Type-hint AvatarFactory, never Avatar.

Model accessor + versioned URL. Never inline the SVG in a list view — return a URL so the browser caches it. Append a short hash of the options to bust caches when you change a style.

protected function avatarUrl(): Attribute
{
    return Attribute::get(fn () => route('avatar', [
        'user' => $this,
        'v'    => substr(md5($this->name), 0, 8),
    ]));
}

Blade component so views stay declarative:

{{-- resources/views/components/avatar.blade.php --}}
@props(['user', 'size' => 40])
<img src="{{ $user->avatar_url }}"
     width="{{ $size }}" height="{{ $size }}"
     alt="{{ $user->name }}"
     {{ $attributes->merge(['class' => 'rounded-full']) }}>

Cache the string, not the object. The Avatar instance is cheap but not something to serialise into the cache.

$svg = Cache::remember(
    "avatar:initials:" . md5($seed . json_encode($options)),
    now()->addDay(),
    fn () => $factory->svg($seed, 'initials', $options)
);

Determinism makes the cache key trivial — the same inputs always produce the same bytes for a given package version.

Persist when the seed is expensive or the render is user-facing. For a registration flow, generate once in an observer and dump to Storage::disk('public'); then avatar_url is an asset URL with no per-request cost and no route. Trade-off: you must regenerate on style/option changes, and you need a backfill command.

static::created(function (User $user) {
    Storage::disk('public')->put(
        "avatars/{$user->id}.svg",
        app(AvatarFactory::class)->svg((string) $user->id)
    );
});

Data URIs for Inertia/JSON payloads. If the seed is already in the payload, ship the data URI and skip a round trip:

return Inertia::render('Profile/Edit', [
    'avatar' => $factory->dataUri((string) $user->id),
]);

Variety without ambiguity. For a "shuffle my avatar" button, don't touch the seed (it must stay stable) — rotate backgroundColor array order or add a rotate/flip option, keyed off a users.avatar_variant integer.

Testing is trivially snapshot-able because output is deterministic:

public function test_avatar_is_deterministic(): void
{
    $a = app(AvatarFactory::class)->svg('[email protected]');
    $b = app(AvatarFactory::class)->svg('  [email protected] ');

    $this->assertSame($a, $b);
    $this->assertStringStartsWith('<svg', $a);
    $this->assertStringNotContainsString('<script', $a);
}

Factories and seeders: $factory->svg((string) $this->faker->uuid()) gives every seeded user a distinct, stable avatar with no network calls — a genuine improvement over Gravatar-based seeders.

Gotchas and Tips

The API is not uniform across styles, and unknown options are typically ignored rather than rejected. A typo like backgroundcolor fails silently and you get default colours. Validate option keys against the style's schema in your wrapper, or at minimum assert on toJson() output in a test.

Array options are hashed, not picked at random. 'backgroundColor' => ['b6e3f4', 'c0aede'] selects one entry deterministically from the seed. Reordering or appending to that array changes the output for every existing user. Treat the option array as part of your schema — version it, don't casually edit it.

Package upgrades can change the pixels. Style definitions evolve between releases. If you store SVGs or hand out immutable cached URLs, pin the exact version in composer.json and regenerate deliberately rather than on composer update.

Normalise the seed yourself. "Jane Doe", "jane doe" and " Jane Doe" produce three different avatars. Lowercase + trim in one place, or use an immutable identifier (user ID) and accept that the avatar won't change when the name does — usually the better product decision.

SVG is not safe to echo blindly. If you ever render inline ({!! $svg !!}), remember the seed can influence text nodes in initials. The library escapes content, but options you pass through from user input (e.g. a textColor from a colour picker) are your responsibility — whitelist hex patterns before they go anywhere near an attribute.

CSP will bite you on data URIs. Base64 SVG requires img-src data: in your Content-Security-Policy. If your policy is strict, prefer the route-based URL.

Emails need PNG, and PNG needs a real renderer. Most mail clients strip or refuse SVG. Converting requires Imagick with proper SVG delegate support — the fallback MSVG renderer mis-renders gradients and masks. If you need raster output, test with rsvg-convert or a headless renderer, and dispatch the conversion to a queue; don't do it in the request cycle.

Check per-style licences before shipping. DiceBear's own code is MIT, but individual styles carry their own terms — several upstream designs are CC BY 4.0 and want attribution. If you're shipping a commercial product, audit the two or three styles you actually enable rather than assuming the package licence covers everything.

Zero dependents means no Stack Overflow surface. Debug by dumping toJson() and diffing against a hand-built new Avatar(...) in tinker. Keep the wrapper thin enough that you can replace the whole thing with a file_get_contents('https://api.dicebear.com/...') call or a hand-rolled initials generator in an afternoon — that's the real insurance policy here.

Don't generate in an N+1 loop. Rendering 200 SVGs in a single request is measurable. The route-plus-browser-cache pattern turns that into one request per user per cache lifetime; the storage pattern turns it into zero.

Extension point: custom styles/definitions, if your version exposes them, are the clean way to add a house style — but given the thin ecosystem, a simpler path is to post-process the SVG string (wrap in a coloured circle, inject a viewBox) inside your AvatarFactory rather than fighting an undocumented registry API.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core