https://github.com/dborth/libgui (Under GPL License)
API documentation · Changelog · Latest build
libgui is a GUI library for the GameCube, Wii, and Wii U created to help structure the design of a complicated GUI interface, and to enable an author to create a sophisticated, feature-rich GUI. It was originally conceived and written after I started to design a GUI for Snes9x GX, and found libwiisprite and GRRLIB inadequate for the purpose.
libgui powers the GUI of several Nintendo homebrew emulators, including Snes9x GX, FCE Ultra GX, and Visual Boy Advance GX. It is a single, shared codebase that targets three different consoles from one source tree - GameCube and Wii share one driver set, and Wii U runs on modern GX2/GPU hardware through an entirely separate one, but the GuiElement/ GuiWindow/GuiButton/etc. class hierarchy your app is built from is identical on all three. It was designed to be flexible and is easy to modify - don't be afraid to change the way it works or expand it to suit your GUI's purposes! If you do, and you think your changes might benefit others, please share them so they might be added to the project!
source/libgui and application code - no #ifdefs in your GUI logic, no per-platform art or asset variants..lang blob, and bitmask text styling (justification, alignment, underline, strike).FileSystemDriver, with full hot-plug detection: up to three simultaneous USB drives on Wii and Wii U, SD Gecko cards on GameCube, and FAT, exFAT, and NTFS volumes on Wii U USB. See Storage.smb:/ device so the rest of the app reads and writes it with plain POSIX calls. See Network shares.Thread, Mutex, Cond) with a cooperative stop protocol and an app-exit safety net, so app and library code can run background work without touching a platform's raw threading API. See Threading.Platform object reports running/paused/exiting state and hardware events (power and reset buttons, the Wii U HOME menu and close requests) the same way on every console. See Application lifecycle.| Platform | Toolchain | Video | Audio | Input | Storage |
|---|---|---|---|---|---|
| GameCube | devkitPPC + libogc2 | GX | AESND | PAD | SD Gecko (slot A/B), SD2SP2, GC Loader, DVD, SMB (Broadband Adapter) |
| Wii | devkitPPC + libogc2 | GX | AESND | WPAD (Wiimote/Nunchuk/Classic/Pro), plus Wii U GamePad support | SD, up to 3 USB, DVD, SMB |
| Wii U | devkitPPC + wut + libwhb | GX2 | AX (sndcore2) | VPAD (GamePad), KPAD/WPAD (Wiimote/Nunchuk/Classic/Pro) | SD, up to 3 USB (FAT/exFAT/NTFS), SMB |
Wii U renders a separate, higher-resolution asset set (data/images_hd, selected in Makefile.wiiu) libgui/ layout code still works in the one shared configurable coordinate space (eg: 640x480).
libgui's core (source/libgui/) never includes <gccore.h>, <gx2/*.h>, <wpad/wpad.h>, or any other platform header. Everything platform-specific sits behind a small set of abstract driver interfaces in source/drivers/, composed by a single Platform object:
PlatformConfig carries the design canvas size and, on platforms with a higher-resolution asset set, the scale factor between that asset set and the design canvas:
There are three concrete Platform implementations - GameCubePlatform and WiiPlatform (sharing GameCube/Wii's driver set), and WutPlatform (Wii U) - selected once at startup based on the build:
That's the only platform branch an app needs to write. Everything else - GuiElement::update(), GuiImage, GuiText, the file browser, and so on - talks only to the interfaces below.
| Interface | Responsibility | GameCube/Wii (drivers/ogc) | Wii U (drivers/wut) |
|---|---|---|---|
VideoDriver | Frame lifecycle, screen size/refresh rate/delta time; hands out an ImageRenderer (textured quads and triangle meshes; a mesh that keeps being drawn is kept as a GX display list or as GX2 vertex buffers) and GlyphRenderer (glyph quads + solid rectangles) | OgcVideoDriver - raw GX, double-buffered XFB | WutVideoDriver - GX2 + libwhb's WHBGfx* helpers, backed by two small custom GX2 shaders (Texture2DShader, ColorShader). UI draws are recorded into a list and replayed once for the TV and once for the GamePad, instead of switching render targets on every individual draw |
AudioDriver | Fixed one-shot PCM voices plus one background OGG stream | OgcAudioDriver - AESND | WutAudioDriver - AX (sndcore2), 16 voice slots plus a ring-buffered stereo stream path, mixed to both the TV and the GamePad |
InputDriver | Polls hardware and produces a per-channel InputPadData snapshot each frame, consumed by a persistent InputController per channel; controls rumble and Wiimote orientation | OgcInputDriver - PAD (GameCube) / WPAD (Wiimote, Nunchuk, Classic, Wii U Pro Controller), plus Wii U GamePad via the vendored libwiidrc | WutInputDriver - VPAD (GamePad stick/buttons/touch) and KPAD/WPAD for up to 4 Wiimotes/Nunchuks/Classic/Pro Controllers |
FileSystemDriver | Storage device enumeration, mount/poll, hot-plug detection, and the network-share driver (StorageDevice, MountResult, SmbDriver) | WiiFileSystemDriver / GameCubeFileSystemDriver, with OgcSmbDriver | WutFileSystemDriver, with WutSmbDriver |
ThreadDriver | Raw thread/mutex/condition-variable primitives | OgcThreadDriver - libogc's LWP | WutThreadDriver - coreinit's OSThread/OSMutex/OSCondition |
The Logger (see Logging) is owned by Platform alongside these drivers and fans each log line out to a set of LoggingDriver backends.
The UI is laid out on a fixed design canvas (640x480 in the demo) that the video driver maps onto the output, so widget positions and sizes are expressed in the same units on every platform.
Platform gives an app one consistent way to find out that it should stop, pause, or reset, regardless of console:
getStatus() returns Status::Running, Status::Paused, or Status::Exiting. On Wii U the status is Paused whenever the app is not in the foreground (for example while the HOME menu overlay is up); the video and audio drivers skip their work while paused, and the app keeps running. Once the OS asks the app to close, or the app calls triggerExit(), the status becomes Exiting and stays there.getSystemEvent() reports hardware/OS events: ShutdownRequested (the power button on the console or a Wiimote on Wii; a close/standby request from Cafe OS on Wii U) and ResetRequested (the reset button, Wii only - soft-reset and keep going). GameCube has no hardware event source and always reports None.shouldExit() is true once either Status::Exiting is set or a shutdown event has been reported, so a main loop only needs to check one thing.requestExit() shuts every driver down and then ends the app the way the platform expects: Wii U asks Cafe OS to return to the system menu (or loader) and waits for the app to leave the foreground before exiting; Wii performs an IOS power-off when a power button started the exit, and otherwise exits normally; GameCube exits. It does not return.Background threads must be stopped before requestExit() - see Thread::JoinAll() under Threading. The demo's main() shows the intended order:
menu.cpp/menu.h and filebrowser.cpp/.h build the actual template screens (settings, storage file browser, network share) on top of the core library and are explicitly not part of the library itself - they're a recommended pattern to build from, not a hard dependency.
Topic guides, each readable here on GitHub and included in the API documentation:
libsmb2, libmocha, libdvm) and build steps for all three consolessmb:/ devicelibgui, Snes9x GX, FCE Ultra GX and Visual Boy Advance GX share one toolchain and one set of dependencies, so there is a single build guide for all of them: Building. It covers installing devkitPro and libogc2 (GameCube/Wii) or wut (Wii U), and building libsmb2 (all platforms), libmocha and libdvm (Wii U) from the dborth forks.
Once the dependencies are installed, from the repository root:
Each Makefile builds the same source, source/drivers, and source/libgui trees, adding only the directories for its platform: drivers/ogc plus drivers/ogc/wii or drivers/ogc/gamecube for Wii and GameCube, and drivers/wut plus drivers/wut/shaders for Wii U.
To enable logging, add -DLOGGING_ENABLED=1 to the build's compiler flags (see Logging).
The GitHub Actions workflow builds all three platforms on every push, deploys the doxygen documentation to GitHub Pages, and keeps a rolling pre-release with the latest .dol, .rpx, and .wuhb builds. It is also the most up-to-date reference for the build steps.
Start from the supplied template example (source/demo.cpp). It shows the full startup and shutdown sequence: create the platform, size the image decode scratch buffer, create the font renderer and string table, start audio and the storage device-checking thread, run the menus, then join background threads and exit. For more advanced uses, see the source code for Snes9x GX, FCE Ultra GX, and Visual Boy Advance GX - all of which build their menu system on top of libgui.
If you have any suggestions for the library or documentation, or want to contribute, please visit the libgui website: https://github.com/dborth/libgui
The API reference is generated with doxygen from the source and this README, and published at https://dborth.github.io/libgui/
This covers both the core GUI classes (source/libgui) and the platform driver layer (source/drivers), including the GameCube/Wii (ogc) and Wii U (wut) driver implementations.
This library was wholly designed and written by Tantric. Thanks also to the authors of GRRLIB and libwiisprite for laying the foundations. Thanks to mvit for the artwork and Peter de Man for the music used in the template. Thanks to FIX94 for libwiidrc, letting a Wii app use a Wii U GamePad.
See CHANGELOG.md for the full, version-by-version history.
[2.01 - October 1, 2026] batches Wii U UI drawing into one TV pass and one GamePad pass per frame instead of switching render targets on every draw (menu frame rate on Wii U roughly doubled in testing), adds a higher- resolution Wii U asset set with PlatformConfig::assetScaleX/Y, fixes text scrolling and Wiimote/GamePad pointer angle math, and improves UDP and USB Gecko logging reliability. Platform::init() now takes a PlatformConfig instead of separate width/height parameters - see Architecture above.
[2.00 - September 23, 2026] adds full Wii U support (GX2 video, AX audio, VPAD/ KPAD input, FSA-based SD storage, USB storage with libdvm), a GameCube build, network shares, multi-drive USB with full hot-plug, and a logging framework - all made possible by refactoring the library behind a proper hardware abstraction layer. See Architecture above and the changelog for the complete list of changes.