The Return of Physical N64 Games
Two years ago, Dominic Szablewski ported his JavaScript game engine, Impact, to C for no practical reason. That decision now has a tangible outcome: Xibalba 64, a new N64 game that publisher Modretro will release as a physical cartridge for their modern N64 clone, the M64. This is only the second physical release of a new N64 game since 2002, following Xeno Crisis in 2023.
The Engine: high_impact
high_impact is the C port of Impact, a 2D game engine that handles sprites, tile maps, and collision. It's modular: platform backends (SDL2, Sokol) and rendering backends (software, OpenGL, Metal) can be swapped without touching game code. This modularity made it a natural starting point for an N64 port.
N64 Hardware and Libdragon
Programming the N64 directly is brutal. The MIPS CPU is big-endian and runs at 93 MHz. It has two coprocessors: the RDP (fixed-function graphics) and the RSP (programmable vector processor). Nintendo's official libultra is legally risky to use, but the open-source Libdragon library provides an SDL-like API for the N64. Szablewski built a new platform backend for high_impact on Libdragon in a few evenings, testing with Biolab Disaster. The game code remained unchanged; performance was "meh" but it proved the concept.
Dev Environment: Emulators and Real Hardware
N64 emulation has improved dramatically. The Ares emulator now fully emulates the RDP and RSP with accurate RSP timing. However, the N64's slow memory bandwidth can only be tested on real hardware. Szablewski used a SummerCart64 flash cartridge with a USB-C port, allowing him to upload ROMs directly from his PC via sc64deployer. His setup: N64 connected via USB, video output captured with a $10 USB analog capture card, displayed in an mpv window on Linux. This enabled rapid iteration on real hardware.
The Game: Xibalba 64
Xibalba 64 is a Wolfenstein 3D-like FPS, but built on a 2D engine. The key trick: since there's no elevation, the game is conceptually 2D. Physics use vec2_t, but drawing needs 3D positions. Szablewski solved this with a union that overlays vec2_t and vec3_t:
typedef struct { float x, y; } vec2_t;
typedef union {
vec2_t xy;
struct { float x, y, z; };
} vec3_t;
// Then entity->pos.xy works for 2D physics, and entity->pos.z for 3D.
This allows zero-cost conversion between 2D and 3D coordinates.
Porting existing levels took two weeks. Then several months went into expanding the game and optimizing the renderer. The level editor, a single HTML file, was extended to support lightmaps and entity properties. Levels are stored as JSON, but compiled to a binary format for the N64 to avoid ~100 ms JSON parsing overhead. The struct definition includes a flexible array for settings, with values stored as float16, int16, or strings. The compiler emits big-endian for N64 and little-endian for x86, avoiding byte swapping.
Rendering: Tiny3D and Batching
Libdragon's rdpq_triangle() can draw individual triangles, but efficient rendering requires submitting batches to the RSP. Tiny3D, another open-source library, handles this with a simple API. The N64's 4 KB texture memory and high latency make texture uploads a bottleneck. Mario 64 used untextured polygons, but that doesn't fit Xibalba 64's style. Instead, Szablewski carefully orders draw calls to minimize texture uploads and batches up to 17 quads with the same texture. He packs render calls into 64-bit integers:
typedef union render_call {
uint64_t packed;
uint32_t hashable;
uint64_t ident : 46;
struct {
uint64_t translucent : 1;
uint64_t texture_index : 9;
uint64_t x : 10;
uint64_t y : 10;
uint64_t w : 8;
uint64_t h : 8;
uint64_t vbi : 14;
uint64_t len : 4;
};
} render_call_t;
These calls are sorted at the end of each frame and issued to Tiny3D.
Visibility: Raycasting
To avoid overdraw, the original Xibalba used a portal system. For the N64 version, Szablewski switched to raycasting: casting 320 rays across the field of view, marking traversed tiles in a bitmap. He optimized this by recursively dividing the field of view until two rays hit the same tile. This reduces the number of rays cast, improving performance.
The Result: A New N64 Game
Xibalba 64 is a full game with more levels, enemies, and weapons than the original demo. It runs on real N64 hardware, and the physical release on Modretro's M64 console is a testament to the N64 homebrew scene's maturity. With Libdragon, Tiny3D, and modern emulators, making a new N64 game is feasible for any determined developer.
What You Can Do Now
If you're inspired to try N64 development, start with Libdragon's documentation and examples. Use the preview branch, not the stable trunk. Get a SummerCart64 for real-hardware testing. And remember: the N64's memory bandwidth is a harsh mistress — test early and often.

