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

Texture Renderer Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

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:

  1. README.md and src/ in the repo — the surface area is tiny; read every file rather than guessing from docs.
  2. The consuming app, blessing-skin-server — this is the only real reference implementation, and it is a Laravel app, so its usage is the pattern to copy.
  3. 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.

Implementation Patterns

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.

Gotchas and Tips

  • Verify the rendering backend before you plan deployment. Versions in this ecosystem have delegated rendering to an external Node toolchain as well as doing it in pure GD. If 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.
  • Validate uploads before they reach the renderer. Minecraft skins are 64×64 or the legacy 64×32, PNG, and depend on the alpha channel. Palette-indexed PNGs and images stripped of alpha render as garbage (transparent regions become black). Reject anything that isn't a PNG of the right dimensions, and cap file size — imagecreatefrompng on a hostile 20000×20000 file will exhaust memory. Set an explicit memory_limit on the queue worker.
  • No config to publish, no facade to alias. Anything you want to tune — backend path, timeout, temp directory — lives in your own config file and your own wrapper. Plan for that instead of hunting for a config/texture-renderer.php that does not exist.
  • Pin the version. "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.
  • Debug by writing intermediates to disk. When a render looks wrong, dump the input bytes and the output PNG side by side and compare against Blessing Skin's own output for the same skin. The failure is almost always the input (alpha, dimensions, format), not the renderer.
  • Extension point is the wrapper, not the library. If you need extra perspectives, legacy 64×32 support, or an isometric 3D view, add it in your 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/.
  • Treat render types as an allowlist, always. The library will happily attempt whatever string you hand it; the security and performance boundary belongs in your controller, not downstream.
  • Honest bottom line: for a general Laravel app this package buys you nothing — it solves exactly one problem, and only if you're building a Minecraft skin/avatar service. In that specific niche it saves you from writing a texture compositor, and the queue-plus-cache pattern above turns it into a solid, boring, fast feature. Outside that niche, don't add the dependency.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings