The apps
There is one product, and it is a web page. Every phone app is a thin shell around that same page, and code is written natively only where a web page cannot do the job: the audio on Android, and the whole of the Apple TV, which has no web view at all.
One web app, everywhere
The server embeds a single-page web app (internal/webui/assets): app.js
for the library, the player and settings, reader.js for books, and a small service
worker. A browser on a computer, a phone's home screen, the Android app, the iPhone app and an
Android TV all show exactly that page. A feature built once - a new radio station, a look for
Now Playing, a category pill - arrives on every one of them the moment the server is updated.
What a page cannot do is mostly about audio. A browser tab can be stopped when the phone locks, cannot always keep a lock-screen player, and on Android a web view has no Media Session API at all. Those are the gaps the native code fills, and nothing else.
What each app is
| App | What it is | Native parts |
|---|---|---|
| Web app | The page itself, in any browser. Installable to a home screen (a PWA) from the secure address. | None |
| Android | A Kotlin shell around the page (android/) | Songs play through Media3's ExoPlayer in a media session service; photo backup; the system bars and camera cutout |
| Android TV, Google TV, Fire TV | The same Android app; the page switches to a TV mode | As Android, plus a TV banner and launcher entry |
| iPhone | A Swift shell around the page (ios/SoundStorm) | Saved servers, dialogs, status bar, photo backup; native audio is the planned next stage |
| Apple TV | A native SwiftUI app (ios/SoundStormTV) talking to the same /api | Everything: tvOS has no web view |
All of them sign in with the same session cookie and speak the same HTTP API. None of them ever talks to a backend directly; every song, film and picture comes through the SoundStorm server.