Any SVG, an editable diagram.

A drawing opens in draw.io as one flat picture. accent-draw opens it as a diagram: every box a box, every label inside the box it belongs to, every arrow glued to the two shapes it joins. Drop a file below and edit what comes out.

$

accent-draw board.svg board.drawio

The pipeline

Five stages, and each knows only its own job

Drawing a picture is easy; recovering the diagram is the work. An SVG says "a rectangle here, some text there, a path with an arrowhead". draw.io wants "this box, labelled so, with an arrow from it to that box". Nothing in a generic SVG says which text belongs to which box, so it has to be worked out -- in one stage, which can be tested on its own.

-

recogniseSources that name their own parts are read by those names: Miro, Mermaid, Graphviz, PlantUML, D2, Excalidraw, Inkscape. An SVG already carrying a draw.io diagram is handed straight back.

-

parseEverything a profile did not name is read as an SVG: the style cascade, full transforms, viewBox and nested svg, use and defs, units. Rectangles stay rectangles and arrowheads stay arrowheads.

-

sceneShapes, text, connectors, frames and groups, as plain data with no draw.io in it. Every sample in the corpus is checked against the scene's own invariants.

-

layoutWhat the source did not say: which text is a box's label, which shape is a frame around others, which two shapes an arrow joins. It fills gaps and never overwrites what a reader already knew.

-

emitThe scene as an mxGraphModel, with stable ids and fixed number formatting, so two runs of the same input give the same bytes and a change shows up as a diff worth reading.

Measured

Four numbers behind the claims above

Each is taken from this repository rather than rounded up for a landing page: the profiles that exist, the tests that run on every change, the size of the file your browser fetches, and what the page uploads.

What you get

What the conversion actually promises

A short list, because each item is something the code is arranged around rather than something it happens to do.

Boxes keep their labels, arrows keep their boxes

Move a box in draw.io and its label moves with it, because the label is the cell's own and not a separate text box parked on top. Its arrows follow, because every bound edge is emitted with fixed exitX/exitY and entryX/entryY - without them draw.io reroutes the edge and throws its real geometry away.

Eight sources read by name

Where a source labels its own parts, reading beats guessing. A Miro board is read widget by widget, a Mermaid flowchart and a Graphviz drawing by the names they write on their nodes and edges, an Excalidraw file from the scene it carries rather than from its sketch. What a profile does not name, the picture reader still draws around it.

Nothing is dropped in silence

A filter, a mask or a pattern that cannot become a native cell becomes an image holding that fragment, and every one of those is listed as a note returned with the diagram. An SVG with nothing recognisable in it is an error, never an empty diagram that looks like success.

The second trip is lossless

The first conversion is an approximation and always will be. But an SVG that already carries a draw.io diagram - what draw.io's own .drawio.svg export is - is not converted from its picture: the diagram inside it is handed back as it is, compressed or not. Every roundtrip after the first is exact.

It runs where you are

The library has no filesystem, clock, randomness or threads in it, which is what lets the same code be a command for a shell script and a WebAssembly module in a page. The demo on this site is the second one: the converter is fetched once and your file never leaves the tab.

The same bytes every time

Cell ids are stable and numbers are formatted one way, so converting the same SVG twice gives the same file and a diff means something. The browser and the command line are held to it too: the corpus is converted through both on every change and compared byte for byte.

A Miro export hands the structure over for free: one group per board item, each tagged with the item's own id. That is why a reader for Miro can be precise, and exactly why it does not generalise. Fed a plain SVG -- a rectangle, a circle, some text -- the Miro reader in this repository wrote an empty diagram and exited successfully.

Everything the tagged formats give away has to be inferred for the rest: which of several overlapping shapes is the box and which is its border, whether an unfilled outline is artwork or a container, which of two nearby boxes an arrow means to touch when its stroked path stops short of its own arrowhead. Those inferences are where the bugs live, so they are kept in one stage, with every threshold scaled by font size or stroke width rather than fixed in pixels, and checked against a corpus of real exports rather than against markup written to pass.

The other half of the work is draw.io itself, which has opinions. A <b> tag in

a label silently kills the label's colour. A bound edge without fixed connection

points is rerouted and its geometry discarded. Labels centre unless told

otherwise, and carry two units of padding on every side unless told otherwise

again. None of that is visible in the XML; all of it is visible in a render,

which is why every change here is judged by putting the source SVG and the

exported diagram side by side.

Try it on your own drawing

Nine samples are loaded and ready - one per source it reads, and two that name nothing at all - or drop a file of your own. The converter runs in the page; nothing is uploaded.