The goal was a tool where you design an API workflow by dragging it out instead of writing it. You pull nodes from a sidebar onto a canvas, connect one node's output into the next node's input, open a panel to configure each one, and then hit play to watch a fake run light up node by node. Think of a tiny cousin of Zapier, or a workflow view that feels a bit like Figma.
Standing on React Flow
I did not want to reinvent a node canvas from nothing, so I built on React Flow and put React 18 and TypeScript around it. React Flow handles the hard parts of a canvas, the panning, the zooming, the little connection handles, so I got to spend my time on the stuff that makes it actually useful. State lives in Zustand, which kept things refreshingly plain. One store, clear actions, no ceremony.
The nodes
There are a few node types, and each one is a small custom React component:
- API request for the actual call you want to make.
- Transform for reshaping the data as it passes through.
- Condition for branching based on what came back.
- Output for where the flow ends up.
Click any of them and a live inspector opens on the side so you can edit its settings, and the canvas updates as you type. That instant feedback is most of what makes the thing feel good to use.
Faking a run
The play button walks the graph and gives every node a status as it goes, idle, then running, then success or error. Watching the little states ripple through the flow is oddly satisfying, and it makes the whole diagram feel alive rather than static.
idle → running → success
↘ error
The two decisions I am proud of
First, cycle detection. Nothing stops you from accidentally wiring a node back into itself, which would spin forever, so the builder checks for loops before it ever tries to run. It felt great to catch a whole class of bugs with one guard.
Second, the transform node is deliberately not a code box. It would have been easy to let people type arbitrary JavaScript and just run it, but this is a browser tool anyone can open, so that is a door I did not want to leave unlocked. It only allows safe things like returning the data as is or a plain JSON literal. Less powerful on paper, much safer in practice, and the right call for what this is.
Little things that mattered
You can save and reload a workflow straight from local storage, so your canvas is still there when you come back. I wrote tests with Vitest to keep the graph logic honest, and I leaned into a dark, modern look because a builder should feel like a place you want to spend time.
Why no AI, and why that felt good
My other recent projects lean on AI, and I like that work. But this one was a reminder that a lot of the joy in building software is just plain engineering. Getting a drag to feel right, catching a cycle before it bites, drawing a clear line around what a feature is allowed to do. No model was going to do that for me, and I did not want it to. Sometimes the whole point is to sit with the problem yourself.
The full source is up on GitHub if you want to poke around the canvas.