Mario Kart World Recomp

mkw-recomp is a native PC port of Mario Kart World for Windows and Linux that runs the game at 30 fps with optional frame generation.

README

mkw-recomp logo

mkw-recomp

Mario Kart World (Nintendo Switch 2) recompiled to run natively on Linux and Windows.

Download the latest release for Windows Download the latest release for Linux (AppImage) Download the latest release for Linux on ARM (AppImage)

Releases · Help wiki · Changelog · Contributing · Sources · Roadmap · Performance · Issues · Discussions · Archive

English · 简体中文 · Español · العربية · हिन्दी · Português (Brasil) · Português (Portugal)

A static recompilation of Mario Kart World (Nintendo Switch 2, versions 1.0.0 and 1.8.0) into a native PC program for Linux and Windows. It needs your own copy of the game, dumped from your own console: nothing of the game is in this repository or in its releases.

It is a recompilation, not an emulator. The game's AArch64 code is translated to C ahead of time and compiled for the PC's CPU (x86-64, or AArch64 on Linux); there is no CPU interpreter or JIT. The GPU is not emulated either: NVN2, the Switch 2 graphics API, is reimplemented on top of Vulkan at the API level, and the game's SM86 shaders are translated to SPIR-V ahead of time. Nintendo SDK functions (nn::*) are replaced by name with our own code.

Status

Early, and moving fast. On 12/11/2026:

  • It boots, plays the intro movies, goes through the menus and races, on Linux and on Windows (x86-64), and on Linux on AArch64 (its own AppImage; tested on an Adreno 740 handheld).
  • The start screen sets the game up from your copy on your machine (generates and compiles the C, translates the shaders, warms up the pipeline cache) and holds every setting: display, graphics quality, controls, hacks.
  • Races run at 60 fps on high-end GPUs and at 30 on mid-range ones; see Performance.
  • Known problems: a few menus (mode, character and vehicle select) still need work, the kart's shadow misses a frame now and then, some audio cuts during movies, and on some AMD drivers the GPU can hang. There is no online play.

Roadmap

The main open work, in order; the details are in docs/roadmap.md.

  • 60 fps in races. Today a race frame is a serial chain: the game finishes its frame (~3 ms*), then the Vulkan back end records the game's big submit (~19 ms*), then the GPU runs it (~10 ms*), and only then does the next frame start. Recording is on the critical path, so the work is recording with less CPU: dynamic state only when it changes, draw caches across frames, parallel recording, and a faster game thread.
  • The picture as on the console: the last shader translator bugs, the kart's shadow, push constants, zero Vulkan validation errors.
  • Every menu checked against the console: mode, character and vehicle select are next.
  • No GPU hangs and less GPU memory, then loading without stutter and a Linux package for non-rolling distributions.
  • 1.8.0 on par with 1.0.0: its ultrawide aspect, shadow map size and fixed seed (#19).

* Measured on 09/11/2026 on our test machine: Radeon 660M APU (Ryzen 5 7535HS), Linux, 720p internal resolution.

Performance

Measured frame times, each with its date, are in docs/performance.md. To add your machine, open a performance report: it goes into the table with the date of the report. The times are the game's own frames: frame generation shows more frames but does not shorten them. 16.7 ms is 60 fps; Frame rate on Automatic (the console's) drops to 30 fps when 60 is out of reach, and a frame over 33.3 ms runs the race slower than real time.

DateGPUInternal resolutionRace fpsRace frame time
11/11/2026RX 7900 XTX (Windows)2160p6016.7 ms
11/11/2026RX 9070 XT (Linux, RADV)720p to 2160p6016.7 ms
10/11/2026RTX 3060 (Windows)1080p~48~21 ms
11/11/2026RTX 3050 Laptop (Windows)720p~3726.7 ms
09/11/2026Radeon 660M (Linux, RADV)720p30-3231-33 ms
11/11/2026GTX 1650 SUPER (Windows)1080p~24~41 ms
09/11/2026GTX 1050 Ti (Windows)1080p22-2442-45 ms

Playing

Stuck or have a question? Search the wiki first: installation, settings, controls, known errors by their log line and a FAQ.

The start screen once the game is set up

The Game files page, where the setup takes the player's dump

  1. Dump Mario Kart World 1.0.0 or 1.8.0 from your Switch 2 (exefs/ and romfs/, decrypted; 1.8.0 with the update merged into the base game's RomFS), or the same dump packed as one .nup or .nx file.
  2. Download the launcher for your system from Releases: on Linux the .AppImage (-aarch64 on ARM; the default game folder is ~/.local/share/mkw-recomp; glibc 2.31 or newer: Debian 11, Ubuntu 20.04, SteamOS and later), on Windows the .zip, unpacked into a folder. Either needs about 30 GB free.
  3. Run the AppImage (chmod +x first) or mkw.exe, open Game files, optionally use Choose game folder to select where the game will be installed (or an existing installation), then point it at your dump (Choose folder or Choose .nup or .nx file) and press Set up. The launcher remembers the installation folder; the compiled game, prepared files, saves, settings and caches live there. Selecting another folder keeps existing files in place. The first setup takes a while (it compiles the whole game and downloads NVIDIA's nvdisasm and ptxas, 84 MB on Linux and 126 MB on Windows, to describe the shader encoding on your machine); after that, Play.
  4. When a newer release is out, the start screen offers it (Update to vX): it downloads it, checks it, replaces the program and sets up again only what changed. Settings → Menu → Check for updates turns the check off.

Requirements: x86-64 CPU with AVX2 (or, on Linux, AArch64 with ARMv8.2: LSE, FP16, RCpc, DotProd, CRC32), a GPU with Vulkan 1.3 (VK_EXT_mesh_shader recommended; without it, task and mesh shaders run as compute), 16 GB of RAM recommended. In a Docker or Podman container on Linux, allow userfaultfd in its seccomp profile (Docker's default refuses it): without it the port cannot tell which game memory changed, and runs several times slower.

Extra features

Beyond the console, all optional and off (or at the console's value) by default:

  • Display: internal resolution above or below the console's, 21:9, 32:9 and 48:9 (races show more at the sides), AMD FSR 1 scaling, HDR on HDR screens, VSync, mailbox or immediate presentation.
  • Frame generation: frames made between the game's (a race at 30 fps shown at 60, or at 240 on a 240 Hz screen). Smoother, not faster: the picture is up to one frame later, and fast motion and the minimap can smear.
  • Frame rate: 20 and 15 fps besides the console's 60 and 30; Automatic drops to them when frames take too long, so a slow graphics card keeps the race at its real speed. Low latency (on by default: it changes no picture, only when each frame starts) starts each frame as late as the card allows, so a press reaches the screen sooner.
  • Graphics: texture filtering and quality, detail distance and shadow quality above or below the console's.
  • Sound: 5.1 surround.
  • Controls: every key and button rebindable, mouse camera, Nintendo, Xbox or PlayStation button icons, motion steering, vibration strength; local multiplayer with one controller each. Switch 2 controllers (Pro Controller, Joy-Con, GameCube) work over Bluetooth and, on Linux, over USB; on Windows USB needs a one-time driver step, below.
  • Hacks: turbo (hold or toggle F2), skip movies, unlock everything, the same randomness every time, straight to time trial or free roam.
  • Languages: the menus in 20 languages; the game itself also in Catalan, Galician and Basque.
  • Game files: choose the installation folder; a dump as folders or as one .nup or .nx file, used where it is; updates from the start screen.
  • Performance overlay (FPS, or CPU, GPU and memory in full) and a one-click system info for bug reports.
Switch 2 controllers over USB on Windows

These controllers only start after a command sent to their second USB interface, which Windows leaves without a driver an app can use. Once per controller, with Zadig:

  1. Plug the controller in with a USB-C cable and open Zadig.
  2. Options → List All Devices, then pick the controller's Interface 1 (USB ID 057E and 2069 for the Pro Controller, 2066/2067 for the right/left Joy-Con, 2073 for the GameCube controller). Not Interface 0: that one is the controller's normal input, and replacing it hides the controller from every other app.
  3. Driver WinUSB, then Replace Driver (or Install Driver).

The same steps apply to a virtual controller that shows up with those USB IDs (Switch2Connect's USB/IP mode). To undo it, uninstall that interface's device in Device Manager with "delete the driver" ticked.

Mods

The start screen's Mods page installs mods as they are published for the game, and lists them in two tabs:

  • Find on GameBanana: Mario Kart World's mods on GameBanana, listed or searched, with each mod's author, license, screenshots and description. Install downloads the file from GameBanana, only when you ask for it.
  • Installed: your mods, each with an on/off switch; Import zip / Import folder takes a mod you already have (.zip, .rar or .7z, with romfs/ and/or exefs/ anywhere inside, including the atmosphere/contents/ layout).

Mods that replace game files (romfs/: skins, textures, texts, courses) take effect at the next start. Mods that change the game's code (exefs/ .ips or .pchtxt patches, such as 200cc or 30 FPS) are built into the game code: turning one on or off rebuilds it before you play (a few minutes). Two mods that change the same archive are merged file by file, and the page asks which one wins where both change the same file. The page warns about mods that replace the game's graphics settings or shaders, which the port handles its own way.

Mods are made by other people and are not tested by this project: one can crash the game or damage your save. Read a mod's page before installing it, keep a copy of your save, and report a mod's problems to its author; when you report a bug here, say which mods were on (the log lists them), or try again without them first.

Building from source

Linux, with uv, clang, lld, ninja, SDL3, Opus, libvpx, zstd, xxHash, the Vulkan headers and VMA 3.4.0 (details in tools/build/README.md). Put your dump in game/ (game/exefs, game/romfs) or set MKW_GAME=<dir>, then from the repo root:

uv run python recomp/gen.py --exefs game/exefs --out build/generated --jobs 8 --patches recomp/patches-mkw.txt  # 1.8.0: patches-mkw-180.txt
uv run tools/shaders/extract.py && uv run tools/shaders/translate.py
uv run tools/build/build.py              # build/mkw; --target windows builds mkw.exe with llvm-mingw
build/mkw

Shortcuts for these flows and the release ones: make build, make appimage (make help lists them all).

From a packed dump (.nup, .nx) and for Linux on AArch64: tools/build/README.md and its AArch64 section.

Translating the shaders needs the SM86 encoding specification, generated from NVIDIA's nvdisasm (not shipped): see tools/shaders/README.md. Everything generated goes to build/, never to git.

FolderContents
recomp/The generator: AArch64 → C
runtime/What plays the console: kernel, memory, SDK replacements, NVN2 over Vulkan, audio, input, menus and launcher
sm86/The shader translator: SM86 SASS → GLSL → SPIR-V
i18n/The menu, start screen and setup texts in every language (gettext .po)
tools/Analysis, setup, build, game runs and diagnostics
tests/Tests without the game or a GPU, in the CI on Linux and Windows
docs/Research, sources and performance
.github/CI, issue and pull request templates

At the root: pyproject.toml and uv.lock (the Python environment of the tools), .gitignore, LICENSE, CONTRIBUTING.md, CHANGELOG.md (each release's changes, its notes), AGENTS.md (a guide for coding agents) and Makefile (shortcuts for the build flows: make help).

Design decisions (30/10/2026)

TopicDecisionWhy
CPUAArch64→C lifter based on totk-pc-recomp's (MIT), extended to ARMv8.1-8.3: LSE atomics, CAS, LDAPR; PAC as identity, MTE tags as 0Same engine family as MKW, and it already scales to a large executable
SystemThe SDK's nn::* functions replaced by name; signatures from the mangled names of main's 1 289 importsNo console services to emulate
GraphicsNVN2 over Vulkan: 529 of its 699 functions share their name with NVN1 (signatures known from totk-pc-recomp and nxnative); 170 are newRecompilation, not GPU emulation
ShadersOur own SM86→SPIR-V translator, offline, with a decoder generated from the DocumentSASS / nvsass-disassembler specificationCovers mesh/task and what Maxwell lacks
Optional Switch 2 featuresHDR on by itself when the display is in HDR, as on the console (Settings > Screen > HDR: Automatic or Off); DLSS, ray tracing and touch behind options, off by default; off, their NVN2 functions exist but do nothing so the game keeps its normal pathConsole hardware extras, not needed to play
DefaultsThe console's look and resolution; lower settings are optionsThe player chooses

How it was made

This port was written with Claude (Anthropic's coding agent) doing most of the typing, under my direction, in about ten days of full-time work: 489 commits from 30/10/2026, every one of them reviewed, measured or tested before it went in. It was not one prompt and done. Behind it:

  • Method more than prompts. Every change of performance was measured with an A/B inside the same run (two runs of the same build differ by up to 12 ms per frame); every rendering fix was checked against the console's own image; shader translator changes are tested off the GPU on every one of MKW's 11 561 programs before a game run; frame captures replay the back end in seconds without the game. The rules that came out of mistakes are written down and enforced by scripts, so the same mistake does not happen twice.
  • What I had learnt before. The recompiler and the runtime grew out of totk-pc-recomp and its Linux port, and out of my earlier work on other recomps (SavageWindRecomp, smo-recomp): the lifter, the launcher and the setup that builds the game on the player's machine, the button icons, the shader control flow. As a maintainer of AnyPS5 I learnt how to translate GPU shaders faithfully, run mesh shaders as compute on GPUs that lack them, and keep a large project honest with checks and measurements.
  • The community's research. eden-nx2's notes on Switch 2, NVIDIA's SASS encoding as documented by DocumentSASS and nvsass-disassembler, Ryujinx and Mesa NAK for shader semantics, and the other Switch 2 ports listed in the sources.

Licenses and credits

This project is under the MIT License. Code taken from other projects keeps its own license, next to it (LICENSE.* files in recomp/, runtime/, sm86/decode/ and runtime/third_party/): totk-pc-recomp, nvsass-disassembler, Dear ImGui, bc7enc, stb_image, AMD FidelityFX FSR 1 and Roboto. Every source used, with its license and what was taken from it (code from MIT projects only; from GPL projects, ideas only), is listed in docs/research.md.

Mario Kart World is © Nintendo. This project is not affiliated with or endorsed by Nintendo, contains no game code or assets, and does not help to obtain them.

Mods belong to their authors and come under their own licenses. This project is not affiliated with or endorsed by GameBanana or any mod's author, does not host, review or distribute mods, and is not responsible for what a mod does: the start screen only shows GameBanana's public listing and downloads a mod from GameBanana when you ask it to.

Contributing

See CONTRIBUTING.md. Bugs and performance reports go to Issues, questions to Discussions.