Backstory
Tehcnical Backstory of Desktop MP3
The journey starting with native Cocoa/AppKit, exploring many cross-platform desktop GUI frameworks, and ending up on Electron.
The Beginning
I wanted to build an offline MP3 music player to easily enjoy my library of MP3 music on macOS without the need for an internet connection and without the complexity of modern music players. I wanted it to have the ease-of-use and retro feel of early music players like Winamp and Sonique. Some of my main priorities were: support for free-form user-interface, low CPU and RAM usage, and small file size.
I built and polished the first version for macOS using Cocoa/AppKit, Storyboards and Objective-C. This framework easily covered all three of my top priorities: the binary was a few megabytes, the app was very resource efficient, and the free-form window was a breeze to implement. (See Figure 1)
I wasn't sure if anyone else out there shared my same interest in an offline desktop MP3 music player for macOS, especially so long after the advent of music streaming services, so I decided to find out by publishing the app under the name of Desktop MP3 in the App Store for Mac. To my surprise, sales started coming in from multiple countries.
Figure 1: Desktop MP3 for macOS
Exploring Cross-Platform Frameworks
Since it was clear that there was a market for a desktop MP3 music player for macOS, I wanted to bring it to Windows and Linux. The first version was built with AppKit which is a macOS-only framework. I needed to either rebuild it natively for Windows and Linux or use a cross-platform framework.
I researched over 30 frameworks (mostly cross-platform, but some os-specific) and each one of them came with its own challenges. Some frameworks resulted in a file size larger than I was hoping for (See Figure 2), some didn't work as consistently as I had hoped, some didn't come with free-form transparent window capabilities baked-in, and some only worked with Mac Catalyst, etc.
Figure 2: Desktop MP3 file size using different frameworks
Making the Cross-Platform Proof-of-Concepts
Using the macOS version as the standard for features and user-interface, I made proof-of-concepts in many of the cross-platform frameworks I had researched. (See Figure 3). Some of the GUI frameworks I tried were Electron, Tauri, QT Widgets, QT QML, OpenFin, Godot 3, Godot 4, Sciter, SwiftUI, Delphi Firemonkey, Lazarus, WxWidgets, QT, Flutter, .NET Avalonia .NET Maui, Fenster, SDL2, Rust (with Iced), Progressive Web App and more.
I also tried Windows-only frameworks in case it came down to needing to maintain a separate codebase. These included .NET WinForms, .NET WPF and Delphi VCL. The Windows-only frameworks worked very well for my specific use case and I was very impressed with them, but I wanted to make sure I could share the same codebase across Windows, Linux and macOS.
Figure 3: Desktop MP3 proofs-of-concept using different frameworks
Click-Through Transparency
Subconsciously, I knew that there was at least one thing I wasn't going to give up, and that was the retro free-form user interface with click-through transparency. After trial and error trying to get a consistent cross-platform experience matching the specific requirements of the macOS version using different frameworks, it came down to three frameworks that offered the least amount of friction to meet Desktop MP3's specific needs: Avalonia, Tauri and Electron.
Avalonia supported two of my top priorities: free-form user interface and low resource usage. File size was going to be larger than I was hoping for, but I was willing to make that sacrifice. The one feature I wasn't going to give up was the ability to click through the transparent regions of the window to the desktop or window behind it. Avalonia supported the transparency, but not the click-through ability on all operating systems. I'm sure if I spend more time on it I could figure out a clever workaround. Even though it didn't make the final cut for Desktop MP3's specific use case requirements, I am extremely impressed with Avalonia and would recommend it to anyone looking for a cross-platform desktop GUI framework.
Tauri supported two of my top priorities: free-form user interface, and small file size. CPU usage was low, but RAM was higher than I had hoped. That was a sacrifice I was willing to make in exchange for the developer experience. I also had some trouble with clicking through the transparent regions of the window to the desktop or window behind it, but I'm certain if I spend more time on it I could figure out a clever workaround. Another concern with Tauri is that because it is reliant on the host-provided browser, it can have slightly different results across operating systems. There is also concern that the host-provided webview can change versions out from under your app at any given time. Even though Tauri didn't make the final cut for Desktop MP3's specific use case requirements, I am very impressed with it and would still recommend it to anyone, especially those wanting cross-platform mobile compatibility in addition to cross-platform desktop compatibility.
Electron supported two of my top priorities: free-form user interface and low CPU usage. The RAM usage and file size were higher than I had hoped, but I was willing to make that sacrifice in exchange for the developer experience. Electron ships with a copy of Chromium, so you know the renderer you tested with is the same renderer the end user will be using. In order to accomplish click-through behavior of the transparent regions, I first used the approach of calling setIgnoreMouseEvents(false) when moving the mouse away from the opaque regions, and setting it back to true when refocusing the app. That approach wasn't always consistent so I later switched to use setShape(rects) to set the shape of click-through regions to match the transparent regions. The latter approach means more work if needing to change the shape at runtime if I add custom skin support in the future, but for now it is working well enough across operating systems.
Because Electron and Tauri use a web-based renderer for the user interface layer, developers already familiar with CSS have no trouble styling the app's user interface. Developers can also take advantage of popular libraries like D3.js for charting, Butterchurn for audio visualization effects (See Figure 3), and popular frontend frameworks like React, Vue, Angular, Svelte, etc.
Figure 3: Desktop MP3 using Butterchurn for audio visualization effects
Ending up on Electron
In the end Electron was chosen because it offered the least amount of friction and provided one of the best developer experiences for Desktop MP3's specific use case. Other frameworks I researched and used for proof-of-concepts are great at what they specialize in, but some of the things that were important to Desktop MP3 were not supported by them.
Some notable audio-related features that some of the higher-level frameworks offer, including Electron, are ready-to-use audio components with baked-in support for multimedia keys and integration with the operating system's audio center.
Desktop MP3 using Electron
What about bloat with Electron?
RAM Usage: When comparing Electron's RAM usage to Tauri's, it is going to be about the same. Tauri doesn't ship with a copy of Chromium like Electron does, but Tauri still loads the os-provided browser engine into memory and, in my case, ended up using around the same amount of RAM as the Electron version.
File Size: When comparing Electron's file size to that of Tauri, the difference is not as much of a concern now as it was 20 years ago. Assuming the average low-end computer's hard drive these days is 256GB, if a Tauri app's file size ends up being around 10MB that means it uses about 0.004% of the total available space. And if an Electron app ends up being around 150MB that means it uses about 0.059% of the total available space.
Open question: I wonder if we have hit the point where the state of the ecosystem is such that the bloat of larger cross-platform desktop GUI frameworks like Electron, Tauri, Avalonia, etc. in exchange for the developer experience and cross-platform compatibility is not as much of a concern as it was 20 years ago.
What about the pricing of Desktop MP3?
The macOS native Cocoa/AppKit version of Desktop MP3 is battle-tested and stable. It is available for a modest price through the macOS app store.
The cross-platform Electron version of Desktop MP3 is still a work in progress, and is currently available for free. The future monetization strategy is yet to be determined.
Final Thoughts
The cross-platform version of Desktop MP3 is still a work in progress, but I have already learned a lot about the different ways of approaching cross-platform desktop GUI development. I became familiar with concepts like Retained Mode vs Immediate Mode and how they affect CPU usage. I also learned about Layered Windows vs Non-Layered Windows and how they affect anti-aliasing, etc.
If you want to follow along with my journey, please consider downloading Desktop MP3 and giving it a try. You can find the download links on the pricing page.
And if you like what you see, please consider leaving a review on the App Store for Mac or the Microsoft Store, or even just send an email to say hello. It would mean a lot to me!
Still Here? Cool, Here's Something Extra
Check out the technology page to learn more about the tech behind Desktop MP3.
About the Author
Anthony Tietjen is a Principal Software Engineer with experience across desktop, mobile, and web. He is a husband and father with a passion for software development, music and the outdoors. Connect with Anthony on LinkedIn and X (Twitter).