Build Gleek
A text-to-diagram editor whose hard problems are staying useful while the source is half-typed, keeping a hand-placed box where you put it after the text changes, and producing an export that still looks right in a program you did not write.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Builds and serves the application. Nothing runs server-side once it is built.
Get it nodejs.org, or your version manager. open ↗
Verify
node --version prints v22 or higher - have readyfree
Why The export embeds it in the file, which is a distribution of the font, and not every licence allows that.
Get it Pick an open licensed family and read its terms before embedding.
Verify
The licence text permits embedding and a copy sits in the repository - installfree
Why Browsers are forgiving about fonts in ways other renderers are not, and the export bug in this category only shows up elsewhere.
Get it A vector editor, a document previewer, anything that renders SVG independently.
Verify
An exported diagram opens in it with correct text - decidefree
Why Every later decision about layout, overrides and export follows from what the source text is allowed to say.
Get it Write the statements you want to type, then design the grammar that accepts exactly those.
Verify
Every statement in the documentation parses and is covered by a test
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- documents(id, title, source_text, format_version, created_at, updated_at, last_opened_at) · the source text is the document and everything else is a cache - revisions(document_id, ordinal, source_text, at) · a capped ring of previous sources, which is a cheaper undo than a command stack and survives a reload - nodes(doc_id, node_id, label, shape) · derived from the source by the parser, never edited directly - edges(doc_id, from_node, to_node, label, style) · likewise derived - overrides(doc_id, node_id, dx, dy, pinned) · manual nudges keyed on the node identifier, which is what lets them survive a re-parse - parse_errors(doc_id, line, column, message) · so a mistake points at a line rather than blanking the canvas - Nothing in this schema stores pixel coordinates as the truth. The layout computes them and the overrides adjust them, which means a diagram opened on a different screen is still the same diagram.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
VITE_APP_TITLE | optional | Diagrams | Shown in the tab. There are no secrets in this build because there is no server. |
VITE_AUTOSAVE_MS | required | 800 | Debounce before a save. Lower costs writes, higher costs your afternoon. |
VITE_REVISION_RING | required | 50 | How many previous sources are kept for undo across reloads. |
VITE_MAX_NODES | required | 300 | Above this the layout and the canvas both stop being pleasant, so warn rather than freeze. |
The build, in order
Text in, graph out, errors on a line
A small grammar parses to nodes and edges, and a half-typed line never blanks the canvas.
A grammar you can read is a grammar you can extend on a Tuesday.
Files
docs/grammar.mdsrc/parse/grammar.tsThe canvas flickering is what kills this kind of editor.
Files
src/state/document.tstests/parse-recovery.test.tsSomewhere is not a useful place for a mistake to be.
Files
src/parse/errors.ts
done when · tick each as it passeswatch out- Throwing away the graph on the first parse error means the diagram vanishes the moment you start typing a new line, which is every few seconds, and the flicker makes the tool unusable for exactly the keyboard-driven workflow that is its reason to exist. Keep the last successful parse rendered, overlay the error on the line it came from, and only replace the graph when a parse succeeds.
A layout that does not jump
The same graph always lays out the same way, and relabelling a box does not rearrange the diagram.
A layout that differs between runs makes every diff meaningless.
Files
src/layout/layered.tstests/deterministic.test.tsA label edit is a repaint, not a rearrangement.
Files
src/layout/cache.tsSo you can see what moved rather than finding it again.
Files
src/canvas/transition.ts
done when · tick each as it passeswatch out- Recomputing the layout on every keystroke means that adding a character to a label reshuffles the entire diagram, and since typing is continuous the picture is in permanent motion and you can never point at anything. Hash the structural part of the graph, recompute only when that hash changes, and treat a label edit as a repaint.
Nudges that survive the next edit
Dragging a box to where you want it keeps it there after the text changes.
Positional keys migrate to the wrong shape.
Files
src/state/overrides.tstests/overrides.test.tsThe layout still has to make sense for everything you did not touch.
Files
src/layout/apply.tsThis is a keyboard tool and the mouse is the afterthought.
Files
src/canvas/keyboard.ts
done when · tick each as it passeswatch out- Storing a nudge against the node's position in an array means inserting a line anywhere above it silently transfers that nudge to a different box, and the user watches an unrelated shape drift across the canvas with no idea why. Key the override on the node identifier from the parser, and drop overrides for identifiers that no longer exist.
An export that opens somewhere else
The exported SVG and PNG look like what was on screen, in programs that are not this one.
An exported SVG cannot go and fetch anything.
Files
src/export/svg.tstests/no-external-refs.test.tsOne rendering path means one set of bugs.
Files
src/export/png.tsIt is the version that will still open in ten years.
Files
src/export/source.ts
done when · tick each as it passeswatch out- An exported SVG that names a web font by family renders in whatever the viewer happens to have, because the SVG specification places a document referenced as an image into a secure processing mode where external references are not resolved at all, so the font never loads, the metrics change and every label overflows its box. Embed the font in the file as a data URI or convert text to paths, and check the export in a viewer that is not a browser tab you already had open.
Work that cannot be lostproduct builder
Autosave survives a reload, browser storage failing is handled, and nothing is trapped in this app.
The alternative is a migration you cannot write because you do not know what you wrote.
Files
src/store/schema.tsPrivate windows and full quotas are normal, not exotic.
Files
src/store/persist.tstests/storage-failure.test.tsThe way out has to be as easy as the way in.
Files
src/store/files.ts
done when · tick each as it passeswatch out- Assuming browser storage is always there means that in a private window, or with site data blocked, or when the quota is full, the autosave silently fails and the user loses an afternoon on a refresh with no warning at any point. Wrap every storage call, surface a failure as a banner offering an immediate download, and never let a save error be swallowed.
That is the whole plan for Gleek. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Multiplayer cursors and comments.
- High-fidelity import of other tools' formats.
- A large template library.
- Freeform shapes with the canvas as the source of truth.
- multiplayer cursors and comments
- large template libraries
- high-fidelity import and export
- presentation and enterprise controls
- A second layout direction, since left-to-right and top-to-bottom suit different diagrams and the graph does not change
- A print stylesheet that puts one diagram per page at a sensible scale, which is surprisingly often what people wanted
- A compact share format that encodes the source in a link, so a diagram travels without a file
Need the files? The project pack on the verdict page hands your agent the whole brief · more diagrams.