xor.dev

uLaunch v1.0: understanding and replacing the Nintendo Switch HOME menu

09 Sep 2024

Hey! uLaunch is my custom Nintendo Switch HOME menu replacement. I have dropped a big and stable release, v1.0, a few months ago.

If you have any sort of curiosity about all the quirks and subtleties of how the HOME menu works internally, or how I got to create a custom replacement, then you will definitely enjoy this post ;)

YouTube

The Nintendo Switch process ecosystem

All Nintendo Switch processes can be classified by several characteristics. First of all, all processes displaying some kind of graphics visible to the user (including games, the HOME menu, notifications, the user page and so on) are applets. The other non-applet processes run in the background, and are typically known as sysmodules/system modules.

However, there are various types of applets. Any game/application is internally an applet (although with some different handling from other applets) but for the other applets, the majority of them are library applets: the user page, the system keyboard, the Mii editor, any web browser used by the console…

Note: games are known as “applications” internally

There are two notorious exceptions, two unique applets known as the system applet and the overlay applet, with unique special permissions. The overlay applet corresponds to the applet displaying notifications, the power menu shown after holding the Power button for a while, and the side menu shown after holding the HOME button for a while.

As you may have already guessed, the system applet is the HOME menu. This is where our story begins.

Inside the HOME menu: qlaunch

The Nintendo Switch HOME menu is just another process inside the console, whose process name is qlaunch, likely standing for “quick launch”. As a system applet, it has special privileges that allow it to launch, close, suspend applications and so on. Similar to other applets, despite having to serve the UI for the system, it is quite lightweight as it only consumes around 50MB of applet pool memory.

Note: the available process memory is split into several memory pools for certain process types. Sysmodules get their own pool, the only running game/application gets its own huge pool, and all applets get their own pool.

The system applet is how the HOME menu process is internally known in reverse-engineered process code. This makes sense as a more general term, since for different special consoles qlaunch may not be used as the HOME menu. For instance, Kiosk units (internally known as “Quest” units) have special firmware which instead have the so-called “Retail Interactive Display Menu” as their special HOME menu, and internal development units have the so-called “DevMenu”.

Note: if you wish to find out what’s known about other obscure retail process replacements used in dev/Kiosk consoles, check this Switchbrew page.

UI and menus

The HOME menu provides the main menu where the games are listed (internally known as the “ResidentMenu”) and several other menus: user page, news, system settings, album, sleep options, eShop and so on.

Most of these are individual library applets; in other words, they are external processes that the HOME menu launches when the user selects them, what may be compared to showing file-open dialogs in desktop PC software, or forms in web pages. This is, in fact, the purpose that library applets serve: they are spawned and shown by another applet for a certain task (that process can also be a library applet, like when the user page applet spawns the keyboard applet over it for the user to change its user name) and closed after the task finishes, returning the result of the task (whether the user cancelled or not, for example) and the output data to be used by the caller applet.

Nevertheless, two of these menus are notorious exceptions: news and system settings, which are not separate applets and are actually part of the HOME menu UI quite like the main menu. This, as later explained, implies an extra amount of work when creating a custom HOME menu.

Nintendo Switch’s hidden easter egg: flog

If you take a look into all the processes inside the Nintendo Switch firmware (even on the latest) you will find two special processes: starter and flog. Both of them belong to a special kind of game/application: they are system applications. These behave almost like regular games/applications, but they are system processes built in the firmware and not regular installed/gamecart games.

The starter process is the process shown for the initial console configuration when booted for the first time. I actually have no clue if there is some sort of technical reason for why the process is a system application instead of being some applet…

The other system application, flog, is something rather unexpected: it consists of a NES emulator with a hardcoded NES ROM inside the code itself. When launched, it emulates said game. Which game is it? It’s Golf, of course! The process name was hinting at it. Well, this is not entirely true: since firmware version 4.0.0 (which is quite old already) the flog executable binary is filled with garbage and cannot be executed through homebrew.

In firmware versions previous to 4.0.0, the HOME menu had special checks where, if the date is set to Satoru Iwata’s passing date and by replicating certain gestures he made during a Nintendo Direct (more detailed description in Switchbrew) the flog process would be launched, and NES Golf would be playable with the detached joy-cons.

flog

A brand-new HOME menu: uLaunch

As many of you probably have noticed, the HOME menu is notoriously simplistic, both in design and features. Surely, it does what it’s meant to do quite efficiently, but it does resonate with the “quick launch” filosophy that can be derived from its process name: it probably was intentionally built like a simple and quick menu, without many of that quirkyness present in older HOME menus, particularly compared to the 3DS era.

The idea of making my own HOME menu first came to my mind when working on Goldleaf, my most well-known homebrew tool. At some point around summer of 2019 I noticed I could replace the HOME menu executable with a specially crafted Goldleaf build, which I showcased on my YouTube channel in this video:

YouTube

Testing with this was fun, but it was not really something users would like, considering Goldleaf is a bit far from being a fully suited HOME menu. But then I kept thinking, and the idea slowly built into my mind: this was something that could be materialized in a new project!

The project started with the temporary name of Project Home and soon got the name of eQlipse (while I’m unclear of what was on my head when coming up with this name, I assume I just combined eclipse and qlaunch and was satisfied with the result) and footage of my first steps on the making can be seen in this video:

YouTube

Around the same time, Reisyukaku started working on their own HOME menu replacement, DeltaLaunch. Regardless, the project has since been inactive. There are no other known/public HOME menu replacements that I’m aware of.

HOME menu basics

Surprisingly enough, back then I did no reverse-engineering on the original HOME menu. In fact, only recently I have started doing so, but until now I didn’t have a huge need to get into that. The reason is how the HOME menu internally works.

Most of the complexity of the HOME menu’s functionality (excluding graphics) relies on its communication with other processes. Several sysmodules take care of all the deep internals of how applets work and interact (mainly am, which stands for “applet manager”, and ns on a higher level, standing for “Nintendo Shell”) and they communicate through IPC, the inter-process communication protocols. For more details into how IPC works, check [emuiibo].

By the point where this project started, other active devs had already reverse-engineered a lot about IPC commands used in applet-related stuff. For example, everything regarding applet and application launching was already documented up to some extent (other devs had already started reverse-engineering the HOME menu) so it was just a matter of playing with IPC commands whose names sounded close to what I was trying to achieve. This is how, for instance, I ran into commands RequestToGetForeground and RequestForApplicationToGetForeground, and why implementing basic HOME menu functionality was not a huge deal.

Through some ns IPC commands, the HOME menu is able to get the list of games in the console, to get their icons, names and so on. I had already used this for Goldleaf, so this was straightforward as well.

The HOME menu, like the overlay applet (the two special applets) are processes always running in the background. In fact, they are the only applet processes that are expected to never exit. If one of them happens to crash and exit, and the am sysmodule finds out that it is not running anymore, it will force a system crash with a dedicated result code.

Another relevant functionality of the HOME menu and other applets are applet channels: these are basically buffers managed by dedicated IPC sub-interfaces, used via certain commands, which allow for sending and receiving data to/from applets. For example, library applets get their input data from their caller applet and send the output data to said applet via a dedicated channel between them.

The relevant channel here is the so-called general channel, which is used by any applet to send requests and whatnot to the HOME menu. This is mainly used by the overlay applet, notifying the HOME menu of its different states. This is, in fact, the way the HOME menu actually knows that the HOME button is pressed (and even if it was a long or a short press). Other than that, games may use it to request to jump to the HOME menu (hence suspending themselves) or to re-launch themselves.

All applet and application processes periodically receive the so-called applet messages. These is some sort of notification system, similar to the one used in main-loops in libraries like SDL2, with a wide range of messages. Not all applets receive all messages. In the case of the HOME menu, these messages allow to detect when the SD card is removed, when the console is (un-)docked, when some processes requested to sleep, when the console is woken up after sleeping, and so on.

Splitting into multiple processes

Memory and graphics were a major roadblock for a while. The project relied on my Plutonium UI libraries, which are essentially a high-level wrapper over SDL2. This is not a problem in general (Goldleaf does the same) but memory requirements get serious when you are the HOME menu. Regular homebrew has around 300-400MB of memory to use, while the applet pool is rather tight: at some point I was using around 180MB of memory (more than three times what qlaunch uses) while the UI was struggling to render anything, and reducing the memory usage would just make it worse.

At some point I was close to giving up on this, but then I came up with an ingenious solution: splitting the functionality of the HOME menu in two proceses. The core process, the system applet (which I appropriately named SystemAppletQDaemon) took care of all “backend” functionality, while a library applet (LibraryAppletQMenu) was used to render the UI. I will refer to them as Daemon and Menu from now on. This scheme saved the project: the vast amount of memory was just needed for the library applet, so when anything else was opened, Menu would be closed, and then reopened by Daemon after the applet/application was closed or suspended. Of course changing the UI libraries was and still is an option, but that would require a rather huge amount of effort (specially now) that I am not willing to spend.

This did save the project, as uLaunch still relies on this mechanism. I came up with a dedicated system for Daemon and Menu to communicate between themselves, dmi (standing for Daemon-Menu Interaction) which relied on custom general channel messages for Menu->Daemon communication, and a custom IPC service for Daemon->Menu communication. Over time I have made minor improvements to this system, but it is still the same underneath.

How am I even able to create a custom library applet? I actually can’t, since the am sysmodule has a hard-coded list of all existing library applets. The solution is to take-over a certain library applet: for example, I can take over the eShop library applet (which is what uLaunch does by default since then) so that Daemon launches the eShop applet, but Menu is launches instead. Like everything under Atmosphère and custom firmware/CFW, none of this changes is permanent, since we’re essentially “tricking” process-launching sysmodules into launching a different executable binary.

First release

The approach I followed for eQlipse, as shown in the footage above, was to include several useful features: an integrated but separate homebrew menu and folder support. Some of the first goals of the project were (and still are) to make homebrew easily accessible from the HOME menu itself, and the ability to sort games in folders like in the old 3DS days.

eQlipse

By this point, I still wasn’t dedicating a lot of effort towards the UI. I just made basic buttons that did their job. Regardless, it was cool enough to make a first release. By the time of the first release, in november 2019, I coined the name uLaunch, both as a reference to the original qlaunch (Rei likely did the same with DeltaLaunch) and as a subtle emphasis on the customization aspect, in the sense that “you launch” games however you like.

User profiles

Early during development of the first release, I decided to follow a slightly different approach regarding user profiles.

Most games require selecting a user profile (mainly for online play and/or savedata). The official HOME menu prompts the user selection library applet just when the game is launched, but I wanted to follow a more PC-like approach.

The user profile is selected on startup, before even jumping to uLaunch’s main menu. This way, any launched game will use that user profile. This approach is still used by uLaunch, and (in my humble opinion) it’s nicer than having to select the user profile per each game launch.

Nevertheless, this is not the only quirky design I considered for user profiles: uLaunch used to have its own password system on early versions. This system made the user-selection process even more similar to PC users, where a password could be set for each user. However, some user complaints (for instance, parents complaining about forgotten or unknown passwords their children had put) made me reconsider the feature, which I eventually decided to remove.

I still ocassionally get users asking about the absence of the password feature in recent uLaunch versions…

Design subtleties

While this was quite a lot of work for me, it was really far from being a suitable HOME menu replacement. Heck, even the current, nice and stable uLaunch still lacks some OG qlaunch features that many users understandably demand in order to switch to it. Where do I begin…

The system settings, as explained above, have to be made completely from scratch, unlike other “menus” which are just a matter of launching the corresponding library applets, like the user page or the album. This is, in fact, still a weak point in uLaunch: there are dozens upon dozens of individual settings in the OG HOME menu, some of which are only half-documented or I completely have no idea how to implement.

The folder system was rather messy, as bugs happened here and there, plus it was a bit annoying to navigate. The UI was overall notoriously slower than OG HOME menu’s, which was annoying as well.

Controls had a lot of room for improvement. In the first release only a few features could be accessed if the console was docked, since those buttons shown above are literal buttons, only clickable by touching them. Again, polishing the UI was not really my top priority while I was trying to drop a first release.

Homebrew taking over processes

Under Atmosphère/CFW, homebrew is launched via the combined efforts of hbmenu and hbloader. The role of hbloader is to take over the album applet (in the same way as described above) which prepares everything and loads hbmenu into memory as the base hub/menu.

hbloader only has a single homebrew loaded in memory for obvious memory-related reasons. When another homebrew is selected from hbmenu, it sets information about the next homebrew to be loaded back in hbloader’s memory, and then exits back to hbloader code, which repeats the same loop. When the next homebrew is mapped in memory and ready to be started, hbloader resets the next-homebrew-to-load information back to hbmenu by default. As you can see, this is just an endless loop of a homebrew running, exiting, and hbloader disposing it and loading in memory the next one.

How could uLaunch launch homebrew on its own, without the usual album-based mechanism? The solution I came up with was to make my own custom version of hbloader, named LibraryAppletQHbTarget. This library applet would take over parental controls applet by default, and took special input sent by Daemon (and previously requested from Menu) of which homebrew to launch. This probably was more complicated than just trying to work with the existing hbloader, but for future releases it ended up actually being useful.

While taking over a process is extremely useful, it is extremely risky as well. In fact, what is stopping anyone from getting their hands on a game binary, and taking over one of their existing games so that this new game can run over the old one? Aside from piracy-related objections, telemetry will be your worse enemy.

It is well known that the console sends telemetry reports of several kinds to Nintendo servers. Moreover, some of them get locally saved if the console is offline, for them to be uploaded the moment the console is connected to the Internet. Banwaves happened for this reason, since Nintendo was able to detect that many homebrew users were running some games over other games.

This became a problem with uLaunch’s attempt to improve homebrew launched as applications.

Homebrew was originally only launched from the album as a library applet, but this limits its memory a few hundreds of MBs as mentioned before. Soon, Atmosphère, hbloader and hbmenu were updated to take over a game being launched if a particular input combination is pressed, R being the default. Since uLaunch had homebrew easily accesible, it would be quite useful if, aside from launching it as a library applet via LibraryAppletQHbTarget, it was also easily launchable as an application.

This alreasy poses a problem: launching homebrew as an application requires an application in the first place, and the user may not have any games in the console. However, there is an alternative: remember starter and flog, those system applications built in the firmware? Indeed, this is what uLaunch used in its first versions. I made a fourth custom process by the name of SystemApplicationQHbTarget which would take over flog by default in order to launch homebrew as applications. Both HbTarget processes share the same code, and merely differ on the output binaries generated when compiling the project.

This was, in fact, a grave mistake of mine. For any console online and without any telemetry blocking (Atmosphère implements some blocking by default, though) Nintendo servers would see a console running flog, something literally impossible in modern firmware versions like the one the console is reporting. In other words, this was a pretty easy way to find yourself banned.

I quickly reversed the issue and, in next releases, a donor system was implemented: the user would have to select a game in the main menu as the “donor game”, so that homebrew would be launched using said game. This is still used, and achieves the goal of being a more straightforward way of launching homebrew as applications without using Atmosphère’s key combinations.

Screen capturing

While going through all the existing IPC commands and slowly figuring out how to implement HOME menu functionality, I came across some interesting commands for screen capturing. There is a dedicated sysmodule for game capturing, used to generate the videos saved on the album, so the existence of unrelated applet-specific commands for screen capturing was rather surprising.

This applet commands are to some extent more powerful than the game recording IPC API, because they capture the entire screen and not only the game layer. When recording a game, all the overlay menus mentioned previously are not recorded since they are drawn on dedicated layers above the game. Moreover, as you may have guessed, game recording only works on games, so the HOME menu or other library applets cannot be captured by this mechanism.

After playing around with the capturing commands, these ended up as two new uLaunch features: when the active game is suspended and Menu is reloaded, it quickly captures the last frame of the game before being suspended, which is then shown in the background in a similar way the 3DS menu deals when a game is suspended.

The second feature, more ambitious, is using Daemon for constantly capturing screen frames in a dedicated thread, which are then sent via USB to the PC and a dedicated program, QForegroundViewer, receives and displays them in real time. The result was quite nice, being able to capture more of the screen than with other existing homebrews like SysDVR, but with major speed in problems: this is just constantly capturing frames after all, unlike the dedicated and polished game-recording services. Since it still serves as a nice way to take screenshots of the entire screen, the feature stuck, except for a brief period where, due to issues with the code and changes in homebrew libraries, crashes and my lack of time, I was providing support updates with this feature disabled until I could get to fix it.

Themeing

From the very beginning of the project, the idea of some sort of themeing system was in my mind. The official HOME menu has the most bland white and black themes imaginable, and uLaunch aimed to be as customizable as possible.

On paper, themes are rather simple: they just consist on a system to replace the default uLaunch assets (icon images and positions, text fonts, colors and sizes, and so on) with custom assets. Moreover, BGM and sound effects had to be there, if uLaunch really was aiming to restore the HOME menu to the glory days of the 3DS.

However, everything gets more messy when actually getting to code. For instance, by the way the main menu or the homebrew menu were programmed, just letting theme makers to place it at an arbitrary X,Y position on the screen would not look good whatsoever. Similar problems arose with other special UI components, and many of them still limit themeing to this day.

Regardless, many users got to show their creativity with custom themes, as can be seen in the unofficial subreddit and on the old channel in my Discord.

First rewrite attempt: uMad

The second release of uLaunch did notoriously expand its features, introducing a new menu to navigate options without using the touchscreen, plus including a bunch of new of said options (album, controller support, power options) and more implemented system settings. The next releases, however, barely introduced anything new. In fact, since v0.2 (which essentially consists on an improved first release) each new release introduced less and less changes, with the last releases until v1.0 being just support updates. Due to lack of motivation and free time during this period of time, I just maintained the project alive with support updates, without really getting into deep improvements… except this is not the true story.

Releases reflect officially and ready-to-use binaries and features, but important changes were happening under the hood, in the shape of potential rewrites of the entire project. uLaunch is a chimere, comprising both backend and frontend aspects and having a lot of subtleties throughout its entire code, to the point where trying to improve a relevant area of the project basically meant (and still would mean) rewriting it almost entirely.

I still have the code of several unfinished rewrite attempts in my hard drive, which I never got to push to the repository because of how unstable they were. Back then I was mostly concerned with the UI, since I was still not satisfied with the design I had chosen when starting the project. For instance, this is a mockup I made for rewrite I was working on after dropping the first release, around December 2019:

MockupDec2019

This is a mockup for the top part of the menu, made around July 2021:

TopMenuMockupJuly2021

In some mockups, I even began testing with the idea of making scriptable themes, so the entire layout of menus could be programmed by theme makers with dedicated JavaScript instead of being limited by theme options, but it proved to be too much for the effort I was willing to put.

Eventually, with some motivation and ideas from other devs (around spring of 2022) I started making decent progress at a rewrite which I funnily decided to name uMad. The UI got a drastic redesign, partially inspired by the 3DS-era HOME menu, and most importantly, the main menu and the homebrew menu got merged, so that users could add homebrews as items in the main menu:

uMad

By comparison, the original uLaunch UI had little to no inspiration from other HOME menus, and was basically inspired on the horizontal-scroll UI of the base Nintendo Switch HOME menu, with minor tweaks which I thought were nice.

Another less important aspect of uMad was internal refactoring: SystemAppletQDaemon became uDaemon and later uSystem, LibraryAppletQMenu became uMenu, the two …QHbTarget processes got even more unified in uHbTarget and later uLoader, QForegroundViewer became uViewer, and so on. This also implied minor code refactoring, like dmi becoming smi.

Despite looking ready in this screenshot, uMad was quite unstable, with various internal bugs. This rewrite planned to change a lot internally, but a big part of it was just partially done if even started. To make matters worse, my lack of motivation and spare time became a problem once more, leaving this rewrite with basically no activity for almost another year.

Second rewrite attempt: uNew

In summer 2023 I started working back on uMad, but that didn’t last long for the same reason as before: the scope of the rewrite meant that too many things needed to be done before it being ready, which were not helpful for my motivation with the project.

This time, however, I tried to fix the ambitious issues with uMad by going on a new direction with the rewrite, one which would combine some of the already-implemented new features/changes and would maintain the rest from the original uLaunch source: this is how I started the uNew rewrite as an attempt to get some of the new stuff, some of which had already years, into the next release.

However, uNew still demanded a lot of testing and bug-fixing before being ready. After working on it for a while, by the end of the summer I was already fed up and left it unfinished.

Since the release of v0.2 back on November 2019 (v0.3 barely introduced anything new anyway) until a few months ago, an almost five-year gap, uLaunch had been looking virtually the same and seen basically no changes other than minuscule internal fixes/improvements, minor UI tweaks and support fixes.

uLaunch0.3

Third rewrite attempt: uNew (again)

This summer, however, I still ocassionally felt the urge to release a nice uLaunch rewrite once and for all. I started working on uNew and finished a bunch of stuff, but the UI soon started to bug me again, to the point where I decided that uNew was in a decent enough state so that I could mess up with the UI once more.

The new philosophy was to take full inspiration from the 3DS UI: an actual grid-like menu (the uMad UI only scrolled vertically despite being resizable like the 3DS grid, which made horizontal scrolling look rather awkward. This had additional advantages, like making the entry system) all the underlying code handling menu entries, folders, adding/deleting/moving them and so on (quite more readable and simple compared to the rather ugly indexing system I came up with when starting with uMad).

I also felt like the transparent input bar was not the best way to show inputs, and that the top menu, along with the game title/author/version texts, were taking up too much space in the top half.

It may sound obvious when the 3DS HOME menu is an inspiration, but I had never thought of including special menu options (album, web browsing, user page and so on) as actual menu entries, and coming up with this idea and seeing it implemented in uLaunch was deeply satisfying. This allowed me to move several top menu options down to the menu as entries themselves, leaving space to include the game strings in the top menu and hence getting that extra space I wanted to invest in the grid menu.

I spent several days entirely dedicated to the implementation, polishing and bug-fixing of the entire UI (as well as designing the icons and background graphics, which was fun despite having very little knowledge and ability using GIMP) but, when I was done, I was more than happy with the design:

YouTube

Heck, I was (and still am) so pleased with how the UI looks now, that I felt I needed video footage rather than plain screenshots to showcase how the new uLaunch was going to look. I bought a cheap HDMI capture cable just to properly record this. I redesigned several aspects (text/icon positions, default icon designs) until I felt it all merged nicely.

In fact, the new grid menu is a nice solution satisfying several complaints from users. It’s nice to navigate, and those who wish to return to something close to the old/classic tray-like menu, they can just resize the grid to have a single row of menu entries.

Moreover, I made an special custom theme with some sounds/BGM from DSi/3DS/Wii HOME menus, which made it dramatically more inmersive. I have still not publicly released this alternative “default theme” due to concerns with distributing official HOME menu audio/BGM, and I am still skeptical odespite really wanting to do so.

I quickly finished the rewrite after polishing the new UI, and to make the proper big, stable release uLaunch neede for the last five years: v1.0.

uManager

Since the first uLaunch releases, many users struggled to swap between uLaunch and the original HOME menu, since this is a nontrivial task. uLaunch consists on several files placed in different folders of the SD card, so a regular user has no clue of which ones to move or remove to get back to the original HOME menu.

The uLaunch README had some steps for manual removal back since early releases, but this still felt quite unintuitive. uLaunch itself could not provide an option to just “swap” both HOME menus, since if it were disabled, there was no way to get back to it from the original HOME menu.

Along with v1.0 I introduced the obvious solution: an external homebrew app that took care of this switching process manually. I also included other miscellaneous uLaunch-related features there, such as update detection and resetting options in case some bug rendered uLaunch unusable. This is how uManager was born.

uDesigner

One of the things that uLaunch was lacking was a theme editor. Some unofficial theme editors were made, and likely discontinued. Themeing was a manual task, having to not only edit all assets but also manually edit the JSON configuration files, all while having to test the theme on uLaunch for any position or size adjustments.

This is why I decided to make a basic theme editor. To avoid any compatibility issues (I was already dealing with uViewer and Java) I decided to make it a webpage. I decided on duplicating some bits of uLaunch’s code, since having some sort of common code shared between web and Switch would be too messy. This was the result. While not being able to implement everything due to time constraints (I wanted to release v1.0 as soon as possible, and the theme editor was my last pending task) it is a nice touch to visualize how the theme looks without having to reboot with uLaunch every time a change is made.

Future of uLaunch

Despite the milestone of v1.0, uLaunch is still a humble attempt on replacing the official HOME menu. This release mosty focused on getting UI and currently implementing features stable, along with some minor new features, but there is still a lot to be done. The vast majority of system settings are waiting to be implemented, and deep thinking is still needed for certain problematic features to be implemented as homebrew: eShop, news, parental controls…

Are there any unique features you’d like to see on the Nintendo Switch’s HOME menu? Anything that the official HOME menu lacks? Feel free to contact me over my different social media profiles, since I’ll be delighted to hear about new feature suggestions.