# GPUI Mobile
A high-performance mobile platform layer for [GPUI](https://github.com/zed-industries/zed), enabling Rust-based UI applications to run natively on **iOS** and **Android**.
[](https://github.com/itsbalamurali/gpui-mobile/actions/workflows/ci.yml)
## Overview
`gpui-mobile` implements the **real `gpui::Platform` trait** from the [Zed](https://github.com/zed-industries/zed) editor for mobile targets. It follows the same architecture as [`gpui_linux`](https://github.com/zed-industries/zed/tree/main/crates/gpui_linux) — a separate crate that implements `gpui::Platform` for a specific OS family.
| **iOS** | Metal via [wgpu](https://wgpu.rs/) | UIKit (`UIWindow` + `CAMetalLayer`) | CoreText | Grand Central Dispatch |
| **Android** | Vulkan / GL via [wgpu](https://wgpu.rs/) | NDK (`ANativeWindow`) | [cosmic-text](https://github.com/pop-os/cosmic-text) + [swash](https://github.com/dfrg/swash) | `ALooper` + thread pool |
### Key Dependencies
| `gpui` | [zed-industries/zed](https://github.com/zed-industries/zed) | `Platform` trait, event types, geometry, text system traits |
| `gpui_wgpu` | [zed-industries/zed](https://github.com/zed-industries/zed) | wgpu renderer, `CosmicTextSystem`, `WgpuAtlas` |
| `wgpu` 28.x | crates.io | Metal backend (iOS), Vulkan/GL backend (Android) |
| `cosmic-text` 0.17 | crates.io | Text shaping & layout (Android) |
| `core-text` 21 | crates.io | Text shaping (iOS, via CoreText framework) |
## Features
- **Full `gpui::Platform` implementation** for iOS and Android
- **GPU-accelerated rendering** via Metal (iOS) and Vulkan/GL (Android)
- **Touch input** with tap-vs-scroll state machine
- **Momentum scrolling** (inertia / fling) — smooth, decelerating scroll after finger lift, matching native platform feel
- **Emoji rendering** — bundled CBDT bitmap emoji font for Android 13+ (where system font uses COLR v1 unsupported by swash)
- **Keyboard input** — hardware and software keyboard support with full keycode mapping
- **Safe area insets** — notch / home indicator / status bar awareness
- **Dark mode** — responds to system appearance changes
- **Example app** with multiple screens: Home, Counter, About, Settings, Components (Apple Glass + Material Design), Animations, Shaders
## Project Structure
```
gpui/
├── Cargo.toml # Crate manifest (gpui-mobile)
├── src/
│ ├── lib.rs # Crate root — re-exports, platform dispatch
│ ├── momentum.rs # Shared momentum/inertia scrolling engine
│ ├── ios/ # iOS platform implementation
│ │ ├── mod.rs # Module root + geometry helpers
│ │ ├── platform.rs # IosPlatform (impl gpui::Platform)
│ │ ├── window.rs # IosWindow (UIWindow + CAMetalLayer + wgpu)
│ │ ├── display.rs # IosDisplay (UIScreen wrapper)
│ │ ├── dispatcher.rs # IosDispatcher (GCD)
│ │ ├── events.rs # UITouch → gpui::PlatformInput
│ │ ├── ffi.rs # C-ABI bridge for ObjC app delegates
│ │ ├── text_input.rs # HID key-code → gpui::Keystroke
│ │ └── text_system.rs # CoreText text shaping
│ └── android/ # Android platform implementation
│ ├── mod.rs # Module root
│ ├── platform.rs # AndroidPlatform (impl gpui::Platform)
│ ├── window.rs # AndroidWindow (ANativeWindow + wgpu)
│ ├── renderer.rs # wgpu device/queue/swapchain
│ ├── display.rs # AndroidDisplay (AConfiguration density)
│ ├── dispatcher.rs # AndroidDispatcher (ALooper)
│ ├── keyboard.rs # NDK keycodes → gpui::Keystroke
│ ├── atlas.rs # GPU texture atlas (etagere)
│ ├── text.rs # AndroidTextSystem (cosmic-text + swash)
│ └── jni_entry.rs # NativeActivity lifecycle + event loop
├── examples/
│ ├── Cargo.toml # Example app crate
│ ├── build.sh # Unified build & run script
│ ├── src/
│ │ ├── lib.rs # App entry points (iOS + Android)
│ │ ├── main.rs # Desktop stub
│ │ ├── screens/ # UI screens (Home, Counter, About, etc.)
│ │ └── demos/ # Interactive demos (Animations, Shaders)
│ ├── ios/ # Xcode project (XcodeGen)
│ │ ├── project.yml
│ │ ├── Sources/ # Swift AppDelegate + bridging
│ │ └── Resources/ # Assets, icons
│ └── android/
│ └── gradle/ # Gradle project
│ ├── build.gradle.kts
│ └── app/
│ ├── build.gradle.kts
│ ├── src/main/
│ │ ├── AndroidManifest.xml
│ │ ├── assets/fonts/ # Bundled CBDT NotoColorEmoji
│ │ └── res/ # Icons, strings
│ └── ...
└── .github/
└── workflows/
└── ci.yml # CI: build + test for iOS & Android
```
## Quick Start
### Prerequisites
- **Rust** 1.75+
- **iOS**: macOS with Xcode 15+, [XcodeGen](https://github.com/yonaskolb/XcodeGen) (`brew install xcodegen`)
- **Android**: Android SDK + NDK r25+, [cargo-ndk](https://github.com/nickelc/cargo-ndk) (`cargo install cargo-ndk`)
### Build & Run
The unified build script handles everything:
```bash
cd examples
# iOS — build, sign, install & launch on connected iPhone
./build.sh ios --device
# iOS — simulator
./build.sh ios --simulator
# Android — build, package APK, install & launch on connected device
./build.sh android --device
# Android — emulator
./build.sh android --emulator
# Release builds
./build.sh ios --device --release
./build.sh android --device --release
```
### Manual Build Steps
#### iOS
```bash
# Add target
rustup target add aarch64-apple-ios
# Build the example (builds gpui-mobile as dependency)
cd examples
cargo build --target aarch64-apple-ios --features "ios,font-kit"
# Generate Xcode project & build
cd ios
xcodegen generate --spec project.yml
xcodebuild -project GpuiExample.xcodeproj -scheme GpuiExample \
-destination "generic/platform=iOS" build
```
#### Android
```bash
# Add target
rustup target add aarch64-linux-android
# Build the shared library
cd examples
cargo ndk -t arm64-v8a -o android/gradle/app/src/main/jniLibs build
# Assemble & install APK
cd android/gradle
./gradlew assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apk
# Launch
adb shell am start -n "com.gpui.mobile.example/android.app.NativeActivity"
```
### Host (documentation / CI check)
```bash
# Compiles the non-mobile fallback (pulls gpui + gpui_wgpu from Zed repo)
cargo check
# Run unit tests (momentum scrolling, keyboard mapping, etc.)
cargo test
```
## Architecture
### iOS
```
IosPlatform (impl gpui::Platform)
├── IosDispatcher — GCD main queue + background queue
├── IosWindow — UIWindow + CAMetalLayer + wgpu Metal renderer
│ ├── touch handler — tap/scroll state machine + velocity tracker
│ └── momentum pump — driven by CADisplayLink via FFI
├── IosDisplay — UIScreen bounds + scale factor
├── events — UITouch → ScrollWheel / MouseDown / MouseMove / MouseUp
└── text_system — CoreText font shaping + rendering
```
### Android
```
AndroidPlatform (impl gpui::Platform)
├── AndroidDispatcher — ALooper (foreground) + thread pool (background)
├── AndroidWindow — ANativeWindow + wgpu Vulkan/GL renderer
│ ├── touch handler — tap/scroll state machine + velocity tracker
│ └── momentum pump — driven by event loop frame callback
├── AndroidDisplay — AConfiguration density + window geometry
├── AndroidTextSystem — cosmic-text shaping + swash rasterisation
│ └── emoji — CBDT bitmap fallback for COLR v1 system fonts
└── jni_entry — NativeActivity lifecycle + input dispatch
```
### Momentum Scrolling
Both platforms share a common momentum engine (`src/momentum.rs`):
- **VelocityTracker** — ring buffer of recent touch samples with weighted least-squares velocity estimation
- **MomentumScroller** — exponential-decay animation producing decelerating scroll deltas each frame
- On finger lift: compute release velocity → start fling
- On new touch: instantly cancel active fling
- Tuned to match native iOS `UIScrollView` / Android `OverScroller` feel
### Emoji Rendering (Android)
Android 13+ ships `NotoColorEmoji.ttf` using COLR v1 color outlines, which `swash` cannot render. The platform detects this at startup by checking for CBDT table presence, and falls back to a bundled CBDT-based NotoColorEmoji (v2.042) from APK assets. Emoji glyphs are rendered using `Format::CustomSubpixel` for full-color RGBA output.
## Platform Support
| iOS (device) | ✅ | iOS 13.0+ | Metal |
| iOS (simulator) | ✅ | iOS 13.0+ | Metal (simulated) |
| Android (arm64) | ✅ | API 26+ | Vulkan (preferred), GL ES 3.0 (fallback) |
| Android (armv7) | ⚠️ Untested | API 26+ | Vulkan / GL ES |
| Android (x86_64) | ⚠️ Emulator | API 26+ | Vulkan / GL ES |
| Host (macOS/Linux) | 🔧 Check only | — | — |
## Cargo Features
| `font-kit` | Enables `font-kit` based font matching on iOS (CoreText) |
| `ios` | (marker) iOS-specific code paths |
| `android` | (marker) Android-specific code paths |
## Example App
The example app demonstrates the full GPUI mobile stack:
| **Home** | Navigation hub with cards linking to all screens |
| **Counter** | Simple interactive counter (tap to increment) |
| **About** | Scrollable tech stack info — tests scroll + momentum |
| **Settings** | Theme toggle, preferences UI |
| **Components** | Apple Glass + Material Design component showcase |
| **Animations** | Physics playground — drag-to-throw, spring animations |
| **Shaders** | WGSL shader gallery with touch-reactive effects |
## CI / GitHub Actions
The repository includes a CI workflow (`.github/workflows/ci.yml`) that:
1. **Checks** the host build (`cargo check`)
2. **Tests** unit tests (`cargo test` — momentum, keyboard, etc.)
3. **Cross-compiles** for iOS (`aarch64-apple-ios`)
4. **Cross-compiles** for Android (`aarch64-linux-android`) using the NDK
5. **Lints** with `cargo clippy`
## Contributing
Contributions are welcome! Please:
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Ensure all targets compile:
```bash
cargo check
cargo check --target aarch64-apple-ios
cargo check --target aarch64-linux-android ```
4. Run tests: `cargo test`
5. Run `cargo fmt --all`
6. Open a Pull Request
## License
This project is licensed under any one of the following licenses, at your option:
- [GNU General Public License v3.0 or later](LICENSE-GPL)
- [GNU Affero General Public License v3.0 or later](LICENSE-AGPL)
- [Apache License, Version 2.0](LICENSE-APACHE)
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this project by you shall be licensed under the same terms,
without any additional terms or conditions.
## Acknowledgements
- [Zed Industries](https://github.com/zed-industries/zed) — for the GPUI framework
- [wgpu](https://wgpu.rs/) — cross-platform GPU abstraction
- [cosmic-text](https://github.com/pop-os/cosmic-text) — Unicode text shaping
- [swash](https://github.com/dfrg/swash) — font rasterisation
- [Google Noto Fonts](https://github.com/googlefonts/noto-emoji) — bundled emoji font (Apache 2.0)