# My Pixel-Art Editor Workflow: Vue, Laravel, and AI

> Source: <https://promptcube3.com/en/threads/2330/>
> Published: 2026-07-23 13:45:34+00:00

# My Pixel-Art Editor Workflow: Vue, Laravel, and AI

I built Pixanima—a browser-based pixel art and animation tool—and the "secret sauce" for the AI sprites isn't the prompt; it's a PHP GD pipeline that forces the image into a grid. Here is the actual logic:

1. Generate a raw image (I use flux-schnell).

2. Area-downscale it to the target grid (e.g., 32x32).

3. Quantize colors via `imagetruecolortopalette`

with ordered dithering.

4. Run a tolerant corner flood-fill to kill the background and create transparency.

That's how you avoid "AI slop" and get something a developer can actually use in a game engine.

## The "Client-Side" Business Logic

The editor is built with Vue 3 and Laravel 12. Since the canvas and project files live in IndexedDB, the whole thing is client-side. Here is a reality check for solo devs: you can't effectively paywall a client-side feature without being a jerk to your users.

Because of this, the editor is free. The only thing I charge for is the AI, because that's the only part with a real marginal cost and a backend requirement.

## AI Inbetweening via FILM

The most useful feature I've implemented is AI inbetweening. Instead of drawing every single frame of a walk cycle, you provide two keyframes. I run Google's FILM frame-interpolation model on the PNGs, get an mp4 back, and use ffmpeg to slice it into stills. Each frame then hits the pixelization pipeline mentioned above. It turns a tedious chore into a few seconds of waiting.

## Bulletproof Credit System

When you're paying for API calls, you can't have a buggy ledger. I implemented an idempotent, charge-then-generate system. The user's balance is just a cache; the `credit_transactions`

table is the only source of truth.

Here is the simplified logic for the credit deduction to prevent double-charging:

``` php
DB::transaction(function () use ($userId, $cost, $reference) {
    $user = User::whereKey($userId)->lockForUpdate()->first();
    
    if ($user->credit_balance < $cost) {
        throw new InsufficientCreditsException();
    }

    // Ensure we haven't processed this specific request reference already
    if (CreditTransaction::where('reference', $reference)->exists()) {
        return; 
    }

    $user->decrement('credit_balance', $cost);
    
    CreditTransaction::create([
        'user_id' => $userId, 
        'amount' => -$cost, 
        'type' => 'spend', 
        'reference' => $reference
    ]);
});
```

This setup ensures that if a request fails or retries, the user isn't robbed of their credits. It's a basic AI workflow pattern, but it saves a massive amount of customer support headaches.

[Next NeoBox: Building a macOS NeoGeo Frontend with AI →](/en/threads/2312/)
