Custom nodes for the Graphene engine are written in Rust and defined using theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/GraphiteEditor/Graphite/llms.txt
Use this file to discover all available pages before exploring further.
#[node_macro::node] proc-macro attribute. A node is a regular Rust function with typed parameters — the macro generates all of the boilerplate needed to integrate it into the engine: type registration, input/output connector wiring, metadata for the UI, and the node executor implementation. Once registered, a node appears in the Graphite editor’s node search and can be wired into any document graph.
The node_macro Proc-Macro
Thenode-macro crate (at node-graph/node-macro/) provides the #[node_macro::node] attribute macro. When applied to a Rust function, it:
- Generates a named struct (the node type) and implements the
Nodetrait for it - Registers the node with a
ProtoNodeIdentifierso the compiler can look it up by name - Extracts doc comments from parameters to produce UI tooltip text
- Supports
#[implementations(...)]to define generic type specializations - Supports
#[default(...)]to set default values for parameters - Optionally generates a GPU shader variant via
shader_node(...)
lib.rs of node-macro also exposes #[derive(ChoiceType)] for defining enum-based dropdown/radio widgets and #[derive(BufferStruct)] for GPU-compatible shader structs.
Basic Node Structure
Here is an example of a real node fromnode-graph/nodes/math/src/lib.rs — the addition node:
- The first parameter
_: impl Ctxis the execution context — always present, never named in the UI - All other parameters become input connectors in the node graph
- Doc comments on parameters become tooltip text in the editor
#[implementations(...)]lists the concrete types this generic parameter should be monomorphized for#[default(...)]sets the default value shown in the properties panel when no connection is made- The function return type becomes the node’s output connector type
Attribute Arguments
The#[node_macro::node(...)] attribute accepts several named arguments:
| Argument | Example | Purpose |
|---|---|---|
category(...) | category("Math: Arithmetic") | Groups the node in the Add Node menu |
name(...) | name("As u32") | Overrides the display name (default: function name in title case) |
properties(...) | properties("math_properties") | Names a custom properties panel renderer |
memoize | memoize | Inserts a Memoize node after this node in subnetwork expansion |
inject_scope | inject_scope | Marks this node as providing a new scope for context injection |
Node Crate Organization
Nodes are organized into domain-specific crates undernode-graph/nodes/:
| Crate | Path | Domain |
|---|---|---|
graphene-core (gcore) | node-graph/nodes/gcore/ | Fundamental types, context, memo infrastructure |
graphene-std (gstd) | node-graph/nodes/gstd/ | Rendering pipeline, web requests, animation |
vector-nodes | node-graph/nodes/vector/ | Vector geometry, paths, boolean ops |
raster-nodes | node-graph/nodes/raster/ | Raster image processing, color adjustments |
graphic-nodes | node-graph/nodes/graphic/ | Compositor nodes, graphic group handling |
transform-nodes | node-graph/nodes/transform/ | Transform, scale, rotate, translate |
math-nodes | node-graph/nodes/math/ | Arithmetic, trig, numeric operations |
repeat-nodes | node-graph/nodes/repeat/ | Repetition and instancing nodes |
blending-nodes | node-graph/nodes/blending/ | Layer blending modes |
text-nodes | node-graph/nodes/text/ | Text rendering and layout |
brush-nodes | node-graph/nodes/brush/ | Brush stroke nodes |
Registering a Node
Nodes defined with#[node_macro::node] self-register their metadata at startup through the graphene_std::registry::NODE_METADATA static. However, for the DynamicExecutor to be able to construct node instances at runtime, each type monomorphization must also be registered in the node registry.
The node registry lives at node-graph/interpreted-executor/src/node_registry.rs. It is a large node_registry() function that returns a HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeConstructor>>. New native node types must be added here using the async_node! macro with their concrete type parameters:
Input/Output Types
Graphene uses a typed connector system. Type mismatches between connected nodes are detected at graph compile time. Common types used in node signatures:| Type | Description |
|---|---|
f64 | Scalar floating-point number |
DVec2 | 2D double-precision vector |
DAffine2 | 2D affine transform |
Color | RGBA color value |
Item<T> | A typed data item carrying attributes alongside its value |
List<T> | A list of typed items |
Vector | Vector path data |
Raster<CPU> | CPU-side raster image buffer |
Raster<GPU> | GPU-side raster texture |
Graphic | A composited graphic element |
Artboard | An artboard with bounds and content |
Context | The execution context (always the first parameter) |
#[implementations(...)] annotation on generic parameters tells the macro which concrete types to generate implementations for. Any combination of input types not listed will not be available as a valid connection in the editor.
Subgraph Nodes
Not all nodes need to be written in Rust. Complex nodes can be implemented as subgraph documents — a.graphite network file that is embedded as a DocumentNodeImplementation::Network inside a DocumentNode. These subgraph nodes appear in the editor just like native nodes.
Double-clicking a subgraph node in the Graphite node graph reveals its interior network, where you can see and modify the underlying composition. Many of the built-in Graphite nodes — particularly higher-level artistic effects — are subgraphs built from simpler native nodes.
GPU Shader Nodes
Raster nodes that benefit from GPU acceleration can provide a shader implementation in addition to their CPU fallback. Shader nodes are written in Rust usingspirv-std and compiled to SPIRV. The #[node_macro::node(..., shader_node(...))] attribute instructs the macro to generate both variants.
GPU shader nodes require the
spirv-std crate and are compiled separately using cargo-gpu. They are only available on native targets with WGPU support. When running in WebAssembly, the CPU fallback path is used unless the browser supports WebGPU. See node-graph/nodes/raster/shaders/ for existing shader node examples.