Let me start with the scene that broke me.
I had two video files sitting on my desktop — Part1.mp4 and Part2.mp4, 73 MB combined. I needed to merge them and shrink them. Ten minutes, tops.
An hour later I was still in the terminal, consulting ffmpeg man pages, copy-pasting filter-complex strings from Stack Overflow, trying to figure out why concat refused to stitch two clips with slightly different frame rates. 57/1 and 56/1. Close enough, right?
ffmpeg disagreed.
I got there in the end. One long one-liner, a lanczos scale, a pad filter for the letterbox, H.265 at CRF 20. Thirty megabytes out. Looked great.
But I closed the terminal and thought: this should have taken thirty seconds, not an hour.
Why Every Existing Tool Disappointed Me
Video compression on Mac should be a solved problem. Somehow it isn’t.
- FFmpeg is a black-belt’s tool. You need it, but you shouldn’t need it for “please make this video smaller.”
- HandBrake opens with forty-seven settings. Forty-seven. Before it’ll touch a file.
- Online compressors want you to upload a 500 MB video to a server. No.
- Compresto / ShrinkIt / Permute are fine, but still ask you to pick a preset. And charge for it.
What I actually wanted was: drop a video, get a smaller one. That’s the whole app.
So one Saturday I decided to build it.
The Thesis: Zero Decisions
macOS already knows how to encode HEVC really well. Apple Silicon has dedicated media-engine silicon built specifically for this. The video files people actually compress are a remarkably predictable distribution — iPhone clips, Zoom recordings, screen captures, AirDropped reels. A well-designed app could inspect any of those, derive a sensible encode plan, and execute without asking the human anything.
No sliders. No presets. No modal settings screen.

And if the output would be bigger than the input — as happens more often than you’d think — don’t even write it.
I named it ByeBye Bytes. Stupid-obvious name. My partner laughed the first time I said it out loud, which was the only focus group I needed.
Architecture first, code later
Instead of bashing code end-to-end, I split the problem into independent modules with explicit contracts.
- Core — media inspection (
AVAsset→SourceProfile), a settings resolver that mapsSourceProfile→EncodeRecipe, a tiny user-settings model - Encoders — three of them:
RemuxEncoder— stream-copy for sources already HEVC at a sensible bitrateSingleFileEncoder— full HEVC re-encode viaAVAssetReader→AVAssetWriterMergeEncoder— a fastAVMutableCompositionpath + a slow CoreImage letterbox path for mixed-resolution inputs- Queue — a
@MainActorObservableObjectwith an actor-gated concurrency cap and throttled progress reporting - UI — SwiftUI throughout, with an ADHD-friendly layout rule: one focal point per state
Each module exposed a small public surface. Shared types lived in Core/Types.swift. Then I parallelised implementation — four modules in flight simultaneously, each with clean file ownership to avoid merge conflicts.
When the pieces came together, only two interface mismatches surfaced (one caller assumed enqueue(urls:kind:), another built submit(urls:)). Both fixed in seconds.
The pattern I keep coming back to: define the contracts first, parallelise the implementation, resolve integration by hand.
Making It Feel Good
Technical correctness is table stakes. The harder part was making the app feel calm to use.

Most compression apps are hostile to my attention. Multiple progress indicators, indeterminate spinners, settings modals that interrupt whatever I was about to do. By the time a 30-second encode finishes, I’ve already opened a new tab and forgotten why I was there.
So I wrote rules for myself:
- One focal point per state. Drop zone or queue, never both mixed together.
- No modals, no settings panel. Zero decision load during normal use.
- Determinate progress only. Indeterminate spinners trigger restlessness. A determinate bar with an ETA is calming.
- State is obvious at a glance. Colour + icon + motion together — never colour alone.
- Completion feels good. Soft “Saved 42 MB” callout, gentle green check. Dopamine without being loud.
- Escape hatches visible. Every running job has a Cancel ✕ — no menu hunting.
- Respect reduced motion. Every animation checks the accessibility env.
When macOS 26 Tahoe shipped with its new Liquid Glass design language, I rewrote every surface to use the new .glassEffect modifier — gated with #available(macOS 26.0, *) so the app still degrades cleanly to .ultraThinMaterial on Sonoma and Sequoia.
My first pass at the “done” row had a full green wash — looked nice in theory, awful in practice. Oversaturated background, poor text contrast on the status line. I scrapped it and replaced the treatment with a neutral glass panel plus a thin colored accent stripe on the leading edge. The state signal lives in the stripe + the icon colour — the rest stays readable.
Sometimes the 10x UI improvement is removing ninety percent of what you put in.
The Icon Was Its Own Project
I wanted the icon to speak Liquid Glass fluently — the new layered format that derives dark / tinted / clear variants automatically from foreground layers on transparent backgrounds.

Squeezing the M-Chip
Once the app was working end-to-end, I turned to performance — the kind of work users never see directly, but feel every time they use the app.
Your Mac has a dedicated chip specifically for video. iPhone uses the same kind of thing to shoot 4K without melting. Most apps don’t fully lean on it. A handful of small changes made a real difference:
Never settles for the slow path.
macOS has a fast way to compress videos (using that dedicated chip) and a slow way (using the regular CPU). The slow way is 5–10× slower. Most apps let the system pick; ByeBye Bytes insists on the fast way, every time. If for some reason the hardware isn’t available, the app tells you instead of silently grinding.
Stops wasting work behind the scenes.
The old merge logic was quietly doing two expensive conversions per frame — taking video data, translating it to a format CoreImage preferred, then translating it back for the encoder. Frames travel through thousands of those per video. Skipping the round-trip shaved an estimated 20–40% off merge time on bigger videos. The result: you spend less time staring at a progress bar.
The first encode feels like the tenth.
Graphics pipelines “warm up” the first time you use them — think of it like a cold engine. The old code was re-warming for every single video. Now the app warms up once and reuses that warmth for the rest of your session. First drop of the day feels as snappy as the twentieth.
Runs smart on your specific Mac.
Different Apple Silicon chips have different numbers of video engines — a base M1 has one, an M1 Pro has two. The app now counts what’s available and runs exactly the right number of encodes in parallel. Don’t over-schedule a base model (it just slows down), don’t under-utilize a higher-end one. Whatever Mac you’re on, it makes full use.
Keeps your photo details.
macOS’s built-in video tools quietly strip metadata — the “taken on June 14th at the beach” info, GPS, camera make and model — every time they re-encode. For iPhone videos, that means your compressed memories lose the data that makes them findable in Photos. ByeBye Bytes copies all of that forward. Your compressed trip.mp4 still shows up on the right day, in the right place, taken on the right phone.
Skip-If-no-gain (My Favourite Feature)
The feature I’m proudest of is almost invisible.
Some files simply can’t be compressed meaningfully. Low-bitrate screen recordings. Ultra-short clips. Already-HEVC videos at a tight bitrate. A naive compressor encodes them anyway, writes a slightly-larger-or-equal file, and calls it a day.
ByeBye Bytes doesn’t do that. After every single-source encode, it compares output size to input. If the saving is below 2%, it deletes the output entirely and marks the job “Already optimized – kept original” with a calm neutral row. Your original file is untouched. No clutter in the output folder.
This is the kind of feature that’s almost invisible in normal use. But the first time it skips for you, you think: oh, thank you.
Shipping in 2026
Distribution has two cheap wins in 2026:
GitHub Releases. ditto-zipped .app with SHA-256 in the notes. One tag, one asset, done.
A personal Homebrew tap.
brew install --cask saiftheboss7/byebye-bytes/byebye-bytes
xattr -dr com.apple.quarantine "/Applications/ByeBye Bytes.app"
(The xattr line clears macOS’s quarantine attribute – unavoidable for ad-hoc-signed apps until I spring for a Developer ID and notarization. On the list.)
Try It
Source & issues: github.com/saiftheboss7/ByeBye-Bytes
Install:
brew install --cask saiftheboss7/byebye-bytes/byebye-bytes
xattr -dr com.apple.quarantine "/Applications/ByeBye Bytes.app"
Or download the .app straight from Releases.
macOS 14 Sonoma or later, Apple Silicon recommended. MIT licensed.
If something breaks, open an issue. If it saves you an hour, star the repo. And if you have a feature you’d want to see next, tell me – I’m listening.
Discover more from Saifiction!
Subscribe to get the latest posts sent to your email.
Add your first comment to this post