# SkyboundTOTK SkyboundTOTK is an experimental native static recompilation project for *The Legend of Zelda: Tears of the Kingdom*, **base game version 1.0.0**. It targets Windows x64 and Linux x86_64. It is not affiliated with Nintendo. Expect graphical problems and incomplete compatibility; a successful build does not guarantee a complete playthrough. The project's AArch64 game code is translated ahead of time into C and compiled locally into a native executable. A runtime implements the services the game expects, and the renderer translates its graphics work and shaders for WebGPU. This is a game-specific port, not a general-purpose Switch emulator. Some graphics translation still happens at runtime. ## Game files and distribution You must supply your own legally obtained, already-extracted, **unmodified 1.0.0 base-game ExeFS and RomFS**. No game files, generated game code, keys, firmware or saves are included in this source project. The build does not extract NSP or XCI files. Version 1.2.1 also builds from its own ExeFS and the RomFS with the update applied (PR #19, contributed and tested by keno80: the build picks the hooks by the main module's build id); everything else in this README was tested on 1.0.0, and other updates are not supported by the game-specific hooks. Keep your game files, generated code, executable package and saves private. The `game/`, `build/` and `dist/` directories are Git-ignored, but check what you are publishing rather than relying on ignore rules alone. The generated standalone package contains copyrighted game-derived data and must not be shared or committed. ## Build on Windows ### Requirements - Windows 10/11 x64 and a GPU and driver supported by wgpu-native. Allow **at least 45 GB free in addition to the original game dump** for intermediate files and the separate packaged RomFS; the build is CPU- and memory-intensive. It runs as many compiles at once as fit in 80% of your RAM at 3.5 GB each (three on a 16 GB PC); set `RX_JOBS=` to choose. - Python 3.10 or newer on PATH, with `lz4` installed: `python -m pip install lz4`. - Visual Studio 2022 Build Tools with the MSVC C++ tools and Windows SDK. Use an **x64 Native Tools Command Prompt** so the compiler can find the Windows headers and libraries. - Clang, clang++ and lld. The build previously used emsdk 6.0.9: install it separately and set `EMSDK` to its directory (the lookup defaults to `C:\emsdk`), or put these LLVM tools on PATH. The build script does not download compilers or Python packages. ### Prepare and build 1. Put the extracted files in the project's `game` folder. The paths must look like this, not `game/exefs/exefs/main` or `game/romfs/romfs/Event`: ```text SkyboundTOTK/ build.bat game/ exefs/ main main.npdm rtld sdk ... romfs/ ActorSystem/ Event/ ... ``` 2. Open an **x64 Native Tools Command Prompt**, change to the SkyboundTOTK directory and run `build.bat`. The launcher pauses at the end so you can read any errors. 3. The script checks the `main` and `sdk` module build IDs and a few RomFS directories, lifts the game code, compiles the native executable and copies the runtime and RomFS into `dist/SkyboundTOTK/`. The checks do **not** verify the entire RomFS or guarantee that a dump is complete. 4. Open `dist/SkyboundTOTK/SkyboundTOTK.exe` to run it. No command-line arguments are needed. Keep `image.bin`, `image.json`, `romfs/`, `wgpu_native.dll` and `SDL2.dll` alongside the executable. The standalone folder can be moved as a unit and does not need the original `game/` folder to launch. The first lift and compile can take a long time. The builder reuses a completed lift only when its recorded game and lifter inputs match. If the lift was interrupted or those inputs change, move the existing `build/` directory aside before retrying. The script refuses to overwrite a nonempty `dist/SkyboundTOTK/`: move the existing package aside before a new build. Copy its `user/` folder into the new package if you want to retain its saves and settings. Do not delete your only save backup. The package normally creates its own `user/` directory beside the executable; it does not automatically use the saves from another installation. Native renderer pipeline cache data is kept in `rxcache/` beside the executable. The executable also accepts an image path and `--romfs` / `--user` overrides for advanced use, but they are not needed for normal launching. ### Build and launch troubleshooting - **Python or `lz4` missing:** install them for the Python on PATH, then reopen the tools prompt. Run `python -m pip install lz4` with that same Python. - **Compiler, headers or libraries missing:** open the x64 Native Tools prompt and check that the C++ tools, Windows SDK, Clang, clang++ and lld are installed and discoverable. Set `EMSDK` if the LLVM tools are in a non-default emsdk directory. - **Wrong module or missing RomFS:** check the extracted folder layout and version. A base-game ID match is not a complete integrity check. - **Existing output or stale/incomplete lift:** move the indicated package or build directory aside, preserving `user/` first, then retry. An interrupted copy can also leave a nonempty package that needs to be moved aside. - **"Not enough memory left" after long play:** older builds kept every render pipeline used in the last 10 minutes, which reached about 14,000 pipelines and 17 GB of memory in one report (issue #10). Past 9000 pipelines, the ones unused for a minute are now released (`RX_PIPELINE_HARD_CAP=` and `RX_PIPELINE_HARD_TTL_S=` change that). - **First launch or new scene stutters:** shader translation and pipeline compilation may happen as scenes are encountered. The native pipeline cache helps prepare previously encountered pipelines on later launches; it cannot guarantee stutter-free play. - **GPU device lost or wrong GPU:** AMD cards lost the WebGPU device at startup while the GPU ASTC decoder was created (issue #1; fixed). The log now includes wgpu's own warnings and errors (`RX_WGPU_LOG=info|debug|trace` for more, `off` for none). `RX_ADAPTER=` (for example `RX_ADAPTER=Radeon`) picks a GPU on a PC with two, and `RX_ASTC_CPU=1` decodes ASTC textures on the CPU instead of the GPU. - **Crash or graphics issue:** note the game version, hardware, driver, location and settings. The standalone startup test initialized the renderer and loaded the packaged RomFS, but did not verify full gameplay or graphics correctness. ## Build on Linux Same game files and same `build_game.py` launcher as Windows. Run `python build_game.py` from the project directory. There is no `build.bat` step. The executable is an ELF. It links SDL3 and FFmpeg from the system and Vulkan through a patched `libwgpu_native.so` that you build. That shared library is not in the repository. The Windows package still uses the bundled `wgpu_native.dll` and `SDL2.dll`. ### Requirements - x86_64 Linux and a Vulkan GPU and driver. Allow **at least 45 GB free in addition to the original game dump**. The build is CPU- and memory-intensive. - Python 3.10 or newer on PATH, with `lz4` installed: `python -m pip install lz4`, or the distro package. - Clang, clang++, lld, and pkg-config. The build script does not download compilers or Python packages. - SDL3 and FFmpeg development files. The build checks these pkg-config modules: `sdl3`, `libavformat`, `libavcodec`, `libavutil`, `libswscale`. - Rust 1.93 or newer, and libclang for bindgen, used only to build `libwgpu_native.so`. Arch Linux packages that satisfy the system dependencies: ```text sudo pacman -S clang lld pkgconf python python-lz4 sdl3 ffmpeg ``` On Debian and Ubuntu the pkg-config modules are the requirement. A typical set is `clang`, `lld`, `pkg-config`, `python3`, `python3-lz4`, `libsdl3-dev`, `libavformat-dev`, `libavcodec-dev`, `libavutil-dev`, and `libswscale-dev`. The SDL3 package name depends on the release. ### Patched wgpu-native Copy the built library to `third_party/wgpu-native/lib/libwgpu_native.so` before `build_game.py`. The headers already in `third_party/wgpu-native/include/` are the matching version. The Windows DLL in that folder is the unmodified v29.0.1.1 release. The Linux library has to include both patches under `third_party/wgpu-native/totk-patches/`. The native patch expects a sibling checkout named `wgpu-patched`. From an empty directory, with `SKYBOUND` set to this repository: ```bash git clone --recurse-submodules --branch v29.0.1.1 https://github.com/gfx-rs/wgpu-native.git git clone --branch v29.0.3 https://github.com/gfx-rs/wgpu.git wgpu-patched git -C wgpu-native apply "$SKYBOUND/third_party/wgpu-native/totk-patches/wgpu-native-29.0.1.1.patch" patch -d wgpu-patched -p1 < "$SKYBOUND/third_party/wgpu-native/totk-patches/wgpu-29.0.3.patch" cargo build --release --manifest-path wgpu-native/Cargo.toml cp wgpu-native/target/release/libwgpu_native.so "$SKYBOUND/third_party/wgpu-native/lib/" ``` If bindgen cannot find libclang, set `LIBCLANG_PATH` to the directory that contains `libclang.so` (often `/usr/lib`) and rerun the cargo build. A smaller library is `cargo build --release --no-default-features --features wgsl,spirv,vulkan` run from `wgpu-native`. The playtest below used a default `--release` build. The `totk-mimalloc` cargo feature is optional. ### Prepare and build 1. Put the extracted 1.0.0 ExeFS and RomFS in `game/`, in the same layout as the Windows instructions. 2. From the project directory, run `python build_game.py`. 3. Run `dist/SkyboundTOTK/SkyboundTOTK`. Keep `image.bin`, `image.json`, `romfs/`, and `libwgpu_native.so` beside the executable. It finds that library through an `$ORIGIN` rpath. SDL3 and FFmpeg stay system libraries. The standalone folder can be moved as a unit and does not need the original `game/` folder or Wine. Lift reuse, the nonempty `dist/SkyboundTOTK/` refusal, and `user/` saves work the same way as on Windows. Native pipeline cache data is `rxcache/pipelines.bin` beside the executable. ### Linux troubleshooting - **SDL3 or FFmpeg missing:** install the dev packages, then check `pkg-config --exists sdl3 libavformat libavcodec libavutil libswscale`. - **Missing `libwgpu_native.so`:** build it as above and copy it into `third_party/wgpu-native/lib/` before running `build_game.py`. The packaged copy has to stay next to the executable. - **`mmap guest window` failed:** the log includes `errno`. The runtime reserves a 4 GB window at a fixed address. A restrictive `vm.overcommit_memory` setting can reject that reservation. - **First launch or new scene stutters:** same shader and pipeline compilation as on Windows. The pipeline cache helps on later launches. - **Existing output or stale lift:** same rule as Windows. Move `dist/SkyboundTOTK/` or `build/` aside, and keep `user/` if you want the saves. ## Controls and display features Focus the game window before using the keys. The renderer briefly reports display settings in the window title; changes are saved in `user/present.txt` for the next launch. | Key | Action | | --- | --- | | F6 | Toggle experimental ultrawide / 16:10. The window must not be 16:9; see below. | | F7 | Toggle experimental frame interpolation. | | F8 | Toggle FSR 1 upscaling. | | F9 | Cycle FSR sharpening. | | F10 | Toggle aspect-preserving presentation versus stretching the image to fill the window. | | F11 | Toggle fullscreen/windowed mode. | **FSR:** The current implementation is FidelityFX Super Resolution **1**, with EASU upscaling and RCAS sharpening in the presentation pass. It is enabled by default and is used when the presented frame is enlarged; otherwise the renderer uses the normal sampling path. FSR 1 is spatial upscaling, not FSR 2/3 temporal upscaling or AMD frame generation, and does not increase the game's internal render resolution. F9 cycles sharpening from sharper to softer values. **Frame interpolation:** This is the project's own experimental image-based optical-flow interpolation, not AMD FSR frame generation. F7 is off by default and inserts estimated frames between real frames, normally targeting twice the displayed frame rate when the hardware can keep up. It does not make the game simulate more frames or reduce input latency; the display runs about one game frame behind. UI and fast motion can smear or distort, and long frame gaps are not interpolated. **Ultrawide:** F6 attempts to adjust the camera and HUD and fill a wider window. It is off by default. A wider-than-16:9 window is needed, but a user reported that F6 stretches the image instead of providing a correctly proportioned wider view. Camera hooks are present, but their behavior in that report has not been resolved or independently verified. F10 stretching alone is not true ultrawide. F6 also works for windows narrower than 16:9, such as 16:10 (1920x1200, 2560x1600) or 4:3: the camera takes the window's shape and the HUD keeps its proportions in a 16:9 band across the middle, while full-screen menus such as the map fill the window (checked at 1920x1200: gameplay HUD, inventory and map). Keyboard and mouse controls follow totk-pc-recomp's layout. WASD moves; the mouse, the arrow keys or IJKL move the camera. Left click attacks (Y), right click shields and locks on (ZL), Space jumps (X), E is action (A), Shift runs and cancels (B), Q opens the abilities (L), R is R, Z is ZL, X or F is ZR (bow), Ctrl crouches, C is first-person view (right stick click), Tab or Enter is Plus, M is the map (Minus) and 1 2 3 4 are the D-pad (left, up, right, down). Click the window to capture the mouse (that click does not reach the game), Esc to release it, and use `-` / `=` to adjust sensitivity. The mouse camera turns smoothly at any frame rate and stops within about 0.1 s of the mouse stopping; `HOS_MOUSE_DECAY` and `HOS_MOUSE_MIN_DECAY` (percent, default 30 and 20) make it stop faster or glide longer, and `HOS_MOUSE_INVERT_Y=1` inverts it. XInput and SDL-supported controllers are also handled; buttons map by physical position, Nintendo controllers included (the right face button is A). On Linux, gamepads are read through SDL3 with those same physical positions. XInput is not used. Keyboard, mouse, and F6 through F11 match the table above. The game speaks English (US) by default. To play in another of its languages, put a `language.txt` next to the executable (`SkyboundTOTK.exe` on Windows, `SkyboundTOTK` on Linux) whose first line is one of `ja`, `en-US`, `en-GB`, `fr`, `fr-CA`, `de`, `it`, `es`, `es-419`, `nl`, `ru`, `ko`, `zh-CN` (or `zh-Hans`), `zh-TW` (or `zh-Hant`); the environment variable `HOS_LANGUAGE` does the same. Anything else falls back to English (US). ### Mods Emulator-style mod folders work: put each mod in `mods\\` beside the executable, with its `romfs\` (files that replace or add to the game's RomFS) and/or `exefs\` (`.pchtxt` or `.ips` patches). Copies laid out as `mods\contents0F2C0115B6000\\` work too. A folder name starting with `-` or `_` turns that mod off, and when two mods replace the same file, the one whose path sorts last wins. The log lists each mod and each file it serves. - RomFS mods work as they are. The resource size table is not merged, so a mod that makes files larger needs to ship its own (most do). - Data patches (`.rodata`, `.data`) apply at startup. Code patches can't, because the game code is compiled ahead of time: lift with `python a64-kit/build.py lift totk --exefs --build build --mods ` and rebuild to compile them in. - Extra code modules (`subsdk*`, for example exlaunch-based mods such as UltraCam) are not loaded. ### Why WebGPU? The renderer targets the WebGPU API and WGSL so the same general renderer and shader backend can be used by native wgpu and by browser WebGPU experiments rather than maintaining wholly separate graphics implementations. On Windows, wgpu-native translates this API to an available native backend, such as Vulkan or Direct3D 12. On Linux it uses wgpu-native's Vulkan backend, with an SDL3 window on Wayland or X11. Choosing WebGPU does not mean the desktop game runs inside a browser. It also has portability and validation tradeoffs, and translation, pipeline compilation and API overhead still require optimization. `build.bat` builds the **Windows native** package. `python build_game.py` builds the **Linux native** package on Linux. Browser functionality and packaging are not promised or validated by either launcher. ## Known issues and limitations These are reports and investigation notes, not a complete compatibility list. Some were observed in earlier TOTKPort builds rather than independently reproduced in standalone Skybound. | Issue | Status | Details | | --- | --- | --- | | Shadows / shaders | **Reported** | Shadow shader problems have been reported. The standalone startup log also showed three shader-decoder assertions; their visual effect and relationship to the shadow issue are unknown. | | Stretched terrain | **Reported** | Terrain can appear randomly stretched; cause and reproducibility need investigation. | | Incorrect terrain textures | **Reported** | Some areas have wrong terrain textures; locations and causes need investigation. | | Weapon and shield wheel background | **Fixed** | The d-pad quick menus opened over a black background; they now take the ability wheel's 1/30 s step while held (PR #11). | | Ultrahand cannot grab | **Fixed** | Aimed objects stayed orange and A missed (issue #9). The game reads the object under the reticle from a GPU pass whose vertex shader stores the result, which WebGPU vertex shaders cannot do; that shader now also runs as a compute shader, and the 16-bit object-id target is kept exact. Objects turn green and A lifts them. | | Ultrawide | **Unresolved** | F6 has been reported to stretch the image instead of providing a correctly proportioned wider view. The exact failure is unknown. | | Zonai Portable Pot particles | **Workaround; retest** | A workaround greatly reduced disappearing-effect spikes in an earlier build, but short stray lines remained and the underlying cause is unknown. Retest in Skybound. | | Depths gloom | **Earlier fix; retest** | Missing or incorrect ground gloom was reported on the path to Ganon. Earlier notes record a fix for a reproduced case; standalone Skybound and other locations need verification. | | Fused-weapon inventory icons | **Workaround; retest** | Black icons were seen in earlier testing. A cache-retry workaround was recorded, but the underlying timing issue remains unexplained; retest in Skybound. | | Browser new-game loading | **Previously reported; retest** | Earlier web experiments had an intermittent loading-screen hang. This is not a verified Windows-launcher issue; the root build does not package a browser release. | | Browser interpolation judder | **Earlier fix; retest** | Earlier web experiments had interpolation judder; notes record a pacing fix. Browser behavior is not validated by the Windows launcher. | | Performance and compatibility | **Ongoing limitation** | Frame pacing, shader warm-up and rendering vary by scene and hardware. A build and startup test are not a full-game compatibility test. | | Linux | **Early play** | One x86_64 Linux build (Vulkan, SDL3, FFmpeg, NVIDIA RTX 4090) got through the opening and onto the surface after the dive. The first enemy could be fought, and tree branches could be picked up. Gamepad and audio worked. This is not a full playthrough. | ## To-do - [ ] Add support for other TOTK versions beyond the 1.0.0 base game. - [ ] Fix all current issues and bugs. ## Source and licenses NotRexed's original project code is offered under the [MIT License](LICENSE). The required AArch64 lifting/runtime and renderer sources originated in NotRexed's Rexcomp-based TOTKPort; unrelated Rexcomp kits and applications are not included. **The whole repository and combined build are not MIT-only.** The AArch64 kit includes GPL-licensed suyu/yuzu components and other third-party code under their own licenses. Their licenses and applicable GPL obligations still apply; see [NOTICE.md](NOTICE.md) and the individual license files. MIT does not grant rights to the game. Before publishing, verify that every contributor whose code is being offered under MIT has agreed, and review the applicable source and binary distribution obligations.