Jev Games

September 17, 2026 · View on GitHub

A visual lab where Jev plays multiple games. This is the next step after mario-jev: the same Jev controller style, a Zero-shot Lab UI, and a plugin split so new games and emulator platforms can be added without rewriting the loop.

Bundled titles:

GamePlatformHow it runs
Super Mario Bros.NES (nes-py)gym-super-mario-bros (SMB1 RAM observations from mario-jev)
Kung Fu / Spartan XNES (nes-py)roms/kungfu.nes (or KUNGFU_NES); RAM map from the NES original
DoomViZDoomOriginal E1M1 Hangar from roms/doom1.wad (shareware) or doom.wad; otherwise Freedoom (different first map)

The model stays Jev. Code owns buttons, hold duration, and (for Mario) landing interrupts.

Setup

Python 3.13 via uv, frontend via bun.

uv sync
# TYPESAFE_API_KEY is already in .env for this checkout
cd frontend && bun install && bun run build && cd ..

Atari is no longer used for Kung Fu. Put a legally obtained NES kungfu.nes in roms/ (or set KUNGFU_NES). Doom uses original E1M1 Hangar when roms/doom1.wad (shareware) or doom.wad is present; otherwise ViZDoom's Freedoom Phase 1 (a different first map).

Visual lab

Two terminals:

uv run jev-games lab
cd frontend && bun run dev

Open http://127.0.0.1:5173. After bun run build, the API also serves frontend/dist at http://127.0.0.1:8000 (or JEV_GAMES_PORT).

  • Run / F5 starts Jev (or the scripted baseline)
  • Step / F10 takes one decision
  • Reset / R restarts the episode
  • Cartridges in the header switch Mario, Kung-Fu, and Doom
  • History / Tape lists attempts; Replay re-runs recorded buttons on the emulator (Esc returns to live)
  • Jev vs Scripted avoids spending API calls while you check the emulator

Every Jev decision is a paid TypeSafe request. Use Step or a short Run, and prefer Scripted until the picture and buttons look right.

Headless play

uv run jev-games play --game mario --policy scripted --decisions 20
uv run jev-games play --game kungfu --policy scripted --decisions 20
uv run jev-games play --game doom --policy scripted --decisions 20
uv run jev-games play --game mario --policy jev --decisions 10

Adding a game

  1. Pick or add a platform under src/jev_games/platforms/ (NES, Atari, Doom today).
  2. Add src/jev_games/games/<name>/game.py implementing Game: create_env, observe, questions, compose, scripted, advance.
  3. Register it in src/jev_games/catalog.py.

Adding another NES game

from jev_games.platforms.nes import make_nes_rom_env

env = make_nes_rom_env("roms/zelda.nes", action_button_lists)
ram = env.unwrapped.ram

Put a legally obtained .nes ROM in roms/, decode that game’s RAM, and write Jev questions the same way Mario does.

A new console (SNES, GB, …) is a new platform module with create_env / frame / memory access. Games should not import emulator libraries directly if the platform can own that.

Layout

  • src/jev_games/engine.py — run/step/reset worker, WebSocket snapshots
  • src/jev_games/platforms/ — emulator adapters
  • src/jev_games/games/ — per-title observations and Jev policies
  • frontend/ — Zero-shot Lab UI (inspired by design-concept.png)
uv run pytest
uv run ruff check src tests