GoldenEye 007 as a native executable. Windows, macOS, Linux. No emulator.

Built from the n64decomp/007 decompilation, so the binary is the game. Mouse and keyboard, any resolution, mods in Lua, and the frame-rate problem actually fixed rather than worked around.

Silo, from the walkway beside the missile

  • All 27 stages, single player and split-screen multiplayer, 64 characters, radar.
  • Mouse and keyboard, on by default. Sensitivity, invert, ESC to release the cursor.
  • Any controller you already own. DualSense, DualShock 4, Xbox, Switch Pro, 8BitDo. Both sticks live, bindings per player.
  • A crouch key. The original makes you hold aim and push down. This gives it a button.
  • A launcher for level, ruleset, cheats, resolution and field of view.
  • Rulesets and horde mode. Health, damage, accuracy and ammo as percentages, with presets.
  • Lua mods. Drop a mod.lua in mods/, get onFrame and friends, no rebuild.
  • Start any mission with any gun, dual wielding included.
  • FXAA, CRT, supersampling, MSAA, arbitrary resolution. All off by default.

The launcher's Controls page

FXAA off, left; on, right

FXAA off left, on right, on the PP7 barrel. It is a screen-space approximation, not MSAA, but on geometry this sparse it is nearly free.

git clone https://github.com/SegfaultEvan/goldeneye-native
cd goldeneye-native
./getv/build_mac.sh all        # or build_linux.sh / build_windows.ps1

You supply your own ROM. The build reads it once to extract assets; what you run afterwards never touches it. Full steps in docs/SETUP.md.

GoldenEye counts per iteration, not per second. 122 of its 135 game files do per-frame work, tuned against the 20 to 30fps real hardware managed. Lock the loop at 60 and everything happens twice as often.

Fixed: the simulation runs on its own divider, the camera interpolates between ticks, and the frame-counted systems count time now. An FN P90 held for 80 frames fires 39 rounds at every divider. It used to be 39, 20 and 10. A twelve-level sweep flags nothing.

Above 60Hz set GETV_REALCLOCK=1 or the world runs fast; the game warns you. That path is reasoned from the code and not measured, because this was built on a 60Hz panel.

Working, measurements and method in docs/FRAME_TIMING.md. No 1964 or Mouse Injector code is used; those are GPL-2.0 and quarantined (docs/REUSE_AUDIT.md).

Graslu raised this publicly and was right to. Identifying it is the harder half and it is not a licensable thing, so the credit is worth more than the code would have been.

If you came here looking for a GoldenEye emulator

Reasonable place to land. The difference matters.

An emulator runs the retail N64 ROM by pretending to be an N64. It works, and for a lot of people it is the right answer. What it cannot do is change the game, because the game inside it is compiled MIPS machine code. Frame-rate quirks, control schemes, resolution limits and anything else baked into the original logic stay baked in. The usual workaround is patching memory from outside, which is fragile and specific to one build.

This is built from a decompilation: the game as readable, editable C. It compiles to a normal executable for your operating system. There is no N64 being simulated, so there is no emulation overhead, no core to configure, no plugin to pick, and no ROM loaded at runtime.

The renderer helps more than it sounds like it should. The N64's RDP is a fixed-function pipeline with a two-cycle colour combiner and 4KB of TMEM, which is close enough to the GL most of us grew up on that translating display lists into draw calls is mostly bookkeeping rather than reinvention. That is why the graphics side of a port like this comes up quickly and then spends years on the last five per cent.

So these are ordinary code changes rather than impossible:

  • widescreen and arbitrary resolution, because the projection is a function we can call
  • mouse and keyboard, because the input layer is ours
  • mod scripting in Lua, because we control the frame loop
  • the frame-rate problem, which is a real bug in the original scripting and is the one thing everybody asks about. See frame timing.

You still need your own ROM. The build reads it once to extract assets. What you run afterwards does not touch it.

Questions people actually ask

Can I play GoldenEye 007 on a modern PC, Mac or Linux machine without an emulator? Yes. That is what this is. You supply your own ROM, the build extracts the assets from it, and what you run afterwards is a native executable.

Does it support mouse and keyboard? Yes, and it is the default. Mouse look with sensitivity and Y-invert, WASD movement, ESC to release the cursor.

Does it run at 60fps? Can it run higher? It renders at 60 by default and the resolution is arbitrary. Above 60 the game's per-frame systems run faster than they were tuned for; see the section above. framerate = 30 is the faithful setting.

Is there widescreen? Resolution is fully configurable, but measured: changing the window aspect does not widen the field of view. The renderer fits the 4:3 view to whatever window it is given. Use fov for a genuinely wider view; it is the setting that changes what you can see. Real aspect-aware widescreen is a roadmap item.

Can I mod it? Yes, three ways: Lua scripts in mods/, roughly 275 GETV_* behaviour gates, and goldeneye.cfg. Texture replacement is on the roadmap, not implemented.

Is multiplayer online? No. Split-screen multiplayer works. LAN and online are roadmap items and are downstream of the frame-timing work.

Can two people play the single-player missions? Partly. It is alpha. Two to four players spawn into a solo mission with its own geometry, props and objectives, and every viewport renders. They do not move yet. Details below.

Do I need the ROM? Yes, your own copy. Nothing in this repository contains game data. Is this the Xbox 360 remaster or the cancelled XBLA version? Neither. Those are separate codebases. This is the Nintendo 64 game, from its decompilation.

How is this different from a source port like Ship of Harkinian? Same idea, different game. A decompilation is turned into a native program with a modern platform layer. This one is GoldenEye.

Does it need Wine, Proton, WSL or a compatibility layer? No. Each platform gets a real native binary. Windows uses mingw-w64 with no MSYS2, Cygwin or WSL involved.

What about split-screen on one PC? That works, with all 64 characters, the radar and the full multiplayer setup.

Can I use a PS5 or Xbox controller? Yes. Input goes through SDL2's game controller layer, so a DualSense, DualShock 4, Xbox pad, Switch Pro controller or 8BitDo is recognised without a mapping file, wired or wireless. Both analogue sticks are live, which the N64 controller could not do.

Is there a crouch button? Yes, and the original does not have one. Retail crouch means holding aim, pushing down, then releasing aim while staying low. Here it is C or LSHIFT, with V to stand, and the original gesture still works if you prefer it.

Does it support gamepads? Yes, through SDL2, including wireless controllers your OS already pairs. Keyboard and mouse are the default and both work at once.

Can it run at 4K? The internal resolution is arbitrary and supersampling is available. Whether that is a good idea on the frame-timing front is covered above.

Is the source available? All of it. That is the point.

All 27 loadable stages boot, render and exit cleanly: 21 load directly, and six are multiplayer-only and need two or more players. There are no known crashes, hangs, or stages that fail to start or end properly.

The remaining ten ids carry no data in the ROM: Citadel, which has a background file but no setup, and nine cut during development. Reaching one now prints which stage it is and what is missing, then exits. Previously they were worse than useless: two spun at full CPU while ignoring SIGTERM, three crashed, and one of those varied between hanging, SIGBUS and SIGSEGV depending on what the heap happened to contain. Loading a multiplayer-only stage on its own says so and names the flag, rather than reporting it as missing data.

Multiplayer works, including split screen, the radar and all 64 selectable characters. The pause watch renders all five pages. Saves persist.

Two to four players can also share a single-player mission, split screen, with coop = 2. The mission loads with its own geometry, props and objectives, every player spawns into it, and the viewports render: Dam draws 5139 triangles at two players and 8412 at four, against 2042 solo.

It is alpha, and the limitation is measured rather than suspected. Under GETV_STATE the players spawn correctly and separated, and none of them moves under scripted input that carries the solo player 16,930 units on the same level. Player 0 is affected too, which rules out the obvious explanations; four have been eliminated with measurements and the remaining search is recorded in the roadmap. Objectives, AI and cutscenes are authored around one Bond and none of that has been adapted either.

Whether it plays correctly from start to finish is untested, and the frame-timing section above is a concrete reason to expect it is not yet feature complete.

That gap is measurable rather than merely stated. tools/playtest.py drives a stage with scripted input and reads the machine-readable run state the game emits under GETV_STATE: whether the player reached gameplay at all, how far they moved, how many objectives the mission has, whether any changed, and whether it completed.

Its current result: all 21 solo missions reach gameplay and the player moves, between 408 and 19,584 units over a 900-frame run, with objective counts matching the missions. No objective advanced, which is expected when the input is "walk forward" and nothing else. So the port is further than "renders" and well short of "plays": reaching a playable state is measured across every mission, and completing one is not.

One reading to know about. Cuba is the credits sequence and reports no objectives, so objectiveIsAllComplete() is trivially true there and the tool prints complete=yes. It is an empty set, not a finished mission.

Not an emulator: no MIPS interpreter and no dynamic recompiler. Not static recompilation: no generated C, no ELF input, no recompiler tooling. Not a fork of the Xbox 360 XBLA remaster.

This project is not affiliated with, endorsed by, or connected to Nintendo, Rare, MGM, Danjaq or EON Productions.

No ROM, no extracted assets and no game data are distributed with this repository, and none ever will be. You need your own legal copy of the NTSC (US) cartridge, dumped to a file. This is not a licensing formality that a mirror quietly works around: every texture, model, animation, sound bank and level layout is read out of your dump at build time and emitted as C. Roughly 746 of the translation units this build compiles are generated that way.

Property Value
Size 12,582,912 bytes exactly
Byte order Big-endian z64
Header magic 80371240
Internal name GOLDENEYE
SHA-1 abe01e4aeb033b6c0836819f549c791b26cfde83

That SHA-1 is the value in ge007.u.sha1 in the decompilation, so a dump with that hash is byte-identical to what a correct US build must produce. If your dump has a .n64 or .v64 extension, or a header of 37804012, it is byte-swapped and must be converted to native big-endian first.

The build reads the ROM through the decompilation's own extraction scripts, which expect it at the root of the decomp checkout under a fixed name, vendor/ge-decomp/baserom.u.z64. The convention used here is to keep dumps in roms/ at the repository root and symlink one into place. .gitignore blocks roms/, every *.z64 / *.n64 / *.v64 / *.elf, all getv/build-* directories (they contain object files compiled from extracted ROM data), *.bmp frame captures, and vendor/ and deps/ themselves. Do not defeat those rules.

Two further things are absent from a fresh clone for related reasons. Fifteen third-party port-layer files - the Fast3D renderer and the audio mixer, inherited from sm64ex - are fetched from a pinned upstream commit by tools/fetch-thirdparty.sh, because their redistribution terms are unresolved. The SDL2 2.30.9 source tree is supplied by you in deps/SDL2-2.30.9, and built from source, because a Homebrew running under Rosetta produces an x86_64 SDL2 that cannot link into an arm64 binary.

Prerequisites: macOS 13+ on Apple silicon, Xcode Command Line Tools, CMake, Python 3, and the stock /bin/bash 3.2. Nothing newer is needed.

tools/fetch-thirdparty.sh fetch                                       # the fifteen files
git clone https://github.com/n64decomp/007 vendor/ge-decomp           # the game's C source
# then: apply getv/patches/0001-source.patch, place your ROM, generate the asset sources
# from it, and apply getv/patches/0002-assets.patch - docs/SETUP.md sections 2.4 and 3
cd getv && ./build_mac.sh sdl && ./build_mac.sh all && ./build_mac.sh run

docs/SETUP.md is the step-by-step guide - every prerequisite, every command, the expected output of each one, and a troubleshooting section. Read it if you have not built this before. The asset-generation step is the one that cannot be shortened: it is a sequence of extraction and code-generation passes, not the one line above, and skipping any of them produces a tree that fails to compile or silently misbehaves.

Two-player split screen with a radar in each pane

An outdoor stage at night: snow-covered rock, a truck, a glass-walled guard post

Split screen in a concrete interior with weapons and armour on the floor

getv/build_mac.sh takes one of sdl, lib, port, app, all, run or env.

  • sdl builds SDL2 2.30.9 for arm64 into ~/.n64tvos/sdl2-mac - deliberately outside the repository, because the repository path contains a space and that has broken header search paths here before. Once per machine.
  • lib compiles the game, assets, audio and platform layer into build-mac/obj.
  • port recompiles only getv/port/** and the two harness objects. About 23 s.
  • app archives the objects into build-mac/libge.a and links build-mac/goldeneye.
  • all is lib followed by app.
  • run launches the linked binary, forwarding any arguments.
  • env prints the resolved SDK, SDL prefix, target triple and output paths.

There is no incremental check - every lib is a full recompile of all 992 objects. Measured at 21 s wall for all on an Apple M1 with warm caches. Compilation is parallel; GETV_JOBS caps the job count and defaults to 6.

Expected output from ./build_mac.sh all:

  mac FAILED: src/tlb_manage.c
mac game: 167 built, 1 failed
mac assets: 746 built, 0 failed
mac audio: 40 built, 0 failed
mac port layer: 23 built, 0 failed

The one failure is expected. src/tlb_manage.c programs the N64's MIPS R4300 translation lookaside buffer. There is no TLB to program here and nothing links against it, so it is left to fail rather than being papered over. Seven further N64-hardware and SGI-dev-host files (usb.c, rmon.c, sched.c, ramrom.c, init.c, indy_comms.c, indy_commands.c) are excluded by name in the build script for the same reason. Any second name in a mac FAILED: line is a real problem.

getv/build_linux.sh takes the same targets. Needs a C compiler, SDL2 and GL headers:

sudo apt install build-essential pkg-config libsdl2-dev libgl1-mesa-dev
CC=gcc ./getv/build_linux.sh all

Optional: tools/fetch_lua.sh for mod scripting and tools/fetch_imgui.sh for the launcher and dev overlay. Both are optional at every level; without them the build omits the feature and the entry points compile away.

Native, with mingw-w64. No MSYS2, no Cygwin, no WSL. One command installs the whole toolchain, SDL2, GLEW, Lua and Dear ImGui:

powershell -NoProfile -ExecutionPolicy Bypass -File tools\fetch_deps_windows.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File getv\build_windows.ps1 -Target all

The build is driven from PowerShell rather than bash on purpose: it needs only the compiler, not a working POSIX emulation layer. getv/build_windows.sh exists for hosts with a healthy MSYS2.

Keyboard is bound to controller port 0 by default: WASD to move, arrow keys to look, Space or Left Ctrl to fire, E or Return to use, Q to aim, Z and X for the shoulder buttons, Tab to pause, IJKL for the d-pad, F11 for fullscreen. A connected gamepad works alongside it - whichever input is held wins, so plugging in a pad never degrades the keyboard and vice versa.

On first run, with no configuration file present anywhere, the game writes a commented template to ~/Library/Application Support/GoldenEye/goldeneye.cfg and immediately reads it back. This is not a convenience: several of the port's tuned defaults - invert_look being the case in point - only exist in that template, and a default that lives in a file nobody has generated is not a default. Edit that file to taste, or regenerate it with --write-config.

Save data is separate, and lands in ~/Library/Application Support/Goldeneye-Native/eeprom.bin. It is 512 bytes: GoldenEye saves to the cartridge's serial EEPROM, and writes are atomic.

A few keys worth knowing:

Key Values Default
resolution WIDTHxHEIGHT, fullscreen, native 1280x960
supersample 1, 2 1
filtering point, bilinear, three-point three-point
framerate 30, 50, 60, off 60
controls any of Rare's eight styles, by number or name 2.2 galore
roster 8, 64 8

Every setting is documented in docs/CONFIGURATION.md. The named cheat system is in docs/CHEATS.md. If you want to change the game rather than play it, start at docs/MODDING.md; the roughly 250 GETV_* environment gates are the practical extension surface, and each defaults to preserving stock behaviour.

getv/port/        platform layer: renderer, audio, input, config, saves, paths
getv/patches/     this port's changes to the decompilation and to the fetched sources
getv/build_mac.sh the macOS build
getv/tools/       measurement harnesses
tools/            asset generation, and the third-party fetcher
docs/             documentation
vendor/           decompilation and fetched upstream sources   (untracked)
deps/             SDL2 source                                  (untracked)
roms/             your ROM                                     (untracked)

Everything not listed as tracked is fetched, cloned, or derived from your ROM.

docs/SETUP.md The build guide. Start here.
tools/playtest.py Drive a stage and report whether it reached gameplay, moved, and advanced objectives.
tools/stage_census.sh Every named stage id: loads, multiplayer only, or carries no data.
tools/render_refs.py Rendering baseline; check reports any stage that drifts.
CONTRIBUTING.md What is specific to this project: no game data, the patch workflow, measuring, building one file, provenance.
docs/CONFIGURATION.md Every configuration key, which are implemented, and which are reserved.
docs/CHEATS.md The game's own cheat system, exposed by name.
docs/MODDING.md How the tree is arranged and where the seams are.
docs/ROADMAP.md Current state, known issues, planned work.
docs/FRAME_TIMING.md The frame-rate question, what causes it, and what a complete fix needs.
docs/VISION.md The long arc, scored against what the tree does today.
docs/REUSE_AUDIT.md What to borrow, what is already borrowed, and what must not be touched.
docs/PORTING.md The platform layer, per file.
docs/THIRD_PARTY.md The fifteen fetched files: what, whence, and why not vendored.
docs/LICENSING.md Where every part came from and which terms are settled.
docs/ASSET_LOADING.md Level asset loading: map, holes, plan.
docs/PERFECT_DARK.md What the MIT-licensed Perfect Dark port offers this one.
getv/port/PROVENANCE.md Per-directory origin of the platform layer.
  • Co-op is alpha. Players spawn into single-player missions and do not move. Four explanations have been eliminated with measurements; what remains is between the stick reaching moveData.analogWalk and speedforwards being applied.
  • Bots are alpha. The player API installs its hook and drives a slot, and the first bot runs against it. It does not yet play the game: driving an empty slot produces no input, which is the next piece of work rather than a claim of working bots.
  • Above 60Hz, set GETV_REALCLOCK=1. The default clock counts a rendered frame as a video field, so a 120Hz display runs the world at double speed without it. The game warns you. The fix is reasoned from the code and not measured on real high-refresh hardware.
  • Jungle hit registration changes with the divider. Bond lands 8 hits at divider 1 and 3 at divider 2 on the same scripted run. Guard positions advance once per tick, so a moving target occupies a coarser set of positions and a shot can pass between them. That is what a lower simulation rate means, not a timer bug, and it is not being papered over.
  • Missing HMS MI5 crest on the multiplayer character select. The same crest renders correctly on the file select screen, so the asset and its decode path are sound.
  • Select File background renders flat black; the original has a faint circular watermark behind the folders.
  • Multiplayer edge cases. Score caps are not enforced on the headless path, and num_shots disagrees with the fire path.

docs/ROADMAP.md carries the full list and the planned work.

LICENSE is MIT, and it covers the original work here: the platform layer under getv/port/ excluding the fetched third-party sources, the build scripts, tools/, and the documentation. It does not and cannot cover anything else. NOTICE states the scope precisely.

Read getv/port/PROVENANCE.md before redistributing anything. It records, per directory, where the platform layer's code came from - in particular that the license status of getv/port/fast3d/, which descends from sm64ex's copy of Emill/n64-fast3d-engine, is unresolved. The notice sm64ex ships is the pre-2021 form, whose second condition bans binary redistribution outright. Do not assume it is MIT.

The decompilation itself has no license file, and its libultra sources carry SGI proprietary headers. That is upstream's situation, but it is a fact about the base this port is built on.

The ROM, extracted assets, and anything derived from them are never distributable under any license.

GoldenEye 007 was made by Rare in 1997. Everything here is a wrapper around their work.

n64decomp/007, led by KholdFuzion with dozens of contributors over nine years, reaching 100% in August 2026. Without it there is no project here at all. The mirror of record is gitlab.com/kholdfuzion/goldeneye_src, and kholdfuzion/goldeneye_docs is the reference that answers questions the source alone does not.

Code that ships in this repository

sm64ex the Fast3D renderer and audio mixer this port's layer descends from
Emill/n64-fast3d-engine the original Fast3D, by Emill and MaikelChan
SDL window, input, audio and gamepads on every platform
Dear ImGui Omar Cornut's immediate-mode UI, behind the launcher and the dev overlay
Lua PUC-Rio's language, which is what makes mods possible without a rebuild
Roboto Condensed The Roboto Project Authors, under the SIL Open Font License 1.1

Provenance for every file, line by line, is in docs/THIRD_PARTY.md and NOTICE.

Work that shaped this without a line of code being taken

Ports are built on each other's hard-won knowledge as much as their source, and several projects below are licence-quarantined precisely so that nothing was taken. The debt is real regardless.

  • Graslu identified the frame-rate problem publicly. It is the single most-cited complaint about the game above 30fps and naming it correctly is the harder half of fixing it.
  • The Perfect Dark PC port is the closest sibling to this work, and the more mature one. Its structure showed what a decompilation port should look like; its netplay design settled the client-server question here; and its simulant model shaped how bots are approached. Read for approach, not copied.
  • Joel Middendorf and the 1964 emulator (1999-2002), and Graslu/1964GEPD which forked it for GoldenEye and Perfect Dark. GPL-2.0 and quarantined, so what was taken is a list of symptoms worth chasing and nothing else.
  • Ship of Harkinian and libultraship proved this shape of port on console-class hardware years before this started.
  • GoldenRecomp, cblock85/GoldenEye64Recomp and chrissotraidis/goldenpad took different routes at the same problem. All on the do-not-read list here, all worth knowing about.
  • The wider N64 decompilation and homebrew community, whose documentation of the RCP, TMEM, F3D microcode and the RDP's combiner is why the renderer came up in weeks rather than years.

If your work is in here and is not named, that is an oversight rather than an opinion. Open an issue and it gets fixed.

Built by Evan King (@SegfaultEvan).