This is a series of posts on building imgplex, best read in order:
Part 1 - The why, what, and how of imgplex
Part 2 - Getting things up and running
Part 3 - The node definition system
Part 4 - Executing the node graph, making it fast
Part 5 - Two graphs in one
Part 6 - Multiple inputs and outputs, processing images as sets
Part 7 - Profiling and Optimization
imgplex is a node-based tool for building and running batch image-processing workflows. ImageMagick does the actual image processing, imgplex builds and manages the commands it runs.
Disclaimer: I used AI tools during the development of imgplex, but this wasn’t a project where I prompted a model and accepted whatever came back. I designed the architecture, tested the implementation, and made the decisions around UX and batch-processing performance. This series covers that process, including the parts that worked and the parts that had to be changed.
The why
In game development we do a lot of texture processing as part of the content pipeline, whether it is creating textures or processing textures from asset packs. As a technical artist I’ve made a bunch of tools of various sorts to automate the process as much as possible, but the use cases are far too different to be covered effectively by a few tools.
AI makes it easy to write a script for one specific problem. The problem is that these scripts quickly pile up, and six months later nobody remembers what they were written for.
I had already used ImageMagick for some of these jobs. It is incredibly powerful, and its commands can be chained together to perform surprisingly complex operations. The difficulty is that artists have to work through a command line and usually cannot see the result until the command has run. For visual work, I wanted something where they could adjust values and see the effect before processing a whole batch.
The what
I decided to build the tool on top of ImageMagick since it can handle every image processing need we have. The idea was to use a node based editor to generate ImageMagick commands. Node based editors are common in game development workflows: we have node based editors for shaders, VFX, and procedural content that artists are already comfortable with (Shader and VFX graph, Houdini, Substance Designer, Blender’s geometry nodes etc).
I was also comfortable building around a graph because I had already spent years working with similar tools in game-development pipelines.
A node based image processing workflow editor would be easy to extend as well: each processing node would represent an ImageMagick operation and know how to contribute its part of the final command. I kept the node definitions in JSON so that adding a new operation would not require recompiling the application.
There was another useful side effect: because imgplex only defines the workflow, I could export its commands and run them from a script without opening the editor, which also opened up possibilities for automated workflows.
The how
Once I had the basic design, I needed to choose a stack. I wanted good desktop performance, but I also wanted to use technologies I could work with quickly enough to finish the application. I wanted to spend my time building the tool, not fighting the tooling.
I evaluated several approaches:
- C++ and Qt: This was the obvious conventional choice. Qt has mature desktop UI support and several node-editor libraries, but I would have been learning both C++ and Qt while also designing the application. I know C# and Python much better, and taking on all three problems at once felt like a recipe for never shipping anything.
- Tauri looked promising: lightweight, Rust backend, web frontend. But I ran into two blockers: in my test transferring a 3 MB image through IPC as a serialized string took roughly 200 ms, and the sidecar lifecycle complexity of managing a separate processing process.
- I seriously considered Godot because GPU shaders would have made previews attractive. I ruled it out after estimating how much desktop UI work I would need for controls such as file pickers, dropdowns, and editable fields. Too much of the initial development would have gone into recreating application UI rather than building imgplex.
- Electron won. Its bundle size and memory use were not ideal, but they were acceptable for this particular tool. More importantly, it gave me consistent cross-platform rendering, direct access to Node.js, and an ecosystem I already knew well enough to move quickly. I could get a basic version running quickly and find out whether the idea was useful before investing in a more complicated native stack.
- For the graph editor, I chose Svelte Flow rather than LiteGraph.js. LiteGraph’s original repository had seen little maintenance, while ComfyUI was working from its own divergent fork. Svelte Flow was actively maintained, MIT-licensed, and designed to integrate with Svelte.
- I chose Svelte 5 for the UI. I preferred its smaller amount of component boilerplate, and its state model worked cleanly with the way Svelte Flow stores graph data.
Next post in this series: Building imgplex: part 2 - Getting things up and running