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.
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.
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.
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.
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.
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.
mermaidis a sizeable library, so the whole component is loaded via a dynamicimport()and only mounts once you scroll to the demo. None of its bytes ship on the lab index. - Theme. The render reads
data-theme(anddata-alien) off<html>and redraws through aMutationObserverwhen 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.