Skip to content

About

Mario Kart 64 native on iPhone and iPad via SpaghettiKart, with Metal, full-analog touch controls, Bluetooth controller routing, local multiplayer, and HD texture packs.

Topics

Resources

Stars

59 stars

Watchers

1 watching

Forks

Repository files navigation

SpaghettiPad

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.

iOS and iPadOS 15 or later Metal renderer Full analog touch controls Bluetooth controller routing Enhanced texture pack support Physical iPhone and iPad tested Build SpaghettiPad with PadMint Join the SpaghettiPad Discord ROM not included

SpaghettiPad racing on Toad's Turnpike with full touch controls on a physical iPad

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.

Built for racing on glass

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.

Current screenshots

SpaghettiPad racing with triple red shells and the full touch controller SpaghettiPad racing through DK's Jungle Parkway with enhanced textures
Every race control, within reach
Hold A, steer with full analog input, drift with R, and fire items from either Z.
Enhanced tracks, native workflow
Import a compatible HD pack through Files and switch between original and enhanced graphics in-app.

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.

Local multiplayer is part of the port

Four-player Mario Kart 64 character selection running in SpaghettiPad on iPad

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.

Enhanced textures, built into the experience

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.

Install status

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.

Get started

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 ripgrep

then 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 .z64 ROM.

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 ripgrep

Clone 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 --device

Replace 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.

First launch

SpaghettiPad never downloads or bundles game data.

  1. Launch SpaghettiPad once so iOS creates its Files-visible folder.
  2. Open Files → On My iPad/iPhone → SpaghettiPad.
  3. Move your supported .z64 into that folder.
  4. Return to SpaghettiPad and tap Rescan.
  5. Keep the app open while it validates the ROM and creates local mk64.o2r.
  6. 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.

Touch controls

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

Physical controllers

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.

Optional mods and texture packs

SpaghettiPad supports compatible SpaghettiKart .o2r, ZIP and unpacked mods. No third-party mod assets are bundled, downloaded or relicensed by the app.

  1. Obtain a compatible pack from its author (for example, MK64 Reloaded or Ocarina NPC Racers). Extract an outer download ZIP if the actual .o2r is inside it.
  2. Copy the pack into Files → On My iPad/iPhone → SpaghettiPad → mods.
  3. Open ••• → Enhancements → Mods and tap Check for New Packs.
  4. 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.
  5. 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.

Current validation

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.

Supported game

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.

Reproducible and ROM-free

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
Loading

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.sh

The 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.

Frequently asked questions

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.

Project map

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.

Community and support

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.

Credits and legal

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.

About

Mario Kart 64 native on iPhone and iPad via SpaghettiKart, with Metal, full-analog touch controls, Bluetooth controller routing, local multiplayer, and HD texture packs.

Topics

Resources

Stars

59 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages