The graph subsystem — for idiots
Class:
idiot. Every step, nothing assumed. Goal: draw a graph on screen and prove it drew, from a cold shell. If you already know Rust, readgraph-guide.mdinstead — this one spells out every keystroke. (Folds the oldfacett-graphview-for-dummies.md— same plain-English content, now covering all five graph crates.)
What you need first
- A terminal (the black window where you type commands).
- The facett repo on disk. Type this and press Enter:
cd /run/media/rickard/T9/git/facett
What "the graph subsystem" even is
You found five crates that all do one thing: draw boxes with lines between them (a dependency graph, a pipeline, a graph database, a 3D call graph, a map of a few servers) — and keep drawing them fast even when there are a lot of boxes. No graph-theory or GPU knowledge needed to use any of them.
| crate | draws… |
facett-graph |
a simple graph, or a left-to-right dependency chart |
facett-graphview |
the same thing, but built to stay fast at huge sizes, and it can hand you back raw pixels |
facett-graphpan |
a graph you can drag around and zoom into |
facett-graph3d |
a graph floating in 3D that spins |
facett-syschart |
a handful of boxes (services) with counters on them, click one to see detail |
The one big idea in facett-graphview: it picks GPU or CPU by itself
Drawing a huge graph is expensive. A graphics card (GPU) does it fast, but not every machine has a usable one (a CI server, a headless box, a laptop with a flaky driver). So facett-graphview doesn't demand a GPU. It probes the machine and picks:
- usable GPU found → draw on the GPU (
vello). - no GPU (or you forced it off) → draw on the CPU (
vello_cpu), which still uses all your cores. This is not a slow fallback — it ships inside egui already and is the proven, default path.
GraphModel + Decorations → decide(probe) → Backend{vello GPU | vello_cpu SIMD} → RGBA pixels
Step 1 — build it
Type and press Enter:
cargo build -p facett-graph -p facett-graphview -p facett-graphpan -p facett-graph3d -p facett-syschart
Wait for it to finish with no red text.
Step 2 — run the tests (proof it draws, no window needed)
Type and press Enter:
cargo test -p facett-graph -p facett-graphview -p facett-graphpan -p facett-graph3d -p facett-syschart
Green test result: ok lines for each crate = every one of them can build a graph, paint it, and check what got painted — without opening a window. That "headless" trick is explained in elm-for-idiots.md if you want to know how.
Step 3 — make one crate actually spit out a picture
facett-graphview ships an example that renders a graph straight to a PNG file on disk — the easiest way to see something without wiring up a whole app. Type and press Enter:
cargo run -p facett-graphview --example render_png
Look at the terminal output for the file path it wrote, then open that .png in any image viewer. You should see coloured boxes joined by lines.
Step 4 — turn on the GPU path (optional)
By default everything above used the CPU. To also compile the GPU seam:
cargo build -p facett-graphview --features gpu
This does not change what you see yet (both paths currently draw through the same CPU rasterizer under the hood — that's an intentional, documented in-progress state, not a bug) — it proves the GPU wiring compiles.
Step 5 — pick a node and click it (interactive canvas)
If you're wiring one of these into a live app (not required to just try it out), the "click a node, see it light up" behaviour lives in DecoratedGraphView (facett-graphview), GraphPanView (facett-graphpan), DepGraphView (facett-graph), Graph3D (facett-graph3d), and SystemChart (facett-syschart). Every one of them follows the exact same recipe:
- You give it nodes + edges (plain data: an id, a label, a colour, a position).
- It paints them and watches for clicks/drags/scrolls.
- A click on a node doesn't change anything by itself — it becomes a named
Msg(likeSelect("a")), and a singleupdatefunction applies it. - You can replay that exact same
Msgin a test with no window at all and check the result — seeelm-for-idiots.mdsteps 5-8 for the full walkthrough of writing that kind of test.
Step 5b — "I already know where my nodes go"
The 3-D one (Graph3D) normally decides where each node goes for you: on a sphere, on a spiral, on a cube grid, or by letting a physics relaxation push them apart. That is the right answer when the nodes are just things. It is the wrong answer when they are places with a number attached — road sensors on a map, each with a speed; servers on a floor plan, each with a load.
For that, you place them yourself:
use facett_graph3d::{Graph3D, Layout3D};
// One [x, y, z] per node, same order as the nodes, all numbers roughly -1..1.
// x and y = where it is on your map. z (up) = the number you measured.
let g = Graph3D::new(nodes, edges, Layout3D::Given).with_positions(positions);
Three things worth knowing, in plain words:
- It remembers. Click another layout in the pane and click back — your placement comes back. It is not thrown away.
- All or nothing. If you hand over fewer positions than you have nodes, it will NOT draw a half-placed picture (the leftovers would pile up at the centre and look like real data). It draws an even cube grid instead — a shape no real dataset ever has, so you can see at a glance that nobody placed it — and tells you so: the pane turns amber and reports the code
facet-graph3d-5. Give it one position per node and it stays green. - How to check it worked (in a test, no window needed): the pane's
state_json()haslayout(what you asked for),given_positions(how many positions you handed over) andlayout_fallback(nullwhen your placement is the one on screen;"grid"when it fell back). Checking "it has nodes" proves nothing — the grid fallback has nodes too.
You can see it running: start the demo (Step 3) and open the tab called graph3d-given. It is a little city of traffic sensors — flat on the map, high where traffic is fast, sunk in the middle where it is jammed.
Step 6 — "is facett-graphview finished?"
No — it's a foundation spike. What works today: the model, the CPU rasterizer (proven, tested), and the GPU code path compiles (the version-matched vello/wgpu/egui-wgpu seam). What's not done yet: reading the finished picture back off the GPU as a live framebuffer, plus turning on the "handle a huge graph" tools it already ships (only-draw-what's-on-screen culling; the edge-bundling, community/semantic-zoom, and GPU-layout modules exist and are tested standalone, but a host has to call them explicitly — they aren't wired into the default render path yet), and the adapters that turn a nornir dep graph / a FalkorDB graph / a pipeline straight into a GraphModel.
Step 7 — "so how fast is it?"
There's a benchmark (cargo bench -p facett-graphview), but be honest about it: right now both backends actually draw on the CPU (the GPU readback is a follow-up), so the number is a CPU-path baseline, not a "we beat Graphviz on the GPU" claim. Don't quote it that way yet.
Step 8 — save your work (if you changed something)
Type these three, pressing Enter after each:
git add -A
git commit -m "facett-graph*: <what you changed>"
git push
That's the whole tour. For the exact API of each crate, read graph-guide.md; for why it's built this way, graph-reasoning.md.