ADR-007: AI draws figures, code cuts and finishes them
Who is this for
Section titled “Who is this for”Developers — read this before moving any image processing step into a prompt, or any prompt step into code.
- Production uses
STICKER_RENDER_MODE=figure: the model draws whole bust figures on flat green; code does the rest. - The first design,
composite(AI heads placed on pre-drawn bodies), stays as the default in code and as the automatic fallback when a figure sheet cannot be made valid. - Status: accepted. Brand and art style are prompt content, not architecture.
Context
Section titled “Context”The first version generated only a sheet of heads and composed each head onto a body template with Pillow. That was predictable but stiff: one body pose per template, and a visible seam at the neck. Letting the model draw the whole figure gives natural poses and gestures, but image models do not reliably respect a grid, a figure count or a clean edge. Whatever the model draws, Telegram needs 12 transparent 512-pixel images of bounded size.
Decision
Section titled “Decision”- The model’s job is narrow: draw N figures in a given grid on
#00FF00, with no outline, shadow, text or emoji. A layout-guide image and a strict layout block in the prompt keep it to the grid (bot/services/ai_pipeline.py). - Everything after that is code in
bot/services/sticker_builder.py: chroma key, cutting cell by cell, splitting figures that were drawn touching, rejecting the wrong grid or a duplicate, despill, the white die-cut outline, fitting to 512×512 and export under Telegram’s size limit. - An invalid sheet is regenerated up to
FIGURE_SHEET_ATTEMPTStimes. If it never becomes valid, the same job is rebuilt in composite mode (FIGURE_FALLBACK_ENABLED), the guest still gets a pack, and the admin gets an information message. Provider unavailability is not a reason for this fallback. - Cutting moved to OpenCV for speed, with a test that pins the result bit for bit to the previous implementation.
Alternatives considered
Section titled “Alternatives considered”| Alternative | Why not |
|---|---|
| Ask the model for 12 separate images | Twelve times the image cost and no shared context between stickers. |
| Ask the model for transparent PNGs with outlines | Unreliable; outline thickness and edges varied from sticker to sticker. |
| Background removal by a segmentation model | A heavy dependency; a flat chroma colour is cheaper and deterministic. |
Consequences
Section titled “Consequences”- Sheet validity rules are code and have tests; new defects found in live runs become new detectors (edge contact, torso-only crop, wrong grid, flat side cut).
- Each attempt of each sheet is saved to a debug folder with a JSON description, under the same 72-hour lifetime as the selfie.
- Green must not appear in outfits: the catalogue texts forbid green shades.
STICKER_RENDER_MODEset to an empty or misspelt value is a start-up error; a missing key meanscomposite.
Evidence
Section titled “Evidence”CLAUDE.md, hard rules 6 and 7;HANDOFF.md, “Render mode figure” and “Known pitfalls”.- Commits
d8b3b7c,5134406,4cf150b,6ef2e1e.
Where to go next
Section titled “Where to go next”Last verified: 2026-11-13 against ai-sticker-pack@b715418 and ai-stickers-landing@e350ff5.