Graphy started as a way to make graph algorithms less abstract — instead of just reading about DFS or Dijkstra, you build them visually and watch them run on a graph you've drawn yourself. It's an educational application that combines graph theory with visual programming, aimed at making graph data structures and algorithms easier to understand through hands-on experimentation.
The app is split into two halves that share the same underlying graph data.
Graph Editor — the left side is a direct-manipulation canvas: click to create a vertex, hold Shift and click another to connect them with an edge, pan and zoom (0.1x–5x) around the graph, select and delete elements, and color vertices/edges to visualize what an algorithm is doing.
Visual Programmer — the right side is a node-based programming environment. You drag out logic nodes (loops, conditionals, data operations), connect them, and use a dedicated "Start" node to access the graph's vertices and edges. Running the program executes the algorithm directly against the graph you built, and you watch it play out step by step.
lib/graph.dart): the core Graph data structure, Vertex and Edge types with position/color/numbering, a Colorable interface for visual styling, and an update-notification system so both halves of the UI stay in sync when the graph changes.lib/visual_programmer/): a Program execution engine, an abstract LogicalNode interface that every node type implements, a NodeManager for node lifecycle, a ConnectionManager that handles wiring between nodes, a ResourceManager for accessing graph data from inside a program, and a small type system with support for generics and class hierarchies so connections between nodes can be type-checked.lib/ui/): the graph screen, the programming screen, a split-screen container dividing the two, and custom widgets for vertices, nodes, and connections.lib/
├── algorithms/ # Graph algorithm implementations
│ └── dfs.dart # Depth-first search
├── ui/
│ ├── screens/ # Main application screens
│ └── widgets/ # Reusable UI components
├── utils/ # Utility classes (vectors, drag helpers, etc.)
├── visual_programmer/ # Visual programming system
│ └── nodes/ # Available programming nodes
├── algorithms.dart # Algorithm registry
├── graph.dart # Core graph data structures
└── main.dart # Application entry point
Underneath, the design leans on a few classic patterns: an observer pattern for reactive UI updates, a strategy pattern for pluggable algorithm implementations, a composite pattern for the hierarchical node structure, and interface segregation to keep LogicalNode, Colorable, and similar interfaces clean and focused.
The part I'm happiest with is the visual programming system itself. Getting node types to interact safely — connections that type-check against each other, support for generics, everything staying reactive when the graph changes — pushed me to actually design a small type system instead of hacking something together. It's the kind of internal architecture nobody using the app will ever notice directly, but it's the reason adding a new node type is a matter of implementing one interface rather than touching half the codebase.
It's still very much a work in progress: algorithm animations, more node types, graph import/export, and saving/loading configurations are all still on the list.