Birdman64

Birdman64 is a native PC port of Pilotwings 64 for Windows and Linux that supports widescreen, high refresh rates, and modern gamepads.

README

Birdman64

Pilotwings 64 as a native PC game for Windows and Linux. Widescreen up to 21:9, your monitor's full refresh rate (144 Hz and beyond), modern gamepads, rebindable controls and an in-game settings menu. No emulator: the game's own code, built for your PC from your own cartridge dump (ROM).

Latest release Platforms License: MIT Built with Rust

Download the latest release, then follow the Quick start. An unofficial fan project; see Legal.

Screenshots

Holiday Island at 1080p, 16:9, 8x MSAA.

A hang glider banking over the coast in a widescreen view

The original 4:3 image (left) and Birdman64 at 16:9 (right). Widescreen shows more of the world instead of stretching it.

Before and after: 4:3 versus 16:9

The rocket belt at 21:9.

Rocket belt in flight at 21:9

A test briefing at 16:9.

Test briefing screen at 16:9

More screenshots: controls and first-time setup

Every key and button can be rebound in the settings menu.

Controls page of the in-game settings menu

The one-time setup on first start takes about a minute.

First start setup screen

System requirements

Windows: Windows 10 or 11, 64 bit. A graphics card that supports DirectX 12 or Vulkan (almost every PC from the last ten years); keep the graphics driver up to date: NVIDIA, AMD or Intel. Nothing else to install: no Visual C++ runtime, no .NET, no emulator. An internet connection once, for the one-time setup. About 200 MB of free disk space. A keyboard or a gamepad (Xbox, PlayStation, Switch Pro and most USB/Bluetooth pads work).

Linux: a 64 bit distro from 2022 or newer (Ubuntu 22.04, Fedora 36, Debian 12, Steam Deck desktop mode, or newer). Vulkan or OpenGL graphics drivers (Mesa, already installed on most desktops). For the AppImage: libfuse2 (Ubuntu/Debian: sudo apt install libfuse2; or start it with --appimage-extract-and-run). Sound uses ALSA/PipeWire (already there on desktops). Internet once, about 200 MB of disk.

macOS: not supported: the port needs a memory layout macOS on Apple Silicon does not allow.

Quick start

  1. On the Releases page, download Birdman64-windows-x64.zip (Windows) or the Birdman64 .AppImage (Linux). The other files (debug symbols, checksums) are for bug reports and verification.
  2. Right-click the zip, choose Extract All and open the extracted folder. Never run Birdman64.exe from inside the zip. Keep the toolchain folder (the bundled compiler) next to the exe: the first start needs it.
  3. Run Birdman64.exe (Linux: the AppImage). Windows may show "Windows protected your PC" (SmartScreen, because the program is not code signed): click More info, then Run anyway.
  4. On first start, choose your Pilotwings 64 ROM when the game asks (a .z64, .n64 or .v64 file, or a .zip containing one; see What's a ROM?). Put the file next to Birdman64.exe and it is found automatically. Only the US (USA) version of the game works.
  5. Wait for the one-time preparation step: the game downloads about 1 MB of the open source decompilation from GitHub and builds it on your machine (a progress window, usually under a minute depending on your PC; it needs about 200 MB of disk space). Internet is only needed the first time. After that the game starts normally every time.
  6. Play! The first launch shows a card with the basic keys: move with W A S D, A = Space, B = Left Shift, Start = Enter, camera with I J K L, F11 for fullscreen, Esc or F10 for settings.

Controls

Keyboard (defaults; rebind everything on the settings screen's Controls page, or in pw64.toml under [input.keyboard], for example A = "Space"):

InputN64 actionWhat it does
W, A, S, D or arrow keysControl stickSteer · move in menus
SpaceAConfirm · thrust, flap, jump, fire
Left ShiftBBack · gentle thrust, parachute
Z or Left CtrlZHold to aim camera/missile, release to shoot
ERChange camera view
EnterStartPause · confirm
I, J, K, LC up, C left, C down, C rightLook around
T, F, G, HD-padNot used in this game
QLNot used in this game
EscSettingsOpen or close the settings screen (when Esc is not bound to a game input)
F10SettingsOpen or close the settings screen
F11 or Alt+EnterFullscreenSwitch between the window and fullscreen

Gamepad (Nintendo layout pads match by position, so on a Switch pad the button printed B is the N64 A):

InputN64 actionWhat it does
Left stickControl stickSteer · move in menus
South button (Xbox: A, PlayStation: Cross, Nintendo: B)AConfirm · thrust, flap, jump, fire
West/East buttons (Xbox: X/B, PlayStation: Square/Circle, Nintendo: Y/A)BBack · gentle thrust, parachute
North button (Xbox: Y, PlayStation: Triangle, Nintendo: X)C upLook around
Right stick (beyond halfway)C buttonsLook around
Left trigger or ZL (Xbox: LT, PlayStation: L2, Nintendo: ZL)ZHold to aim camera/missile, release to shoot
LB / L (Xbox: LB, PlayStation: L1, Nintendo: L)LNot used in this game
RB / R and RT / ZR (Xbox: RB, RT, PlayStation: R1, R2, Nintendo: R, ZR)RChange camera view
Start (Xbox: Menu, PlayStation: Options, Nintendo: +)StartPause · confirm
D-padD-padNot used in this game
Select (Xbox: View, PlayStation: Create, Nintendo: minus)Settings screenOpen or close the settings screen

Features

  • Widescreen by default on wide monitors (any ratio up to 21:9, menu backgrounds stay 4:3 by design); fill the screen without letterbox bars
  • Window, borderless fullscreen or exclusive fullscreen with a chosen video mode
  • High frame rate: runs at your monitor's refresh rate, 144 Hz and beyond
  • MSAA (1x, 4x, 8x) and render scale (supersampling or upscale) with a linear or nearest filter
  • The N64's 3-point texture filter (set the filter to n64, see PW64_FILTER below)
  • Texture packs (PNG files, keyed by content hash)
  • Optional V-Sync style pacing to remove judder
  • OLED care: the HUD drifts and the screen dims a little to spread wear
  • Gamepads (including Switch 2 controllers over Bluetooth, experimental)
  • An in-game settings screen (F10, Esc or pad Select) that rebinds every key and button and saves to pw64.toml
  • One-time setup that builds the game from your own ROM: nothing but our own code ships in the download

How it was made

Birdman64 went from an empty repository to a 1.0 release in six days (27 September to 3 October 2026). NoahVl designed and led it, directing a team of AI coding agents:

  • Orchestrator and workers: a lead agent (Claude Opus 5.5) plans the work, delegates it and reviews every change. A fast, low-cost model (GLM 5.3-Flash) runs the routine tasks in parallel and wrote 44% of the commits, which keeps the expensive model for architecture, debugging and review.
  • Human in the loop: product and design decisions, legal ground rules, and play-testing every build.
  • Verified, not trusted: CI on Windows and Linux with warnings as errors, 321 tests, and scripted flights whose frames are checked before a change lands.

The result: about 47,000 lines of Rust in 12 crates and roughly 250 commits. That covers a replacement for the N64 operating system, graphics and audio engines, asset tools and a one-click launcher. The design notes are the agents' shared memory, so every session picks up where the last one stopped.

Settings and files

Settings screen: press F10, Esc (or pad Select) to pause the game and change options. Changes are saved when you close the screen; volume and most graphics options apply immediately, a few (MSAA, widescreen, fill screen) are marked "(restart)" and need the game restarted to apply. Reset rows restore the defaults.

pw64.toml example (all keys optional, the same options exist as environment variables):

[graphics]
msaa = 4                   # 1, 4 or 8
scale = 2.0                # render scale, 0.5 or more (1 = window size)
scale_filter = "linear"    # or "nearest"
filter = "n64"             # N64 3-point texture filter, or "bilinear"
widescreen = "16:9"        # 1, "w:h", a ratio like "2.33", or 0 (off)
fps = "monitor"            # "monitor", 30..1000, or 0 (uncapped)
vsync = false              # display-paced pacing (less judder, more latency)
display_mode = "windowed"  # "windowed", "borderless" or "exclusive"
fullscreen_resolution = "1920x1080@60" # exclusive video mode WxH[@Hz]
show_fps = false           # frame rate in the window title
no_audio = true            # no audio output device
volume = 0.8               # 0.0..1.0

[input.ble]
enabled = true             # Switch 2 pads over Bluetooth LE

[oled]
drift = false              # HUD drift for OLED burn-in care
brightness = 1.0           # 1.0, 0.85, 0.8, 0.75 or 0.7

[ui]
pause_in_background = true # pause when you switch windows or unplug the controller

Where files live: everything goes in one folder. How that folder is chosen is described under Save files below.

The one-time setup cache (the downloaded decompilation and the compiled game module) lives in a cache folder next to them: next to the exe in a portable install, else %LOCALAPPDATA%\Birdman64\cache (Windows) or ~/.cache/birdman64 (Linux). The Linux AppImage always uses the per-user locations above. Deleting the cache is safe: the next start just builds the game once more.

Save files: the folder holds the save (pw64.eep), the settings (pw64.toml) and crash.log. It is chosen once at start, in this order: the PW64_DATA_DIR environment variable when set; next to the exe when that folder holds portable.txt or pw64.eep and is writable (portable use, for example on a USB stick: create an empty portable.txt there; a folder like C:\Program Files is not writable); otherwise the per-user folder, %APPDATA%\Birdman64 (Windows) or $XDG_DATA_HOME/birdman64, else ~/.local/share/birdman64 (Linux). A fresh extraction has no marker next to the exe, so it uses the per-user folder: updating stays a matter of unzipping the new version anywhere, and saves, settings and the remembered ROM carry over. The Linux AppImage always uses the per-user location. The start-up log prints [paths] data dir: <path> with the folder that was chosen. To edit pw64.toml by hand, open that folder from the settings screen ("Open save folder"); outside a portable install, a pw64.toml placed next to the exe is not used.

The save itself, pw64.eep, is a raw N64 EEPROM image: no header and no byte swapping (unlike .v64 ROM files). It is written as 2048 bytes. The game's two save files sit at offsets 0x000 and 0x100 inside it (Birdman64 emulates a 4 Kbit EEPROM, so the first 512 bytes are the part the game uses).

Using an emulator save: quit Birdman64 and back up your pw64.eep first, then copy the emulator's save file over it. A Project64, mupen64plus or simple64 .eep file (512 or 2048 bytes) works as it is. A RetroArch Mupen64Plus-Next .srm file starts with the EEPROM contents, so a copy renamed to pw64.eep works too (only the first 2048 bytes are read; the next save writes a 2048-byte file). To go back to an emulator, copy pw64.eep under the emulator's save file name, or set PW64_EEP=<path> and Birdman64 uses (and updates) that file directly. Never replace the save file while the game is running: the game keeps the save in memory and overwrites the whole file at the next save.

Useful environment variables for players: every option in pw64.toml also exists as a PW64_* environment variable, which wins over the file when both are set:

VariableEffect
PW64_MSAA=<1|4|8>MSAA sample count (restart)
PW64_SCALE=<f>render resolution as a fraction of the window (below 1 upscales)
PW64_SCALE_FILTER=<linear|nearest>filter for the blit when the render resolution differs
PW64_FILTER=<bilinear|n64>texture filter (the N64 look is n64)
PW64_WIDESCREEN=<1|w:h|0>widescreen aspect; the default is your monitor's aspect when it is wider than 4:3 (up to 21:9)
PW64_FILL_SCREEN=<0|1>no letterbox bars around world views (default: follows widescreen)
PW64_FPS=<monitor|N|0>frame rate (uncapped with 0)
PW64_VSYNC=<0|1>display-paced pacing (V-Sync)
PW64_DISPLAY_MODE=<windowed|borderless|exclusive>window, borderless fullscreen or exclusive fullscreen
PW64_FULLSCREEN_RES=WxH[@Hz]the exclusive fullscreen video mode
PW64_OLED=<0|1>HUD drift and dimming for OLED screens
PW64_BLE=<1|0>Switch 2 controllers over Bluetooth LE
PW64_ROM=<path>which ROM file to use
PW64_DATA_DIR=<path>folder for saves and settings
PW64_EEP=<path>exact save file to use instead of pw64.eep
PW64_TEX_PACKS=<dir>replace textures from a PNG pack
PW64_NO_AUDIO=1run without an audio device

The developer variables live in Developing.

What's a ROM?

A ROM is a copy of the game cartridge's data, made with a cartridge dumper from a cartridge you own. We can't provide or link one. Birdman64 needs the US version of Pilotwings 64: Troubleshooting shows how to check which file you have.

Updating

Download the new zip and extract it anywhere. Saves, settings and the remembered ROM live in your user folder (see Save files above), so the new version picks them up automatically. Keep the toolchain folder next to the exe: the first start of the new version rebuilds the game once, briefly showing the setup screen again.

Uninstalling

Delete the folder you extracted, then delete the per-user folder: %APPDATA%\Birdman64 and %LOCALAPPDATA%\Birdman64 on Windows, ~/.local/share/birdman64 (or $XDG_DATA_HOME/birdman64) and ~/.cache/birdman64 on Linux. That removes your saves and settings too, so back up pw64.eep first if you want to keep them.

Troubleshooting

  • "The ROM does not work" or the game refuses to start: only the US (USA) version of Pilotwings 64 is supported. European or Japanese cartridges and ROMs from other regions will not work. To check which file you have, compute its SHA-1 hash: on Windows, certutil -hashfile rom.z64 SHA1; on Linux, sha1sum rom.z64. The US version in .z64 byte order has SHA-1 ec771aedf54ee1b214c25404fb4ec51cfd43191a (.n64/.v64 files have a different hash but are converted automatically).
  • Windows shows a SmartScreen warning: the program is not code signed. Click More info, then Run anyway.
  • "No compatible graphics adapter was found": the renderer needs Vulkan, DirectX 12 or OpenGL support on your GPU. Update your graphics driver from your GPU vendor's website (links in System requirements) and try again.
  • The one-time build step fails or your antivirus intervenes: the game compiles the decompiled game on your machine once, which looks like a compiler to antivirus software. Allow it in your antivirus, or add an exclusion for the game folder, then try again. If the bundled compiler (the toolchain folder next to the exe) was removed or blocked, re-extract the zip, keeping the exe and the folder together.
  • The setup screen shows an error: it has a Retry button and shows the path of a build.log file. Try Retry first; if it keeps failing, open an issue and attach the build.log it points to (bug reports about the setup without that log are hard to diagnose).
  • Linux: the AppImage does not start: it needs libfuse2, which recent distributions (Ubuntu 22.04 and newer) no longer install by default. Either install libfuse2 or run it with --appimage-extract-and-run.
  • Verify a download: every release file carries a build provenance attestation. With the GitHub gh CLI: gh attestation verify <file> --repo <owner>/<repo>.
  • Where are my saves? in the save file pw64.eep (see Settings and files). To back a save up, copy that file somewhere safe while the game is not running.
  • The game crashes: a crash.log file is written in the same folder as your saves. To report a bug, open an issue and attach crash.log, the output of Birdman64.exe --version, your GPU model, your OS and the SHA-1 of your ROM. Never attach the ROM itself.

Building from source

You need:

  • Rust stable (https://rustup.rs), any of the usual toolchains (Windows: the MSVC one). No Python and no LLVM install needed.
  • Linux x86_64: libasound2-dev, libudev-dev, libdbus-1-dev, pkg-config and xz-utils.
  • The C compiler, zig 0.16.0 (the same one the release uses to build the game on players' machines): one command downloads it into tools/zig/ and checks its sha256. Or point PW64_ZIG at your own zig 0.16.0.

The decompilation is a git submodule, so clone recursively:

git clone --recursive https://github.com/USER/Birdman64
cd Birdman64
cargo run -p pw64-cbuild --example get_zig --features fetch
cargo run --release -p birdman64

Pass your ROM path as the argument, drop it next to the exe, or let the first-run picker find it. macOS is not supported.

Developing

How it works:

  1. Native game: the game logic from the Pilotwings 64 decompilation is compiled natively (zig's bundled clang, the same compiler players use, driven by pw64-game's build script) and runs on a Rust replacement for libultra (pw64-platform): coroutine threads, PI/SI/AI/VI devices, message queues.
  2. Rust renderer and audio: the display lists the game builds are interpreted by pw64-gfx (Fast3D + RDP HLE on wgpu); the RSP audio microcode (aspMain) is HLE'd by pw64-audio.
  3. Full Rust (long-term): C modules are replaced one at a time by Rust equivalents, each checked against the C behaviour, until no C remains.

Documentation: ROADMAP.md is the roadmap and status; the docs/notes/*.md files are topic notes (formats, graphics, audio, input, native build, the Rust port).

Testing and linting:

cargo test --workspace
cargo clippy --workspace --all-targets

A scripted headless flight check (drives the title menu into a flight and dumps PNG frames to tmp/):

PW64_INPUT_SCRIPT=crates/birdman64/scripts/fly_hang_glider.txt \
PW64_MAX_RETRACES=2700 PW64_NO_THROTTLE=1 PW64_NO_INPUT=1 \
PW64_DUMP_FRAMES=150 cargo run --release -p birdman64

C patches: fixes and small changes to the decompiled C live in crates/pw64-game/patches/ as unified diffs applied at build time. *