Inspiration
Art is the bottleneck for solo game developers. AI image tools should solve it, but they produce pictures, not assets — and a game asset has objective requirements a picture doesn't:
- the background must actually be transparent, or it can't be composited
- a tileset must actually tile, or seams show in-game
- asset #7 must match asset #1, or the game looks like a collage
There's also a newer problem. Valve rewrote Steam's AI disclosure rules in January 2026 into a two-tier system, and roughly 20% of 2025 releases used generative AI. Answering honestly means knowing, per asset, which model made it, from what prompt, and whether the file you shipped is the file that was generated. Almost no workflow can answer that at all.
Spriteblaze does both.
What it does
Define your art style once as a Style Bible — palette, perspective, line weight, mood. Every asset in the project inherits it, so consistency is a property of the project rather than something you retype.
Each generation runs a Genblaze AgentLoop: generate → evaluate → retry.
The evaluator runs deterministic Pillow checks — border transparency, subject
bounding box, palette adherence, edge tileability — and anything scoring below
0.85 is regenerated. Crucially, the evaluator's critique is threaded into the
next attempt's prompt via AgentContext.last_evaluation, so the retry is
corrective, not a blind re-roll.
Then it produces pipeline output, not loose files: a packed texture atlas
with Godot .tres and Unity import metadata, and a Steam-shaped AI
disclosure built from hash-verified manifests held immutable under B2 Object
Lock.
How we built it
We wrote a Genblaze provider adapter. Runware isn't among Genblaze's
thirteen shipped adapters. Rather than call it around the side of the SDK —
which would leave those generations outside the manifest, sink, and retry loop
— we implemented it as a first-class SyncProvider with a ModelRegistry
carrying real pricing and ProviderErrorCode mapping. Its assets are
indistinguishable from a native adapter's.
There is no database. Backblaze B2 is the entire persistence layer, doing seven distinct jobs: job store, project store, content-addressable asset store (dedup by SHA-256), manifest store under COMPLIANCE Object Lock, thumbnails, search index, and the serving layer via presigned URLs. Job state living in B2 is what removes the serverless timeout from the critical path — any function instance can serve any poll.
Challenges we ran into
A quality gate nothing could pass. Our framing check scored opaque pixel fraction against a 0.45 ideal. A humanoid sprite is tall and thin — even perfectly framed it covers ~30% of a square canvas. Every asset burned all four attempts while the loop climbed toward a ceiling it could never clear. Fixed by measuring the subject's bounding box instead.
Palette tolerance picked by vibes. A tolerance of 60 scored a genuinely on-palette sprite 0.333. We swept 40→160 and chose 110, which separates on-palette (0.920) from off-palette (0.004) without saturating.
Provenance that credited the wrong model. We read run.steps[-1] for
attribution — which is the background remover, not the generator. In a
product whose pitch is trustworthy provenance, that's the worst possible bug.
A provider that succeeded while storing nothing. NVIDIA writes inline
base64 to output_dir, defaulting to the working directory — and Genblaze's
sink refuses to transfer files outside temp. Generation succeeded, the transfer
failed, and the only signal was one log line. No hash, no manifest, nothing in
B2.
An SSRF we shipped and then caught. The outpaint endpoint fetched a caller-supplied URL server-side, from a public endpoint with network egress — cloud metadata and internal hosts were reachable. Now allowlisted to our own bucket, redirects refused, resolved IPs checked. 8/8 attack URLs rejected.
What we learned
Read the interface before the prose. Genblaze's README shows a 15-line quickstart; the installed package exports 104 symbols, including the entire agentic-evaluation subsystem this project rests on. And Genblaze's preflight warnings are unusually good — when Google's Imagen models 404'd, the error text itself named the workaround.
Every constant we guessed was wrong. Every constant we measured was right.
What's next
Reference-image locking across a full sprite sheet, seam-aware tileset generation, and an idle/walk/attack frame-set generator.
Built With
- agentloop
- backblaze-b2
- boto3
- genblaze
- gpt-image-1
- next.js
- nvidia-nim
- openai
- pillow
- python
- react
- runware
- s3
- typescript
- vercel
Log in or sign up for Devpost to join the conversation.