Play ROMs directly in your terminal.
rom is a small libretro frontend for macOS and Linux. It renders native
pixels with the kitty graphics protocol, supports real key-release events,
save states, audio, fast-forward, and live terminal-theme recoloring.
rom does not include games, BIOS files, or emulator cores. Only run software
you are legally entitled to use.
Quick start
You need Ghostty or kitty and a C compiler.
On macOS:
On Ubuntu or Debian:
sudo apt install build-essential libasound2-dev
Then:
git clone https://github.com/jhickner/rom cd rom make ./rom "path/to/game.sfc"
The first time you open a ROM for a platform you have no core for, rom offers
to fetch and build that core.
Run rom directly in Ghostty or kitty, not inside tmux. tmux interferes with
the graphics and keyboard protocols.
Optional installation:
make install PREFIX="$HOME/.local"Cores
rom uses libretro cores: .dylib on macOS and .so on Linux.
Open a ROM without its core and rom asks before doing anything:
rom: no core installed for roms/Link's Awakening.gb
gambatte_libretro.dylib can be built from https://github.com/libretro/gambatte-libretro
and installed into /Users/you/.config/rom/cores.
Needs git, make, and a C/C++ toolchain, plus a few minutes.
Fetch and build it now? [Y/n]
Say yes and it shallow-clones the repository into ~/.config/rom/src/, builds
it, installs the core, and starts the game. Say no and it prints the filename
and repository so you can build it yourself. Runs without a terminal on stdin
skip the prompt and print the same instructions.
Cores are searched in:
~/.config/rom/cores/./cores/<executable>/../cores/
Use --core <path> to select one directly.
| ROM | Core |
|---|---|
.sfc .smc .fig |
snes9x_libretro |
.nes |
fceumm_libretro |
.gb .gbc |
gambatte_libretro |
.gba |
mgba_libretro |
.md .gen .smd |
genesis_plus_gx_libretro |
.pce |
mednafen_pce_fast_libretro |
Usage
| Option | Description |
|---|---|
--core <path> |
Use a specific core |
--fullscreen |
Fill the terminal window |
--scale <n> |
Integer zoom in inline mode, 1–8 (default 2); change live with [ / ] |
--slot <n> |
Initial save-state slot, 0–9 |
--no-audio |
Disable audio |
--recolor <mode> |
off, hue, nearest, duotone, or dither |
--recolor-strength <0..1> |
Blend recoloring with the original |
--keys |
Print current key bindings |
--selftest <n> |
Run n frames without a terminal |
--shot <file> |
Save the final self-test frame as BMP |
--force |
Skip terminal graphics detection |
Inline mode is the default. It leaves scrollback intact and removes its Kitty image when the game exits.
Controls
| Key | Action |
|---|---|
| Arrows | D-pad |
z / x |
B / A |
a / s |
Y / X |
q / w |
L / R |
| Enter / Right Shift | Start / Select |
| Ctrl+C or Ctrl+Q | Quit |
p |
Pause |
| F2 / F3 | Save / load state |
| F6 / F7 | Previous / next slot |
| F5 | Reset |
| Tab | Fast-forward while held |
| F8 | Cycle recolor mode |
[ / ] |
Scale down / up (inline mode) |
- / = |
Volume down / up |
m |
Mute |
Terminal colors
rom reads the terminal's ANSI palette, foreground, and background at
startup. Colors are matched perceptually in Oklab through a prebuilt lookup
table, so the result is stable and fast.
| Mode | Result |
|---|---|
hue |
Keeps shading while adopting theme hues |
nearest |
Maps directly to the terminal palette |
duotone |
Uses the background-to-foreground ramp |
dither |
Mixes nearby palette colors to recover shades |
Start with --recolor hue. Press F8 to compare modes while playing.
Config and saves
The config is created at ~/.config/rom/config. Edit it to change keys,
volume, scale, recoloring, or focus behavior.
[options] scale = 2 recolor = hue recolor_strength = 1.00 pause_on_unfocus = true [options.gb] scale = 4
Sections may be suffixed with snes, nes, gb, gba, genesis, or pce
for system-specific overrides. Run rom --keys <rom> to see the effective
settings. Volume changes are remembered separately for each ROM; the configured
volume is the initial default.
| Path | Contents |
|---|---|
~/.config/rom/config |
Settings and bindings |
~/.config/rom/saves/ |
Battery saves |
~/.config/rom/states/ |
Save states |
~/.config/rom/rom.log |
Frontend and core log |
Games pause when the terminal loses focus and resume when it returns. Saves are written atomically and SRAM is autosaved every five seconds when changed.
Limitations
- macOS (CoreAudio) or Linux (ALSA)
- Ghostty or kitty required
- Software-rendered cores only; no GL or Vulkan cores
- Player 1 keyboard input only
- Core options use their defaults
Licensed under the MIT License.
