A Game Boy / Game Boy Color emulator overlay for the Nintendo Switch, built on libultrahand.
Play GB and GBC games on top of any running application.
- Full Game Boy (DMG) and Game Boy Color (GBC/CGB) emulation via an expanded fork of Walnut-CGB (a fork of Peanut-GB)
- Supports ROM-only, MBC1, MBC2, MBC3 (with RTC), and MBC5 (including rumble) cartridge types
- Accurate 59.73 Hz Game Boy clock rate, decoupled from the display vsync
- LCD ghosting / frame blending: per-game 50/50 blend of consecutive frames to reproduce the phosphor persistence that 30 Hz flickering transparency effects were designed for
- Fast-forward (4x) via ZR double-click-hold; audio pauses for the duration and resumes cleanly on release
- No Sprite Limit: per-game toggle that lifts the 10-sprites-per-scanline hardware cap so flickering transparency effects show all sprites every frame
Overlay mode: emulator drawn inside the standard Ultrahand overlay panel (448x720 framebuffer) alongside the UltraGB menu chrome.
- 2x pixel-perfect: 320x288 viewport, integer scale with letterbox.
Fixed overlay (default): overlay panel is anchored to the left edge of the screen, identical to all other Ultrahand overlays.
Free overlay: the overlay panel floats freely anywhere on screen. Repositionable by touch hold (≈1 s) on the game screen or KEY_PLUS hold (1 s) + left stick. Position is saved between sessions.
Windowed mode: framebuffer-accurate floating window placed anywhere on screen with no UI chrome.
- Integer scales: 1x through 6x (scale range is heap- and mode-gated; see Requirements)
- Repositionable by touch hold (≈1 s) or KEY_PLUS hold (2 s) + left stick
- R3 / L3 click to step scale up / down in-game (relaunches at new scale)
- Position and scale saved to
config.ini
Cycled per game from the per-game settings screen. All modes work for both DMG and CGB games.
| Mode | Behaviour |
|---|---|
GBC (default) |
CGB games use hardware color. DMG games receive the real GBC boot ROM title-based colorization (per-game lookup from hardware-verified palette database); unrecognised or unlicensed games fall back to greyscale. |
DMG |
Classic four-shade green Game Boy LCD tint. |
Native |
True greyscale: raw luminance values, no tint. |
Simulates the dark inter-pixel gap of a real Game Boy Color LCD by dimming the last row and column of each scaled source pixel block to approximately 12.5% brightness. Applies in both overlay and windowed modes; automatically invisible at windowed 1x (no room for a gap at 1:1 scale).
D-pad, A, B, Start, and Select are drawn below the game screen and mapped to touch input each frame.
- Game Boy volume: global GB audio output level (0–100).
- Active Title volume: per-process master volume of the running background Switch title, controlled independently. Adjusted live while the overlay is open and automatically restored to its pre-game level when the overlay closes.
- Audio Balance: per-game GB audio trim (−150% … 0% … +150%) stored in the per-game config. Applied as a power-of-2 gain multiplier on top of the master volume so individual games can be normalised without affecting global volume.
The overlay UI chrome (background, button colours, border) is fully themeable via .ini files placed in sdmc:/config/ultragb/ovl_themes/. A wallpaper (448x720 .rgba format) can be selected from sdmc:/config/ultragb/ovl_wallpapers/ and is displayed behind the game screen when expanded memory permits.
| Input | Action |
|---|---|
| A | GB A |
| B | GB B |
| X / + | GB Start |
| Y / − | GB Select |
| D-Pad | GB D-Pad |
| Touch (virtual buttons) | GB D-Pad / A / B / Start / Select |
| ZR double-click-hold | Fast-forward (4x) |
| ZL double-click, then hold (≈0.5 s) | Toggle controller pass-through to background app |
| R3 click (solo) | Switch to free overlay mode |
| L3 click (solo) | Switch to fixed overlay mode |
| Launch combo | Return to ROM selector (normal) / close overlay (quick-launch or direct mode) |
Free overlay only:
| Input | Action |
|---|---|
| Touch hold on game screen (≈1 s) | Enter drag mode: move overlay, release to save position |
| KEY_PLUS hold (1 s) + left stick | Joystick reposition mode |
| Input | Action |
|---|---|
| A | GB A |
| B | GB B |
| X / + | GB Start |
| Y / − | GB Select |
| D-Pad | GB D-Pad |
| ZR double-click-hold | Fast-forward (4x) |
| ZL double-click, then hold (≈0.5 s) | Toggle controller pass-through to background app |
| Touch hold inside window (≈1 s) | Enter drag mode: move window, release to save position |
| KEY_PLUS hold (2 s) + left stick | Joystick reposition mode |
| R3 click (solo) | Step scale up (1x → 2x → … → max) |
| L3 click (solo) | Step scale down |
| Launch combo | Return to UltraGB menu / close overlay (quick-exit mode) |
| Input | Action |
|---|---|
| A | Launch ROM |
| Y | Open per-game settings |
| Right / Configure footer | Go to Configure page |
| Left / Games footer | Return to ROM list (from Settings) |
| B | Close overlay |
- Battery saves (SRAM): written on ROM unload; stored at
sdmc:/config/ultragb/saves/internal/ - Quick-resume state: full CPU/PPU/APU snapshot saved automatically when the overlay closes; restored on next launch; stored at
sdmc:/config/ultragb/states/internal/ - User save states: 10 manual slots per game; stored at
sdmc:/config/ultragb/states/ - SRAM backup slots: 10 manual SRAM backup slots per game, independent of save states
Press Y on any ROM in the selector to open its settings screen.
| Item | Description |
|---|---|
| Save States | 10 named slots: save, load, or delete any slot |
| Save Data | 10 SRAM backup slots: manual snapshots of battery save data |
| Reset | Cold boot the game (deletes the quick-resume state) |
| Palette Mode | Cycle GBC → DMG → Native; applied live without restarting |
| No Sprite Limit | Lift the 10-sprites-per-scanline hardware cap; on by default |
| LCD Ghosting | Enable 50/50 frame blending for accurate flicker reproduction (memory-gated: see below) |
| Audio Balance | Per-game GB volume trim from −150% to +150%; press Y while focused to reset to 0% |
| Item | Description |
|---|---|
| Game Boy | GB audio output level (0–100); tap the speaker icon or press Y (when focused) to mute/unmute |
| Active Title | Background Switch title volume (0–100); tap the speaker icon or press Y (when focused) to mute/unmute; reverts to pre-game level on overlay close |
| Item | Description |
|---|---|
| Mode | Toggle between Overlay and Windowed; takes effect on next ROM launch |
| LCD Grid | Enable/disable the LCD inter-pixel gap simulation |
| Overlay | Submenu: Position (Fixed / Free) and Theme |
| Windowed | Submenu: Scale (1x–6x, heap-gated) and Docked Resolution (720p / 1080p) |
| Item | Description |
|---|---|
| Quick Combo | Assign a button combo to launch directly to the last played ROM from anywhere |
| Boot Paused | Start the emulator with the game paused on launch |
| Boot Cold | Always cold-boot the game on launch (skips quick-resume state restore) |
| Button Haptics | Enable/disable rumble feedback on controller button presses |
| Touch Haptics | Enable/disable rumble feedback on screen touch (virtual buttons, drag reposition) |
| Item | Description |
|---|---|
| Position | Fixed (anchored left edge) or Free (repositionable floating panel) |
| Theme | Select a UI theme from sdmc:/config/ultragb/ovl_themes/; "default" always available |
| Wallpaper | Select a background wallpaper from sdmc:/config/ultragb/ovl_wallpapers/ (requires 6 MB+ heap); "default" pass-through mode shows the preset Ultrahand UI wallpaper behind the overlay instead (if set) |
| Item | Description |
|---|---|
| Scale | Cycle 1x → 2x → … → max; capped by available heap and ROM size (see Requirements) |
| Docked Resolution | 720p (default, 1.5x VI layer) or 1080p (pixel-perfect, 1:1 VI layer); takes effect on next windowed launch |
Assigning a combo in Settings registers it system-wide and deconflicts it from other overlays and packages automatically. When triggered, the overlay launches straight into the last played ROM, bypassing the selector. The launch combo then closes the overlay entirely rather than returning to the menu.
The Switch overlay heap is capped per system configuration. UltraGB adapts automatically.
| Heap | Windowed max scale | In-game wallpaper | LCD Ghosting | Screenshots |
|---|---|---|---|---|
| 4 MB | 3x | ✗ | ✗ | ✓ |
| 6 MB | 5x | ✓ | ROMs < 2 MB only | Disabled at 5x for ROMs ≥ 2 MB (1080p) |
| 8 MB | 5x (6x when docked + 1080p + ROM under 4 MB) | ✓ | ROMs < 4 MB only | Disabled at 5x for ROMs ≥ 4 MB (1080p) |
| 10 MB+ | 5x (6x when docked + 1080p) | ✓ | All ROMs | ✓ |
ROMs that exceed the current tier's playable size are shown in the selector with a warning colour and cannot be launched.
- Nintendo Switch with Atmosphère custom firmware
- Ultrahand Overlay and nx-ovlloader v2.0.0 installed
- ROMs in
.gbor.gbcformat placed anywhere accessible on the SD card
- Download the latest
ultragb.ovlfrom Releases - Copy it to
sdmc:/switch/.overlays/ - Launch via Ultrahand
The ROM directory defaults to sdmc:/roms/gb/ and can be changed in sdmc:/config/ultragb/config.ini (rom_dir key).
Requirements: devkitPro with devkitARM, libnx, and the libultrahand library.
export DEVKITPRO=/opt/devkitpro
make -j6Output: ultragb.ovl
The build targets C++26, ARMv8-A with SIMD/CRC/crypto extensions tuned for Cortex-A57, full LTO with 6 parallel LTRANS jobs, and links against libcurl, mbedtls, and libnx.
sdmc:/
├── switch/
│ └── .overlays/
│ └── ultragb.ovl
├── config/
│ └── ultragb/
│ ├── config.ini ← global settings (rom_dir, volume, scale, etc.)
│ ├── ovl_theme.ini ← active overlay theme (copied from ovl_themes/ on select)
│ ├── ovl_wallpaper.rgba ← active overlay wallpaper (copied from ovl_wallpapers/ on select)
│ ├── ovl_themes/ ← user-provided .ini theme files
│ ├── ovl_wallpapers/ ← user-provided .rgba wallpaper files
│ ├── saves/
│ │ └── internal/ ← pre-set SRAM battery saves
│ │ └── <game>/ ← user save-data slots
│ ├── states/
│ │ ├── internal/ ← quick-resume state (one per game, auto-managed)
│ │ └── <game>/ ← user save-state slots
│ └── settings/
│ └── <game>.ini ← per-game settings (palette, ghosting, audio balance, etc.)
└── roms/
└── gb/ ← pre-set GB/GBC roms directory (.gb / .gbc only)
- ppkantorski:
- Mr-PauI:
- Walnut-CGB (GBC core, CGB palette system, dual-fetch optimisations)
- deltabeard:
- Peanut-GB (original GB core)
- libretro:
- Gambatte (pallet tables from
gbcpalettes.hused ingb_core.h)
- Gambatte (pallet tables from
- LIJI32:
- SameBoy (portions used for reference in correcting Walnut-CGB)
Contributions are welcome! If you have any ideas, suggestions, or bug reports, please raise an issue, submit a pull request or reach out to me directly on GBATemp.
This project is licensed and distributed under GPLv2.
