Shipping BatchTone: 25 commits, three days
Not a tutorial. One product, every decision in the order it was actually made, including the one that took longer than the feature.
The short version
- The working product took about six hours. Everything after that was selling it.
- Pricing was decided before the name. Commit 14 and commit 15, in that order.
- The unglamorous work came early on purpose: licensing at commit 12, before the icon.
- Real data broke it immediately. Three freezes in 33 minutes, all on a real LUT pack.
- The last mile is signing and packaging, and it is where release day actually goes.
What this is
The commit log of one product, in the order it happened. BatchTone applies a colour LUT to a whole folder of photos or video at once instead of one file at a time. First commit to signed release was three days and 25 commits, and the useful part is not the speed, it is where the time went. The working product was about six hours. Everything after that was the business of selling it.
Every other post here about building alone is a how-to. This one is a receipt.
Day one: six hours to a working thing
The first commit is called LUTFlow prototype: batch LUT with per-file strength. That name is worth noting twice: once because it is not the product's name, and once because the per-file strength was in the very first commit rather than added later. It was the reason to build it at all.
The second commit adds pixel tests for the shader. That is unusual for a prototype and it paid for itself immediately: a colour transform that is subtly wrong looks plausible, and without a test you find out from a customer.
Then, within 33 minutes:
19:11 Add a persistent LUT library with a preview grid
19:20 Fix the freeze when importing a real LUT pack
19:34 Fix the LUT grid freezing the app when opened
19:44 Stop previews vanishing: own the image handles you keep
Three bugs in half an hour, all the same kind: the thing worked on one file and fell over on a real folder. That is what real data does to a prototype, and it is the argument for pointing it at real data on the first evening rather than the first week.
By midnight, video was in and the encoder question was settled: prefer the operating system's hardware encoder over a software one, because a card of footage should not be an overnight job.
So: a working product in an evening. This is the part people mean when they say a small tool can be built in a day, and they are right. They are also describing about a quarter of the work.
Where it stopped being about the code
Commit 12, roughly two-thirds of the way through day two:
Licensing, packaging and the legal paperwork for selling
Before the icon. Before the name. Before any of the things that feel like finishing a product. Then:
01:39 One product, one price: 7 days of the whole app, then a licence
02:10 Rename to BatchTone, and write down what the brand is
The price was decided before the name. That order is not an accident and it is the opposite of how most side projects go. People name the thing in hour one, design a logo in hour two, and discover in month three that they never decided what it costs or who buys it.
Deciding the commercial shape first meant the name had something to describe. LUTFlow described a mechanism; BatchTone describes what it does for you.
The last mile is longer than it looks
Day three is almost entirely distribution:
Keep signing credentials out of the repository
Build ffmpeg for macOS 12 on Apple Silicon, not for this machine
Cover, thumbnail, and a packaging run that actually completes
One command to cut a release, and a way for the app to notice
Sign the disk image, not just the app inside it
Two of those are worth pulling out.
"Not for this machine" is the works-on-my-machine trap, caught before release rather than after. A dependency built against whatever your laptop happens to have will refuse to start on a customer's older OS, and you will hear about it as a refund.
"Sign the disk image, not just the app inside it" was found on release day. Signing the app is the step everybody knows about; the container it arrives in is a separate signature, and macOS will complain about the one you forgot.
Neither of those is interesting. Both of them are release day.
What it cost, honestly
| Phase | Roughly | Share |
|---|---|---|
| Working product | 6 hours | The part people picture |
| Licensing, pricing, brand | ~4 hours | Before the icon |
| Signing, packaging, release | ~6 hours | Release day |
| The site and its posts | Separate project | Ongoing |
That ratio is the whole point, and it is the same claim how long it takes to build an app alone makes in the abstract: that the feature is about a third and the rest is the unglamorous machinery. Here is one instance of it with timestamps.
What made three days possible
Not speed. Three decisions, all of them subtractive:
- One job, one kind of person. A LUT, across a folder, on a Mac. No library, no catalogue, no cloud, no accounts. Scoping an MVP you can finish is that cut, and the version here was brutal.
- A price, not a plan. One product, one payment, a seven-day trial of the whole thing. No tiers to design, no metering to build, no upgrade path to reason about, which removed days of work that a subscription would have demanded. Pricing for solo founders covers why that is a product decision and not a marketing one.
- The boring work early. Licensing at commit 12 rather than commit 24. Doing it early meant the release was a release, not a discovery.
What it does not prove
It would be dishonest to leave this as a three-day success story, so:
Three days is the build, not the business. A shipped product with no users is a shipped product with no users, and the distribution work starts now, which is the slower half and the one the Income Loop is actually about.
It is short because it is small. One job, one platform, no accounts, no server. Anything with users, sync or a backend is a different order of work; that is most of what building a SaaS alone covers and almost none of it applied here.
Fifteen years of doing this made the six hours possible. Someone learning Flutter and code signing at the same time is not slow; they are doing two things.
The transferable part is not the speed. It is the order: real data on day one, the commercial shape before the name, and the unglamorous work before the icon.
You can try BatchTone for seven days, and the build is being written up as it goes the same way everything else here is.
Frequently asked questions
How long does it take to build a Mac app alone?
For this one, three days from first commit to signed release, but the part that made it work was about six hours. The rest was licensing, packaging, code signing and release tooling, which is the part nobody budgets for.
What is BatchTone?
A macOS app that applies a .cube LUT to a whole folder of photos or video at once, with a strength dial for each file. It exists because doing that one clip at a time is the slowest part of colour work.
Should I name the product first?
No. This one was called LUTFlow for the first fourteen commits and was renamed once it was clear what it actually did. Naming early commits you to a guess about the product.
What took the longest?
Not the feature. Shipping our own ffmpeg build, code signing, notarisation and packaging, and finding on release day that signing the app is not the same as signing the disk image.
Is three days normal?
No, and it is not the point. It was possible because the scope was one job for one kind of person and because the unglamorous work was done early rather than discovered late.
The system behind this, written down
Everything above is the map. The Income Loop is the work inside it: modules 0–6 from the problem you solve to the offer that pays for it, plus ten traffic paths: the deeper post banks, the content sales systems and the full software build sequence, in one place.
Get The Income LoopNot ready to pay for anything? The Basic Income Loop is free and includes a complete seven-day starter for Threads, Instagram or software, enough to find out which one suits you before spending anything.