Build Gleek

YESback to the verdict

0%0 of 16 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

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.

estimated effort one sittingthe files for this build are in the project pack

RuntimeReact with TypeScript and Vite, everything in the browser and no server at allSource of truthThe diagram is the text; the canvas is a view of itStorageIndexedDB holding a versioned document record, with autosave on a debounceLayoutA deterministic layered layout recomputed only when the graph structure changesExportSVG with the font embedded, and PNG rendered from that same SVG at a chosen scale

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. 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

  2. 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

  3. 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

  4. 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.

VariableNeededExampleWhere the value comes from
VITE_APP_TITLEoptionalDiagramsShown in the tab. There are no secrets in this build because there is no server.
VITE_AUTOSAVE_MSrequired800Debounce before a save. Lower costs writes, higher costs your afternoon.
VITE_REVISION_RINGrequired50How many previous sources are kept for undo across reloads.
VITE_MAX_NODESrequired300Above this the layout and the canvas both stop being pleasant, so warn rather than freeze.

The build, in order

  1. 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.

    1. A grammar you can read is a grammar you can extend on a Tuesday.

      Files docs/grammar.mdsrc/parse/grammar.ts

    2. The canvas flickering is what kills this kind of editor.

      Files src/state/document.tstests/parse-recovery.test.ts

    3. Somewhere is not a useful place for a mistake to be.

      Files src/parse/errors.ts

    done when · tick each as it passes
    watch 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.
  2. A layout that does not jump

    The same graph always lays out the same way, and relabelling a box does not rearrange the diagram.

    1. A layout that differs between runs makes every diff meaningless.

      Files src/layout/layered.tstests/deterministic.test.ts

    2. A label edit is a repaint, not a rearrangement.

      Files src/layout/cache.ts

    3. So you can see what moved rather than finding it again.

      Files src/canvas/transition.ts

    done when · tick each as it passes
    watch 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.
  3. Nudges that survive the next edit

    Dragging a box to where you want it keeps it there after the text changes.

    1. Positional keys migrate to the wrong shape.

      Files src/state/overrides.tstests/overrides.test.ts

    2. The layout still has to make sense for everything you did not touch.

      Files src/layout/apply.ts

    3. This is a keyboard tool and the mouse is the afterthought.

      Files src/canvas/keyboard.ts

    done when · tick each as it passes
    watch 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.
  4. An export that opens somewhere else

    The exported SVG and PNG look like what was on screen, in programs that are not this one.

    1. An exported SVG cannot go and fetch anything.

      Files src/export/svg.tstests/no-external-refs.test.ts

    2. One rendering path means one set of bugs.

      Files src/export/png.ts

    3. It is the version that will still open in ten years.

      Files src/export/source.ts

    done when · tick each as it passes
    watch 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.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more diagrams.