facett-graphview — crate card
Reverse-engineered (from source — verify, don't trust the name)
- One-line pitch: A domain-agnostic, scalable 2D graph render ENGINE, vello-backed, that runtime-selects GPU (vello/wgpu) vs multithreaded-SIMD CPU (vello_cpu) by hardware.
- Does: Renders a
GraphModel(nodes id/label/pos/fill/stroke + edges) plus a caller-suppliedDecorationsoverlay — mirroring nornir'sgraph_render.rsshared API so nornir'sdraw_graphcan swap painters without touching callers.Backend{Wgpu,VelloCpu} +decide(GpuProbe)pick the path;render_to_rgbareturns straight RGBA8. Also carries graph-layout machinery: force-directed edge bundling (fdeb), community detection, metro/depgraph layouts, and a GPU CSR layout (gpu_layout::GraphCsr::from_arrow, featurearrow). Lowers nodes to facett-core L0 SDF QuadInstances / edges to LineInstances through the core CpuCanvas (CONS-CORE seam). - FalkorDB browser (
falkormodule): the graph-DB IDE data half — an egui-free view-model (FalkorBrowser) that takes a Cypher query → nodes/edges → a force-laid-outGraphModela host paints throughDecoratedGraphView. The transport is a pluggableCypherRunnerseam (fn run(graph, query) -> Result<CypherResult>): the redis/RESPGRAPH.QUERYwire lives at the consumer (korp/dwarves), so this crate stays pure-Rust + headless.CannedRunnerstands in for a live DB in tests +local(). Nodes are coloured categorically by primary label; positions come from the reusedgpu_layout::relax_cpuforce layout (no second layout path).state_json= endpoint + round-tripped query + status(Ok{nodes,edges}/Error{message}fail-loud, never silent-empty) + label breakdown + node/edge dump. Pureupdate(Msg)for non-I/O (SetQuery/Clear/Select/SetEndpoint); the one I/O step is the explicitrun_query(runner). - Key deps:
facett-core(L0 kernel/backend seam),vello_cpu0.0.6 (reference CPU raster, already transitive via epaint),egui(Color32 compat only),serde_json,serde. Optionalgpu: vello 0.9 / wgpu 29 / pollster / bytemuck / facett-core wgpu. Optionalarrow: arrow-array 58. - Shape: lib, ~5.5k lines. Modules: metro, gpu_layout, clip, decorated_view (owning Facet), depgraph_layout, community, fdeb, falkor (FalkorDB browser view-model), l0, cpu, backend, model, analysis, gpu, layout.wgsl.
- Observed role in the workspace: Positioned as the eventual single home for every graph surface (nornir arch/dep/release dashboards, korp, graph-DB browsing). Complements facett-graphpan (the minimal borrowed canvas) — this is the consolidated engine + owning
DecoratedGraphViewFacet + theFalkorBrowsergraph-DB browse view-model.
FalkorDB browse data-flow (the falkor seam)
Cypher text ─(FalkorBrowser::run_query)─▶ CypherRunner::run(graph, query)
│ (redis GRAPH.QUERY at the consumer;
│ CannedRunner in tests/local())
▼
CypherResult { nodes, edges }
│ build_model: id→index, label→categorical colour,
│ GraphCsr::from_edges → relax_cpu force layout (REUSED)
▼
GraphModel ──(DecoratedGraphView::with_model)──▶ interactive pan/zoom pane
│ (click-select + pan/zoom;
│ world_to_screen() maps a node
│ back to a screen pixel for
│ out-of-band/robot hit-testing)
└▶ FalkorBrowser::state_json {query, status, node_count, edge_count, labels, …}
Live consumer: facett-demo's falkor tab (facett_demo::falkor_tab::FalkorTab) wires this data half to the DecoratedGraphView view half over a stubbed in-memory CannedRunner (no live redis), and is robot-tested (kittest) — renders nodes+edges, a synthesised click selects a node via DecoratedGraphView::world_to_screen.
The camera: fit recentres, fit_model FRAMES
DecoratedGraphView carries a pan/zoom camera in its GraphViewState. Two things move it and they are not the same thing:
fit()/Msg::Fit— recentres atzoom = 1. It is the ⊙ affordance's historical meaning and it does not look at the model.fit_model(viewport, margin)— the real bounds fit:zoomso the model'sworld_bounds()fillsviewportinsidemarginpx,panso the box centre lands at the widget centre. Its zoom floor is0.001, deliberately below the interactiveMsg::ZoomByclamp of0.25, because a fit is a computed answer and not a gesture. A no-op on an empty model.
Why it exists. Until facett 019fbab7 the crate advertised a 100 000-node lane and had no way for a host to look at one: Fit is zoom 1 and ZoomBy bottoms out at 0.25, so any world box more than 4× the widget was unreachable. Measured on korp 2026-09-01 — a live 132-node FalkorDB scene laid out at one chip of clearance per node spans ~3 500 world units and, in a 900 × 640 pane, added 0.006 of ink over the SAME pane holding an empty model. The pane was chrome and a few stray chips.
The math is facett_graphpan::GraphView::fit_bounds, reused rather than re-derived — the two crates share a camera model, so they must share the fit (LAW 5).
Demoed in facett-demo's falkor tab as the ⊙ Frame button, with state_json().camera / .framed so a driver asserts the camera actually moved; frame_button_puts_every_node_inside_the_pane asserts on projected node positions, not on the zoom scalar.
Fill in (one line each — only the human knows these)
- Primary consumer(s):
- Why it exists (vs the obvious alternative):
- Hard constraint (airgap / no-C-deps / no-FFI / pure-Rust / etc.):
- Release cadence & independence (rides a parent? own repo someday?):
- Status (production / prototype / experimental / stubbed):
- Must-NOT-change invariant:
- Biggest known gap or TODO:
- Anything a newcomer would get wrong about it: