Custom engines
An engine is any class implementing Engines\EngineInterface:
public function generate(string $seed, ?string $name, int $size, array $options): ?string;
public function getContentType(): string;
generate()returns the avatar content (SVG markup, binary data, a data URI, or a URL), ornullto decline and let the fallback chain continue.getContentType()returns the MIME type of the produced content.
Implementing
Extend Engines\AbstractEngine to inherit the default image/svg+xml content
type and the fetchUrl() helper for remote sources.
use Renfordt\AvatarSmithy\Engines\AbstractEngine;
use Renfordt\AvatarSmithy\Support\Name;
class MonogramEngine extends AbstractEngine
{
public function generate(string $seed, ?string $name, int $size, array $options): ?string
{
$initials = Name::make($name ?? $seed)->getInitials();
if ($initials === '') {
return null; // decline; fallback chain continues
}
// ... build and return SVG markup
return $svg;
}
}
To produce a non-SVG type, set the $contentType property (or override
getContentType()):
protected string $contentType = 'image/png';
For a remote source, use the inherited helper, which applies a 5-second timeout, a single-redirect cap, and a 5 MiB response limit:
$content = $this->fetchUrl($url); // null on failure
Reading options
The $options array is the builder's option bag. Read the keys your engine
needs and validate types defensively, mirroring the built-in engines:
$shape = is_string($options['shape'] ?? null) ? $options['shape'] : 'circle';
Registration
Built-in engines are resolved by name in AvatarBuilder::createEngine(), a
match expression. To add a custom engine to the named-lookup mechanism, add a
case there:
protected function createEngine(string $engine): EngineInterface
{
return match (strtolower($engine)) {
'monogram' => new MonogramEngine(),
// ... existing engines
default => throw new RuntimeException("Unknown engine: {$engine}"),
};
}
The resolver is closed (a fixed match), so registering a name requires editing
this method. Without it, you can still drive a custom engine by calling its
generate() directly and wrapping the result in a GeneratedAvatar:
use Renfordt\AvatarSmithy\GeneratedAvatar;
$engine = new MonogramEngine();
$content = $engine->generate($seed, $name, 256, []);
$avatar = new GeneratedAvatar($content, $engine->getContentType(), $name, 256);
Determinism
Built-in local engines derive all randomness from the seed via Support\Name
(an MD5 hash). Follow the same approach so identical inputs produce identical
output.