4 blog diagrams overflowed their card this week: how we stopped fixing it by hand
Back to the blog
Articleverboo codedev toolstutorialautomação

4 blog diagrams overflowed their card this week: how we stopped fixing it by hand

MafraSeptember 17, 20265 min read

The comment at the top of our diagram generator says why it exists: "AI-generated diagrams get text wrong and draw differently every call, so there's no guarantee the pt, en and zh versions are the same drawing." We swapped AI for code exactly to solve that. Except code has bugs too, and ours sat there, never fixed for good, for at least 6 days: four diagrams published this week shipped with a text note cut off past the card border, fixed by hand, the same way every time.

Why aren't the blog's diagrams generated by AI?

Because generative AI draws differently every call. Each article ships in three languages (pt, en, zh), and every version needs the exact same geometry, only the text changes. An AI image generator doesn't guarantee that: sometimes it swaps a color, sometimes it gets a word wrong, sometimes it draws an extra box on one side. The fix was to take the drawing out of AI's hands and put it in code: a Python script (render.py, using Pillow) reads a JSON spec file and draws the same structure in all three languages, changing only the strings.

How does the generator actually work?

Each diagram is a specs/<name>.json file, with a layout (fluxo, comparativo or capa_vs) and a locales key holding pt, en and zh inside. Text that never translates (a command, a flag, a variable name) lives at the root of the spec; whatever gets translated lives inside locales. Running it looks like this:

python3 render.py specs/diagram-name.json pt en zh

One PNG per language comes out in out/, same geometry, same colors, only the string changes.

What bug showed up at least 4 times in 6 days?

Every piece of text in the diagram was drawn with a direct call to d.text(), at a fixed position, with zero width checking. Each step's card has a width computed by dividing the available space by the number of steps; if that step's note was longer than that width, it just kept drawing past the card's edge. Nobody had noticed until the text got long enough, and it happened again, and again:

DatePostWhat overflowed
2026-09-12Codex burns tokens while it waits for younotes for steps 1 and 2
2026-09-16Verboo Code's free tokens ran outnotes for steps 1 and 2
2026-09-16Why Claude Code usage reset on its ownbranch label, cut off at the right edge
2026-09-17Response language in Verboo Codestep notes

In two of those rounds the log itself already said "same bug seen in earlier posts": the real number of times this happened is higher than these 4 rows, these are just the ones that got a date and a post tied to them in our execution log. The fix was always the same: open the note, eyeball the character count, shorten it, regenerate, and hope the English and Chinese versions also fit, because each language needs a different amount of text to say the same thing.

How did we fix it, so there isn't a fifth time?

Instead of trusting the eye, the generator now measures before it draws. A new function, ajusta(), uses d.textlength(), the same Pillow function that already centered the "vs" on the comparison-track covers, to know, in pixels, whether the text fits the available width. If it doesn't, a binary search finds the longest chunk of text that still fits and appends an ellipsis:

def ajusta(s_, fo, maxw):
    if maxw <= 0 or d.textlength(s_, font=fo) <= maxw * S:
        return s_
    lo, hi = 0, len(s_)
    while lo < hi:
        mid = (lo + hi + 1) // 2
        if d.textlength(s_[:mid].rstrip() + "…", font=fo) <= maxw * S:
            lo = mid
        else:
            hi = mid - 1
    return (s_[:lo].rstrip() + "…") if lo > 0 else "…"

Applied to the four spots that had overflowed at some point: each step's title and note, the error branch's label, and every line of the branch's notes. There's no more guessing how many characters fit per language: the code measures pt, en and zh, each with its own font, and each one decides on its own whether it needs to truncate.

Flowchart: write the spec, measure before drawing with d.textlength, render all 3 PNGs; the branch shows what happens when a note is longer than the card, cut off with an ellipsis
This very diagram's branch label ("note longer than the card?") didn't fit the available space in Portuguese, and got cut off on its own while generating that image. In English and Chinese, with very different character density, the same label fit whole. Live proof that the truncation decision can't be made once, for Portuguese, and reused for the other two languages.

What this doesn't fix: the text still sits on a single line and gets cut, it never wraps to a second line. A note that's too long loses information instead of taking up more vertical space on the card. It solves the real problem (text spilling past the card), it isn't the final version of a text-fitting system.

The same priority guides Verboo Code: measure instead of guess. Open-weight models running on dedicated GPUs, with unlimited tokens, so you can retry as many times as it takes until the result is right, instead of finding out mid-test that your quota ran out.

Enjoyed this article?
Share knowledge with your network.
// Read also

Related articles