Build EdrawMax
KINDAback to the verdict
A browser diagram editor whose hard problems are never being the only copy of your own document, connectors that stay attached to shapes through every move, and an undo stack that is provably complete rather than mostly complete.
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 Runs the development server, the build and the test suite.
Get it nodejs.org or your version manager. open ↗
Verify
node --version prints v22 or higher - have readyfree
Why The persistence design exists because these behave differently, and testing in only one of them guarantees you ship the fallback untested.
Get it Any two current browsers from different engine families.
Verify
Save and reopen work in both, by the intended path in each - decidefree
Why This is the decision the whole build hangs on, and making it implicitly means making it wrong.
Get it Write down that the cache covers unsaved changes since the last file write and nothing else. open ↗
Verify
The statement appears in the README and a test clears storage and loses nothing saved - have readyfree
Why Connector routing and text sizing only misbehave on real content, and a demo of four boxes will never show you the problem.
Get it Rebuild an architecture or process diagram you actually use.
Verify
It renders, exports and reopens with labels intact
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- the document file: format_version, pages, shapes, connectors, styles · one JSON object, readable without the editor - pages(id, name, ordinal, width, height, grid) · a document is pages, and a single page is a document with one - shapes(id, page_id, kind, x, y, w, h, rotation, style_ref, text, ports_json) · ports are named points, because connectors attach to names rather than coordinates - connectors(id, page_id, from_shape, from_port, to_shape, to_port, waypoints_json, routing, style_ref) · never two absolute points - styles(id, name, declarations_json) · named, so changing the look of every process box is one edit - file_state(handle_ref, last_written_at, last_written_hash, dirty) · surfaced in the interface rather than living in a variable - commands: an in-memory stack of do and undo pairs; nothing in the application mutates a document outside one.
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 |
|---|---|---|---|
CACHE_DB_NAME | required | diagram-cache | The indexed database used for crash recovery only. Evictable by design. |
SAVE_PROMPT_SECONDS | required | 120 | How long a new document may go without a file before the editor insists. |
STALE_SAVE_WARN_MINUTES | required | 10 | After this long without a file write, the indicator changes state visibly. |
TARGET_SHAPE_COUNT | required | 500 | The size the performance test generates and the README promises. |
EXPORT_SCALE_DEFAULT | required | 2 | Default raster scale. The dialogue shows resulting pixel dimensions. |
The build, in order
A file on disk within the first minute
Every document has somewhere real to live and the interface says when it last got there.
One of them can be evicted and it is not the file.
Files
src/persist/file.tssrc/persist/cache.tsThe number that tells you whether your work exists.
Files
src/ui/SaveState.tsxNever resolve somebody else's conflict for them.
Files
src/persist/reconcile.tstests/reconcile.test.ts
done when · tick each as it passeswatch out- Treating the indexed database as the document store gives you a fast first version and a support request in six weeks from somebody whose month-old diagram is gone, because script-writable storage is evictable under published rules and the user did nothing wrong. Write to a file the user chose, keep the cache for crash recovery only, and make the last-written-to-file time something on screen rather than something in a console log.
- When the cache and the file disagree after a crash, silently preferring one of them loses the other, and whichever you pick will be the wrong one for somebody. Store a hash of what you last wrote, detect the divergence on open, and offer both copies with their times rather than resolving it for the user.
Connectors that stay attached
Moving a box moves everything joined to it, and manual bends survive.
The identifier survives the move; the coordinate does not.
Files
src/model/connectors.tstests/connectors.test.tsSo a small move does not erase somebody's work.
Files
src/routing/waypoints.tsRun it in the suite after every mutating operation.
Files
src/model/validate.tstests/validate.test.ts
done when · tick each as it passeswatch out- Storing a connector as two absolute points takes five minutes and detaches the first time anybody moves a box, which is the single thing that makes a diagram tool feel broken; re-routing from scratch on every move instead throws away the bends somebody spent ten minutes placing. Anchor to shape and port, keep waypoints relative to the anchors, and drop a waypoint only when it has become impossible, saying so rather than silently straightening the line.
Undo that is provably complete
Any sequence of operations, fully undone, returns the document exactly as it was.
And assert in a test that none is missing one.
Files
src/history/commands.tstests/inverses.test.tsIt is the cheapest way to find the operation you forgot.
Files
tests/undo-property.test.tsUndo that loses your selection makes you check what happened.
Files
src/history/stack.ts
done when · tick each as it passeswatch out- Undo by snapshotting the whole document is correct and becomes unusable on a large diagram because every keystroke copies it, while undo written per operation is fast and is wrong in exactly the one operation somebody forgot to cover, which you will find after a user has lost an hour. Make every mutation go through a command with an inverse, assert in a test that every registered command type has one, and let a property test over random sequences find the gap instead of a user.
An export you can reopen
The SVG that goes to a colleague carries the document that made it.
The picture and the document should be one file.
Files
src/export/svg.tstests/export-roundtrip.test.tsBoth consequences, in words, at the moment of choosing.
Files
src/ui/ExportDialog.tsxNobody wants to guess what scale four means.
Files
src/export/raster.ts
done when · tick each as it passeswatch out- An SVG whose text elements name a font renders with overlapping labels on any machine that lacks it, and converting text to outlines fixes the picture while making the words unselectable and the file much larger. This is a trade-off rather than a bug, so put it in the export dialogue with both consequences written out, and embed the source document so the editable version travels with whichever picture was chosen.
Many diagrams, and a canvas that stays usableproduct builder
A folder of documents opens quickly and a large diagram still responds.
The claimed limit should be a test, not an impression.
Files
tests/perf/large-doc.test.tsscripts/generate-doc.tsDragging should not walk the document.
Files
src/canvas/hittest.tsOne bad file should not abort forty good ones.
Files
src/export/bulk.ts
done when · tick each as it passeswatch out- A canvas that is comfortable at fifty shapes and unusable at five hundred is the usual outcome, because everything re-renders on every pointer move and hit testing walks the whole document each time. Generate a document at the size you claim to support, measure the frame time while dragging, index shapes spatially for hit testing, and treat the number in the README as a promise a test checks rather than a hope.
That is the whole plan for EdrawMax. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Multiplayer cursors and comments.
- Import from proprietary diagram formats.
- A large template and shape library.
- Presentation mode and slide export.
- large template libraries
- high-fidelity import and export
- presentation and enterprise controls
- multiplayer cursors and comments
- Automatic layout for a graph you paste in, which is a solved algorithm and a large quality jump
- A text format for the document that reads well in a diff, so diagrams can live beside code
- Shape libraries loaded from a file, once the document format has stopped changing
Need the files? The project pack on the verdict page hands your agent the whole brief · more diagrams.