Why I started building an installer toolset
By Kitsune
Work notes Ā·Developer Tools Rust GPUI UX
Installers are one of the first pieces of an application that someone has to trust.
It asks for space on their machine, sometimes asks for permissions, and then does work they cannot fully see. I think that deserves a thoughtful interface.
They were also my hyper-fixation growing up. (I owe lots of apologies to my parents for installing 6 different versions of InstallShield on the home computer)
My search for a modern Windows installer started with appearance - I wanted something like Advanced Installer, but without the price tag and CI burden, but it quickly expanded into questions about the developer experience. How much control would I have over the UI? What would the build workflow look like? How much of the process could fit into development outside Windows?
Eventually, that search became the beginning of a new installer toolset.
Appearance was the starting point
I spent time considering existing approaches, including NSIS and Velopack. NSIS looked promising to me, but the default Modern UI 2 aesthetic wasnāt⦠really modern anymore. Donāt get me wrong, I love the XP aesthetics, but thatās not the first thing I want my customers to see.
I wanted more room to shape the experience: typography, layout, motion, and the way the installer communicates what it is doing. At the same time, I didnāt want choosing a particular visual design to make every other part of the tool awkward to work with.
That led me toward exploring Rust and GPUI (I may play some more with QtQuick in the future? I still have to figure out itās licensing for static binaries though sadly).
Progress needs to tell the truth
A good-looking progress bar is easy to imagine. A useful one depends on the work underneath it.
There are stages where the application can measure a fraction of completed work, and stages where it only knows what operation is running. I want the interface to communicate that difference clearly.
For this toolset, my design goal is to represent the actual operation well enough that the UI can explain it. Preparing, downloading, extracting, and finalizing should be meaningful states if those stages exist in the chosen installation flow.
The same principle applies when something goes wrong. An error message should help someone understand what failed and what they can do next. The underlying engine has to retain enough context to make that possible.
Try a progress model
Step through this mock installation. Downloading and extracting have measurable progress within their own stage. Preparing and finalizing report an operation without inventing a percentage.
Show the work the installer can measure
PS: this is a mock. I'm not installing cryptominers on your machine. Pinky promise.
Preparing
The operation is running; its completion percentage is unknown.
Try a simulated error during a stage, then retry. This is an interface experiment, not a working installer. The progress values arenāt estimates of total installation time, and the controls donāt write any files.
Developer friendliness includes the build
One of the comparison criteria I added during the research was cross-development and compilability. That reflects how I work: I care about what can be authored and built from Linux, as well as what ultimately needs Windows-specific handling or validation.
I donāt expect a framework choice to settle all of those questions. Packaging, signing, permissions, upgrades, and uninstall behavior each need deliberate decisions.
My goal is to make those boundaries understandable to the developer using the tool. I want a small application to have a straightforward path, with explicit ways to handle the cases that need more control.
And the solution to configuration is⦠Nix
I needed a language to describe the final state of the installer. I could use JSON, YAML, or TOML, but I wanted something that could also express the build and packaging process.
Is there any better language than Nix for that? I donāt think so. It is a declarative language, it can express build and runtime dependencies, and it can be used to generate the final installer artifact. Plus, I have been working lots with Nix lately, on NixOS and Nixpkgs, so it should be a breeze, right?
I had to implement my own platform-agnostic parser and schema, but I think it was worth it. As an added bonus, I can let the most ambitious part of this project - the āStudioā - work in tandem with advanced users that need custom behaviour in their installers.
As a way to allow for advanced behaviours (and even custom themes), I implemented Roto. Iām still looking at other possibilities, as my main goal is to be able to get everything precompiled and ready to go when shipping installer artifacts, but I think Roto is a good start.
The name is still part of the experiment
Iām currently calling this project āTailforgeā, and working on building Tailforge Builder - a GUI for creating and testing installer configurations, heavily inspired by the commercial software that I liked to play with in my childhood.
Who knows, maybe one day Iāll offer it as a commercial product too š
