Android
Ruins Launcher
An Android home screen that grew into a phone OS layer — and updates itself over the air from our own server.
- 78,156
- Lines of Kotlin
- 25
- OTA builds
- 7
- Bundled apps
- 30
- Manifest components
across 399 files
shipped to the device
each with its own launcher icon
activities, services, IMEs, wallpaper, HCE
What it is
Inside Ruins Launcher
Ruins Launcher started as a home screen with one idea: a central dot that expands into an arrangeable pattern of app icons, in one of four geometries. It is still that, and it is now also the shell for a small family of applications that ship inside it — seven with their own icon in the drawer, plus a keyboard, a voice input method and a live wallpaper that register as system components rather than apps. Nothing here is a wrapper around someone else’s app.
It does not come from an app store. It reads a manifest from our own server, compares version codes, downloads, verifies the SHA-256 and hands the package to the system installer. The publish script bumps the version before building, so a failed build never republishes a number, and the manifest is only written once the APK is actually in place.
Most of the engineering sits in the details. The wallpaper is a six-pass OpenGL ES 3.0 renderer whose gyroscope parallax works on the quaternion the sensor provides rather than the orientation helper — whose roll is undefined exactly when you hold a phone upright in portrait. A shader that fails to compile flashes magenta at 2 Hz rather than rendering silent black. Debug builds ship non-debuggable so that no one can ask the Keystore to decrypt the vault over a cable, while keeping the debug signing key so upgrades install in place.
Built with
- Kotlin
- Jetpack Compose (Material 3)
- OpenGL ES 3.0 + GLSL
- Media3 / ExoPlayer
- C++20 + NDK
- Android Keystore
- DataStore
- kotlinx.serialization
Capabilities
What it actually does.
The home screen: an expanding icon group
Tap a central dot and it opens into Flower, Honeycomb, Grid or Arch. Long-press to drag and reorder; long-press the dot for layout, icon size and membership. A real HOME app running over a translucent wallpaper-showing surface, with icon-pack support and one-tap adoption as your default launcher.
Ruins Images — generation against your own GPU
The largest of the companion apps. It talks to our own inference box over an encrypted tunnel, keeps a named prompt library storing parameters alongside the pictures they produced, and keeps a generation alive while the page is closed.
The tenancy strip above the prompt
Before you press Generate, Ruins Images asks the GPU arbiter who currently holds the card and says so. It replaces a render that used to fail seconds in with an out-of-memory error. Deliberately silent when nothing is contending — a strip that always has a sentence in it stops being read.
Ruins Plan — a document two models write into
A plan that a small planning model and the large coding model edit together, streamed to the phone as they go. The delimiter protocol they speak is parsed here as it arrives, so an answer applies to the document in place rather than arriving as a wall of text to copy out.
Ruins Player — music, with its own Discord card
A Media3 player that publishes Rich Presence through the native Social SDK on a phone with no Discord app installed. It runs under a second Discord application from the launcher shell’s, because a refresh token is bound to one client id and the two cards would otherwise collide.
Ruins Calendar — events and reminders
Months, events and reminders that fire through the same alarm plumbing as the clock, so a reminder survives a reboot rather than quietly vanishing with the process that scheduled it.
Ruins Timing — alarms and timers
Alarms with five bundled tones, a full-screen ring activity that wakes the display over the lock screen, and timers that keep counting in a foreground service instead of dying when the app is swiped away.
Ruins Dream — sleep tracking
A sleep screen that watches for movement and sound overnight and keeps the record, with the audio capture running as its own service so the screen can be off while it works.
Ruins Keyboard, and a gesture to summon it
A keyboard written from scratch with its own settings, plus an accessibility service that watches for a three-finger gesture and opens the keyboard on the nearest text field — without ever intercepting touches, so nothing else on screen notices it is there.
Ruins Voice — speech, as a system input method
A separate voice IME and a recognition service registered system-wide, so dictation is available to any app that asks for speech input, not only to ours.
Neon Sunset — a native live wallpaper
Six render passes from twelve GLSL files: sky and clouds, stars, sun, a displaced grid mesh, bloom, then VHS grain. Gyroscope parallax works on the quaternion the sensor provides rather than the orientation helper, whose roll is undefined exactly when a phone is held upright — with auto-recentring, so it behaves lying down or flat on a desk. A shader that fails to compile flashes magenta rather than rendering a silent black screen. Ported from a Wallpaper Engine scene by Benjamin Halko; the engineering is ours, the artwork is not.
Notes, feeds and the rest of the shell
Notes with automatic linking between them, an RSS reader, and icon-pack support, all living in the launcher surface itself rather than as separate apps.
Tap two phones to hand something over
Tasks and calendar events transfer by NFC through a host card emulation service, so sharing is a physical gesture between two handsets with no account, no server and no pairing step.
An encrypted vault
Files are sealed with AES-GCM under a key held in the phone’s hardware keystore, behind a PIN that is never stored — only a salted PBKDF2 hash of it. Wrong guesses back off exponentially rather than linearly, because a six-digit PIN is a small space: the twentieth wrong guess costs a minute, and reaching the ten-thousandth would take longer than the phone will last. The on-disk format is deliberately separated from the key handling, since the keystore cannot be reached from a unit test and framing is exactly where an encryption format goes wrong — an off-by-one in a header makes every sealed file unreadable, and sealed files are the one thing here that cannot be regenerated.
Why the debug build is not debuggable
Debug builds ship with debugging switched off, so nobody can ask the keystore to decrypt the vault over a cable — while keeping the debug signing key, so upgrades install in place. Swapping to a release key would force an uninstall, and an uninstall clears the keystore entry, which would turn every sealed file into permanent noise.
It updates itself, over the air
Reads a manifest from our own server, compares version codes, downloads, verifies the SHA-256 and hands the package to the system installer. Twenty-five builds have gone out this way. No store, no review queue. The publish script bumps the version before building, so a failed build never republishes a number, and the manifest is written only once the APK is actually in place.
Related
Where it sits.
A client of it — image generation, chat, and the GPU tenancy strip.
AI Relic
Private infrastructure · active development
A self-hosted AI stack — an 80-billion-parameter coding model on our own GPU, and the coding environment built around it. Nothing leaves the machine.
Read more →