Original Super Nintendo games, written from scratch in C with PVSnesLib. These are real ROMs: each one is a single LoROM cartridge image under 512 KB, uses no enhancement chips, and boots on actual SNES hardware as well as emulators. A runtime region check keeps them running correctly on both NTSC (60 Hz) and PAL (50 Hz) consoles.
Inside you'll find a complete action-platformer demo and a smaller project that exercises the full build pipeline end to end.
A SNES action-platformer demo set in a haunted graveyard.
- Flow: title screen → play → "Game Over" (on death) or "Thanks for Playing" (on finish),
driven by a
TITLE → PLAY → END / GAMEOVERstate machine. - World: a 4800 px horizontally-scrolling level with 3-depth HDMA parallax, a per-scanline colour-math sky gradient, and a moon — rendered by a custom 64×32 page-streaming engine that keeps the whole level resident in under 16 KB of VRAM.
- Hero: run / jump / attack / hurt, gravity + per-tile collision (solid ground + one-way platforms), with movement speeds that stay equal on NTSC and PAL.
- Enemies: three types sharing two streamed sprite slots — skeleton (rises from the ground, chases), hell-gato (paces back and forth), ghost (floats, bobs, turns to face you) — each with sword-kill + contact-knockback combat and a shared fiery death poof.
- Hazards & life: spike pits (−1 HP), a 3-HP limit → game over, fall-out respawn.
- Audio: original looping music (separate in-game and title tracks) + sound effects, via snesmod.
Art: the graphics are adapted from the GothicVania Cemetery pack by ansimuz, released under CC0, reworked to fit SNES VRAM and palette limits. (Full credits below.)
A region-aware "hello world" that walks the whole pipeline end to end (C → 816-tcc → WLA-DX → ROM → Mesen2 → hardware) and shows identical behaviour at 50 Hz and 60 Hz.
| Tool | Version | Installed at | Source |
|---|---|---|---|
| PVSnesLib | 4.5.0 (released 2025-12-28) | ~/pvsneslib → $PVSNESLIB_HOME |
release 4.5.0 (pvsneslib_450_64b_darwin.zip) |
| Mesen2 | 2.1.1 (released 2025-07-06) | /Applications/Mesen.app |
release 2.1.1 (macOS_ARM64_AppleSilicon) |
Built and tested on macOS 26.4.1, Apple Silicon (arm64). Both the PVSnesLib tool binaries and Mesen are native arm64 — no Rosetta required.
PVSnesLib finds all its tools through a single environment variable, exported from ~/.zshrc:
export PVSNESLIB_HOME="$HOME/pvsneslib"That's all the build needs — devkitsnes/snes_rules references every tool (816-tcc, wla-65816,
wlalink, gfx4snes, smconv, snesbrr) by absolute path under $PVSNESLIB_HOME. make comes from the
Xcode Command Line Tools. Open a new terminal (or source ~/.zshrc) so the variable is set.
From a project directory (gothicvania/ or hello-world-region/):
make # produces <ROMNAME>.sfc (+ .sym for the debugger)
make clean # remove build artifactsThe committed
gothicvania/res/*.pngand*.binare the source of truth for the art, andmakebuilds the ROM straight from them. The original source-art pack isn't in the repo, so thetools/adapt_*.py/build_*.pyconverters are kept as readable references only — they no longer run (see the Makefile's "FROZEN ART" note).
mesen gothicvania/gothicvania.sfc # helper defined in ~/.zshrcThe mesen helper passes the ROM as a CLI argument (open -na Mesen --args <abs-path>). Plain
open -a Mesen file.sfc won't work — Mesen.app declares no .sfc document type, so it launches
without loading the ROM. You can also drag the .sfc onto the window, or use File → Open (⌘O).
To see the NTSC/PAL behaviour, force each region in Mesen's emulation settings.
PVSnesLib's shared build rules post-process the linker's .sym file with GNU-style
sed -i '<script>'. macOS ships BSD sed, which misparses that form and fails the final build
step (sed: ... extra characters at the end of h command) even though the ROM itself links fine.
The fix is to rewrite the two in-place edits in $PVSNESLIB_HOME/devkitsnes/snes_rules (around lines
178 and 184) to a portable temp-file form:
# before (GNU-only, breaks on macOS BSD sed):
@sed -i '<script>' $(ROMNAME).sym
# after (portable, works with BSD and GNU sed):
@sed '<script>' $(ROMNAME).sym > $(ROMNAME).sym.tmp && mv -f $(ROMNAME).sym.tmp $(ROMNAME).symThe two scripts are s/:// and / SECTIONSTART_/d;/ SECTIONEND_/d;/ RAM_USAGE_SLOT_/d;. This file
lives in the PVSnesLib install (outside this repo) and is shared by every PVSnesLib project on the
machine, so re-apply the change after reinstalling or upgrading PVSnesLib. The original is preserved
as snes_rules.orig.
- Art — GothicVania Cemetery by ansimuz, released under CC0. Adapted to fit SNES VRAM and palette limits.
- PVSnesLib by Alekmaul and contributors — the C toolchain and SNES library these games are built on.
- Mesen2 by SourMesen — emulator and debugger.

