
August 28, 20268 min read
The project page said one provider and no characters. Three weeks and forty-eight releases later, we had to go fix both sentences.
Writing this post started with opening our own CHANGELOG.md, which we hadn’t actually done in a few weeks. Two claims on the Pixelkiln project page turned out to be wrong before we’d gotten through the first page of it. “One provider today. PixelLab is the only backend actually implemented right now.” Wrong since the second week of September. “Animated, multi-direction characters are explicitly out of scope.” Wrong since the middle of this month.
The last post was about the account audit that found three bugs in the tool by actually using it. Since then, Pixelkiln went from 0.1.0 to 0.48.0, sixty-one releases in about three weeks, and the shape of the tool changed more than any single release note suggests. This is the part of that changelog that actually mattered, not a version-by-version recap.
At launch, the manifest-and-lockfile model was provider-agnostic by design, but PixelLab was the only thing actually plugged into it. The project page said as much, and named Retro Diffusion as the next real candidate for a second backend.
That seam got used, more than once. Multi-provider image generation landed first, then a self-hosted ComfyUI provider, then Scenario (hosted third-party models, tested against BFL Flux 2 Dev), and Retro Diffusion itself went in as an adapter alongside them. PixelLab is still the default and still the only one rated production-ready; the other three are marked experimental in the project’s own provider comparison doc, each billed in a different unit:
| Provider | Status | Cost unit |
|---|---|---|
| PixelLab | Production | generations |
| Retro Diffusion | Experimental | USD |
| Scenario | Experimental | compute units |
| ComfyUI (self-hosted) | Experimental | free, no metered charge Pixelkiln can see |
That last row matters more than it looks. Pixelkiln never adds a generations count, a dollar figure, and a compute-unit total into one number, because they aren’t the same kind of thing. A mixed run takes a separate budget ceiling per provider:
pixelkiln plan
pixelkiln gen \
--budget pixellab=12 \
--budget scenario=60 \
--budget comfyui=0which is what makes it reasonable to send a prompt-sensitive building through PixelLab, a background through Retro Diffusion, and a private model experiment through a local ComfyUI graph, all from the same manifest, without any of those budgets bleeding into each other.
The original contact sheet was intentionally minimal: a page you look at for a few seconds, pick a candidate, and close. That’s still true for picking. But a read-only gallery of every generation shipped in September, and within days it stopped being read-only: editing a style’s prompt prefix, suffix, and palette with the blast radius shown before you commit to it, generating and reviewing straight from the page under a budget, restoring or regenerating orphaned and untracked records, comparing two records side by side.
Then it went further than a review UI usually goes. Pixelkiln now installs and serves a pinned build of Pixelorama, the open-source pixel art editor, directly from the gallery. You can open a generated sprite in a real editor in your browser, paint over it, save the result back as a tracked hand edit, and reopen the same layered file later. ComfyUI’s ordered frame sets open as Pixelorama frames. A “compare with generated” reference layer keeps the original AI output visible underneath while you touch it up.
None of that needed new plumbing for the hard part. plan already compared a file’s hash against the lockfile and reported it orphaned when someone hand-edited a PNG outside the tool. The editor bridge runs on that same contract, just reachable from inside the gallery now instead of only from a hex diff.
The README still says, as of this writing: “Animated, multi-direction characters are explicitly out of scope. PixelLab models those as a fundamentally different kind of object… and a mature, purpose-built importer already exists elsewhere for that.” That line was accurate for the first three weeks of the project’s life.
Then character generation shipped as a managed asset type: bases, states, and animations, tracked the same way an icon or a badge is tracked. The follow-on releases filled it in fast, mostly in the same week: proportions, guidance, isometric mode, and reference sprites for bases; pose frames, subject and style hints, prompt enhancement, and a palette for animation loops; concept images and style anchors for the higher-tier bases; a pro-flash engine option for bases.
A character was never going to be one generation, so most of the real work was the dependency graph rather than the art: a base has to exist before a state can be generated from it, and a state before an animation. gen now runs that whole chain, base through animation, in one invocation under one shared budget, instead of three manual steps. adopt was extended to bring characters already sitting on the account under the manifest, the same reconciliation idea from launch applied to a completely different PixelLab object type. A mirrored asset, a loop flipped to face the other direction, comes back free, since it’s a horizontal flip rather than a new generation.
The pricing is real and it isn’t flat: per the same provider doc, a standard character base costs 1 generation, a v3 base 2 to 9, a pro base 20 to 40; a state costs 20 to 40 regardless of tier; an animation ranges from 1 (a template, or a 64px loop generated from text) up to 40 for the pro engine. That range is the reason plan had to learn to talk about characters explicitly, rather than letting them quietly ride on the cost model built for single objects.
Literally today: the submit-time cost estimate now gets reconciled against what PixelLab actually billed. The gap was real. A live run this week estimated a 64px character state at 40 generations; the balance actually moved by about 22. poll now reads the provider’s reported usage once a job completes and records it as billed, alongside the original estimate, so plan, history, and the gallery can show both numbers whenever they differ. It’s the same instinct as everything else in this project: measured, not assumed, applied one more time to the thing that tells you how much money you’re about to spend.
The release automation from the last post’s open items shipped right at public launch: semantic-release, a GitHub Actions workflow, npm’s OIDC trusted publishing, no long-lived tokens. Forty-eight correctly-versioned releases in three weeks, several days with more than one, is what “it worked” looks like in practice: nobody hand-bumped a version number the entire time. The same pipeline is what caught and enforced the quieter change of requiring Node.js 22 or newer, once the LTS schedule made that the responsible default.
Pixelkiln is public and on npm now, MIT licensed, with a small marketing site if you want to look before installing anything. But the provider work is explicitly unfinished: ComfyUI‘s pose-to-frame workflow needs a live, pinned benchmark before it’s more than infrastructure; Retro Diffusion‘s multi-candidate, tileset, GIF, and spritesheet paths are mock-tested but haven’t run a real paid job yet; Scenario needs a benchmark against the same briefs as the other three before it’s actually comparable to them. Midjourney is still not a target; it has no public API, and every wrapper that exists automates its Discord client against Midjourney’s own terms of service.
If you’ve had to pick between a hosted provider and something you can point at your own GPU for the same asset pipeline, I’d be curious what that tradeoff looked like on your end.
Discussion
Comments are powered by Disqus. Sign in once, comment anywhere.
