Skip to content

tu6ge/ferrum-flow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

297 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FerrumFlow

A high-performance, extensible node-based editor built with Rust and gpui. Designed for building visual programming tools, workflow editors, and graph-based UIs.

This project is in early stage (alpha), API may change

Features

  • Plugin-based architecture
  • Interaction system (drag, pan, select, etc.)
  • Undo / Redo (Command pattern)
  • Viewport control (zoom & pan)
  • Box selection & multi-select
  • Node / Port / Edge model
  • Custom node rendering system
  • Built with performance in mind
  • Multi-user collaboration support (by plugin)
2026-04-05.11.08.00.mov

GitHub

Usage

cargo add ferrum-flow

Architecture Overview

The system is designed with clear separation of concerns:

Core Concepts

  • Graph Stores persistent data (nodes, edges, ports)

  • Viewport Handles zooming and panning

  • Plugin System Extends behavior (rendering, input handling, etc.)

  • Interaction System Manages ongoing user interactions (dragging, selecting, etc.)

  • Command System Enables undo/redo support

Plugin System

Plugins are the primary extension mechanism:

pub trait Plugin {
    fn name(&self) -> &'static str;

    fn setup(&mut self, ctx: &mut InitPluginContext);

    fn on_event(&mut self, event: &FlowEvent, ctx: &mut PluginContext) -> EventResult;

    fn render(&mut self, ctx: &mut RenderContext) -> Option<AnyElement>;

    fn priority(&self) -> i32 {
        0
    }

    fn render_layer(&self) -> RenderLayer {
        RenderLayer::Overlay
    }
}

Responsibilities

A plugin can:

  • Handle input events
  • Start interactions
  • Render UI layers
  • Modify graph state

Interaction System

Interactions represent ongoing user actions, such as:

  • Node dragging
  • Box selection
  • Viewport panning
pub trait Interaction {
    fn on_mouse_move(&mut self, event: &MouseMoveEvent, ctx: &mut PluginContext) -> InteractionResult;

    fn on_mouse_up(&mut self, event: &MouseUpEvent, ctx: &mut PluginContext) -> InteractionResult;

    fn render(&self, ctx: &mut RenderContext) -> Option<AnyElement>;
}

Interaction Lifecycle

Start → Update → End / Replace
pub enum InteractionResult {
    Continue,
    End,
    Replace(Box<dyn Interaction>),
}

Command System (Undo / Redo)

Implements the Command Pattern:

pub trait Command {
    fn execute(&mut self, ctx: &mut CommandContext);
    fn undo(&mut self, ctx: &mut CommandContext);
}

Built-in Features

  • Undo / Redo stacks
  • Composite commands
  • Easy integration via PluginContext
ctx.execute_command(MyCommand { ... });

Node Rendering

Rendering is fully customizable via a registry:

pub trait NodeRenderer {
    fn render(&self, node: &Node, ctx: &mut RenderContext) -> AnyElement;

    // custom render port UI
    fn port_render(&self, node: &Node, port: &Port, ctx: &mut RenderContext) -> Option<AnyElement> {
        // ... default implement
    }

    // computing the position of port relative to node
    fn port_offset(&self, node: &Node, port: &Port, graph: &Graph) -> Point<Pixels> {
        // ... default implement
    }
}

Render example:

div()
    .absolute()
    .left(x)
    .top(y)
    .w(width)
    .h(height)
    .bg(white())

Graph Model

pub struct Node {
    pub id: NodeId,
    pub node_type: String,
    pub x: Pixels,
    pub y: Pixels,
    pub size: Size<Pixels>,
    pub inputs: Vec<PortId>,
    pub outputs: Vec<PortId>,
    pub data: serde_json::Value,
}

Creating Nodes (Builder API)

graph.create_node("math.add")
    .position(100.0, 100.0)
    .input()
    .output()
    .build(&mut graph);

Performance

Designed to scale to large graphs:

  • Viewport-based rendering (virtualization)
  • Layered rendering system
  • Interaction-aware rendering (degraded mode during drag)
  • Ready for spatial indexing

Design Principles

  • Separation of data and interaction
  • Plugins over hardcoded behavior
  • Explicit state transitions
  • Performance-first rendering
  • Composable architecture

Feature parity & gap analysis (TODO)

We want an explicit, maintained view of supported vs partial vs missing relative to React Flow’s documented capabilities (nodes, edges, handles, selection, keyboard, minimap, controls, snapping, grouping/subflows, accessibility, etc.):

  • Audit — Walk the React Flow feature list and map each item to FerrumFlow (plugin, core graph, or N/A by design).
  • Gap list — For every row, mark done, partial, missing, or different by design (short rationale).
  • Surface in this README — Add a compact table or bullet matrix here (or link to docs/react-flow-parity.md if it grows large).

Contributions welcome: propose a matrix in an issue or open a PR that extends this section.

Mid-term design goals

Foundation work that unlocks most other extensions:

  • Separate data, logic, and rendering — Clear boundaries between graph/state, interaction and commands, and GPUI (or future) paint so features can grow without entangling layers.
  • Large-graph performance — Investigate arena-style allocation for nodes/edges and ID-based references instead of pointer-heavy graphs to improve locality and scale.

Long-term / directional

No active schedule; keep these in mind when designing APIs above.

  • Abstract / pluggable render backend — Allow FerrumFlow to sit inside existing render systems (similar in spirit to graph editors embedded in tools like Blender or Unreal: the host owns the surface; the library supplies model + interaction contracts).
  • WASM target — When the stack allows, support Web deployment paths.
  • Predictive rendering for collaboration — Reduce felt latency in multi-user editing (optimistic / speculative UI reconciled with synced state, e.g. CRDT-backed updates).

Contributing

Contributions are welcome!

Feel free to open issues or PRs for:

  • New plugins
  • Performance improvements
  • API design suggestions

License

Apache2.0

About

A high-performance, extensible node-based editor framework

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages