First iPhone run: which title, how to build and install it¶
Measured 2026-10-27 on the iOS Simulator (iPhone 17 Simulator, Apple-silicon Mac under heavy load from other sessions), branch claude/ios-candidate-2026-10-27. Audio off (NAPPLE_AUDIO_OFF=1). Data: Testing Material, keys 22.1.0, firmware 22.1.0. Nothing here has run on a physical iPhone yet.
Recommendation: The Legend of Zelda: Link's Awakening (LAS, 01006BB00C6F0000, base v0). It is the only title that boots, renders correctly and plays on the Simulator. A signed device IPA is already built (see below).
Ranked table¶
Footprint = phys_footprint of the app process (what iOS jetsam judges). The Simulator keeps Metal textures outside the process, so on a phone add the GPU share (unmeasured, memlog: prints it on a device).
| # | Title | Footprint peak / steady | Simulator fps | Visual quality | Input | Verdict |
|---|---|---|---|---|---|---|
| 1 | LAS | 640 MB peak in the intro movie, 790 MB peak in play; steady 550-620 MB (title / menus), 780 MB in play (Marin's room) | 57-60 in play and in the 1080p intro movie (NAPPLE_PERF_LOG), gpu_ms_max about 1-2 ms |
Correct: intro movie, title, file select, difficulty, name entry, the opening cutscene and Marin's house all render with the tilt-shift look, no visible glitches | Scripted keys (NAPPLE_INPUT_SCRIPT) drive it from boot to gameplay; the on-screen pad draws correctly |
Go. Needs the title's L+R at the title screen, name entry through the system keyboard applet |
| 2 | SMO | 743 MB steady, 861 MB peak at the menu (35 s after launch) | menu only | Start / Assist Mode menu renders correctly | A on the menu starts "Compiling shaders" and the process sits at 0 % CPU (Simulator GPU: 32-byte colour attachment budget, device A11+ has 64; known from the earlier run, which aborted with the 48-byte assertion) | Not testable on the Simulator past the menu. Second choice for a phone only if LAS fails; a 5 GB game and 1 GB+ footprint once in the world are likely |
| 3 | ACNH 3.0.3 + DLC | none: aborts in 3 s | - | no frame | - | Blocked on the Simulator: Texture Cube Array is not supported on this device (mtl_tex_get). A-series devices support cube arrays, so a phone may pass; unverified. 11 GB of data |
| 4 | MK8D (latest update, AArch64) | none: aborts in 4 s | - | no frame | - | Blocked on the Simulator: source texture pixelFormat RGBA8Unorm not compatible with texture view pixelFormat RGBA32Uint (a texture-view usage flag missing in mtl_tex.m, gfx owner). 11 GB of data. Not a first-run candidate |
Screenshots (docs/screenshots/ios-candidate/): las-intro, las-title, las-file-select, las-device-layout-difficulty, las-marin-room-1, las-marin-room-2, smo-menu, smo-after-A-compiling-shaders-hang.
Memory against the iPhone limit¶
- LAS in play: 782 MB footprint (guest-mapped 3.28 GB of virtual size, almost all untouched), 60 fps. Far under the 1.8 GB target. No pool or budget change was needed for LAS; the footprint is dominated by the guest's own touched pages and the 5-6 GB of address space is free (only touched pages count).
- The device layout was exercised on the Simulator:
NAPPLE_HEAP_CAP_MB=3328 NAPPLE_ALIAS_GIB=1reproduces the 6 GiB device window (3.25 GiB heap cap, 1 GiB alias). LAS boots, plays the intro movie, reaches the title and the new-game flow with it (the old note that LAS aborts in its movie library with the 3.25 GiB cap did not reproduce). Footprint 551-622 MB. - The paired phone is an iPhone 16 Pro Max (8 GB); the profiles on this Mac belong to a free account (no
increased-memory-limit), so the default limit applies. A 790 MB peak plus the GPU share leaves a very large margin. - New: a memory log (
runtime/src/memlog.m): every 20 s on iOS (NAPPLE_MEMLOG=1elsewhere,NAPPLE_MEMLOG_SECS) onememlog:line with footprint, footprint peak, guest-mapped bytes,MTLDevice.currentAllocatedSize(0 on the Simulator) and, on iOS,os_proc_available_memory(). It is the first thing to read after the first phone run (Files > Napple > logs, ordevicectl device process launch --console). - New cheap optimisation: iPhone / iPad default to handheld mode (720p), via the input binding default (
input/src/bindings.c); a docked 1080p render target costs GPU memory and heat a phone does not need. Verified on the Simulator (operation mode: handheld (720p)). A savedinput.jsonorNAPPLE_OP_MODE=dockedoverrides it.
Input¶
- On the Simulator the Mac cannot deliver touches to the app (
simctl/ tool taps never reach it, same as the earlier notes), so the touch pad is exercised only visually here. Use a physical controller (the pad hides when one is connected) or the touch pad on the phone itself. - Scripted keys work and were used for all runs. LAS:
NAPPLE_INPUT_SCRIPT="100:L+R,112:A,119:A,126:A,133:DOWN,138:A,..."withNAPPLE_SWKBD_ANSWER=Linkreaches the game; on a phone press L+R (the touch L and R buttons together) at the title, A through the menus, A on the name field (keyboard applet) then down to OK.
Build and install the LAS IPA (free account, this Mac)¶
Already built here (signed with Apple Development: er.talevi@duocuc.cl (7HV79NKWDA), profile iOS Team Provisioning Profile: com.napple.las, team P2CG46TQ57, device 00008140-001421A2219B001C = the paired iPhone 16 Pro Max; codesign --verify --deep --strict passes; profile expires 2026-11-02):
~/Desktop/NappleIOS/LAS-com.napple.las.ipa (4.0 GB). Not installed on the phone by this session.
Install it (phone unlocked, Developer Mode on, trusted):
xcrun devicectl device install app --device 00008140-001421A2219B001C ~/Desktop/NappleIOS/LAS-com.napple.las.ipa
xcrun devicectl device process launch --console --device 00008140-001421A2219B001C com.napple.las
First launch of a free-account app: Settings > General > VPN & Device Management > trust the developer certificate. Studio route: iPhone & iPad pane, drop the LAS NSP, Target iPhone, pick identity 6C04BD3C... and profile com.napple.las, Build + Install.
Rebuild from scratch (needed after 2026-11-02 or a code change; 10 GB of scratch disk, about 4 minutes):
cd Napple
VPX=1 tools/build_ios_deps.sh && tools/build_ios.sh # libopus + libvpx, runtime/build-ios/napple-runtime
TM="<Testing Material>"
target/release/napple build "$TM/The Legend of Zelda Link’s Awakening [01006BB00C6F0000][v0].nsp" \
-k "$TM/Keys 22.1.0/prod.keys" --firmware "$TM/Firmware.22.1.0.zip" --target ios \
--runtime runtime/build-ios/napple-runtime --signing-identity 6C04BD3CC87D879A77B9C36B557ABB477557D69F \
--provisioning-profile "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles/3c8c76a4-0b33-402a-bc38-95996824b97f.mobileprovision" \
--bundle-id com.napple.las --ipa -o out/las
napple build --list-signing shows the identities and profiles. Two other profiles exist (com.napple.smo, com.napple.mk8d) for the other titles. Identity 4 (E2817BD6...) is a different certificate that those profiles may or may not carry; 6C04BD3C... is the one in the LAS profile.
What to check on the phone, in order¶
- The app opens and reaches the intro movie (a
cannot load ... dlerrorline means dyld refused a hand-built dylib; seedocs/architecture/ios.md"Risks"). memlog:lines: footprint should stay under 1.5 GB;metal ... MBis the GPU share;system still allowsshould stay above 1 GB.- Title (L+R), file select, new game, Link wakes up in Marin's house, walk.
- Thermals after 10 minutes; 60 fps at 720p is the expectation.
Not covered / open¶
- Everything physical: exec-page rules, dyld on a phone, jetsam, thermals. LAS's
memlognumbers on the device replace the estimates above. - The Simulator-only GPU limits that block SMO, ACNH and MK8D are gfx work (colour attachment 48 -> 32 bytes, cube arrays, texture-view usage), left to the gfx owners; not touched here.
memlogGPU figure is 0 on the Simulator.