An enhanced fork of libtesla (originally by WerWolv) combined with the libultra utility library — a comprehensive foundation for Nintendo Switch overlay development.
- Fully anti-aliased rendering — rounded rects, uniform rounded rects, bordered rounded rects, and circles
- Global alpha limiter for smooth show/hide transitions and glyph rendering
- Rewritten
Listclass withjumpToItem, proper wall handling, and no pointer caching TrackBarandTrackBarV2with touch support, click animations, and haptic feedbackToggleListItem,CategoryHeader(with right-side value display), and other standard UI elementsOverlayFrame/HeaderOverlayFramewith auto-scrolling titles and subtitlesswapTopage navigation with crash-safe rapid input handling- Font Manager with universal glyph cache and full multi-language glyph support
- Smooth list item text scrolling, shake-highlight at list boundaries
- Full
theme.inisystem with extensive color variables covering every UI surface - Per-overlay theme overrides via
UI_OVERRIDE_PATH— scoped to/config/<OVERLAY_NAME>/ - Wallpaper support (
.rgba, 448×720 px) with heap-aware loading and optimized rendering - Status bar widget — clock, temperature, battery, backdrop, and border (opt-in via
USING_WIDGET_DIRECTIVE)
- Automatic string translation at render time via
drawString - Per-overlay language files (ISO 639-1 JSON) in
/config/<OVERLAY_NAME>/lang/ - All language font glyphs accessible regardless of the active system language
- WAV sound effect playback (8–48 kHz, 16-bit PCM) via libnx
audout, with volume control - Sound and haptics each run on dedicated background threads for reliability and performance
- Haptic rumble patterns for click and double-click feedback
- Multi-slot toast notification system (up to 8 concurrent; 4 on 4MB heap)
- JSON-based API notifications written to
/config/ultrahand/notifications/by any app - Optional notification icons (50×50 RGBA), titles, timestamps, duration, alignment, and font size
- Per-app notification filtering via flag files; API toggle hotkey for live enable/disable
tsl::notification->showandtsl::notification->showNowfor queued and immediate display
- Full touch support alongside controller input — tap, hold, swipe, and drag
- Configurable per-item touch, hold, and release behavior on
ListItem tsl::shiftItemFocusfor programmatic focus control
- curl-based file downloads with retry logic and NTP auto-sync for SSL reliability
- Internet access verification before initiating downloads
- Per-download socket init/exit to minimize memory pressure
- File & path — copy, move, delete, mkdir, wildcard matching, directory traversal, dot-clean
- INI — full read/write, section and key management, pattern-matched bulk edits
- JSON — read/write via cJSON (migrated from jansson)
- Hex — binary file editing by offset, swap, string, decimal, reversed decimal, and custom pattern
- Strings — trim, split, format, version parsing, placeholder resolution
- Lists — file-backed list reading, set operations, filtering
- Mod conversion —
.pchtxtto.ipsor Atmosphere cheat format (with@disabledflag support) - Debug — thread-safe timestamped logging via
USING_LOGGING_DIRECTIVE
- Full drop-in replacement for libtesla — all existing Tesla overlays work without modification
- All overlays act as combo launchers for any overlay registered in Ultrahand's
overlays.ini - Launch Recall — combo re-entry returns to the exact overlay/package previously launched
- Ultrahand signature (
ULTR) embedded at link time to enable first-class Ultrahand integration - Unsupported overlay warning when launching overlays compiled against incompatible AMS versions
A growing ecosystem of libultrahand-based overlays, all launchable and manageable directly from Ultrahand Overlay:
| Overlay | Description |
|---|---|
| Ultrahand Overlay | Fully scriptable overlay menu ecosystem — the primary libultrahand reference implementation |
| Status Monitor | Real-time CPU/GPU/RAM, temps, battery, and frequency stats |
| sys-clk | Per-game CPU/GPU/memory overclocking and underclocking |
| FPSLocker | Custom FPS targets and display refresh rates for retail games |
| Fizeau | Color temperature, saturation, gamma, and contrast adjustment |
| ovl-sysmodules | Toggle system modules and monitor memory usage on the fly |
| QuickNTP | One-tap NTP time sync |
| NX-FanControl | Custom fan curve control |
| Tetris | Fully playable Tetris running as an overlay |
| UltraGB | Game Boy / GBC emulator running on top of any game |
| ReverseNX-RT | Per-game handheld/docked mode switching |
| SysDVR | SysDVR stream control overlay |
| EdiZon | In-game cheat and save editor |
| DNS-MITM Manager | DNS-based network filtering management |
- devkitPro with
devkitA64andlibnx - The following pacman packages:
(dkp-)pacman -S switch-curl switch-zlib switch-minizip switch-mbedtls
switch-minizipis only required if your overlay uses download or unzip functionality.
MSYS2 will mangle compiler arguments that start with / (like devkitPro paths and flags), causing build failures. Prevent this by adding the following to your ~/.bashrc:
if [[ -n "${DEVKITPRO:-}" ]]; then
export MSYS2_ARG_CONV_EXCL='*'
fiThen reload your shell:
source ~/.bashrcThis disables MSYS2's argument conversion entirely when building with devkitPro and avoids any path-mangling issues.
The easiest way is to use ultrahand.mk. Add this after your SOURCES and INCLUDES definitions, adjusting the path to where you placed libultrahand:
include $(TOPDIR)/lib/libultrahand/ultrahand.mkAlternatively, add these manually:
SOURCES += lib/libultrahand/common lib/libultrahand/libultra/source lib/libultrahand/libtesla/source
INCLUDES += lib/libultrahand/common lib/libultrahand/libultra/include lib/libultrahand/libtesla/includeLIBS := -lcurl -lz -lminizip -lmbedtls -lmbedx509 -lmbedcrypto -lnx-lminizip can be omitted for overlays that do not use download or unzip functionality.
libultrahand initializes the following libnx services. If your project already initializes any of these, remove the duplicates to avoid conflicts:
fsdevMountSdmc();
splInitialize();
spsmInitialize();
ASSERT_FATAL(socketInitializeDefault());
ASSERT_FATAL(nifmInitialize(NifmServiceType_User));
ASSERT_FATAL(smInitialize());i2cInitialize() is only used when USING_WIDGET_DIRECTIVE is enabled.
For libultra download methods, also call these in your service init/exit:
initializeCurl(); // in initServices()
cleanupCurl(); // in exitServices()The following reflects the flag set used across official libultrahand projects. The target architecture is ARMv8-A on the Cortex-A57:
ARCH := -march=armv8-a+simd+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -Wall -Os \
-ffunction-sections -fdata-sections \
-fomit-frame-pointer -fuse-linker-plugin \
-finline-small-functions -fno-strict-aliasing \
-frename-registers -falign-functions=16 \
$(ARCH) $(DEFINES)
CXXFLAGS := $(CFLAGS) -std=c++26 \
-fno-exceptions -fno-rtti \
-fno-unwind-tables -fno-asynchronous-unwind-tables \
-ffast-math -Wno-dangling-else
LDFLAGS := -specs=$(DEVKITPRO)/libnx/switch.specs \
$(ARCH) -Wl,-Map,$(notdir $*.map) \
-Wl,--gc-sections -Wl,--as-needed
-fno-exceptionsand-fno-rttiare strongly recommended for overlay binaries. IfUSE_EXCEPTION_WRAPis enabled,-fno-unwind-tablesand-fno-asynchronous-unwind-tablesshould be set as well.
LTO is highly recommended and should use parallel LTRANS jobs for faster builds. The simplest approach is to auto-detect the available CPU count:
NPROC := $(shell getconf _NPROCESSORS_ONLN 2>/dev/null || nproc 2>/dev/null || echo 1)
CXXFLAGS += -flto=$(NPROC)
LDFLAGS += -flto=$(NPROC) -fuse-linker-pluginOr specify a fixed thread count (e.g. for CI environments):
CXXFLAGS += -flto=6
LDFLAGS += -flto=6 -fuse-linker-pluginAll libultrahand overlays should append the ULTR four-byte signature to the final .ovl binary. This is how Ultrahand identifies libultrahand-compiled overlays in the overlay menu:
$(OUTPUT).ovl: $(OUTPUT).elf $(OUTPUT).nacp
@elf2nro $< $@ $(NROFLAGS)
@printf 'ULTR' >> $@All directives should be added to both CFLAGS and CXXFLAGS unless your CXXFLAGS is already defined as $(CFLAGS), in which case adding to CFLAGS before that line is sufficient.
Scopes a theme.ini and wallpaper.rgba to your overlay at /config/<OVERLAY_NAME>/:
UI_OVERRIDE_PATH := /config/<OVERLAY_NAME>/
CFLAGS += -DUI_OVERRIDE_PATH="\"$(UI_OVERRIDE_PATH)\""
CXXFLAGS += -DUI_OVERRIDE_PATH="\"$(UI_OVERRIDE_PATH)\""If the theme still does not appear, add the INITIALIZE_IN_GUI_DIRECTIVE as a fallback:
CFLAGS += -DINITIALIZE_IN_GUI_DIRECTIVE=1
CXXFLAGS += -DINITIALIZE_IN_GUI_DIRECTIVE=1Requires UI_OVERRIDE_PATH. Place ISO 639-1 named JSON files in /config/<OVERLAY_NAME>/lang/:
{
"English String": "Translated String",
"Another String": "Another Translation"
}Translation is applied automatically on every drawString call based on the active Ultrahand language setting.
CFLAGS += -DUSING_WIDGET_DIRECTIVE=1
CXXFLAGS += -DUSING_WIDGET_DIRECTIVE=1Activates i2cInitialize() internally — remove it from your own service init if present.
Enables thread-safe file logging to <packagePath>/log.txt via logMessage(). Useful for debugging command execution and overlay behavior:
CFLAGS += -DUSING_LOGGING_DIRECTIVE=1
CXXFLAGS += -DUSING_LOGGING_DIRECTIVE=1Disables the default back-button (KEY_B) behavior, allowing your overlay to handle it independently. Useful for overlays that implement custom or full-screen navigation:
CFLAGS += -DNO_BACK_KEY_DIRECTIVE=1
CXXFLAGS += -DNO_BACK_KEY_DIRECTIVE=1# Apply -O3 to rendering components only (tesla.hpp)
CFLAGS += -DTESLA_TARGETED_SPEED
CXXFLAGS += -DTESLA_TARGETED_SPEED
# Apply -Os to libultra utility components only
CFLAGS += -DULTRA_TARGETED_SIZE
CXXFLAGS += -DULTRA_TARGETED_SIZEThese can be used together — TESLA_TARGETED_SPEED optimizes the hot rendering path while ULTRA_TARGETED_SIZE keeps utility code compact.
Enables launcher-specific code paths used exclusively when building the Ultrahand Overlay launcher itself. Not intended for general overlay development:
CFLAGS += -DIS_LAUNCHER_DIRECTIVE=1
CXXFLAGS += -DIS_LAUNCHER_DIRECTIVE=1Intercepts C++ exception entry points at the linker level, eliminating unwind table overhead. Requires including <exception_wrap.hpp> at the top of your main.cpp:
CFLAGS += -DUSE_EXCEPTION_WRAP=1
CXXFLAGS += -DUSE_EXCEPTION_WRAP=1
CXXFLAGS += -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables
LDFLAGS += -Wl,-wrap,__cxa_throw \
-Wl,-wrap,_Unwind_Resume \
-Wl,-wrap,__gxx_personality_v0Contributions are welcome. Please open an issue, submit a pull request, or reach out on GBATemp.
Licensed under GPLv2 with a custom library under CC-BY-4.0.
Copyright © 2023–2026 ppkantorski
