Skip to content

v0.17.0 — browser play surface

Choose a tag to compare

@apiad apiad released this 13 Jun 21:46
· 49 commits to main since this release

Headline

The browser is now a first-class play surface. Boot Pokémon Emerald, scan a QR to your phone, and you're playing on the couch — no SDL window, no install on the phone.

gbax play emerald --no-sdl
# auto-opens http://127.0.0.1:8420/stream?mode=controller in your default browser

What's new since v0.16.0

Browser stream (the big one)

  • GET /stream — self-contained HTML page with a stylish GBA-bezel viewer. Dark theme, status / fps / KB-per-frame HUD, 🔇/🔊 audio toggle. ?mode=viewer just watches; ?mode=controller adds the on-screen pad.
  • WS /stream/ws — bidirectional WebSocket.
    • Server → client: framebuffer bytes. Default is raw RGBA8888 (240×160×4 = 153,600 B/frame, pixel-perfect, ~4.5 MB/s @ 30 fps). ?format=jpeg&quality=92 switches to JPEG for constrained links.
    • Client → server: {"type":"buttons","buttons":[...]} to drive input, {"type":"fast_forward","on":true} to TURBO. Same runtime.set_buttons path the SDL keyboard, USB gamepad, and couch already use — set-union all the way down.
  • WS /stream/audio/ws — live PCM s16le stereo @ 32 kHz via a new AudioBus fan-out. Browser decodes through an inline AudioWorklet ring buffer; click toggles, auto-resumes on first user gesture for iOS/Safari autoplay policy.
  • On-screen controller: D-pad, A/B (offset GBA style), L/R shoulders poking out the bezel, Select/Start pills, TURBO pill. Pointer Events handle multi-touch; keyboard shortcuts mirror the SDL play loop (arrows / X / Z / A / S / Enter / RShift). Dock layout flips between portrait (controls beneath the screen) and landscape (controls flanking the screen) — buttons never overlap the canvas.

gbax play --no-sdl

Skip the SDL window entirely. Runs a 60 Hz daemon thread, hosts the FastAPI server on the main thread, pops http://127.0.0.1:8420/stream?mode=controller in the user's default browser. Listen is implicit. The browser tab is the console.

Audio fixes

  • Fast-forward dysync fixed. While fast_forward is set (local L-Shift, browser TURBO, or both), _on_audio mutes. Chipmunk audio gone. On the falling edge the SDL audio queue is cleared so the first normal samples don't sit behind a silence buffer.
  • New gbax.api.audio_bus.AudioBus — many-producer many-consumer thread-safe PCM fan-out. Bounded per-subscriber queues; slow viewers drop chunks instead of blocking the play thread.

Gamepad support (USB / Bluetooth)

Plug in any pad SDL2's GameController DB recognizes (XInput, DualShock/DualSense, 8BitDo, Steam Controller, generic clones — most things with a USB connector). Multiple pads + the keyboard + the HTTP API + the browser combine via set-union. Hot-plug works. Default layout in docs/cli.md.

The couch — peer-to-peer plugin events

A new substrate for cross-instance plugin events. Two gbax instances on the same machine (or eventually across the internet) become "peers" in a "room" and trade typed events through a tiny broker.

  • gbax.couch.Broker + gbax.couch.Client — async Unix-socket fanout, capability-filtered receive.
  • gbax.couch.handle.CouchHandle — sync façade the SDL play loop uses.
  • gbax couch broker / send / listen / whoami / room-code CLI.
  • Plugin API: p.emit_couch("…"), @p.on_couch_event("…"), ctx.couch. Receive handlers fire on the SDL thread so they can safely touch the runtime.
  • Persistent identity at ~/.gbax/identity.json. Wireguard-style three-word room codes via gbax couch room-code (spunky-lilac-buck).
  • Demo plugin: gbax.plugins.pokemon.emerald_couch — press G to gift a Master Ball to your first peer.

gbax browse — interactive ROM picker

gbax browse [<query>] — Textual TUI over the bundled 3,555-entry No-Intro index. Live filter as you type, ↑/↓ to navigate, Enter to download. Variants collapse into groups with (+N) badges; multi-variant groups open a modal picker. ROMs already in ~/.gbax/roms/ get a green . Empty search shows a curated list of ~100 famous GBA titles.

Landing page redesign

https://apiad.github.io/gbax/ — rotating 10-game screenshot showcase, three-audience cards, ascii art GBA bezel as the hero, and a 'Three commands' / 'Or, point-and-click' install path.

Try it

pip install --upgrade gbax
gbax download "pokemon emerald"
gbax play emerald --no-sdl

Migrating from v0.16.0

No breaking changes. gbax play keeps the same CLI; --no-sdl is opt-in. All existing HTTP endpoints unchanged. Plugin API gained additions (emit_couch, @on_couch_event, ctx.couch); old plugins keep working.

Full diff

v0.16.0...v0.17.0