blessing/texture-renderer
A PHP package for rendering Minecraft skin textures into 3D previews. Part of the Blessing Skin ecosystem, it turns uploaded skin and cape images into displayable renders, letting you generate character previews for profiles, user panels, and skin galleries with minimal setup.
blessing/texture-renderer is a small Composer library from the Blessing Skin ecosystem that turns a Minecraft skin/cape PNG into a rendered preview (head, front, back, side, etc.). Treat it as a utility library, not a Laravel package — there is no service provider, no facade, no publishable config, and no migrations. Your integration work is entirely on you, which is the single most important thing to know before adopting it.
Minimal path:
composer require blessing/texture-renderer
Check ext-gd (and, depending on the version, whether the renderer shells out to Node — see Gotchas) before you assume it will work in your container.
Where to look first, in order:
README.md and src/ in the repo — the surface area is tiny; read every file rather than guessing from docs.composer.json for the exact PHP/GD/Node constraints.First use case — the one you will actually ship first: generate a head avatar from an uploaded 64×64 skin.
// Namespace/signature: confirm against src/ — this package is small and under-documented.
use Blessing\TextureRenderer\Renderer;
$png = (new Renderer())->render($skinBytes, 'head', 128);
return response($png)->header('Content-Type', 'image/png');
If that produces a sane 128×128 head shot, you have validated the whole dependency. Do that smoke test on day one.
Wrap it in a service, don't call it from controllers. The renderer is stateless and cheap to instantiate, but you want one place to change when the API shifts (it will — 4 stars, 0 dependents means near-zero API stability guarantee).
final class SkinPreview
{
public function render(string $bytes, string $view, int $size): string
{
return (new Renderer())->render($bytes, $view, $size);
}
}
Cache aggressively — this is the whole game. Rendering is CPU-bound image manipulation, so never do it in a hot request path without a cache. Key on content, not on user, so identical uploads share work:
$key = 'render:' . sha1($skinBytes) . ":{$view}:{$size}";
return Cache::rememberForever($key, fn () => $this->render(...));
For bytes rather than DB rows, write to disk and let the web server or CDN serve them:
$path = "renders/" . sha1($skinBytes) . "/{$view}-{$size}.png";
Storage::disk('public')->put($path, $this->render(...));
Pre-render on upload in a queued job. When a user uploads a skin, dispatch a job that renders the handful of sizes/views your UI actually uses (head 32/64/128, body 256, …) and writes them to storage. Then your avatar route is a redirect to a static file — no PHP in the image path at all.
// app/Jobs/RenderSkinPreviews.php
foreach (['head' => 128, 'front' => 256, 'back' => 256] as $view => $size) {
// ...
}
Route shape. Mirror Blessing Skin's convention, which keeps the URL cache-friendly and the controller trivial:
Route::get('/avatar/{hash}/{view}/{size}.png', AvatarController::class)
->whereIn('view', ['head', 'front', 'back', 'left', 'right'])
->whereNumber('size');
Whitelist view in the route (or a validation rule) rather than passing user input straight through — see Gotchas.
Invalidate on update. Store the texture hash alongside the skin record and key your cache on it. A re-upload produces a new hash, so stale previews expire naturally; no manual busting.
node is required, your PHP-FPM image is not enough and you'll discover this in production. grep -r node src/ is thirty seconds well spent.imagecreatefrompng on a hostile 20000×20000 file will exhaust memory. Set an explicit memory_limit on the queue worker.config/texture-renderer.php that does not exist."blessing/texture-renderer": "1.x" with a committed lockfile. With 4 stars and zero dependents, you are the de facto QA. Read the diff before every composer update.SkinPreview service — either by post-processing the package's output with GD or by dropping in a different renderer behind the same interface. Do not patch vendor/.How can I help you explore Laravel packages today?