# Staticplay SD1 Mobile (On-Device, Android) Goal: ship a **real offline** Android app (no servers, no cloud) that runs an SD1-class model **on-device** using **NNAPI** (via a native runtime). This repo currently includes a working offline SD1.5 ONNX "pack" runner (unzip + inspect + generate). ## Key points (no surprises) - Use a **prebuild** / **native build** (Expo Go won't cut it for native inference). - "Offline" means the **model files are on the phone** (bundled in the APK or copied into app storage). - ONNX Runtime is integrated via a tiny **Android native module** (no JSI auto-install). ## Run (Android) ```bash cd /home/tiny/projects/staticplay-sd1-mobile export ANDROID_HOME=/home/tiny/Android/sdk export PATH="$ANDROID_HOME/platform-tools:$PATH" npx expo prebuild --clean npx expo run:android # debug (uses Metro) ``` For a fully offline build (no Metro), install the release build: ```bash cd /home/tiny/projects/staticplay-sd1-mobile/android NODE_ENV=production ./gradlew :app:installRelease ``` Then press "Test native ONNX (NNAPI -> CPU)" in the app. ## Bundle With Expo (Windows, release APK) Use these commands from this project root. ```powershell # 1) Install dependencies (once) npm install # 2) Regenerate native Android project if config/plugins changed npx expo prebuild --platform android --clean # 3) Build release APK cd android ./gradlew.bat :app:assembleRelease # 4) Install to connected phone (USB debugging on) ./gradlew.bat :app:installRelease ``` APK output path: `android/app/build/outputs/apk/release/app-release.apk` Notes: - This v2 build uses package id `com.anonymous.staticplaysd1mobile.v2`, so v1 can stay installed. - Some setup buttons can take longer than expected (especially inspect actions). - Generation works offline but is still being optimized for speed. - Website: `https://staticplay.co.uk` ## SD1.5 pack + generation (offline) 1) Put the SD1.5 ONNX pack zip at the app external directory as: `/storage/emulated/0/Android/data/com.anonymous.staticplaysd1mobile/files/sd15-onnx-pack.zip` 2) In the app: - (Optional) `Show app external pack path` (for sanity check) - `Unzip SD15 pack from external` (one-time; can take minutes) - `Load tokenizer (bundled)` (no external files required) - Toggle backend: - `Backend: NNAPI (experimental)` = fastest, can be unstable on some devices/drivers - `Backend: CPU (safe)` = slower, but avoids NNAPI driver issues - `Generate 512x512 (quick 4)` to prove the end-to-end pipeline - `Generate 512x512 (quality 20)` for higher quality (slower) 3) Output images save to the same app external folder as `sd_out_*.png`. ## SD1 plan (high level) 1) Pick an SD1 distilled variant (LCM/Turbo-style) to keep steps ~4-8. 2) Export components to ONNX (text encoder, UNet, VAE decoder). 3) Quantize mostly UNet (INT8) + keep VAE in FP16/BF16. 4) Run inference via a native runtime with NNAPI; fall back to CPU if NNAPI can't compile a node. 5) Ship the ONNX files in-app (or as offline downloadable packs). ## V2 notes (2026-02-12) - This branch installs as a separate app id (`com.anonymous.staticplaysd1mobile.v2`) so v1 stays on device. - Guided mode is enabled to show one button at a time for easier setup flow. - Some actions can take longer than expected, especially: - `Inspect pack UNet` - `Inspect pack text_encoder` - `Inspect pack vae_decoder` - first unzip/generation after launch - Overall generation is currently functional but still slower than target. Ongoing work is focused on speed improvements. - Public site: `https://staticplay.co.uk`