asobou
v0.2.2
Published
Play retro games directly in your terminal
Maintainers
Readme
[!note]
The game used in the demonstration above is Alter Ego.
Overview
Asobou is a command-line tool that allows you to play retro games directly in your terminal. Simply run:
asobou 'Super Mario Bros.zip'Asobou detects the system, ensures a suitable emulator is available, picks the best renderer your terminal supports, and starts the game.
If you do not have a game file handy, you can use asobou brew to try one from the internet:
asobou brew indivisibleonnes.nesOr use npx to run Asobou without installing it globally:
npx asobou brew indivisibleonnes.nesThis loads the game Indivisible on NES from https://github.com/retrobrews/nes-games/blob/master/indivisibleonnes.nes and starts it.
Prerequisites
Asobou's default renderer works with terminals that support Terminal graphics protocol. Here is a non-exhaustive list of supported terminals (sorted alphabetically):
- Ghostty (Linux, macOS)
- iTerm2 (macOS)
- Kitty (Linux, macOS)
- Rio Terminal (Linux, macOS, Windows)
- WezTerm (Linux, macOS, Windows)
Kitty has the best overall experience for running Asobou.
Asobou requires an active internet connection to download emulator binaries from https://buildbot.libretro.com/ when needed.
Asobou requires you to provide the game (ROM file), as it does not bundle any game content.
Installation
You do not need to install anything if you just want a quick try — run it with npx:
npx asobouFrom npm:
npm install asobou -gFrom crates.io:
cargo install asobouWith cargo-binstall:
cargo binstall asobouWith mise:
mise use github:arianrhodsandlot/asobou -gYou can also manually download the binary from the releases page. It is a standalone executable that does not require any additional dependencies.
Usage
Here are some typical usage examples:
Start a game
asobou 'Super Mario Bros.zip'Start a game and render it as ASCII characters
asobou 'Streets of Rage 2.md' --renderer=asciiRun with an explicit core
asobou 'Super Castlevania IV.zip' --core=snes9xLoad a save state at startup
asobou 'Super Metroid.sfc' --state=~/backup.stateLoad the latest managed state at startup
asobou 'Super Metroid.sfc' --resumeInstall a libretro core
asobou core install genesis_plus_gxSet a configuration value
asobou config set rewind.buffer_size_mb 64List saved states, filtered
asobou state list 'Pokemon Emerald.gba' --core=mgbaDownload and play a homebrew game from https://retrobrews.github.io/
asobou brew flappybird.nesPrint help
asobou --helpConfiguration
Asobou loads the first applicable config path:
- The exact path in the
ASOBOU_CONFIGenvironment variable $XDG_CONFIG_HOME/asobou/config.toml~/.config/asobou/config.tomlon Linux and macOS%APPDATA%\asobou\config.tomlon Windows
The config file is optional; omitted settings keep their defaults. Explicit command-line values override configuration values.
[audio]
muted = false # Disable game audio when true
[display]
fps = 60 # Maximum terminal refresh rate, from 1 to 240
renderer = "auto" # auto, graphic, block, ascii
primary_screen = false # Use the primary buffer when true
[input]
# Each input takes one standalone key, and a key cannot be assigned to more than one input.
# Keys follow the RetroArch conventions. Printable characters are written directly; the other supported names are:
# space enter escape tab backspace
# up down left right home end pageup pagedown insert del
# f1 through f24
# num0 through num9
# period comma slash minus equals leftbracket backslash rightbracket
# backquote quote semicolon tilde
# capslock numlock print_screen scroll_lock pause menu
# shift rshift ctrl rctrl alt ralt
# left-super right-super left-hyper right-hyper left-meta right-meta iso-level-3-shift iso-level-5-shift
# numpad-0 through numpad-9 keypad0 through keypad9
# numpad-decimal kp_period numpad-divide divide
# numpad-multiply multiply numpad-subtract kp_minus
# numpad-add kp_plus numpad-enter kp_enter
# numpad-equal kp_equals numpad-comma
# numpad-up numpad-down numpad-left numpad-right
# numpad-home numpad-end numpad-page-up numpad-page-down
# numpad-insert numpad-delete numpad-begin
up = "up"
down = "down"
left = "left"
right = "right"
a = "x"
b = "z"
x = "s"
y = "a"
start = "enter"
select = "rshift"
l = "q"
r = "w"
quit = "escape"
rewind = "r" # Hold to rewind
save_state = "f2" # Save a new state to `data_dir`
load_state = "f4" # Load the newest state
# Optional buttons, unbound by default:
# l2 = "e"
# r2 = "u"
# l3 = "t"
# r3 = "y"
[paths]
# Data lives in `$XDG_DATA_HOME/asobou` and cache in `$XDG_CACHE_HOME/asobou` by
# default (`~/Library/Application Support/asobou` and `~/Library/Caches/asobou` on
# macOS, `~/.local/share/asobou` and `~/.cache/asobou` on Linux). `paths.data_dir`
# and `paths.cache_dir` override the base directory: cores and save states go
# under `data_dir/cores` and `data_dir/states`, brew downloads under
# `cache_dir/brew`. Values must be absolute or start with `~/`. These settings
# take precedence over the `XDG_DATA_HOME` and `XDG_CACHE_HOME` environment
# variables, which are used only when the corresponding key is unset (an empty
# variable counts as unset).
cache_dir = "~/.asobou/cache" # Override the cache base (brew downloads)
data_dir = "~/.asobou/data" # Override the data base (cores, save states)
[rewind]
# Rewind steps back while the rewind key is held. A higher `granularity` uses
# less memory and CPU but rewinds in coarser steps; once `buffer_size_mb` is
# reached the oldest snapshots are dropped. Disabling rewind frees the key for
# other bindings and hides it from the on-screen status line.
enabled = true # Snapshot-based rewind
granularity = 2 # Frames between snapshots
buffer_size_mb = 20 # Memory cap for stored snapshots
[state]
save_on_exit = false # Save a state when exiting cleanly
resume = false # Resume the last state on startup
[status]
# The status text is centered and dimmed over the bottom of the rendered frame.
# Set `status.enabled` to `false` to hide both lines, or toggle `gamepad` and
# `controls` independently. Save and load notifications remain visible when the
# keybinding status is hidden. Notifications are anchored to the bottom-left and
# do not change the centered keybindings' position.
controls = true # Show save, load, rewind, and exit on the lower line
enabled = true # Show the on-screen keybinding status
gamepad = true # Show gamepad inputs on the upper status lineSupported platforms
Many more cores are available at https://buildbot.libretro.com/. The following platforms and default cores are tested and cover most popular systems.
| Platform | Default Core | | ---------------------- | --------------- | | Atari 2600 | stella | | Atari 5200 | a5200 | | Atari 7800 | prosystem | | Atari Lynx | handy | | Game Boy | gambatte | | Game Boy Advance | mgba | | Game Boy Color | gambatte | | Game Gear | genesis_plus_gx | | Megadrive / Genesis | genesis_plus_gx | | NES / Famicom | nestopia | | Neo Geo Pocket (Color) | mednafen_ngp | | Super Nintendo | snes9x | | WonderSwan (Color) | mednafen_wswan |
Other platforms and cores not listed here may work with Asobou too, but are not tested.
Cores that require GPU acceleration do not work with Asobou.
Under the hood
Asobou is a libretro frontend: the emulation itself is performed by libretro cores, shared libraries such as nestopia_libretro.so on Linux, snes9x_libretro.dylib on macOS, or mgba_libretro.dll on Windows. Asobou locates, loads, and drives these cores, turning their output into something a terminal can display.
Emulation and rendering run on separate threads: the emulation thread captures video only when the renderer requests a frame, and hands the latest frame to the render thread through a mailbox. The active renderer then draws it:
graphic— sends the frame as raw RGB data, using zlib compression when supported, via the Terminal graphics protocolblock— downsamples the frame into colored half-block cells (▀)ascii— maps pixel brightness to ASCII characters
Credits
- libretro and its emulation cores
- Terminal graphics protocol proposed by Kitty
Alternatives
Related
You might also be interested in my other project: Nostalgist.js, a JavaScript library used for running emulators of retro consoles inside browsers.
