Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 172 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,185 @@
# Graph Explorer

https://graph-explorer.net
Explore and edit Graphviz (DOT) and Mermaid diagrams.

Explore graphs visually.
- **Website:** <https://graph-explorer.net>
- **Web app:** <https://graph-explorer.net/app>
- **Downloads:** [latest release](https://github.com/jpablo/graph-explorer/releases/latest)

## Shareable URLs
![The Graph Explorer window, with a DOT diagram, the attribute toolbar, and the DOT source](site/img/window-dot.webp)

Graph Explorer can load a diagram directly from the URL query string.
Graph Explorer shows DOT and Mermaid text as a diagram that you can work on.
Select a node to change its style. Hide the parts that you do not need. Drag
from a node to add an arrow. Each edit also changes the source text.

- Parameter: `dot=<urlencoded DOT text>`
- Example: `https://<host>/diagrams/<projectId>?dot=<encodeURIComponent(dot)>`
- Behavior on open:
- If any existing project’s persisted source exactly matches `dot`, that project opens.
- Otherwise, a new project is created and initialized with `dot`.
Graph Explorer has three parts:

Create a link from the UI:
- Toolbar link icon (top‑right)
- Commands palette entry: “Share URL”
- **The desktop app** for macOS, Windows, and Linux. It follows your diagram
files: when a file changes on disk, the diagram changes on the screen.
- **`gx`**, a command-line tool. It reads and edits diagram files, and it tells
the desktop app what to show. Coding agents can use it.
- **The web app** at <https://graph-explorer.net/app>. It needs no install.

Notes:
- The `dot` parameter uses `encodeURIComponent`. Very large diagrams may produce long URLs; a compact format may be added later.
## Features

## Planed features
- Add support for Mermaid diagrams
- Improve performance
- I18n
- More precise DOT support
- Keyboard navigation
- Cloud storage
- User defined themes
- Documentation
- More examples
- **Large graphs.** Show or hide the nodes before or after the selection, one
layer at a time or all of them. Collapse a group into one node, or zoom into
it. Press `/` to find a node and `⌘K` to find a command.
- **Edit the diagram.** Change the shape, fill, border, and font from the
toolbar. Drag from a node to add an arrow. Drag the end of an arrow to connect
it to a different node. Edit DOT records and HTML tables one cell at a time.
- **Graphviz layout.** The `dot` layout engine is a port of Graphviz 13.0.1 to
Scala (see [`graphviz/`](graphviz/README.md)). For the same input, it makes
the same SVG as Graphviz, byte for byte. The other engines (neato, fdp, sfdp,
twopi, circo, osage, patchwork) come from Viz.js.
- **Mermaid.** All the diagram types of Mermaid 11 show and change while you
type. In a flowchart, you can also select, hide, and edit the nodes.
- **Copy and share.** Copy the diagram or the selection as SVG, or copy the
graph as DOT or JSON. Copy a link that holds the full diagram. The link opens
in the web app.
- **Themes.** Ten themes, and an experimental 3D view.

# License
## Desktop app

[License](./LICENSE)
Download the file for your platform from the
[latest release](https://github.com/jpablo/graph-explorer/releases/latest).

| Platform | File | Notes |
|---|---|---|
| macOS (Apple silicon) | `graph-explorer-desktop-vX.Y.Z-macos.dmg` | Signed and notarized. There is no build for Intel Macs. |
| Windows (x64) | `graph-explorer-desktop-vX.Y.Z-windows.exe` | The file is the app. It is not signed, so SmartScreen can show a warning. |
| Linux (x86-64) | `graph-explorer-desktop-vX.Y.Z-linux` | The file is the app. Run `chmod +x` on it. It needs WebKitGTK 4.1 (`libwebkit2gtk-4.1-0` on Debian and Ubuntu). |

The desktop app does not update itself. Download each new release.

What the desktop app adds to the web app:

- **Open a file from disk.** Run `gx open diagram.dot`. The app has no file
picker, so open files with `gx`.
- **Live reload.** The app watches the files that it shows. After a save in
your editor, the diagram shows the change.
- **Save back.** Press `⌘S` (`Ctrl+S` on Windows and Linux) to write your edits
to the file. If the file changed on disk, the app asks which version to keep.
- **A library on disk.** Library diagrams are files in
`~/.graph-explorer/library`. The app and `gx` share them. Set `GX_HOME` to use
a different folder.

## gx

`gx` is a separate file in each release: `gx-vX.Y.Z-macos`, `gx-vX.Y.Z-linux`,
or `gx-vX.Y.Z-windows.exe`. Put it in a folder on your `PATH` and make it
executable. On macOS, the first run needs an internet connection, because macOS
checks the notarization.

```bash
gx status # the library folder, and if the desktop app runs
gx run arch.dot list-nodes # the nodes of a file
gx run arch.dot set-attribute \
--params '{"targets":["node:db"],"name":"shape","value":"cylinder"}'
gx import arch.dot # add the file to the library, linked to it
gx open arch.dot # show the file in the desktop app
```

Only `gx open` and `gx session` need the desktop app. All other commands work
with no window. Run `gx help` for the full list.

**Coding agents.** [`skills/gx`](skills/gx/SKILL.md) is a skill that tells a
coding agent how to use `gx`. Run `gx skill` to get its address for your
version of `gx`.

## Web app

The web app is at <https://graph-explorer.net/app>. It keeps your diagrams in
the storage of your browser, so they are only on that browser.

The web app can open a diagram from a link:

- The form is `https://graph-explorer.net/diagrams/<id>?dot=<text>`, where
`<text>` is DOT or Mermaid text, encoded with `encodeURIComponent`.
- If a diagram in your library has the same id or the same text, that diagram
opens. If not, the app makes a new diagram from the text.
- To make a link, press `⌘K` and run the command "Share URL". The desktop app
makes the same links, so a diagram from the desktop opens in the web app.
- A very large diagram makes a very long link.

## Build from source

You need [sbt](https://www.scala-sbt.org/) and [Node.js](https://nodejs.org/).

```bash
git clone https://github.com/jpablo/graph-explorer.git
cd graph-explorer
npm install
```

Run the web app with hot reload. Use two terminals:

```bash
sbt "~viewer/fastLinkJS"
```

```bash
npm run dev
```

Then open <http://localhost:5173/app>. The product page is at
<http://localhost:5173/site/>.

Run all the tests:

```bash
sbt testFull
```

Under sbt 2, `sbt test` runs only the tests that failed before or whose code
changed. `sbt testFull` runs all of them.

Make a production build of the web app and the product page (output in `dist/`):

```bash
sbt viewer/fullLinkJS && npm run build
```

Build the desktop app. It needs Rust and the Tauri CLI
(`cargo install tauri-cli --version "^2"`), and it puts `dist/` into the app, so
make the production build first:

```bash
cd desktop/src-tauri && cargo tauri build
```

Build `gx`. It needs sbt and [scala-cli](https://scala-cli.virtuslab.org/),
which gets GraalVM:

```bash
scripts/build-gx.sh
```

[Development.md](Development.md) tells how to make a release.

## Repository layout

| Folder | Contents |
|---|---|
| [`shared/`](shared) | The graph model, the DOT parser, and the Mermaid scan. Compiled for the JVM and for JavaScript. |
| [`graphviz/`](graphviz/README.md) | The port of the Graphviz `dot` layout engine. |
| [`viewer/`](viewer) | The app itself, in Scala.js and Laminar. The web app and the desktop app use it. |
| [`desktop/`](desktop) | The desktop app (Tauri). |
| [`gx-core/`](gx-core), [`gx-cli/`](gx-cli) | The `gx` tool. |
| [`skills/gx/`](skills/gx/SKILL.md) | The skill for coding agents. |
| [`site/`](site) | The product page at <https://graph-explorer.net>. |
| [`docs/`](docs) | Design notes. |

## Hosting

Netlify builds the site with
[`scripts/build-viewer-netlify.sh`](scripts/build-viewer-netlify.sh).
[`_redirects`](viewer/src/main/resources/_redirects) sends `/` to the product
page (`site/index.html`) and all other paths to the web app (`index.html`). The
web app shows its library at `/app`.

## License

[Apache License 2.0](LICENSE)

Copyright 2025 Juan Pablo Romero and the graph-explorer contributors.
81 changes: 81 additions & 0 deletions site/flow-svg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""Make the inline SVG for the "desktop" section of site/index.html.

Run from the repository root:

python3 site/flow-svg.py > /tmp/flow.svg

Then paste the output over the <svg id="flow"> element in site/index.html.

Graphviz makes the layout. This script removes the colors and fonts that
Graphviz writes, because site/site.css sets them from the page theme. It also
gives each node a `data-node` name and each edge a `data-from` and `data-to`
name, which site/site.js uses to show the neighbours of a node.
"""

import re
import subprocess
import sys
import xml.etree.ElementTree as ET
from pathlib import Path

SVG = "http://www.w3.org/2000/svg"
ET.register_namespace("", SVG)


def q(tag: str) -> str:
return f"{{{SVG}}}{tag}"


source = Path(__file__).with_name("flow.dot")
svg_text = subprocess.run(
["dot", "-Tsvg", str(source)], check=True, capture_output=True, text=True
).stdout
root = ET.fromstring(svg_text)

# Graphviz writes a size in points. The page sets the size with CSS.
for attr in ("width", "height"):
root.attrib.pop(attr, None)
root.set("id", "flow")
root.set("role", "group")
root.set("aria-label", "How the desktop app, gx, and your files connect")

graph = root.find(q("g"))
graph.remove(graph.find(q("title")))
background = graph.find(q("polygon")) # Absent when bgcolor is transparent.
if background is not None:
graph.remove(background)

for group in list(graph):
kind = group.get("class")
title = group.find(q("title"))
name = title.text.replace("&#45;", "-") if title is not None else ""
if title is not None:
group.remove(title)
group.attrib.pop("id", None)
if kind == "node":
label = " ".join(t.text for t in group.iter(q("text")))
group.set("data-node", name)
group.set("tabindex", "0")
group.set("role", "button")
group.set("aria-label", label)
elif kind == "edge":
source_name, target_name = name.split("->")
group.set("data-from", source_name)
group.set("data-to", target_name)
group.set("aria-hidden", "true")

for element in root.iter():
for attr in ("fill", "stroke", "font-family", "font-size", "stroke-width"):
element.attrib.pop(attr, None)

# An arrowhead is the only polygon in an edge. It needs its own class, so
# that CSS can fill it.
for edge in graph.iter(q("g")):
if edge.get("class") == "edge":
for polygon in edge.iter(q("polygon")):
polygon.set("class", "head")

out = ET.tostring(root, encoding="unicode")
out = re.sub(r"\s*xml:space=\"preserve\"", "", out)
out = out.replace("ns0:", "").replace(":ns0", "")
sys.stdout.write(out + "\n")
28 changes: 28 additions & 0 deletions site/flow.dot
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// The diagram in the "desktop" section of the product page.
//
// site/index.html holds the SVG that Graphviz makes from this file. After a
// change here, run `python3 site/flow-svg.py` and paste its output over the
// <svg id="flow"> element in site/index.html.
digraph flow {
rankdir=LR
nodesep=0.35
ranksep=0.7
bgcolor="transparent"
node [shape=box fontname="Helvetica" fontsize=13 height=0.5 margin="0.18,0.08"]
edge [fontname="Helvetica" fontsize=11 arrowsize=0.7]

editor [label="Your editor"]
agent [label="Coding agent"]
file [label="diagram.dot" shape=note]
gx [label="gx"]
library [label="Library\n~/.graph-explorer" shape=folder]
desktop [label="Graph Explorer\nDesktop" penwidth=2]

editor -> file [label="saves"]
agent -> gx [label="runs"]
gx -> file [label="edits"]
gx -> library [label="imports"]
gx -> desktop [label="opens"]
file -> desktop [label="live reload"]
library -> desktop [label="shared folder"]
}
Binary file added site/img/window-dot.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added site/img/window-mermaid.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading