vinicius73/lavatar
Lavatar is a Laravel package for generating avatar images from names or emails. It creates initials-based avatars with customizable colors, fonts, and sizes, caches generated images, and integrates easily with Eloquent models for simple user profile avatars.
Reality check first. vinicius73/lavatar last shipped in July 2015, which puts it in the Laravel 4.2/5.0 era. On a modern app (Laravel 8+) composer require vinicius73/lavatar will almost certainly fail on illuminate/support, intervention/image, or PHP version constraints. Try it in a scratch branch first:
composer require vinicius73/lavatar --dry-run # read the conflicts before committing
If you genuinely need it (legacy app, or you're evaluating for a migration), the path to a working install is:
Install and publish config.
composer require vinicius73/lavatar
php artisan vendor:publish --provider="Vinicius73\Lavatar\LavatarServiceProvider"
The provider namespace and config key (config/lavatar.php) are worth confirming directly in vendor/vinicius73/lavatar/src — the README is terse and the docs predate Laravel's package-discovery conventions.
Read the source before the docs. With 24 stars and a 2015 release, src/ is the documentation. Look for the service provider (container bindings, config merge), the trait in src/Traits or similar, and the Blade helper/component registration. Ten minutes there saves an hour of guessing.
Attach the trait to your User model.
use Vinicius73\Lavatar\Traits\LavatarTrait;
class User extends Authenticatable
{
use LavatarTrait;
}
First use case: the profile fallback. The canonical integration is "show uploaded photo, else generated initials." Wire it once in Blade and use it everywhere:
<img src="{{ $user->profile_photo ?? lavatar($user->name) }}" alt="{{ $user->name }}">
Confirm the helper's exact signature (name vs. model instance) in the source; adapt the call site, not the template.
Where to look first: config/lavatar.php for palette/size/font settings, then the Blade registration in the service provider. That tells you the public API surface in two files.
Fallback chain in a single accessor. Don't scatter ?? logic through views. Wrap the package behind your own accessor so the template never knows which generator ran:
public function getAvatarUrlAttribute(): string
{
return $this->profile_photo
?? ($this->hasGravatar() ? $this->gravatarUrl() : lavatar($this->name));
}
This is also your escape hatch — when you eventually replace Lavatar, only this method changes.
Gravatar-then-Lavatar. The package's stated niche. Check for a real Gravatar response (or just assume it, since Gravatar returns a default image) and fall through to initials. Cache the Gravatar probe per email so you're not doing an HTTP round-trip on every page render.
Precompute, don't render on request. Image generation is CPU-bound and involves disk I/O. Generate at account creation via a model observer, or a queued job, and persist the path:
User::created(fn ($user) => GenerateAvatar::dispatch($user));
Then the accessor reads a column, not a generator. This is the single biggest performance decision you'll make with this package.
Deterministic colour per user. Rather than a random palette pick (avatars change colour between requests — users notice), seed off a stable value:
$color = config('lavatar.palette')[$user->id % count(config('lavatar.palette'))];
If the package doesn't expose a per-call colour argument, subclass it or override the container binding.
Blade isolation. Wrap output in your own component (<x-avatar :user="$user" />) rather than calling the package helper in 40 templates. You get one place to add loading="lazy", alt escaping, and width/height attributes.
Config in version control. Publish config/lavatar.php and commit it. Font paths, output disk, and image dimensions belong in your repo, not in vendor defaults that shift under you.
composer.json, or fork it into your org (repositories → vcs) and patch freely. Do not rely on upstream fixes; there won't be any.ImageManager instead of the Image facade). A composer constraint conflict here is the most likely install blocker — resolve by pinning Intervention Image to the old major if nothing else in the app needs it.php-gd compiled with FreeType, text rendering silently degrades to empty or broken images. Verify with php -r "print_r(gd_info());" and check FreeType Support. Imagick is an alternative driver if the config exposes it.base_path()/storage_path() or bundle the .ttf in your repo. A blank avatar in staging but not locally is usually this.substr() rather than mb_substr(), accented and CJK names produce mojibake or empty avatars. Test with José, Øyvind, and a CJK name. If it breaks, override the initials method rather than patching vendor.alt attribute. Blade helpers that return raw <img> markup are an XSS vector if the name flows into an unescaped attribute. Use {{ }} around anything user-supplied, or return only the URL and build the tag yourself.storage/app/public, you need php artisan storage:link. If you're behind a CDN or a non-standard ASSET_URL, asset() vs url() vs Storage::url() produce different results — pick one and verify it in production-shaped config.config('lavatar') return merged values? (2) is the container binding resolving? (3) is the output directory writable by the web user? (4) can GD load the font? php artisan tinker with a single call isolates all four faster than log-reading.vendor/ directly; you'll lose it on the next composer install.laravolt/avatar is the maintained spiritual successor with the same concept, and a ~30-line SVG initials generator is genuinely competitive for this use case — no GD dependency, infinitely scalable, cache-friendly. Keep the $user->avatar_url accessor signature identical and the swap costs you an afternoon.How can I help you explore Laravel packages today?