{% extends "main.html" %} {% block extrahead %} {{ super() }} {% endblock %} {% block tabs %} {{ super() }}
v0.16.0 alpha MPL-2.0 Linux x86_64

Game Boy Advance you can drive.

An emulator for hackers, speedrunners, and AI researchers. Plays Pokémon Emerald in a window with sound and a keyboard — and in the same session exposes the framebuffer, memory bus, and input as an HTTP API any coding agent can reach.

Same emulator. Same session. Same API. Whether you're the player or the algorithm, you're in the loop together.

Three commands.

Pokémon Emerald, in a window, with sound.

$ pip install gbax
$ gbax download "pokemon emerald"
$ gbax play emerald

The wheel ships a prebuilt mgba_libretro.so. No cmake. No apt-get. No $GBAX_CORE_PATH.

Or, point-and-click
$ gbax browse

Interactive search-as-you-type over all 3,555 ROMs. Arrow keys to navigate, Enter to download. ROMs you already own show a green .

The cooperative loop.

Bring a keyboard. Bring a gamepad. Bring an LLM.

Every input source — keyboard, controller, HTTP — drives the same runtime via the same lock. They combine by set-union; none of them blocks the others. Plug in two pads, plug in an agent, keep your hand on the keyboard. All of it works together.

Human
AB LR SelectStart
Ctrl+19 save slot
Shift+19 load slot
L-Shift 8× fast-forward
F12 screenshot
🎮 USB / Bluetooth pad — XInput, DualShock, 8BitDo, Steam, clones
SDL window · keyboard · gamepad · macros · save states
Agent
POST /action GET /frame GET /memory/0x02024284 POST /buttons POST /capture_state GET /savestate/3 GET /plugins/emerald_party/party
HTTP · script · LLM · pipe

What you get.

One install. Seven surfaces.

🎮

3,555 ROMs

Fuzzy-searchable No-Intro index bundled. gbax download pulls from the public archive.org mirror. Bring games you own.

🌐

HTTP API

Framebuffer, full memory bus, input, cheats, save states, an atomic /action for multi-step agent plans, and a live /stream over WebSocket.

🧩

Plugins

Python files that hook the play loop and publish HTTP routes under /plugins/<name>/…. Bundled Emerald party plugin shows the pattern.

🧪

State tracker

Supervised memory inference. Label what's true (hp=22, scene=overworld). gbax intersects across captures and finds where each value lives.

⌨️

Macros & cheats

Ctrl+R records, F1F9 replay. ~6,700 cheat codes vendored from libretro-database; no network at runtime.

📺

GPU shaders

crt-lottes out of the box, custom WGSL when you want pretty, via the [gpu] extra.

📱

Browser stream

/stream serves a stylish GBA-bezel viewer page; /stream/ws pushes pristine RGBA frames at 30 fps. ?mode=controller docks an on-screen pad — play on your phone, your laptop, anything in between.

Built for three.

Same emulator. Three audiences.

The nerdstalgic

You want to remember.

  • 🎮 Browse the cartridges from your shelf — gbax browse
  • 🕹️ Plug in any USB or Bluetooth pad — XInput, DualShock, 8BitDo, generic clones
  • 💾 Save state anywhere — even mid-boss
  • Fast-forward the grind on Left-Shift or the left trigger
  • 🍀 Pin a cheat to F1 when you're stuck

The agent layer doesn't even have to be running.

The speedrunner

You want to practice.

  • ⌨️ Macros bound to any letter — Ctrl+R records
  • 🎟️ ~6,700 cheat codes vendored offline
  • 🎚️ Hotkey save slots, 8× on Left-Shift
  • 🤖 Bring an AI companion — Claude Code, OpenAI Codex, OpenCode

Keyboard, gamepad, and the agent — all in the same loop, never blocking each other.

The scientist

You want a laboratory.

  • 🏟️ 3,555 hand-crafted environments — the level designers were genre masters
  • 🥊 Tournaments and atomic multi-step actions
  • 🏷️ Supervised state-tracker labels — say what's true, gbax finds where it lives
  • 🧩 Plugins that write their own plugins
  • 🔌 BYO agent or wire an RL loop on /action + /state

Take it for a spin.

Three lines, and you're in.

# Linux x86_64 — bundled core, no extra setup
$ pip install gbax
$ gbax download "pokemon emerald"
$ gbax play emerald --listen --plugin gbax.plugins.emerald_party
{% endblock %} {% block content %}{% endblock %} {% block footer %} {{ super() }} {% endblock %}