DEV Community

yohan
yohan

Posted on Edited on Originally published at cnblogs.com

Essays — AI-Generated Blog Diagrams

Overview

I used to make diagrams with Mermaid: drop a code block into Markdown and a figure appears. That works fine, and AI is good at Mermaid.

But Mermaid only goes so far. For richer figures you need a drawing tool, and hand-drawing is expensive.

This post explores how to produce blog diagrams with AI.

Goals

  1. Describe a figure in text; AI draws it from that description.
  2. Stable output — not a surprise every run. The same brief should yield the same figure; changing one word should only change what it ought to.
  3. Local generation — no token burn.

Exploration

I found five approaches.

Rough.js

Idea. Rough.js is a hand-drawn style canvas library. With a handwritten font, rectangles and lines pick up jitter and look like a sketch.

Brief.

// x / w for each box is hand-computed
box(doc, 30,   60, 150, 130, 'gray',  'Power on',     ['kernel + init']);
box(doc, 227,  60, 195, 130, 'gray',  'Boot script',  ['/etc/init.d/codesyscontrol']);
box(doc, 469,  60, 225, 130, 'blue',  'Runtime',      ['codesyscontrol.bin']);
// two more boxes omitted
arrow(doc, 181, 125, 221, 125);
Enter fullscreen mode Exit fullscreen mode

Result:

Rough.js with hand-computed coordinates

Pros. Full control of layout; not limited by a layout engine.

The figures in this post use this method.

Rough.js + auto layout

Idea. Same drawing path, but coordinates are not hard-coded: measure text width, size the box, center the row.

Brief.

// content only — no positions or widths
flowRow(doc, [
  { tone: 'gray',   title: 'Power on',   sub: ['kernel + init'] },
  { tone: 'gray',   title: 'Boot script', sub: ['/etc/init.d/codesyscontrol'] },
  { tone: 'blue',   title: 'Runtime',    sub: ['codesyscontrol.bin'] },
  { tone: 'orange', title: 'Read boot app dir', sub: ['.app + .crc'] },
  { tone: 'green',  title: 'Verify & load', sub: ['enter cyclic tasks'] },
]);
Enter fullscreen mode Exit fullscreen mode

Result:

Auto-layout result

Pros. Edit copy without re-placing boxes. Overflow fails loudly instead of relying on eyeballing the PNG.

D2 --sketch

Idea. D2 is a diagram DSL. Nodes and edges go in text; the layout engine places them; --sketch adds hand-drawn jitter. Export SVG → PNG. Fonts and Chinese line-height are the usual pitfalls.

Brief.

direction: right

power:  "Power on\nkernel + init"        { shape: rectangle }
script: "Boot script\n/etc/init.d/\ncodesyscontrol" { shape: rectangle }
rt:     "Runtime\ncodesyscontrol.bin" { shape: rectangle }
// two more nodes omitted

power -> script -> rt -> read -> load
Enter fullscreen mode Exit fullscreen mode

Result:

D2 sketch

Pros. Best auto-layout of the five — a few lines of DSL and the structure is placed for you.

HTML/CSS + screenshot

Idea. Boxes as HTML, layout via CSS flex, then headless browser (Playwright) to PNG. Cost: you install a browser.

Brief.

<div class="flow">
  <div class="node" style="border-color:#495057;background:#f1f3f5">
    <div class="t">Power on</div>
    <div class="s">kernel + init</div>
  </div>
  <svg class="arrow">…</svg>
  <div class="node">…</div>
</div>

.flow { display: flex; align-items: center; gap: 6px; }
Enter fullscreen mode Exit fullscreen mode

Result:

HTML/CSS result

Pros. Web layout powers: wrapping, spacing, radii. Tweak styles in the browser.

Mermaid handDrawn

Idea. Mermaid’s built-in hand-drawn theme (look: handDrawn). Long Chinese labels often break the layout and need tuning.

Brief.

flowchart LR
  power["Power on<br/>kernel + init"]:::tgray
  script["Boot script<br/>/etc/init.d/<br/>codesyscontrol"]:::tgray
  rt["Runtime<br/>codesyscontrol.bin"]:::tblue
  power --> script --> rt
  classDef tgray fill:#f1f3f5,stroke:#495057
  classDef tblue fill:#e7f5ff,stroke:#1971c2

Result:

Mermaid handDrawn

Pros. Lowest friction — no install; a code block in Markdown is enough. AI knows it well.

The five differ mainly in who computes coordinates and how much style you can control. All are code-generated figures.

How I actually use it

In daily writing I stay in lazy mode.

  1. Write concept.md first: outline, section leads, and the idea chain in plain words.
  2. Let AI fill prose. Where a figure is needed, insert a figure brief: what to draw, layout, what to emphasize.
  3. Human review and edit.
  4. AI generates again and replaces the brief with the image.

Example brief:

Figure
- Content: full write→figure pipeline, 5 steps
- Layout: five boxes in a row, arrows between them
- Emphasis: the only human step — human review; width 1200px
Enter fullscreen mode Exit fullscreen mode

Full write-to-figure pipeline

While writing this section I literally typed the brief like this:

Screenshot of inserting a figure brief while writing

Then AI produced the figure above.

Sample output quality

A couple of local samples:

IoT technology stack

Axis state

Mermaid would struggle with figures like these. Dragging boxes in an online tool burns your fingers. Calling a large image model burns tokens and often “surprises” you on edits.

With a local pipeline the artifact is a file on disk: fix it by hand (re-render) or say what to change — the next run stays stable.

Integration

Treat figure generation as a skill, or fold it into Agents.md — whatever matches how you want the loop to run.

Attachment

Full code for all five methods:

five-methods.zip

I only just started on this path — better ideas welcome.

Top comments (0)