n64brew2025 is a Nintendo 64 homebrew entry with a fully scripted asset pipeline
Our team entry for the 2025 brew game jam
At a glance
- What is it?
- n64brew2025 is a team entry for a 2025 brew game jam, written in C with libdragon and tiny3d, where a Makefile drives the whole build including exporting meshes and levels from Blender files. It suits N64 homebrew developers who want to see how a full asset pipeline is wired together.
- Who is it for?
- Adopt n64brew2025 as a reference if you are writing Nintendo 64 homebrew and want to see how a libdragon and tiny3d project structures its asset pipeline, or if you are entering a homebrew jam and need a working baseline. Do not adopt it as a general purpose engine, since it is one specific game with its own levels and assets, and do not expect the toolchain to be stable, because the build pins the preview branch of libdragon.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 44 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A jam entry where the build system is the interesting part
n64brew2025 is described simply as a team entry for the 2025 brew game jam, and the repository is small enough to read in an afternoon. What is in it is a Nintendo 64 homebrew project written in C, with the game itself named Junk Runner 64. The top level holds the source in src/, assets in assets/, tooling in tools/, documentation in docs/, a Makefile, a Dockerfile, and the built data files, with .pak and .ram artefacts for a couple of versions and a .bs1 file. The primary language in the repository metadata is C, and the licence is MIT. The reason it is worth an article even though it is a game jam entry is the build system. A homebrew project on a 1996 console has to solve asset conversion, font conversion, level export and ROM assembly, and the Makefile here solves all of that explicitly, in a way that shows up clearly in the file names and targets. For a reader who wants to build on a modern console, the patterns of separating source assets from generated ones are still the transferable part.
The Makefile is the architecture of the project
The Makefile reads like a summary of the whole project, which is the main reason to read it. It sets a verbose flag, names the source and build directories, and adds optimisation and debug macro flags to the compiler options before pulling in the platform makefile from libdragon:
V=1
SOURCE_DIR=src
BUILD_DIR=build
N64_CFLAGS += -O3 -DNDEBUG
include $(N64_INST)/include/n64.mk
N64_ROM_TITLE = "Junk Runner 64"
N64_ROM_REGION = E
# N64_ROM_REGION = P
N64_ROM_SAVETYPE = sram256k
include $(T3D_INST)/t3d.mkThe ROM title and region are build-time metadata, and the save type is set to 256 kB of SRAM, which tells you the game persists progress to a cartridge save. The region line is worth noting because the Pal variant is present but commented out, and region changes are exactly the kind of detail that is easy to miss and impossible to guess. The tiny3d makefile is included alongside the libdragon one, so the 3D rendering side of the project comes from a separate engine. There is also an asset packing tool referenced from the libdragon install at the N64_INST/bin/mkasset path, and a tests target that builds a separate test ROM alongside the main all target which produces junkrunner64.z64.
Assets are generated, and Blender is part of the build
The documentation states that the build system exports files and levels from blend files, and that is the part of the pipeline with the most moving pieces. The Makefile finds sources with find and shell substitutions, and each asset type has its own conversion rule. Fonts are discovered by searching assets/ for ttf files, and each one is converted to a font64 resource through the tool pointed at by N64_MKFONT, with a specific font given a monochrome flag and a size of 12. Images follow the same pattern, with png sources found in assets/ and converted to sprite resources by N64_MKSPRITE, which also reads a sibling json file to decide the format and applies compression. Meshes are the most involved step. The export sources are the python scripts under tools/mesh_export/, the mesh sources are blend files under assets/meshes, and the rule builds a .tmesh and an .anim from each blend file by invoking Blender in background mode with a script called t3d_mesh.py, passing the output path as an argument. So the full chain is Blender to blend file, blend file to tmesh plus animation, and the whole thing is triggered by make. A commented out BLENDER_4 line pointing at a specific developer home directory path survives in the file, which is a small illustration of how personal a build configuration can become.
Audio gets its own sidecar configuration file
Sound is handled by a convention rather than by a code path, and it is a neat piece of design. You can place a .txt file with the same name as an mp3 or wav in the same directory, and put flags for audioconv64 in it that apply to that sound. The available options are listed in the documentation, and they cover the things you would actually want to vary per clip:
WAV/MP3 options:
--wav-mono Force mono output
--wav-resample <N> Resample to a different sample rate
--wav-compress <0|1|3> Enable compression: 0=none, 1=vadpcm (default), 3=opus
--wav-loop <true|false> Activate playback loop by default
--wav-loop-offset <N> Set looping offset (in samples; default: 0)
--wav-seek <SEC|FILE> Enable seeking support:
- if SEC is a float, add a seekpoint every SEC seconds
- if FILE, read a list of seekpoints (one per line):
* integer sample offsets, or
* timestamps in [hh:]mm:ss[.mmm] formatThe per file approach means the compression choice is a property of the asset rather than a global setting, so a music track can stay uncompressed while a dialogue clip uses vadpcm, and a looping ambience clip can carry a loop offset without a separate piece of code. The default compression is the vadpcm variant, opus is available as a third option, and seeking supports either a fixed interval or a list of explicit seekpoints, with timestamps in a bracketed hour minute second format.
The Docker route exists because the toolchain is the hard part
Building N64 homebrew needs a cross compiler, a 3D engine, and a modelling application, and getting all three onto one machine is most of the work. The project offers a Docker route and a manual route. The container path is two commands:
docker build . -t n64brew2025
docker run -v ./:/n64brew2025 -it --rm n64brew2025 makeThe image is built on ubuntu:latest, installs build-essential, libpng-dev, wget, git, xz-utils and jq, then downloads the libdragon gcc toolchain deb for mips64 from a continuous prerelease release URL, clones libdragon from its preview branch and builds the install and tools targets, clones tiny3d and builds it, and finally downloads and unpacks Blender 4.5.8 linux x64 into /opt/blender, installing the X11, GL and Mesa libraries Blender needs. The environment variables N64_INST, T3D_INST and BLENDER_4 are set to the install prefixes, which is exactly what the Makefile consumes. The manual route asks for the same three things installed by hand, the preview branch of libdragon, tiny3d, and Blender 4.5.8 somewhere on the system with the BLENDER_4 environment variable pointing at the executable, after which you run make. The container approach is the one to use if you do not already have a working homebrew setup, and it also pins the Blender version, which matters because the mesh export scripts are written against it.
Where this repository stops being useful
The limits are clear and they are not really the project's fault, since it was built for a weekend. It is one game, so there is no general purpose engine here to lift, and the asset conventions are tied to this game's own directory layout and to the tools/mesh_export scripts. If you want to start a different homebrew project, the useful part is the Makefile structure and the Dockerfile, not the src/ tree. The second limit is the toolchain, and it is a real one. The container pins the preview branch of libdragon and a continuous prerelease of the gcc toolchain, which means the build is reproducible today and may not be tomorrow, since a moving branch can change under you. That is a sensible choice for a jam entry and an awkward one for a project you intend to maintain, and it is worth weighing before you adopt the same approach. The third limit is hardware in a broader sense. A game built for a 1996 console with 4 MB of RAM has to fit in the cartridge budget, and the Makefile shows that constraint being managed with compressed assets, 256 kB of save RAM and a ROM region setting. Nothing in this repository scales to a modern title, and the people who read it for that reason are reading the wrong part. The dependency chain of libdragon, tiny3d and Blender is the actual lesson here, and that lesson is that on a constrained platform the asset pipeline is the real engineering.
Editorial conclusion
Adopt n64brew2025 as a reference if you are writing Nintendo 64 homebrew and want to see how a libdragon and tiny3d project structures its asset pipeline, or if you are entering a homebrew jam and need a working baseline. Do not adopt it as a general purpose engine, since it is one specific game with its own levels and assets, and do not expect the toolchain to be stable, because the build pins the preview branch of libdragon. Before you start, read the Makefile targets and the tools/ directory to understand what is generated from Blender, and confirm the Blender version your BLENDER_4 variable points at matches the 4.5 series the Docker image installs.
Frequently asked questions
What is n64brew2025?
It is a team entry for the 2025 brew game jam, a Nintendo 64 homebrew project written in C and named Junk Runner 64. The project is MIT licensed and the repository holds the game source, assets, a Makefile, a Dockerfile and the built data files.
How do I build n64brew2025?
With Docker, build the image and run make inside it, using `docker build . -t n64brew2025` and `docker run -v ./:/n64brew2025 -it --rm n64brew2025 make`. Without Docker, install the preview branch of libdragon, tiny3d and Blender 4.5.8, point the BLENDER_4 environment variable at the blender executable, and run make.
How does the n64brew2025 build handle meshes and levels?
The build system exports files and levels from blend files. The Makefile finds blend sources under assets/meshes and the export scripts under tools/mesh_export/, and invokes Blender in background mode with the t3d_mesh.py script to produce a .tmesh and an .anim for each mesh.
How do I configure audio options in n64brew2025?
Place a .txt file with the same name as an mp3 or wav in the same directory and put audioconv64 flags in it. The options include forcing mono output, resampling, choosing compression between none, vadpcm and opus, enabling looping with a sample offset, and enabling seeking either every SEC seconds or from a list of seekpoints.
What are the build targets in the n64brew2025 Makefile?
The default all target builds junkrunner64.z64, and a tests target builds a separate junkrunner64_test.z64. The Makefile also sets the ROM title, the ROM region, a 256 kB SRAM save type, and includes the libdragon and tiny3d makefiles.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/lambertjamesd-n64brew2025)Was this useful?