Mario Kart 64 on iPhone and iPad—with touch controls and Bluetooth controller routing.
Native Metal rendering, full-analog touch steering, four-player controller
routing, local multiplayer, and optional enhanced texture packs.
SpaghettiPad packages the full SpaghettiKart source port as a native iOS/iPadOS app. It brings Mario Kart 64 to the screen in your hands with Metal rendering, true analog touch steering, a grip-first control layout, Files-based setup, built-in Bluetooth controller routing, and optional enhanced visuals.
This repository contains the mobile integration, pinned maintained sources, and reproducible build scripts. It does not contain Mario Kart 64, a ROM, extractable or playable Nintendo game assets, a playable ROM-derived archive, or MK64 Reloaded. Gameplay screenshots are retained as documentation. Read the scoped rights and licensing boundary; it does not relicense SpaghettiKart, its dependencies, texture packs, or game material. This is a source-available integration repository, not a single, uniformly licensed open-source distribution.
The source-maintenance handoff records the current maintained source workflow, exact component pins, remaining release-source qualification, and scoped rights notices.
Note
AI disclosure: SpaghettiPad uses substantial AI assistance for code, tests, documentation, debugging and maintenance. Some support replies and maintenance tasks are automated. There is no audited percentage of AI-generated code. Build, test and device records describe what was checked. This disclosure concerns SpaghettiPad's workflow, not the authorship of its upstream projects.
The touch layout keeps the controls under your thumbs and the race visible. The left side puts L and Z above a full-analog stick. The right side keeps R and a second Z above A and B, with Start deliberately separated from the action controls.
Touch is not painted over the whole display: empty space still belongs to the
game, the settings menu hides the race controls while open, and the persistent
••• button always provides a way back.
These are current physical-iPad captures using locally supplied game data. The ROM and optional texture pack used to create them are not part of this repository.
SpaghettiPad carries four N64 controller ports, deterministic connection-order assignment, and SpaghettiKart's split-screen modes into the native iOS build. The touch controller parks itself when hardware controllers are present and returns after the last one disconnects.
Four-player selection is working, and two-player split-screen rendering has been exercised. Full physical-controller Grand Prix, VS, battle, reconnect, and sustained three/four-player performance remain documented hardware gates; the README does not turn a working menu into an unearned compatibility claim.
Copy compatible SpaghettiKart packs into the Files-visible mods folder,
then open ••• → Enhancements → Mods. Each installed pack has its own saved
switch, current status and conflict explanation. Character replacements can
layer over HD textures; replacements for the same racer are mutually exclusive.
The owner accepted the build 6 selector on an iPhone 14.
MK64 Reloaded HD has been imported and rendered on a physical iPad. No texture pack is bundled, downloaded, mirrored, or redistributed by this project.
Version 0.2.1 fixes the SDK 27 launch crash and black game image by updating SDL's scene startup and orientation handling. The final build was checked on physical iPadOS 27 and iOS 26.6.2 devices. Existing IPAs need a rebuild; see the SDK 27 investigation and validation. PadMint selects the latest public release, so check that it selects 0.2.1 before rebuilding.
| Option | Status | What to do |
|---|---|---|
| Make your own IPA with PadMint | Available | On an Apple Silicon Mac with Xcode, PadMint builds SpaghettiPad from this repository's latest release and saves an unsigned IPA; install it with AltStore Classic, SideStore or Sideloadly. See Get started. |
| Local iPhone/iPad build | Available now | Build and sign with your own Apple development team by following Build from source. |
| Simulator | Available now | Use it for development and UI testing. It cannot replace physical-device acceptance. |
| App Store / TestFlight | Not announced | No App Store listing or public TestFlight exists. |
The current development build has been signed, update-installed, and played
on a physical iPad and iPhone. Files import, local mk64.o2r loading, touch
gameplay, menus, audio, saves, local multiplayer paths, and MK64 Reloaded HD
have been exercised on iPad. The customizable phone layout, A hold assist,
safe-area menu placement, texture-pack rendering, and Grand Prix play have
also been exercised on iPhone.
Those results do not certify every configuration. Preview 4's signed source build was update-installed on a physical iPad with the existing bundle ID; runtime logs reached archive, audio, scene, SDL mapping, and foreground controller initialization. Readback hashes proved that game data, saves, configuration, and controller/touch preferences were unchanged. Physical Bluetooth, wired, natural-sleep, full-mapping, and multi-controller acceptance, sustained multiplayer performance, a complete touch-only Grand Prix, and a complete tilt-driven Grand Prix remain explicit validation gates.
Build computer: SpaghettiPad's PadMint recipe currently supports an Apple Silicon Mac (M1 or newer) with full Xcode and the iOS platform installed. The Xcode command-line tools alone are not enough. Intel Macs are not currently listed as supported build hosts in the recipe.
PadMint itself runs on Windows and Linux too, but its experimental iPhone/iPad build path on those systems is for KartPad. SpaghettiPad currently has no supported Windows, Linux, or phone-only build path. A Windows sideloading tool can install an IPA you already built; it does not compile SpaghettiPad. If you cannot access a compatible Mac, the current personal-build route is unavailable.
The easy way: on that Mac, install the build libraries once:
brew install cmake ninja pkgconf sdl2 glew nlohmann-json libpng libzip \
tinyxml2 libogg libvorbis opus opusfile sdl2_net ripgrepthen download PadMint, unzip it,
double-click PadMint.command and choose SpaghettiPad. PadMint builds the app from this
repository's latest release and saves an unsigned IPA in your Downloads folder. Install it with your
sideloading tool, then choose your ROM in the app (see First launch). Releases
publish no app: the app is compiled from the SpaghettiKart decompilation, so you make your own.
By hand:
You need:
- an Apple Silicon Mac with full Xcode, its iOS platform and command-line tools;
- Homebrew;
- an Apple ID configured in Xcode for physical-device signing; and
- your own legally acquired Mario Kart 64 US 1.0, big-endian
.z64ROM.
The supported ROM has SHA-1:
579c48e211ae952530ffc8738709f078d5dd215e
Install the host dependencies:
brew install cmake ninja pkgconf sdl2 glew nlohmann-json libpng libzip \
tinyxml2 libogg libvorbis opus opusfile sdl2_net ripgrepClone and build:
git clone https://github.com/chrissotraidis/spaghettipad.git
cd spaghettipad
# Simulator
scripts/build-ios.sh --simulator
# Physical iPhone or iPad
DEVELOPMENT_TEAM=ABCDE12345 \
BUNDLE_ID=com.yourname.spaghettipad \
scripts/build-ios.sh --deviceReplace ABCDE12345 with the 10-character team identifier shown in Xcode and
use a bundle identifier that belongs to you. Keep that bundle identifier
unchanged for later update installs so iOS can retain the app container.
The device app is written to:
build-ios/Release-iphoneos/SpaghettiPad.app
If Xcode needs to register the device or create a provisioning profile, open
build-ios/Spaghettify.xcodeproj, select the Spaghettify scheme and your
device, then choose your team under Signing & Capabilities.
See the complete build guide for pinned-source, package-audit, and signing details. Before sharing a source snapshot or build, follow the release checklist.
SpaghettiPad never downloads or bundles game data.
- Launch SpaghettiPad once so iOS creates its Files-visible folder.
- Open Files → On My iPad/iPhone → SpaghettiPad.
- Move your supported
.z64into that folder. - Return to SpaghettiPad and tap Rescan.
- Keep the app open while it validates the ROM and creates local
mk64.o2r. - Relaunch if instructed, then press the on-screen Start button.
The ROM and generated game archive remain in the app container. They are ignored by Git and rejected by the repository's app and package audits.
Maintainers may instead use scripts/generate-port-archive.sh to create a
local ref/mk64.o2r, then copy that archive into the installed app's
Files-visible folder. ref/ is ignored local storage; never commit or upload
its contents.
The current controller is arranged for landscape play:
- Left: L and Z above the full-analog control stick.
- Right: Z and R above A and B, plus Start and the four C buttons.
- Menu: the persistent
•••button opens settings and stays reachable when gameplay controls are hidden. - Layout editor: use Settings → Controls → Customize Touch Layout to move controls, resize them from 70% to 150%, or hide unused buttons.
- Touch toggle: use Settings → Controls → Touch Controls to hide or restore the gameplay overlay.
- Legacy toggle: use Settings → Controls → Legacy Touch Controls to restore the original fixed layout without customization or A hold assist.
- Tilt: opt-in steering, sensitivity, and recenter controls are under Settings → Controls.
The touch D-pad is intentionally omitted because Mario Kart 64's normal racing
controls do not use it. Hold A for 0.65 seconds during a race, then lift your
finger to keep accelerating; the A • label and a short haptic confirm the
hold. Tap A again to release it. Z and R always remain momentary. Opening the
menu releases held input and hides the gameplay controls; closing it restores
them only when Touch Controls is enabled.
Phone and tablet layouts are saved separately and survive relaunches. See Touch controls for editor behavior, safety releases, legacy mode, and current physical-device validation.
| Touch control | Mario Kart 64 action |
|---|---|
| Analog stick | Steer and navigate |
| A | Accelerate / confirm; race-only hold assist |
| B | Brake, reverse / cancel |
| Z | Use or hold an item |
| R | Hop, drift, and powerslide |
| L | Cycle the race display |
| Start | Pause / start |
| C buttons | Camera and display controls used by the game |
••• |
Open or close the SpaghettiKart menu |
SpaghettiPad uses libultraship's engine-managed SDL2 game-controller layer and
a pinned controller mapping database. The engine owns SDL_GameController
handles by SDL joystick instance ID; the iOS integration installs default SDL
mappings for all four N64 ports. Reconciliation keeps valid ownership stable,
closes detached or identity-mismatched handles, and assigns newly available
controllers to the first free player slot. A sole returning controller therefore
reclaims player 1, while a genuinely additional controller takes player 2 or
the next free slot without moving player 1.
Reconciliation runs at startup, controller add/remove/remap events, foreground resume, and a bounded active check. Gameplay receives only attached, identity-matching handles; releasing stale ownership leaves neutral input. When a physical controller is detected, the touch gameplay overlay parks so it does not send duplicate player-1 input; it returns after the last controller disconnects. Existing mappings and preferences are not reset, and SDL is not blindly restarted.
The default extended-gamepad layout is:
| Physical control | Mario Kart 64 input |
|---|---|
| Left stick | Analog stick / steering |
South face button (A on Xbox) |
A / accelerate |
West face button (X on Xbox) |
B / brake and reverse |
| Left trigger | Z / use or hold item |
| Right shoulder or trigger | R / hop and drift |
| Left shoulder | L |
| Menu/Start | Start |
| Right stick up/right | C-up/C-right |
| North/east face buttons | C-left/C-down |
| D-pad | N64 D-pad |
That describes the implemented path, not a blanket hardware certification. Deterministic tests cover missed removal with held input, neutral release, player-1 reclaim, additional-player assignment, two-controller preservation, and foreground reconciliation. Automatic button mapping, Bluetooth/wired sleep and reconnect, rumble, and sustained one-to-four-player sessions still require physical testing across Xbox, PlayStation, Nintendo, and MFi controller models. See Physical-device acceptance for the exact gate.
SpaghettiPad supports compatible SpaghettiKart .o2r, ZIP and unpacked mods.
No third-party mod assets are bundled, downloaded or relicensed by the app.
- Obtain a compatible pack from its author (for example,
MK64 Reloaded or
Ocarina NPC Racers). Extract an outer
download ZIP if the actual
.o2ris inside it. - Copy the pack into Files → On My iPad/iPhone → SpaghettiPad → mods.
- Open ••• → Enhancements → Mods and tap Check for New Packs.
- Enable the packs you want. A blocked switch explains which overlapping pack to turn off first. New packs start off; the existing HD choice carries over.
- Tap Apply Changes and Close, confirm, then reopen from the Home Screen. Current race progress is lost when closing; saved game data is preserved.
Switches save immediately; cancelling the close dialog leaves the current race running but retains selections for the next launch. The page distinguishes what is active now from what will change after relaunch. Keep filenames stable because selections are stored per filename. Replacing an archive requires a relaunch even if its switch did not change.
HD textures load before character replacements. Two character packs replacing the same racer cannot coexist, even when they replace different animation frames. Other overlapping resources are exclusive. Packs requiring another optional mod, invalid manifests, and older character paths are rejected with an explanation. This checks resource conflicts, not every possible visual or gameplay incompatibility.
Ocarina NPC Racers replaces all eight racers. Child Link (Luigi), Kris (Yoshi) and Ralsei (Toad) are additional private test candidates; their older downloads need compatibility conversion for this engine. Original author links and current validation are in mod notes. Start with HD; 4K remains a performance experiment pending its own hardware evidence.
| Area | Current result |
|---|---|
| Native app | arm64 iPhoneOS and arm64 Simulator builds target iOS/iPadOS 15+ |
| Rendering | Metal rendering works in Simulator and on a physical iPad |
| Game setup | Files-visible supported-ROM import and local mk64.o2r loading work |
| Touch | Analog steering and race controls have been exercised on a physical iPad; full acceptance still requires the documented touch-only GP |
| Texture packs | MK64 Reloaded HD has been imported, loaded, and rendered on a physical iPad; full-GP performance evidence remains |
| Saves and updates | Preview 4's signed source build was installed in place on a physical iPad; readback hashes matched for the game archive, texture pack, saves, config, and controller/touch preferences |
| Controllers | Engine-managed SDL2 stale-handle reconciliation and stable four-port ownership pass deterministic regression tests; physical Bluetooth, wired, natural-sleep, mapping, and multiplayer sessions remain |
| Tilt | The persisted motion-to-stick path, recentering, touch priority, and foreground recalibration pass Simulator tests; physical feel and a tilt GP remain |
| Packaging | Version 0.2.1 build 8 passes the unsigned app and package audits; exact local validation hashes and hardware results are in SDK 27 validation. No compiled app is supplied by the current source-only release. |
| CI | Hosted checks compile and package the unsigned iPhoneOS app without uploading the personal-use IPA; ROM-free does not mean cleared for publication |
The project deliberately keeps build, Simulator, process, and physical-device evidence separate. The remaining-work ledger records the detailed proof and open gates.
| Game | Engine | Status |
|---|---|---|
| Mario Kart 64 US 1.0 | SpaghettiKart | Supported |
| Other Nintendo 64 games or ROM revisions | Other source ports/emulators | Not supported by this app |
SpaghettiPad is a native integration of one source port, not a general Nintendo 64 emulator. A different game or ROM revision cannot be substituted.
flowchart LR
A["SpaghettiPad scripts"] --> B["Pinned maintained source graph"]
B --> D["ROM-free iOS app or unsigned IPA"]
E["Your supported ROM"] --> F["Files-visible app folder"]
D --> G["On-device validation and extraction"]
F --> G
G --> H["Local mk64.o2r and gameplay"]
I["Optional user-supplied texture pack"] --> J["Files-visible mods folder"]
J --> H
The normal compile never reads your ROM. scripts/build-ios.sh fetches exact
maintained source revisions, verifies clean inputs, generates the ROM-free
spaghetti.o2r through the separate oracle, and builds the app. Your game data is
introduced only after installation.
To create an unsigned, re-signable preview package from an unsigned device build:
scripts/package-ios.shThe default command refuses a signed app. Locally signed packaging is an
explicit maintainer-only mode: REQUIRE_SIGNED=1 scripts/package-ios.sh.
The packager audits the bundle and rejects Simulator products, original ROMs,
ROM-derived mk64*.o2r/.otr files, imported texture packs, unexpected port
archive contents, and stale signing material. The public package contract is
an unsigned IPA that the installer signs with their own Apple ID; do not
distribute a maintainer development profile.
Where is the IPA?
There is no public IPA: SpaghettiPad is compiled from the SpaghettiKart decompilation, so PadMint builds your own on an Apple Silicon Mac. See Get started.
Does this repository include Mario Kart 64?
No. You must provide your own legally acquired supported ROM. Do not open issues requesting game data, extracted assets, or download links.
Does it support Bluetooth controllers?
The engine-managed SDL2 controller path, mapping database, stable four-player ownership, stale-handle cleanup, and foreground reconciliation are included. Physical Bluetooth, wired, natural-sleep, full-mapping, and multi-controller behavior are still being verified, so support is not yet advertised as universal.
Can the HD texture pack be bundled with SpaghettiPad?
No. Texture packs remain optional third-party content obtained by the user from the pack author's official page. SpaghettiPad only provides the Files import and enable/disable workflow.
Does SpaghettiPad require JIT or a jailbreak?
No. It is a native arm64 source-port build. A sideloaded IPA still requires normal iOS code signing, but gameplay does not require JIT.
Is this an App Store or TestFlight release?
No. App Store, TestFlight, AltStore PAL, AltStore Classic, and SideStore distribution have different signing, review, account, and regional requirements. None should be implied until that exact path is published and tested.
What is the licensing status?
Each upstream component retains its own license and copyright. The pinned SpaghettiKart revision has no top-level license. In issue #731, its maintainer pointed to the mk64 decomp's documented CC0-consent effort and to the established distribution practice of other Harbour Masters ports. SpaghettiPad's free, ROM-free unsigned preview follows that community practice, but the open consent issue is not a formal license for all SpaghettiKart code. Commercial, paid-access, and official-store rights remain unresolved. See RIGHTS_AND_LICENSES.md; no project grants rights to Nintendo material or third-party texture packs.
| Path | Purpose |
|---|---|
scripts/build-ios.sh |
Complete Simulator or device build |
scripts/generate-port-archive.sh |
Local-only ROM validation and mk64.o2r generation |
scripts/package-ios.sh |
Audited unsigned/signed IPA packaging |
scripts/check-repo-safety.sh |
Tracked-asset, history, patch, script, and documentation gate |
patches/ |
Historical patch mapping; ordinary builds use maintained source commits |
docs/screenshots/README.md |
Physical-device and Simulator screenshot catalog |
docs/BUILDING.md |
Full build, signing, and package-audit guide |
docs/INSTALL_IPA.md |
Unsigned developer-preview installation boundary |
docs/HARDWARE_ACCEPTANCE.md |
Physical-device validation workflow |
docs/RELEASE_CHECKLIST.md |
Source and IPA publication gates |
docs/remaining-work.md |
Evidence ledger and remaining gates |
RIGHTS_AND_LICENSES.md |
Project, upstream, and game-data rights boundary |
Generated source trees, builds, artifacts, ROMs, ROM-derived archives, texture packs, device evidence, and signing identifiers are ignored and must never be committed.
Join the Discord for help and news. It is one community for SpaghettiPad and its sibling projects, such as KartPad, BlueWake and MeleePad: ask about setup, building with PadMint, and installing, share how it runs on your device, and hear about new releases first.
Found a bug? Open an issue with your device, its OS version, and the steps that led to it.
SpaghettiPad exists because of SpaghettiKart, libultraship, Torch, SDL, SDL_GameControllerDB, and their contributors. Its mobile control work also draws on lessons from HarkinianPad, while MK64 Reloaded is an independent, optional user-supplied visual pack.
SpaghettiPad is an unofficial community project and is not affiliated with or endorsed by Nintendo, Harbour Masters, or the MK64 Reloaded project. Nintendo, Mario, and Mario Kart are trademarks of Nintendo. All projects, copyrights, and trademarks belong to their respective owners.



