tldraw
Thinking and explaining on a canvas
An infinite drawing canvas for boxes, arrows and notes. Its files are plain JSON, so a diagram can be generated by a script and then dragged around by hand.
Most of what I build is a graph: a table feeding three tables, each feeding a campaign, with gates in between. Those are much easier to argue about as a picture than as a list of column names. tldraw is where that picture goes when it needs to be moved around, annotated, or shown to someone.
How I use it
Generated first, arranged by hand. I build the file from a small spec of nodes and edges, so the boxes and arrows are correct before I touch them, and then I drag things until the layout says what I mean. Generating gets the facts right. Hand arranging gets the emphasis right, and no automatic layout has ever picked the emphasis I wanted.
One diagram per question. A fifty node picture of an entire system is a wall, not an explanation. I draw the company level flow, then the person level flow, then the push path, as separate pictures. Each one answers one question and fits on a screen.
The same spec drives both formats. Node and edge definitions live in one file and can be rendered either as a text diagram for the repository or as a canvas. Which means switching between them is a choice about the audience, not a rebuild.
Text diagrams for the repo, canvas for the conversation. A text based diagram diffs in version control and rebuilds itself from live data. tldraw is the one I open when I am still deciding what the thing should be, or when I am walking someone through it and expect to be interrupted.
What I have learned the hard way
Text lives in a rich text field, not a plain one. The obvious plain text property still exists and is deprecated, so a file written with it loads as a diagram full of empty boxes. This was the single biggest cause of blank output when I started generating files, and it fails quietly rather than refusing to open.
The file validator rejects any key it does not recognise. Leave one debugging field on a shape while you are working and the whole file is invalid, not just that shape. Useful strictness, harsh the first time.
A file that parses is not a file that opens. The only check I trust is rendering the diagram to an image and looking at it. Valid JSON with the wrong shape records produces a perfectly well formed picture of nothing.
The palette is fixed, so brand colours do not survive. A colour that is not in the set is silently mapped to the nearest one it has, which is fine for thinking and wrong for anything that is supposed to match a design.
Resources
This is one part of a stack. The rest is on the tools page, and what I build with it is on work.