A browser IDE for making Sega Mega Drive / Genesis games in
mdlua's PICO-8-flavored Lua. Write
code, draw sprites, compose the sheet, drop in music and sound, build a real
.bin ROM, and play it in the emulator — all in a tab. No SGDK, no
cross-compiler, no server, no install: the real m68k-elf-gcc toolchain
(cc1 → as → ld → objcopy, plus the Z80 driver tools) runs as WebAssembly in a
Web Worker, and the ROM boots on the Genesis Plus GX core.
The browser build is byte-identical to an mdlua CLI build of the same
source and assets — it is the exact same compiler and build driver
(buildGenesisC from romdev-toolchain-m68k-gcc, every seam env-injected),
just hosted in a worker instead of node. CI enforces this on every push.
- Projects. Saved in the browser (IndexedDB), started blank or cloned
from a gallery of the SDK's example games (with live emulator-screenshot
thumbnails). Export/import as a plain
.zip. - Code editor. Monaco with mdlua completions — the entire SGDK API (732 verbs) plus the curated PICO-8 verbs — and live diagnostics from the real compiler on every keystroke, plus a problems panel.
- Build & run. Play (Ctrl+Enter / Ctrl+R) compiles Lua → C → m68k-gcc
WASM →
.binwith a live progress bar, then runs it on Genesis Plus GX. Keyboard and any standard-layout gamepad drive the 6-button pad (a mapper handles non-standard controllers); fullscreen grabs the controls. The toolchain prewarms at startup; a warm edited rebuild is ~350 ms (the SDK runtime units are cached). - Sprite editor. Pencil / eraser / fill / line / rect / eyedropper,
marquee select with copy/cut/paste, zoom, an 8px
spr(n)cell grid, and a palette manager that enforces the Genesis's 16-color line budget (15 colors- transparent). Import PNG or Aseprite; export
sheet.png.
- transparent). Import PNG or Aseprite; export
- Animation. Pick a sprite range and preview it cycling at any fps in the
SDK's three modes (loop / once / pingpong), with flip-X/Y toggles; copy the
ready-to-paste
spr(anim(...))line. - Music. A song-bank manager: import
.vgm/.vgz/.xgc(compose in DeflemMask or Furnace, export VGM) — the list order is themusic(n)index, converted to XGM2 byte-identically to SGDK's xgm2tool. Preview builds a tiny player cart and runs it on the real YM2612 + PSG. - SFX. A WAV bank (order =
sfx(n)index); each entry previews the actual on-cart sound (down-converted to 8-bit 13.3 kHz), not the source. - Palette. A 9-bit BGR-accurate CRAM designer (8 levels/channel, 4 lines
of 16), the PICO-8 palette on PAL0, and
pal()/backdrop()/fade()snippets — the Genesis's live-CRAM control. - Raster lab. An
hscroll(line, x)designer with wave / parallax / split presets, a live preview, and a generated_draw()loop to copy — plusfade/shade_mode/hud/camerasnippets. - SGDK API browser. Every one of the 732 SGDK verbs, grouped by header, searchable, insert-at-cursor — the discoverability surface for the SDK's 100% coverage.
- Debugger. A live hex view of the running game's 68000 work RAM
(
$FF0000, 64 KB), ~10 Hz refresh, click a byte to poke it. - Battery saves.
save()/load()SRAM persists per project across sessions (into the browser), restored when you reopen the game. - Import. Bring in a project
.zip, or a PICO-8.p8/.p8.pngcart — code (glyphs neutralized) and__gfx__(the P8 16-color palette maps 1:1 onto a Genesis palette line) convert into a new project to port from. - Cheatsheet. The SDK's full verb reference, rendered in a tab.
npm install # also stages the WASM toolchain into public/md (postinstall)
npm run dev # open the printed localhost URLClone an example from the New Project gallery, edit, Ctrl+Enter to build
& run. Click the game screen for sound and keys (arrows = d-pad, Z/X/C =
A/B/C, V/B/N = X/Y/Z, Enter = Start, Shift = Mode) — or plug in a gamepad.
⬇ .bin downloads the ROM for a flashcart/EverDrive or any emulator.
Everything comes from npm packages — this repo is the UI:
| piece | source |
|---|---|
| Lua → C compiler, diagnostics, completions | mdlua/compiler (pure JS, runs in-page) |
| asset converters (PNG/Aseprite/Tiled/WAV/VGM) | mdlua/compiler browser-safe modules |
| Genesis runtime C sources | mdlua/md-sdk (staged) |
THE build driver (buildGenesisC, env-injected) |
romdev-toolchain-m68k-gcc/build |
cc1-m68k / as / ld / objcopy + sjasm / bintos WASM |
romdev-toolchain-m68k-gcc/wasm (staged) |
| SGDK library tree (headers, libmd seed, ld script, crt) | romdev-toolchain-m68k-gcc/share (staged as one manifest) |
| Genesis Plus GX emulator core | romdev-core-gpgx/wasm (staged) |
scripts/stage-toolchain.mjs (postinstall) stages those artifacts into
public/md/. The build worker fetches them once, compiles each tool's WASM
once, then calls buildGenesisC() with env.runTool / loadGlue / share / hash
injected — the identical pipeline the mdlua CLI and the romdev MCP server run.
Playwright drives real headless Chromium:
npm testtest/browser-build.mjs— hello AND starfall-with-its-sheet-and-map build in the browser byte-identical to the CLI's ROMs, and the ROM renders on the core.test/ui-drive.mjs— end-to-end through the real UI: gallery, clone, Play, diagnostics gating, all editor tabs, SGDK insert, the anim example builds.test/emu-audio.mjs— a browser-built music (VGM bank) and sfx (WAV bank) cart are both audible on the core.test/browser-sram.mjs— asave()survives an SRAM round-trip and aload()reads it back.test/browser-perf.mjs— a warm edited rebuild stays under 800 ms.test/gen-thumbs.mjs(npm run thumbs) — regenerates the gallery thumbnails by building + running every example headlessly.
MIT (this repo). The staged toolchain, SGDK library, and emulator core are their own projects under their own licenses (the m68k GCC toolchain is GPL-3.0 + the GCC Runtime Library Exception, so built ROMs are not encumbered; SGDK is MIT; Genesis Plus GX is under its non-commercial license) — they are npm dependencies staged at install, never vendored in this repo.
