# egui-snarl: node graph interfaces for the egui framework

> egui-snarl is a Rust crate for building node graph user interfaces on egui. The graph itself holds only typed data, while a viewer trait decides what each node looks like, how many pins it has and what happens when a wire is connected, so the same graph can be rendered very differently in different applications.

**zakarumych/egui-snarl** — Customizable egui node-graph library

- Repository: https://github.com/zakarumych/egui-snarl
- Website: https://crates.io/crates/egui-snarl
- Stars: 604 · Forks: 90
- Language: Rust
- License: NOASSERTION
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/zakarumych-egui-snarl

## A node graph crate, and why it is called snarl

egui-snarl is a crate for creating and manipulating node graph user interfaces, and the project notes say it contains all the necessary features and more are planned. The name is explained with a single line: because that is how any complex visual graph looks like. A snarl is a tangle, and the author picked the word for the shape of the thing rather than for a feature of it.

The scope is a library, not an application. There is no window, no menu bar and no node palette. What you get is a graph structure, a set of layout rules, and a trait that you implement to say what your nodes are and what they do. That split is the design decision everything else follows from, and it is why the crate is published on crates.io with documentation on docs.rs rather than shipped as a tool.

The repository is a Cargo workspace with the crate and a demo package, the crate version is 0.12.0, it is on edition 2024 and it requires Rust 1.92 or newer. The licence in the manifest is MIT or Apache-2.0 at your option, and the repository carries both licence files. The workspace pins the egui stack to version 0.36 across egui, eframe and the extras package.

## Data-only nodes, and a viewer that draws them

The first feature is typed data-only nodes. The Snarl structure is parametrized by the type of the data the nodes hold, and that type may be an enum of the node variants or a custom node constructor type, with the choice left to the author. The graph therefore knows nothing about what a node means. It knows that a node exists, that it sits at a position, and that wires run between its pins.

The second feature is the viewer trait, SnarlViewer, which is also parametrized by the node type. It decides the node's title interface, how many pins the node has, and fills in the content of each pin. The demo example shows what that means in practice: a pin can hold a drag integer value, a text input, a button or an image, and there is no stated limit, because each pin's content is whatever the viewer puts into the provided egui UI object.

The split is the interesting part for an adopter. Your node data stays plain Rust types, so it can be tested without a display and serialised without a custom format, while the presentation lives entirely in an implementation of the trait. A second application can render the same graph with a different viewer, and the graph does not have to change.

## Five spaces make up a node

The node layout is divided into five spaces, and each one has a defined job and a defined amount of user-defined content. The header is at the top of the node and carries a collapsing button when the collapsible flag in the style is set, plus user-defined content, with a label showing the node name by default.

Input pins are placed on the left below the header. Each pin contains a shape on the left edge, and the shape can be interacted with to connect or disconnect the pin, with user-defined content placed after it. The body of the node sits in the centre and is optional, but the notes say it comes in handy for some node kinds and contains only user-defined content. Output pins are on the right below the header, the same as input pins except that the pin shape goes to the right edge. The footer is below the other spaces, similar to the body in that it is optional and holds only user-defined content.

That layout is the reason the crate can be styled to match an application rather than the other way round. The parts that are fixed are the pin shapes and the connection points, and everything else in a node belongs to whoever implements the viewer.

## The application decides what a connection means

Two features make the viewer responsible for behaviour rather than only for appearance.

The first is user-controlled responses for wire connections. When a new wire is connected in the interface, the viewer is notified and decides what happens. The documentation lists the options explicitly: it may create that connection, ignore it, add more nodes, play a beep sound or send e-mails. That last example is a good indication of the intent, since the crate does not decide that a connection is a connection.

The second is the context menus. Right-clicking a node, if configured, opens a menu filled by a viewer method, and that method is given a reference to the graph and the node id, so it can add options to remove the node, configure it or do anything else. Right-clicking the background opens a second menu, also filled by a viewer method, this time given a reference to the graph, and it can add or remove nodes or configure the whole graph.

The result is that the crate never mutates your data behind your back. Every decision that changes the graph, from a connection to a context menu to a shortcut, is a call into your code, which is a design that pays off when a user does something the author did not anticipate.

## Wires, bundles, and the yank gesture

Multiconnections are supported, and the gestures for them are specific. You can connect or reconnect many pins at once: when dragging a new wire, hovering over a pin on the same side while holding Shift adds a wire from it into the bundle. Starting a drag from a pin while holding Ctrl, which is Cmd on macOS, yanks the existing wires out of that pin so they can be dragged into another pin.

The wire rendering is a separate concern from the connection logic, and it is described as a carefully crafted formula that can be customised to scale differently through the style struct. The background is configurable in the same struct, with a note that a blank colour background may be desirable while a faint pattern helps fill visual emptiness, and with provided patterns such as a grid or a custom function of your own.

Both of those are style level decisions, which is the point: an application that wants its own node graph look can set the wire curvature and the background once, in the style, rather than overriding drawing behaviour.

## Serialisation, and the dependencies that keep it small

The Snarl structure stores only the graph, meaning the placed nodes and the wires between them, which is what makes it suitable for serialisation and deserialisation. Support for serde is there, and the crate deliberately does not choose a format for you, so you pick your own.

That support is behind a feature flag, and the feature definition shows exactly what it turns on:
```
[features]
serde = ["dep:serde", "egui/serde", "slab/serde"]
```
The interesting detail is the third entry. serde support is propagated to the slab crate as well, because slabs are how the graph stores its node and pin allocations, and a node id is a slab index. Getting that wrong would mean a graph that could not be round-tripped, so the feature reaches into the dependency rather than only into the graph itself.

The rest of the dependency set is small and purposeful. egui provides the interface, the slab crate handles the allocation of nodes and pins, smallvec is used with the const_new feature, and ahash is pulled in without default features for hashing. A syn dependency sits in the workspace for the derive work that the optional egui-probe integration needs, and the wasm target has its own development dependencies, which is how the web demos in the project are built.

## Running the demo, and the known rough edges

The demo example shows some of the features of the crate, and it is not optional decoration in the build sense, because the example entry in the manifest declares its required features:
```
[[example]]
name = "demo"
required-features = ["serde", "egui-probe"]
```
So to run the demo you enable the serde and egui-probe features, and the project notes give the exact cargo invocation for that. The demo is a separate package in the workspace, with its own manifest and an index file, which is how the web version is served.

The rough edge worth knowing about is UI scaling. The notes are candid that egui itself does not support UI scaling, and that egui-snarl works around it by scaling independent UI elements separately, which works but leaves some artefacts. Since a node graph is exactly the kind of interface where pin positions have to line up precisely, an artefact in the scaling is more noticeable here than it would be in a form layout.

The other thing to check is the version pairing. The crate is written against egui 0.36, and the manifest pins egui, eframe and the extras package to that version, so a project on a different egui release will need to see whether the two line up. There is a Discord channel for the project, a web demo hosted on the author's pages, and a third party noise application and a logic project built on top of the crate, which is the best evidence that the viewer separation works in practice.

## Conclusion

egui-snarl suits a Rust developer building a node editor on egui who wants the graph logic separated from the rendering, because the viewer trait is the seam that lets one graph serve several presentations and lets the application decide what a connection means. It is the wrong choice if you need the crate to own your node behaviour, since it deliberately holds only data and expects you to supply the semantics through the viewer, and it is the wrong choice if your egui version is not 0.36, since the crate is written against that release. Before you adopt it, check the feature list, since serde and the egui-probe integration are optional and the demo example will not build without them, and read the licensing file yourself, because the manifest states MIT or Apache-2.0 while the repository licence field is recorded as a custom licence that GitHub could not classify. The crate version is 0.12.0, edition 2024, and it needs Rust 1.92 or newer.

## FAQ

### What is egui-snarl?

It is a Rust crate for creating and manipulating node graph user interfaces on egui. The graph holds only typed data, and a viewer trait decides the node title, the number of pins, the content of each pin and what a new connection means.

### How do I define my own node types?

Snarl is parametrized by the type of data the nodes hold, which can be an enum of your node variants or a custom node constructor type. You then implement the SnarlViewer trait for that type to decide the title interface, how many pins each node has and what goes inside them.

### Can I save and load a graph?

Yes. Snarl stores only the graph, the placed nodes and the wires between them, so it is straightforward to serialise. Serde support is behind an optional feature, and the crate leaves the format to you, so you can pick JSON or anything else.

### How do I run the egui-snarl demo?

The demo example declares the serde and egui-probe features as required, so enable both and run the demo with cargo, as the project notes describe. The demo is a separate package in the workspace, and a web version of it is hosted on the author's pages.

### Does egui-snarl support UI scaling?

Partly. The project notes that egui itself does not support UI scaling, and that egui-snarl provides it by scaling independent UI elements separately, which works but leaves some artefacts.

## Sources

- [Issues](https://github.com/zakarumych/egui-snarl/issues)
- [Project website](https://crates.io/crates/egui-snarl)
- [README](https://github.com/zakarumych/egui-snarl/blob/main/README.md)
- [zakarumych/egui-snarl on GitHub](https://github.com/zakarumych/egui-snarl)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/zakarumych-egui-snarl
