Electron + TypeScript app that sideloads APKs, Windows apps, and Linux ARM64 builds onto a Steam Frame through Valve's SteamOS devkit protocol: devkit pairing or password SSH, mDNS headset discovery, upload and registration via Valve's vendored devkit-utils scripts, Lepton logcat streaming, and a light/dark UI with a browser mock for previews. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Frameloader
Drop an APK, a Windows app, or a Linux ARM64 build onto Frameloader and it shows up in your Steam Frame's library, under Non-Steam, ready to launch. Open source, cross-platform (macOS, Windows, Linux), and built on the same mechanism Valve's own SteamOS Devkit Client uses.
Drop it in. It's in your library.
How it works
Frameloader does not touch Steam's shortcut files or require anything installed on the headset beyond Developer Mode. It speaks Valve's SteamOS devkit protocol:
- Pairing. The headset runs a small pairing service on port 32000. Frameloader generates an RSA key, posts it to
/register, and you approve the request on the headset (Settings → Developer → Pair new host). From then on it logs in over SSH with that key. You can also connect with the Developer Mode password instead. - Upload. Valve's device-side helper scripts (
devkit-utils, MIT, vendored unmodified invendor/devkit-utils) are copied to~/devkit-utilson the headset.steamos-prepare-uploadcreates~/devkit-game/<id>/, and your files are copied there over SFTP. - Register.
steam-client-create-shortcuttells the running Steam client about the title and which runtime to use. Steam adds "Devkit Game: " to your library, no restart needed. - Launch.
steam-devkit-rpc run-gamestarts it, or you pick it from the headset's library.
| You drop | Runtime (Steam compat tool) | Status |
|---|---|---|
.apk (arm64-v8a, API ≤ 30) |
Lepton | Primary path. Each app runs in its own persistent Lepton container, so save data survives. |
Windows .exe or a zip/folder with one |
Proton Experimental or Proton (stable) | Works through FEX. Needs a Proton already installed on the headset. |
| Linux ARM64 build | Steam Linux Runtime 4 (ARM64) | Starts natively; self-contained builds only. |
| Linux x86-64 build | – | Refused: the Frame won't install the x86-64 runtime for sideloaded titles. |
For Android apps, Frameloader reads the manifest to pick a name and icon, refuses 32-bit-only and too-new APKs with a plain explanation, and writes Lepton's lepton-show-flatscreen marker for non-VR apps so they're actually visible. OBB files dropped with an APK go into obb/ next to it.
Using it
- On the headset: Steam Settings → System → Enable Developer Mode, then Settings → Developer → Set User Password.
- Open Frameloader. Headsets with Developer Mode on show up under "Found on your network" (they advertise Valve's devkit service over mDNS); click one, or type a hostname or IP. Click Pair with headset. Open Settings → Developer → Pair new host on the headset and approve.
- Drop a file. Check the name, pick a runtime if there's a choice, click Install to Frame.
Logs for Android titles stream straight into the app (row → Logs). The Activity drawer at the bottom shows every command sent to the headset.
Development
pnpm install
pnpm start # build and run Electron
pnpm dev # esbuild in watch mode (run `electron .` separately)
pnpm typecheck
pnpm test
pnpm dist:mac # or dist:win / dist:linux
The renderer can be previewed in a normal browser with simulated data: serve dist/ and open index.html?mock=connected (also fresh, empty, offline, nolepton, fail).
pnpm install must be allowed to run the electron and esbuild build scripts (see pnpm-workspace.yaml). If Electron's binary is missing, run node node_modules/electron/install.js.
Troubleshooting
- "Couldn't find frame.local." Frameloader resolves names itself over mDNS, then the OS resolver, then by browsing for the devkit service, then the last known IP. If all fail: the Frame is asleep (it drops off the network), Developer Mode is off, or the network blocks multicast (guest/isolated Wi-Fi). Typing the IP from Quick Settings always works.
- Pairing says the headset didn't answer. Steam must be sitting on the Pair new host screen while Frameloader asks.
- "Steam isn't running on the headset." Registration needs the Steam client up; put the headset on or wake it and try again.
- A 2D Android app launches but nothing shows. Reinstall with "Show a 2D window" on (Advanced).
- Lepton missing. Click Install next to the Lepton chip (it asks Steam to install app 3056000); confirm on the headset.
- Compat tool alias. Valve's current scripts expect
lepton. If your firmware wants a different name (older builds usedfauxdroid), add"compatToolOverrides": {"lepton": "lepton-stable"}to Frameloader'sconfig.jsonin its user-data folder.
Credits
- Valve's SteamOS Devkit Client (MIT) for the device-side scripts and the protocol.
- Lepton (MIT) for documenting how Android titles are launched.
- Frame Control (MIT) for field notes that verified each runtime on real hardware.
MIT licensed.