IS
All experiments
live

Mermaid Sketch — diagrams that look hand-drawn

You write text in the Mermaid language and a diagram appears next to it with wobbly, hand-drawn shapes. The presets were generated with GPT ahead of time; in the editor you can tweak the code and watch it redraw live.

lab note
Why I built it

I wanted diagrams that read like a napkin sketch rather than strict corporate BPMN — friendlier, and more honest about how precise they actually are. I also wanted to feel how plain text turns into a picture, and to wire that up to GPT generation.

What I learned

Since v11, Mermaid has a built-in look: handDrawn mode — it runs shapes through rough.js, and perfect rectangles turn wobbly. No separate library needed. And securityLevel: strict passes the final SVG through DOMPurify, so a public editor can safely take any input.

Where it broke

The first version called GPT straight from the browser on every render — money down the drain and an open door for abuse. I flipped it: there is no live GPT in production at all. Diagrams are generated ahead of time by a local script (scripts/mermaid-gen.mjs), stored as presets, and the page is a pure client-side render with zero network calls.

Stack
Mermaidrough.jsOpenAI

A sketch, not a blueprint

Mermaid is a language where a diagram is described in text: write A --> B, get an arrow from A to B. Handy, but by default the picture comes out sterile — even rectangles, perfect lines. That form subconsciously promises a precision a napkin sketch never has.

Since v11 Mermaid has a look: handDrawn mode: under the hood shapes are run through rough.js, and the lines get slightly shaky — as if drawn by hand. Below is a live editor. Hit the presets on top or edit the code on the left; the picture redraws itself.

live demo
Loading demo…

Where GPT comes in

I didn't hand-type the preset examples character by character — I dictated descriptions and turned them into Mermaid with GPT (the same token that powers my TIL-note generation). But the key point is where that happens:

The script is as simple as it gets: it takes a description as an argument, sends it to OpenAI with a system prompt of "return strictly valid Mermaid and nothing else", strips any ```mermaid fences, and prints the clean code to the console. Then I read it over and paste it in as a new preset.

node --env-file=.env.local scripts/mermaid-gen.mjs "signup funnel: request, review, email, done"

How the render works inside

Three details matter:

  • Laziness. mermaid is a sizeable library, so the whole component is loaded via a dynamic import() and only mounts once you scroll to the demo. None of its bytes ship on the lab index.
  • Theme. The render reads data-theme (and data-alien) off <html> and redraws through a MutationObserver when you switch — the sketch lives in the site's light, dark, and "alien" themes alike.
  • Errors. Before rendering, the code goes through mermaid.parse(); on broken syntax I show a tidy error but keep the last good picture on screen, so it doesn't flash empty on every typo.