Building BatchTone: what I planned and what shipped
The spec said four platforms, a free tier and RAW. The app that shipped does one platform, one trial and no RAW, and it is better for it.
BatchTone is a Mac app that applies one colour LUT to a whole shoot, photos and video together, with a strength dial on every file. I built it in Flutter with a GLSL shader for photos and a bundled ffmpeg for video. The first plan promised four platforms, a free tier with watermarks and RAW support. The app that shipped is macOS on Apple Silicon, a seven day trial of everything, and no RAW. Each of those cuts is in the repo with a reason, and this post goes through them.
I already wrote up the three days from first commit to release as a timeline. This post covers the decisions behind it: the problem, the plan on paper, and what changed between the spec and the app.
The problem it solves
Applying a LUT to one file is easy. Applying it to eighty is a job.
The spec puts it plainly: one LUT at 100% is too strong on the backlit frames and too weak on the indoor ones. So you grade the batch, then go back through it file by file and fight the ones that came out wrong.
Before writing code I listed what people use today: ffmpeg's lut3d filter, Photoshop, Lightroom (where a .cube file has to be converted into a profile first), DaVinci Resolve with its learning curve, and a handful of small LUT apps. They all apply a LUT; the gap is in batching it, with a different strength per file. If that is your problem today and you want the free routes, applying a LUT to multiple clips covers them.
What the research said, honestly
The market research is dated 17 September 2026, the day the first commit landed. The competitors were almost all Mac or iOS apps, and the closest one had no strength control per file and ran only on iOS.
The demand was real: threads from people with eighty LOG clips to convert, a client who wanted drone footage delivered out of log, photographers grading a wedding.
And then a line I am glad I wrote down:
No thread was found where someone explicitly asks for per-file LUT strength inside a batch. The intensity dial is an inferred improvement, not a documented request.
The feature I built the product around was my guess. The verdict in the same file was "real, recurring, underserved, but not a blue ocean". I built it anyway, knowing that the dial was a bet and the batch was the need. Writing the difference down made it easier to judge later, which is the point of validating an idea before you fall for it.
The plan versus the app
| The plan | What shipped | |
|---|---|---|
| Platforms | macOS, Windows, iOS, Android from one Flutter codebase | macOS 12 or later, Apple Silicon only |
| Pricing | A free tier (20 files, watermarked video) plus a paid one-time tier | A seven day trial of everything, then one licence |
| RAW | Planned | Cut |
| LUT formats | .cube now, .3dl later | .cube |
| Positioning | A wedge for LOG footage from drones and cameras | One LUT across a whole shoot, photos or video |
Why only macOS
The video side is where the platforms differ. On a Mac I could build ffmpeg myself and lean on the operating system's hardware encoder. On mobile, the standard ffmpeg binding for Flutter was retired in January 2025, and the live fork is GPL in its basic package. In a closed paid app that matters. The notes leave mobile video as "binding TBD", and that was the honest state of it.
So the four-platform plan became one platform that could be finished, signed and supported. The codebase is still Flutter, so the shader, the library and the licence code do not need rewriting for the next one. The site lists a Windows build and exposure controls as coming next, both included in the same purchase.
Why the free tier died
A free tier with 20 files and a watermark sounds generous. The comment above the trial code explains why I dropped it: a crippled trial answers none of the questions a buyer has, and it annoys exactly the people the app is for.
The questions are technical. Does it read my camera's files? Does it keep my metadata? Does it handle my LUT pack? A watermark answers none of them. Seven days of the whole app answers all of them, and when the trial ends, exporting stops and nothing else does. The batch and the library stay where they were. It is the same argument I make in free trial versus freemium.
Why RAW was cut
Developing RAW is a different product. It needs a demosaic step, a white balance model and camera profiles before a LUT ever touches the image. BatchTone does not develop RAW, and the site says so: if you shoot RAW plus JPEG, use the JPEGs.
The rules that did not change
Five lines from the spec survived every cut:
- Never touch the originals. Every export is a new file.
- Keep the photo metadata. Date, camera and GPS carry over from JPEG originals, with a switch to strip them.
- The session survives a crash. Close the app and the batch is there when you open it.
- The preview is the export. Photos go through the same GPU shader for both. Video goes through ffmpeg with the same blend arithmetic.
- Tolerate broken LUTs. Some DJI .cube files put a tab inside the size line, which ffmpeg rejects. A file a camera maker ships is a file the app has to read.
The strength dial itself is one line of maths: the result is a mix of the original and the graded image, by the strength you set. The blend happens in display-encoded space, like layer opacity in Photoshop. The technical notes carry a warning to myself: do not market it as colorimetrically correct. I have not.
What was hard
Licences before features
A Homebrew ffmpeg is a GPL build. It cannot ship inside a closed, paid app. So BatchTone bundles its own ffmpeg, built as LGPL with VideoToolbox and without the GPL or non-free options, and runs it as a separate process instead of linking it.
The encoder order follows from the same constraint: the hardware encoder first, and the software H.264 encoder only as a fallback on my own machine during development. That keeps both the GPL and the H.264 patent questions out of the shipped app. Nobody sees this work, and if I had skipped it the app could not be sold at all.
A library of 150 LUTs
The first LUT library froze the app. The numbers from the notes:
- Parsing one 33 point cube took about 51 ms.
- The naive version used about 220 MB and froze the interface for about eight seconds on 150 LUTs.
- Parsing 12 LUTs on the main thread stalled it for 493 ms. Moved to background isolates, the stall was 8 ms.
The fix was to copy files on import and read only their first 4 KB, parse at most two at a time off the main thread, and keep 24 previews on the GPU with the visible one pinned. Every preview in the library is your own first frame, graded, so you pick a look by seeing it on your footage.
Updates without a framework
I looked at Sparkle, the usual Mac update framework, and passed. It replaces the app underneath the user and needs its own signing key and feed. Instead, the app reads a small manifest and shows a bar when a new version exists. The comment in that commit says an update is news, not a question, so it is a bar and not a dialog, and it stays quiet while an export is running.
Who it is for, and who it is not for
For: photographers and video editors who grade a whole shoot with one look and need a few frames to sit lower than the rest. Wedding and event shooters, people converting LOG footage, anyone who has exported eighty files one at a time.
Not for:
- RAW development. Use your RAW editor, then bring the JPEGs.
- A full grade. One LUT per batch, no stacked creative LUT, no exposure control yet.
- Windows or Intel Macs, for now.
- A handful of clips. If it is five files, do them by hand in the editor you already have.
The design follows the same rule: a dark interface with one amber accent, because colour is judged against a dark surround, and nothing in the interface is more saturated than the image.
If you are building something of your own, the transferable lesson is in the table above. I cut the plan to what one person could finish on one platform, and kept the five rules a professional would check on day one. Scoping an MVP is the general version of that cut. Easy Reels is the other video tool I build, and its story went the opposite way: more features first, then a lot of deleting.
BatchTone, if one LUT across a shoot is your job
A note on fit first. If you grade a few clips a week inside Resolve or Premiere, keep doing that: you do not need another app. BatchTone does not replace a grade, and it will not fix a badly exposed clip.
BatchTone applies one .cube LUT to a whole folder of photos and video on your Mac, with a strength dial per file, a library previewed on your own footage, and exports that leave the originals alone. Seven days of the whole app, then one licence.
Frequently asked questions
What is BatchTone?
A Mac app that applies one .cube LUT to a whole folder of photos and video, with a strength dial for each file. It exports JPEG, PNG or H.264 MP4, never touches the originals and uploads nothing.
Does BatchTone run on Windows or Intel Macs?
Not today. It needs macOS 12 or later on Apple Silicon. A Windows build is listed on the site as coming next; there is no Intel build.
Can BatchTone process RAW files?
No. RAW was in the first plan and was cut. If you shoot RAW plus JPEG, run the JPEGs through it.
Is the strength dial colour accurate?
It blends the original and the graded image in display space, the way a layer's opacity works in Photoshop. That is what most people expect from a strength control, and I do not sell it as colorimetrically exact.
Why build a Mac app with Flutter?
The plan was four platforms from one codebase. Only macOS shipped, but the shader, the library and the licensing are written once, so a second platform is a port and not a rewrite.
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.