A Celeste64-inspired Nintendo 64 demake built with libdragon and tiny3d. The current build features an animated Madeline model, the Forsaken City A-side world, and movement with jumping, dashing, and wall climbing.
The project keeps gameplay code engine-light while the ROM layer handles N64 input, rendering, and streaming the baked world.
Milestone 1: Baked level pipeline + first playable room
Completed:
- ROM boots, runs, and loads baked levels (TrenchBroom →
.map→.lvl+.colmesh) - Player moves/jumps/dashes on collision mesh
- Multiple rooms supported (first-room + full Forsaken City map-pack)
- Fall respawn to checkpoint
- Strawberry collection
- Material catalog with textured geometry
- Full Forsaken City A-side
1.mapas one traversable world: one global collision mesh + per-cell LVL2 visual rooms + map-pack v4 manifest (tools/ogworld/canonical IR →MapRuntime+WorldCollision)
In progress:
- Hardware traversal validation under Ares/Mupen64Plus (see
tests/rom_traversal_acceptance.md) - Verifying collision mesh queries under the Forsaken City map geometry
See .agents/map-creation.md for the full end-to-end pipeline (author → bake → load).
The full A-side 1.map is baked through the canonical world IR into one
global CMSH + per-cell LVL2 rooms + a map-pack v4 manifest (MPP2/MPP3 remain readable):
make bake-forsaken-city
# or
python3 tools/bake_interconnected_map.py assets/og_converted/maps/1.map \
--out-dir build/bake-fc-1200 --chunk-size 1200 --scale 0.2 \
--mappack-id forsyken-cityThe runtime (MapRuntime + WorldCollision) owns ONE global CMSH for the map
lifetime and one authoritative active visual room. All static queries resolve
through the global mesh; the active room exposes a compatibility pointer to
it. Render origins are per-cell centers so the full map's absolute coordinates
do not overflow the int16 fixed-point packing.
- Add more entity types (hazards, traffic blocks, moving platforms).
- Extend room graph / level transitions.
- Introduce scene scripting (Pyrite64 planned, hand-authored for now).
Core physics and collision query logic can be tested on host without the N64 toolchain:
g++ -std=c++17 -Isrc/user \
tests/level_loader_test.cpp \
src/user/gameplay/world/level_loader.cpp \
-o /tmp/level_loader_test && /tmp/level_loader_test
g++ -std=c++17 -Isrc/user \
tests/coll_mesh_query_test.cpp \
src/user/gameplay/physics/coll_mesh.cpp \
-o /tmp/coll_mesh_query_test && /tmp/coll_mesh_query_testNote: tests/gameplay_smoke.cpp depends on <libdragon.h> via entity dispatch and cannot compile on host. Verify the full gameplay loop on ROM instead.
After installing the libdragon N64 toolchain and Tiny3D:
./compile-rom.shBuilds madeline_cube_rom.z64 (libdragon + tiny3d):
- Player spawns on the active room (set by
kBakedLevelPathingameplay_scene.cpp) - Baked level geometry from TrenchBroom
.mapfiles - Textured faces from material catalog
- Collision mesh queries for floor/wall detection
- Analog movement,
Ajump,Bair dash, fall respawn - Strawberry collectibles
To author a new room, see .agents/map-creation.md for the full pipeline (TrenchBroom → bake.py → runtime load).
- Pyrite64 for editor/runtime integration
- libdragon underneath for N64 SDK/runtime
- tiny3d underneath for 3D rendering and future GLTF assets
