A lightweight, model-first graph engine for building visual editors, workflow tools, diagramming apps, and low-code interfaces.
This library gives you a fully structured graph core (nodes, ports, edges), plus systems for selection, history, commands, interactions, hit-testing, keyboard, and serialization — all cleanly separated and fully extensible.
Everything is built around a consistent graph data model:
- Nodes
- Ports
- Edges
- Graph state
- Validation
- Selectors
- Utils
Each system is isolated and replaceable:
- Event System
- Selection System
- Command System
- History (Undo/Redo)
- Interaction System (drag, marquee, etc.)
- Hit Testing
- Keyboard Input
- Serialization
The engine runs without any renderer — perfect for:
- React
- Next.js
- Node.js
- Python bindings
- CLI tools
- Server-side layout
You can add:
- Custom node types
- Custom commands
- Custom interactions
- Custom validation rules
- Custom serialization formats
pnpm add open-flow
# or
npm install open-flow
# or
yarn add open-flowimport { createGraph, addNode, addEdge } from 'open-flow';
// Create graph
const graph = createGraph();
// Add nodes
const nodeA = addNode(graph, {
id: 'A',
type: 'default',
position: { x: 100, y: 100 },
});
const nodeB = addNode(graph, {
id: 'B',
type: 'default',
position: { x: 300, y: 100 },
});
// Add an edge
addEdge(graph, {
id: 'A->B',
source: { node: 'A', port: 'out' },
target: { node: 'B', port: 'in' },
});open-flow/
├── Core Model
│ ├── GraphModel
│ ├── NodeModel
│ ├── PortModel
│ └── EdgeModel
│
├── Engine Systems
│ ├── Event System
│ ├── Selection System
│ ├── History System
│ └── Command System
│
├── Interaction Systems
│ ├── DragManager
│ ├── MarqueeManager
│ ├── HitTester
│ └── KeyboardManager
│
└── Serialization
└── GraphSerializer
Each system is isolated, testable, and replaceable.
- GraphManager
- NodeManager
- PortManager
- EdgeManager
- Events (node/port/edge/graph)
- Selection (single + multi)
- Commands (structured updates)
- History (undo/redo)
- Dragging
- Marquee selection
- Hit testing (nodes, ports, edges)
- Keyboard shortcuts
- JSON export/import
- Safe graph rehydration
commandManager.execute({
type: "node:add",
payload: { id: "N1", position: { x: 100, y: 200 } }
});
historyManager.undo();
historyManager.redo();const hit = hitTester.hitTest(pointer);
if (hit.type === "node") {
console.log("Node under cursor:", hit.nodeId);
}const json = graphSerializer.export(graph);
const restored = graphSerializer.import(json);- Renderer plugins (HTML/SVG/Canvas/WebGL)
- React bindings (@graph-engine/react)
- Next.js integration
- Python bindings
- CLI tools
- Layout algorithms (Dagre/ELK)
- Theme system
- Plugin system
- Collaboration layer (Yjs/CRDT)
Pull requests are welcome! Please open an issue to discuss new features or improvements.
MIT License