Advisory 03 — transparency is a post-process, not a generation parameter
To: docade · From: WootBuild · Date: 2026-08-18 Status: open — docade decides Trigger: calibration run r-20260818-42e1 returned three opaque PNGs against a spec that requires a cutout.
Advisories are recommendations. docade owns the product and decides. What WootBuild owes you here is the price of each option, not a preference dressed as a constraint.
The finding
Six of your ten lanes — plush, prize, lyle, ui-art, world, crane — declare transparent: true in collectible-512 and scene-512. Two more (glyph, avatar) declare it on SVG specs, where it is free and fine.
No image model WootBuild can route to produces a transparent raster background. Verified 2026-08-18 against each endpoint's own OpenAPI schema, not inferred:
| Endpoint | Transparency parameter |
|---|---|
fal-ai/flux-2 (dev) | none |
fal-ai/flux-2-pro | none |
fal-ai/flux-2-flex | none |
fal-ai/flux-2-max/edit | none |
fal-ai/ideogram-v4 | none |
fal-ai/gpt-image-2 (+ /edit) | none |
| Gemini image family | none |
fal-ai/recraft/v4/text-to-image | background_color — sets a colour, not alpha |
WootBuild's router previously claimed otherwise. That flag was wrong, was never verified, and is now corrected — a transparent raster request fails loudly rather than routing to a model that cannot do it.
This also blocks something you already designed. Your derived.silhouettes entry produces the 18 uncollected-state silhouettes by alpha-flatten — a deterministic transform of an alpha channel. No alpha, no silhouettes, and that was the one batch costing zero art budget.
What it costs to change
A. Cut out in normalize — recommended
Generate on a known flat ground the prompt controls, then remove it programmatically in the normalize step (sharp, already a dependency).
- Per-asset cost: $0.
- Build cost: small — one normalize stage, plus a QA check that the cutout actually has alpha and no halo.
- Risk: plush is the hard case. Soft fabric edges and fine fibres are exactly where naive chroma-key leaves a halo or eats the silhouette. Your principle 2 (separation without a rim) makes halos especially visible on
#262c4a. - Verdict: right default. Cheap, reversible, no new vendor.
B. Route a matting model as a second pass
A dedicated background-removal endpoint after generation. These slugs resolve live on fal today (verified 2026-08-18; pricing not yet checked): fal-ai/birefnet, fal-ai/birefnet/v2, fal-ai/bria/background/remove, fal-ai/imageutils/rembg, fal-ai/ben/v2/image.
- Per-asset cost: one extra call per image. Cheap per unit, but it is a cost that scales with all 204 pieces, unlike A.
- Build cost: a new
mattecapability in the router plus an adapter. - Risk: low quality risk — this is what these models are for, and they handle soft fur/fabric edges far better than a threshold. Adds a vendor dependency to every collectible asset.
- Verdict: the fallback for whatever A cannot cleanly cut. Probably needed for plush specifically.
A and B compose. Try A first per asset, fall back to B when the mechanical alpha check fails. That keeps the common case free.
C. Ship opaque on #262c4a
- Per-asset cost: $0. Build cost: $0.
- What it costs you instead: collectibles can no longer sit on any other ground. That kills the prize gradients (
#7c5cff → #4ac8ff), which are the one saturated ground in the product, and it kills the derived silhouettes. It also bakes a background decision into 204 files, so changing--raisedlater becomes a re-render of the whole catalog rather than a token edit. - Verdict: cheapest today, most expensive later. Not recommended, but it is a legitimate choice if you want art on screen this month.
D. Move the collectible register to vector
recraft-v4-svg produces true SVG, where transparency is free.
- Verdict: wrong register. Your form language is soft-bodied plush with a shading pass; that is not what the vector model is for. Keep vector for
glyphandavatar, where it already is.
What WootBuild recommends
A, with B as the fallback for plush, and no change to your manifest or your specs. transparent: true stays the correct declaration — it describes what the asset must be, and it is now WootBuild's job to satisfy it in normalize rather than pretend a model does it.
What we need from you
Nothing blocking. This is WootBuild's problem to build. It is written down because it changes the delivery date on six lanes, and because it turned one of your zero-cost batches (the silhouettes) into a dependency.
One question, when convenient: are the 18 silhouettes still wanted as a derived alpha transform, or has the uncollected state moved on since 14-ASSET-MANIFEST.md §5 was written? If they are still wanted, that raises the priority of getting a genuinely clean cutout rather than a passable one.