NXForge is a Mac-focused downstream of nxnative by seedds and its contributors. It is two things on top of nxnative's engine: the NXForge Converter, a Mac app that finds your games and builds and rebuilds them, and a Mac player layer: the in-game Quick settings sidebar with pixel-art scaling for 2D games, a CRT filter, FXAA, anisotropic filtering, cheats, mods, screenshots and recordings, and control remapping. The engine itself is nxnative's, untouched: this repository pins one nxnative commit and keeps NXForge's changes beside it as a small set of patches and files, so nxnative's updates come in whole (UPSTREAM.md). Everything below works as it does in nxnative; Upstream says how the two projects relate.
Play your own Nintendo Switch games natively on Mac, iPhone and iPad. Bring your game (its NSP files) and your prod.keys; one script turns them into an IPA that you sideload.
It is not an emulator: the game's own code runs directly on the Apple chip, with Switch graphics rebuilt on Metal. Nothing from any game is in this repository, and the project is not affiliated with Nintendo or any game publisher.
Switch 2 games have started too: Donkey Kong Bananza, Splatoon Raiders, Fire Emblem Fortune's Weave, Pokémon Pokopia, Hyrule Warriors: Age of Imprisonment, Mario Kart World and Mario Tennis Fever play on the Mac, packed from one .nup file or a dump of the game; iPhone and iPad are untested.
NXForge exists because of nxnative, created by seedds and built up by its community of contributors: the engine, the rewriter, the host, the NVN, Vulkan and OpenGL layers on Metal, the game profiles and the packing scripts all come from there. NXForge builds on an exact nxnative commit (layer/ENGINE), so every contributor's work comes in as they wrote it, and its MIT license and copyright notice stay in LICENSE; NOTICE records the attribution.
NXForge stays a downstream, not a replacement. It moves to nxnative's latest main branch regularly (scripts/layer.py update), and fixes that help every platform go back to nxnative as small pull requests; UPSTREAM.md has the policy. Please report problems that also happen with plain nxnative there, and problems with NXForge's own features here.
Switch 2 games are built from one .nup file or a folder of their files, not from NSPs, and are tested on the Mac only: see Switch 2 games.
NXForge Converter turns your games into Mac apps from a window, with no command line: it checks the tools, checks the game files against your keys, builds and signs the app, keeps a list of your builds and rebuilds them when the engine changes. Other community projects build on nxnative with apps of their own (NX2Apple, NX Play, the NxNative Launcher, LumaNX); they are separate projects, and questions about them go to their own pages.
You need a Mac with macOS 26.6 or later, Xcode 27.2, Homebrew and Python 3.12 or newer (an arm64 one, not an Intel Homebrew's). An iPhone build also needs Xcode's iOS platform (Xcode → Settings → Components).
The shaders are built with Xcode 27.2's Metal compiler. Select it before step 1: sudo xcode-select -s /Applications/Xcode.app. With several Xcode versions installed, name this one Xcode-27.2.app and select it with sudo xcode-select -s /Applications/Xcode-27.2.app.
1. Install the tools (only once), in Terminal:
xcodebuild -downloadComponent MetalToolchain
git clone https://github.com/gnosticgeek/nxforge.git && cd nxforge
python3 scripts/layer.py assemble && cd tree # the engine: nxnative plus NXForge's layer (UPSTREAM.md)
brew install xcodegen zstd glslang
brew install --cask dotnet-sdk
python3 -m pip install lz4 "capstone>=5,<6" fonttools nsz zbic "backports.zstd; python_version < '3.14'"
2. Put your game in a folder: the game, plus its update and DLC if you have them (.nsp, .xci, .nsz or .xcz):
~/Games/MarioWonder/
Super Mario Bros. Wonder [010015100B514000][v0].nsp
Super Mario Bros. Wonder [010015100B514800][v327680].nsp
DLC can also sit in a subfolder named DLC (any letter case, or DLCs): the build reads that folder for DLC only, so keep the base game and its update beside each other in the game's folder.
Any version works, with or without an update: the script packs the newest version in the folder. Each game was tested on one version; with another the script builds it with that version's own shaders and says so, and fixes made for the tested version's code, such as the 60 fps ones, don't apply to it.
3. Build, with your game folder and your prod.keys:
python3 scripts/build_ipa_from_nsp.py ~/Games/MarioWonder -k ~/keys/prod.keys
The IPA appears in the game's folder. The first build takes 30–60 minutes and needs free disk space of about twice the game's size plus 10 GB; building again is much faster.
To play on the Mac instead, add --platform mac-app: you get a Mac app of the game to open from Finder, with a settings window before the game (frame rate, render scale, docked or handheld, language, MetalFX upscaling, rumble) and its save in a Saves folder beside it. In the game, Esc opens Quick settings: pixel-art scaling, a CRT filter, anisotropic filtering, the frame-rate counter, volume, controls, mods, cheats, screenshots and recordings (A Mac app). All options: The packing script in detail.
Install the IPA on your iPhone or iPad with a sideloading tool such as AltStore, Sideloadly or LiveContainer. If your tool offers Increased Memory Limit, turn it on: the bigger games need it.
Game too big to install? Build again with --romfs separate, and run the command the script prints once to copy the game files to your phone (Quick reinstalls).
Controls, saves and settings: Playing. Known issues are in each game's note; there are no amiibo and no online features.
A Switch 2 game is built from one NUP container (a .nup file) or a folder of its files, not from NSPs. Neither needs prod.keys. A game this project has no profile for is surveyed and gets a provisional profile, as NSPs do (Port another game), which may not boot. You get a Mac app; iPhone and iPad are untested.
From a .nup file, which holds the base game, its updates and DLC in one file. Give the file, or a folder that holds it:
python3 scripts/build_ipa_from_nsp.py ~/Games/DonkeyKongBananza.nup --platform mac-app
Hyrule Warriors: Age of Imprisonment is played this way: its 47 GB NUP unpacks in under five minutes. A NUP that carries the game's control data (its NACP) and icon gives the app the game's name and icon; otherwise the name comes from the game's profile and the app has no icon.
A NUP without the base game also works, when its base package is empty or it has none and its updates are marked standalone_update: the update is taken as the whole game, and the script says so. If the game then stops on missing files, that update holds only what changed: pack a NUP with the base game. The newest update is selected by default; --package v<N> selects another version in the container. Such a container has no v0 (base game) to select.
From a folder of files. The script expects this layout (updates and dlc are optional):
~/Games/DonkeyKongBananza/
base/exefs/ main, main.npdm, sdk, rtld
base/romfs/
updates/458752/exefs/ the update's version, as a decimal number
updates/458752/romfs/ the patched RomFS, not a patch
dlc/040074a01bf13001/0/romfs/ the DLC's title ID
python3 scripts/build_ipa_from_nsp.py ~/Games/DonkeyKongBananza --platform mac-app
An update's folder alone will do (no base/), and so will exefs/ and romfs/ directly in the folder, as nup extract writes them, which count as base/. The app has no icon, because the folder holds none. To turn such a folder into a NUP: nup pack ~/Games/DonkeyKongBananza game.nup.
Games tested on Mac or iPhone. See the per-game notes for tested platforms, progress and known issues:
Needs iOS / iPadOS 26 or later on an iPhone 15 Pro or newer (A17 Pro chip or later) or an iPad with an M1 chip or later: the games' textures are BC-compressed, and older iPhones can't read that format. Other games aren't supported yet. For them the script writes a survey and still tries its best to pack an IPA, guessing the game's settings; such an IPA may not start.
Under a game, "60 fps with 1.2.0" means it runs at 60 fps (30 on the console) with that update. "Up to 120 fps" names no update because the host finds the frame rate in the game's code, whichever version it is; choose it under Frame rate, on a screen that shows 120 Hz.
How it works · Game notes · Bring-up and debugging · Front ends · Contributing · Working with upstream
This project is built on other people's work:
- nxnative (MIT) by seedds and its contributors, which NXForge is a downstream of (see above).
- d2r-mobile (MIT) developed this native-execution approach, for Diablo II: Resurrected. nxnative started as a copy of its generic parts: the NSO rewriter, the host that stands in for Horizon, the NVN-on-Metal layer and the iOS app shell. Fixes go both ways.
- Ryujinx (MIT): its shader translator (
Ryujinx.Graphics.Shader,Ryujinx.CommonandSpv.Generator1.3.2, indm/third_party/ryujinxwith a few fixes listed in its README) turns the games' Maxwell shaders into SPIR-V. Its emulation of the kernel and system services is also a reference when the host's behaviour is in doubt. - Atmosphère: its kernel, mesosphère, is the reference for Horizon's synchronization semantics (address arbiter, condition variables).
- yuzu: Maxwell instruction encodings for the shader reference tool, and a cross-check for kernel behaviour.
- LibHac: reads NSPs and layers updates over the base game in
dm/tools/nx_extract. hactool did the first extractions. - SPIRV-Cross: SPIR-V to Metal Shading Language. glslang compiles the GLSL of OpenGL games to SPIR-V for it.
- MacNativeGames (MIT): the GPU widening of 8-bit indices and in-pass clears in
dm/gfx/nvn/nvn_mtl.m, and the visibility-counter lowering in the shader translator. - deko3d (zlib): its texture layout size algorithm is ported in
dm/gfx/nvn/nvn_tex.c. - libvpx (VP9 movies), stb_vorbis (movie sound), the Vulkan headers and NVIDIA FLIP ship in
dm/third_partywith their licenses (list). - Capstone, lz4, fontTools and XcodeGen are used by the build.
- Other nxnative front ends (all MIT) gave NXForge ideas, reimplemented here: NX Play (Keep This Build), the NxNative Launcher (quitting from the controller, Atmosphere-layout mods) and NX2Apple (issue forms; in 0.10.0 the newer Metal compiler check and the pointer hiding, taken from its patches 0034 by LNPANDY and 0032 by v0lumehi, and ports of its build-input check for older builds, frame-time recording and dropped files). LumaNX gave the converter's failure explanations and its checked save snapshots.
- ns2ios-shell (MIT) by xinerqu: the closed standard input for
vk_shaders.py's child processes (0.13.0).
MIT (see LICENSE), the license nxnative is published under; the copyright notice for seedds stays with it, and NOTICE lists where NXForge's code comes from. Third-party code keeps its own license; see dm/third_party.














































































































































