Minimal GBA emulator frontend. Loads mgba_libretro.so directly via ctypes
Works on Non-Arch if you install the deps before launching the installer and also manually unintsall them
Dependencies: libSDL2 + mgba_libretro.so + Python ≥ 3.10
chmod +x install.sh && ./install.shThe installer:
- Checks for Python 3.10+, libSDL2, and
mgba_libretro.so(installing via pacman if missing) - Runs an interactive config wizard (ROM path, scale, audio, keybinds)
- Copies scripts to
~/.local/share/tinygba/ - Creates a launcher at
~/.local/bin/tinygba
tinygba # ROM from config
tinygba ~/roms/emerald_hack.gba # override ROM
tinygba --config my.cfg ~/roms/game.gba # override config + ROM
tinygba --conf # edit config in $EDITOR / nano
tinygba --no-tui ~/roms/game.gba # game window only, no terminal
tinygba --version # print version[general]
editor = nano # editor for 'tinygba --conf' ($EDITOR takes priority)
pause_on_unfocus = false # pause when window loses focus
[core]
path = /usr/lib/libretro/mgba_libretro.so
system_dir = # BIOS directory (empty = install dir)
save_dir = ~/.local/share/tinygba/sram
[rom]
path = ~/roms/pokemon_emerald.gba
[video]
scale = 4 # 4× = 960×640 window
vsync = true # cap to 59.7275 fps
[audio]
enabled = true
buffer = 2048 # queue buffer in samples
[saves]
state_dir = ~/.local/share/tinygba/states
screenshot_dir = ~/.local/share/tinygba/screenshots
reload_slot = 99 # slot used by dev-reload (keep away from normal slots)
reload_settle = 0.1 # seconds of silent frames after ROM reload
[keybinds]
# SDL2 scancode names: https://wiki.libsdl.org/SDL_Scancode
btn_a = X btn_b = Z btn_l = A btn_r = S
btn_start = Return btn_select = BackSpace
btn_up = Up btn_down = Down btn_left = Left btn_right = Right
save_state = F2 load_state = F4 prev_slot = F6 next_slot = F7
screenshot = F8 reload = F5 fast_forward = Space
pause = P reset = F10 quit = Escape| Command | What it does |
|---|---|
r / reload |
Dev reload — save → reload ROM from disk → restore state |
save [N] |
Save state to slot N (default: active slot) |
load [N] |
Load state from slot N (default: active slot) |
slot [N] |
Show or set the active slot |
states |
List all save states for the current ROM |
press <btn> [N] |
Press button for N frames (default: 1) |
hold <btn> |
Hold button until release |
release [btn] |
Release one or all held buttons |
combo <a+b> [N] |
Press a button combo for N frames |
pause |
Toggle pause |
ff |
Toggle fast-forward |
reset |
Soft reset |
screenshot / ss |
Save BMP screenshot |
sram [path] |
Show SRAM info, or inject a .srm save file |
rom [path] |
Show current ROM, or switch to a new one |
info |
Session info (ROM, core, slot, scale, held buttons…) |
binds |
Show current keybind mapping |
clear |
Clear the log pane |
q / quit |
Exit TinyGBA |
Buttons: a b l r start select up down left right
reload (or r, or F5) is designed for ROM-hack iteration:
- Serialises the current game state into slot 99
- Calls
retro_unload_game→retro_load_gameon the (possibly recompiled) ROM file on disk - Runs a handful of silent frames so the core settles
- Deserialises the state back
Everything happens in-process — no process kill/relaunch — so it's near-instant. Tweak reload_settle in config if state-restore glitches after reload (try 0.3).
| Key | Action |
|---|---|
| F2 | Save state (active slot) |
| F4 | Load state (active slot) |
| F5 | Dev reload |
| F6 / F7 | Previous / next slot |
| F8 | Screenshot |
| F10 | Soft reset |
| Space | Toggle fast-forward |
| P | Toggle pause |
| Escape | Quit |
All hotkeys are configurable in [keybinds].
scripts/
tinygba.py Main loop, SDL2 window, save states, TUI command dispatch
libretro.py ctypes bindings for the libretro core API (mGBA)
sdl2_bindings.py ctypes bindings for libSDL2 (video, audio, input, events)
config/
tinygba.cfg Default config (copied to install dir by install.sh)
install.sh Interactive Arch Linux installer
uninstall.sh Uninstaller (preserves save data by default)
chmod +x uninstall.sh && ./uninstall.shSave data (states / sram / screenshots) is preserved unless you explicitly opt in to removing it.

