- NintendoWare Bezel Engine 1.56: nearly all of RomFS is in Bezel Engine archives (.bea, magic SCNE, every entry a zstd frame). shader_split.py reads them (bea_members): 2,125 shaders, most of them the engine's own in System.nx.bea. The 12 geometry shaders of Bezel's line renderer do not build (the main menu chart's outlines are missing); ten pixel shaders that choose their texture handle between two of the game's uniform buffers at run time do not load. The survey names Bezel Engine archives (profile_guess.py, the NSP script's notes) - nninitStartup picks virtual address memory (a 60 GB StandardAllocator region) or a heap by IsVirtualAddressMemoryEnabled, which the host answered yes for every game. The new profile key sys_resource reports the NPDM's system resource (0 here); the survey writes it for new games, profiles without it keep the 32 MB answer - SDK 11 calls that reach a service: GetHardwareOpusDecoderWorkBufferSize(int, int), the IR camera (every camera unconnected), LoadCachedNintendoAccountInfo, Enable / DisableIndividualFileDataCache, ldn::GetNetworkConfig and the socket overloads with plain sockaddr - Movie decoder: the activity previews loop with Flush and Start from four threads. An input index the game held across a flush went back to the free list and was handed out twice; the fifth pending packet overwrote the decoder's mutex and the process died in 2 runs of 5. A send now claims such an index, held indices are withheld for 250 ms after a flush, pend[] cannot overflow, a flush keeps each slot's last picture and an output with no picture leaves the client texture as it was (the black flash at every loop). DM_MOVIE_TRACE=1 logs every decoder call - The crash handler takes SIGABRT; a command buffer with no GPU start time no longer counts the whole clock as GPU time - Handheld with Boost (op_mode, perf_mode): handheld, the game reads the touch screen; Boost gives 1920x1080 - 60 fps, sound, previews and saves; the title, enrollment, the menus and activities of every category. About 1.5 GB resident at the first activity, 1.86 GB after 15 minutes of activities (the game's pools as each activity loads). Prewarm list recorded through enrollment and a full activity. Not yet tested on an iPhone
nxnative
Play your own Nintendo Switch games natively on 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.
Acknowledgements
This project is built on other people's work:
- d2r-mobile (MIT) developed this native-execution approach, for Diablo II: Resurrected. nxnative (first called smbw-mobile) 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.
- 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.
Games
All of these are tested on an iPhone and playable:
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.
Pack an IPA
1. Get nxnative and its tools (once, on a Mac with Xcode and Homebrew):
git clone https://github.com/seedds/nxnative.git && cd nxnative
brew install xcodegen zstd spirv-cross
brew install --cask dotnet-sdk
python3 -m pip install lz4 capstone fonttools "backports.zstd; python_version < '3.14'"
2. Put one game's NSPs in a folder, base game (an NSP, or an XCI cartridge dump) and update (and any DLC):
~/Games/MarioWonder/
Super Mario Bros. Wonder [010015100B514000][v0].nsp
Super Mario Bros. Wonder [010015100B514800][v327680].nsp
3. Run the script:
python3 scripts/build_ipa_from_nsp.py ~/Games/MarioWonder -k ~/keys/prod.keys
The IPA appears in the same folder (here ~/Games/MarioWonder/SMBWMobile.ipa). The first build takes 30–60 minutes, later ones about 10. You need free disk space of about twice the NSPs' size plus 10 GB. Options such as -o (output path) and --app-name are listed by -h.
4. Install the IPA with your sideloading tool (AltStore, Sideloadly, LiveContainer, …). The app gets the game's name, icon and version (the update's version, for example 1.2.1 for Mario Wonder; the base game's when there is no update).
Play
Touch controls. Tap 2D / 3D at the top to switch layouts; the app remembers your choice. Wonder, Engage, Dread, 13 Sentinels, Link's Awakening, Ace Attorney Investigations Collection, Unicorn Overlord, Rhythm Heaven Groove, Octopath Traveler 0, Pokémon Legends: Z-A, Cuphead, Absolum, Brain Memory Training Academy, The Great Ace Attorney Chronicles and STEINS;GATE RE:BOOT start in 2D, the other games in 3D (STEINS;GATE RE:BOOT's quick save is R3, in the 3D layout). In 3D, the right stick (the camera in most games) is not drawn: swipe on the right third of the screen, starting anywhere off the buttons. In Super Mario Galaxy and Super Mario Galaxy 2, other touches outside the controls move the pointer; in Captain Toad: Treasure Tracker they touch the game's screen (touch blocks, stun enemies). A connected game controller hides the touch controls and keeps every button.
Shaking. Shake the iPhone to shake the controller, in games that read its motion: Super Mario Odyssey's motion moves (such as the cap throw on a shake) need it, and Odyssey only takes them in its default docked mode. A light bump does not count; a sharp flick of the phone does.
- Game language is English by default. Pick another when packing with
--language(-l), by code or by name:-l ja,-l zh-Hans,-l French(LANGUAGEin Spyder). It must be one the game has; the script prints the game's languages and stops on one it lacks. To change it without rebuilding, add a line such asDM_LANG=zh-HanstoDocuments/env.txt. - Saves and logs are in the Files app, under the app's name:
save/andlog.txt. When something goes wrong, sendlog.txt(the previous run islog.prev.txt). - Short stutters the first time a new scene appears are normal: the app compiles graphics for it once and remembers them for the next launch.
- Reinstalling: some sideloading tools give a reinstalled app a new data folder. Copy
save/andpso_user.tsvover from the old one to keep your progress. - Settings without rebuilding: put lines like
DM_OPMODE=0(handheld mode: lower resolution, higher frame rate) inDocuments/env.txt.DM_FPS_TARGET=30keeps Breath of the Wild, Tears of the Kingdom and Octopath Traveler 0 at their original 30 fps, which saves battery.DM_SHOW_FPS=1shows the frame rate at the top left (--show-fpswhen packing turns it on from the start).
Known issues
- No amiibo and no online features.
- Fire Emblem Engage: after switching away from the app and back, some sounds may stay silent until you restart it.
- Fire Emblem: Three Houses: small square patches on the ground where decals land.
- Super Mario Galaxy and Super Mario Galaxy 2: effects drawn as points or lines come out one pixel wide.
For developers
How it works, the script's options, running games on the Mac, adding a game, and per-game notes: docs/development.md. In-depth bring-up and debugging notes: docs/agents.
License
MIT (see LICENSE). Third-party code keeps its own license; see dm/third_party.


























