A free, open-source launcher for Android TV and Google TV, laid out around what you actually watch.
Quick on the remote, calm to look at, and nothing leaves the house.
One APK, no account: copy it to a USB stick, open it on the TV, and you are about five minutes from a new home screen. Full steps.
Keeps itself current from this repository's releases · Android 9 and up, arm64 and 32-bit ARM
The home screen that comes with a TV works for the company that made it. It is slow on the hardware it ships on, it fills the rows with things to buy, it plays trailers you did not ask for, and it phones home about all of it. The thing you were in the middle of watching is in there somewhere.
Lounge starts from that thing. One picture, the title, how much is left, and a button. Under it, rows you arrange yourself: what you are watching, your apps in your order, live channels with a guide, the inputs on the back of the TV. It reads what the apps on the TV already publish, what your media server knows, and what you tell it, and it keeps all of that on the TV.
The Stage. The top of the screen is given to one thing at a time: the episode to continue, the channel that is on, the app you open every evening at this hour. A strip under it holds the next few. Move down into the rows and the Stage lowers to a band with the title still on it; move back up and it rises again, one continuous picture, nothing squeezed.
Rows you own. Continue watching comes from every app that publishes it, from the TV's own listings, and from plugins. Your apps sit in the order you pin them, sorted by how recently you opened them until you do. Games get a row of their own, marked when a controller is connected. Hold OK on any tile for a menu: pin, move, hide, pin it to the Stage, app info, the store page, uninstall. Rows with nothing in them stay out of the way.
Streaming apps, including Netflix, appear in Continue watching when they publish readable Watch Next entries on your TV. Enable TV listings in Settings; Lounge refreshes them when you return from a player. TV listings troubleshooting explains how to check what an app actually publishes.
Live TV with a guide. Channels from the TV's tuner and from plugins show what is on now, and a guide lays the schedule out as a grid of channels and time.
The TV itself. HDMI inputs with the names their devices announce over CEC and whether anything is plugged in. On a streamer, a TV controls card turns the TV on and switches to the right input, sends sound to a soundbar, changes the volume, or turns everything off.
Now playing. Music or a podcast playing in the background shows as a chip in the top bar and a card with play, pause and skip.
Search. Apps, what you have been watching, and whatever the plugins can find, from one box.
Screensaver and live backgrounds. The screensaver shows the artwork from the Stage and the rows with a slow push-in, or one of nine abstract scenes drawn on the TV's graphics chip in your theme's colours. Plugins can add scenes (PLUGINS.md). Any scene can also run behind the home screen, dimmed so the tiles stay the brightest thing in the room.
Set up once. Five screens on first run: how it should look, which accesses to allow, making it the home screen, pairing a phone, done. Every one is reachable again from Settings.
Settings, Phone companion shows a QR code and a six-digit code. The page at
http://<tv>:8787 works in any browser on the same network and can be added to the phone's
home screen like an app. The TV serves it itself and remembers the phone until you forget it.
- What's on mirrors the home screen. Tap a tile and it opens on the TV.
- Remote has a d-pad, Back, Home, Menu and the media keys, a field that types into whatever the TV has focused, and a place to paste a link that opens on the TV. With Power Setup connected, the keys reach whatever app is in front.
- Layout reorders the rows and your pinned apps, and shows what is pinned to the Stage.
- Plugins configures the installed plugins and installs new ones from a file or a link.
- More backs up your layout and settings as one file and restores it, lists the paired phones, and shows the TV's diagnostics.
A plugin is a WebAssembly module in a signed .lgp bundle. It runs inside the core under a fuel
budget and a memory cap, with no access to Android, the file system, sockets or other plugins:
it can only fetch from the hosts its manifest names, keep a small private store, read its
settings and log. What it publishes becomes tiles, Stage spotlights, channels in the guide or
rows of its own. The TV pins each publisher's key when you install a plugin and refuses an
update signed by anyone else; the plugins built into the APK are vouched for by the APK
itself. Any language that targets core WebAssembly will do: the interface is eight imports
and six exports with JSON in between.
Fifteen ship in the APK, written against the same SDK as anyone else's. Turn on the ones you use from the phone or the TV's settings.
| Plugin | What it adds |
|---|---|
| Jellyfin | Your server's resume points and next episodes in Continue watching, its newest additions and your favourites as rows, and search, each opening on its page in the Jellyfin app |
| Emby | Your server's resume points and next episodes in Continue watching, its newest additions and your favourites as rows, and search |
| Plex | Your server's On Deck in Continue watching, its newest additions as a row, and search |
| Kodi | A Kodi library: resume points, the next episodes, recent additions and Live TV, played on whichever Kodi you choose |
| Trakt | What you paused, what is next and your watchlist, whichever service they live on |
| IPTV | An M3U playlist as channels, with a guide from XMLTV |
| HDHomeRun | The tuner's channels and guide, played in the TV's own player |
| Tvheadend, Channels DVR, NextPVR | A DVR's channels, guide and recordings |
| Twitch | The channels you follow that are live, in Live now and the guide |
| YouTube channels | Channels and playlists through their public feeds, no account needed |
| Internet Archive | Free films, cartoons and television from archive.org, with search |
| Immich photos | A shared Immich album as the screensaver |
| Art mode | Public-domain paintings from the Met and the Cleveland Museum of Art on the screensaver |
A sixteenth, Sample library, lives in the repository but not the APK: eighteen public-domain films with their posters, so you can see Lounge with something on it. The pictures in this file show a made-up horror library instead: every title, poster and name in them is invented. PLUGINS.md takes you from nothing to a plugin on your TV.
Plugin submissions are welcome. Open a pull request that adds yours under plugins/ once it
passes the checklist in PLUGINS.md.
The idea is a dim living room at night with one bright thing in it. The backdrop is dark velvet and the focused tile is the lamp: its artwork's own colour spills onto the wall and glows around it, the tiles beside it lift as if lit from the side, and after a minute without the remote the lights go down. Ten themes change the walls and the lamp and nothing else.
Type is Bricolage Grotesque and Figtree, both bundled, the three sounds are rendered rather than sampled, and the mark is a plush coral sofa. Reduced motion follows the system or your choice, and Lite mode turns the shader and the spill off for a TV that needs it. The whole system is written down in DESIGN.md.
Download Lounge-<version>.apk from the Releases page, or build it yourself
(below). It runs on Android TV and Google TV from Android 9.
- Copy the APK onto a USB stick and plug it into the TV.
- Open the APK with a file manager on the TV. Google TV has none built in, but any from the Play Store will do. The first time, Android asks you to let that file manager install apps.
- Open Lounge. Its setup makes it the home screen through Power Setup: when it asks, turn on USB debugging in Developer options, then choose Allow on the TV's prompt and tick Always allow.
No USB stick? Install Downloader from the Play Store, open
github.com/Gingerbreadfork/lounge/releases in it, choose the APK, and carry on from step 3.
With USB debugging on and a computer on the same network, this installs Lounge and makes it the home screen; press Home and its setup starts:
adb connect <tv>:5555
adb install -r Lounge-<version>.apk
adb shell cmd package set-home-activity tv.lounge.launcher/.MainActivityOn Google TV the stock home and its setup app outrank any home you choose, so switch them off
too. They stay installed, and pm enable with the same names brings them back; do that before
you uninstall Lounge, or the TV is left without a home screen.
adb shell pm disable-user --user 0 com.google.android.apps.tv.launcherx
adb shell pm disable-user --user 0 com.google.android.tungsten.setupwraithPower Setup does all of this from the TV as well, and can undo it. It also grants the optional accesses, drives the TV over HDMI-CEC, sets the screensaver and compiles Lounge ahead of time, showing each command before it runs.
Lounge checks the Releases page twice a day, verifies a newer APK against its published hash and installs it while you are in another app. From Android 12 there is no prompt after the first update, and with Power Setup there is none at all; otherwise a tile on the home screen offers it. On Google TV, Play Protect may warn the first time that it does not know the developer: choose More details, then Install anyway. Settings, Updates turns the check off, if you would rather manage updates yourself with Obtainium pointed at this repository.
The shell is Kotlin and Compose for TV. Everything that decides what to show is a Rust core behind a UniFFI boundary: a graph of apps, programmes, channels and inputs with their usage, ranking into the Stage and the rows, a SQLite store, and an artwork pipeline that decodes each picture once and writes every size the screen needs. Plugins run in wasmi inside that core. The companion is an axum server in the same process, with the Svelte 5 app embedded at build time, about 30 KB gzipped.
The APK is 19 MB. On a Google TV Streamer the release build is on screen in about a second
from a cold start, sits a little over 100 MB, and keeps the main thread under 5 ms on nine
frames out of ten while you move around. A TCL television with a Mali GPU runs the same build
at about 75 MB and is bound by its GPU rather than its CPU. Both are measured with the scripts
in tools/.
Lounge reaches only what you gave it an address for, the artwork the TV's other apps publish, and GitHub twice a day for updates. There are no accounts and no analytics.
You need JDK 21, the Android SDK with platform 37 and NDK 27, stable Rust with cargo-ndk and
the wasm32-unknown-unknown target, cmake, a C compiler and zlib's headers for the bundled
image libraries, and Node 24 with pnpm 10.
rustup target add wasm32-unknown-unknown aarch64-linux-android armv7-linux-androideabi
cargo install cargo-ndk
(cd companion && pnpm install)
tools/plugins/build.sh # bundles and signs the built-in plugins into app assets
cd android && ./gradlew :app:assembleReleaseGradle runs the Rust and web builds itself: it compiles the core for both ABIs with cargo-ndk,
generates the Kotlin bindings, and builds the companion with pnpm when node_modules is
present. The plugin publisher key is created on first use at ~/.config/lounge/publisher.key
and never enters the tree.
There are three build types: debug installs beside a release as tv.lounge.launcher.debug,
release is shrunk with R8 and carries a baseline profile, and profile exists only to capture
that profile with tools/baseline-profile.sh. Release builds are signed with the debug key
unless lounge.storeFile, lounge.storePassword, lounge.keyAlias and lounge.keyPassword
are set in ~/.gradle/gradle.properties.
Every push builds and tests the whole thing on GitHub and keeps the APK as an artifact named
lounge-apk-debug-signed. It is signed with the debug key, so no release can update it once
installed. Pushing a tag publishes a release; docs/RELEASING.md has the
rules and the secrets it needs.
cd companion && pnpm install && pnpm build # once: the core embeds the phone app and needs it built
cd core && cargo test --workspace # the core: graph, ranking, colour, store, artwork, plugins
cd plugins && cargo test --workspace # the SDK and the built-in plugins
cd android && ./gradlew :power:testDebugUnitTest
cd companion && pnpm exec svelte-check
cd companion && LOUNGE_TV=http://<tv>:8787 pnpm dev # the phone app against a real TVOn a device, tools/drive.sh <serial> <out dir> walks a fixed path through the launcher and
saves a screenshot after every step, tools/framestats.sh <serial> prints per-phase frame times
for that path, and tools/baseline-profile.sh <serial> captures a fresh baseline profile from
the profile build. The scripts compile the installed build the way a real install ends up, so
frame times mean something.
android/ Gradle project: app, core/{bindings,design,platform}, collector/*, feature/home, power
core/ Rust workspace: lounge-core (UniFFI), -graph, -store, -artwork, -plugins, -companion
plugins/ Rust workspace: the plugin SDK, the built-in plugins, lgp-tool
companion/ Svelte 5 phone app, embedded into the core at build time
design/ fonts, the mark's sources and renderer, the sound renderer
docs/ the pictures in this file, and how to release
tools/ device drives, frame timing, the baseline profile, builds, the README's icons
workdir/ ignored by git: your own notes, logs and measurements
DESIGN.md is the design system every screen follows. PLUGINS.md is for writing a plugin.
MIT. The bundled fonts are under the SIL Open Font License; see design/fonts/.










