An unofficial Music Assistant player for LG webOS TVs. It shows the artwork, word-by-word lyrics and the queue, lets you browse and play from the remote, and draws MilkDrop visuals in time with whatever your speakers are playing.
Try the demo in a browser → It runs on made-up data. Use the arrow keys and Enter as the remote's arrows and OK, and Escape as Back; OK → Display switches between Visuals, Album and Lyrics.
Afterglow is independent of, and not endorsed by, Music Assistant or LG. It began as a fork of Michael Nestrud's viz-man.
What it does
- Album, Lyrics and Visuals views. Album shows the complete artwork with the song, artist and up next. Lyrics adds timed lyrics with the current line leading, word-by-word karaoke when the lyrics carry word timing, and paged plain lyrics otherwise. Visuals is MilkDrop on its own or with a track card; MilkDrop can also run behind the artwork and lyrics, or stop entirely.
- Lyrics from Music Assistant, with an online fallback. When Music Assistant has none, the TV looks the song up on LRCLIB itself (see Privacy). A per-TV Lyrics timing control moves the words up to 10 s earlier or later, and Retry lyrics asks again.
- Browse and Search. Recently played, favourite playlists, albums, songs and artists, radio stations, all playlists and albums (the whole library, read as you scroll), and search with the TV keyboard or voice. Play now, play next, add to the queue or start radio. Details goes to the playing song's album or artist.
- Audiobooks and podcasts. Browse them, Continue listening where you left off, change the speed and jump between chapters.
- Queue. Play, move and remove upcoming songs; shuffle, repeat, crossfade, keep playing when the queue ends, volume and sleep timer. Playing on picks the speaker; picking a silent one moves the music there and each speaker says what it plays. With the TV as a speaker, Join adds it to the music playing elsewhere and Move here brings that music to the TV. Speakers together joins or leaves a sync group and sets each member's own volume.
- Idle poster. With nothing playing, the paused song, books and episodes in progress, or recent music is set as a poster, one OK away from playing; after a session it offers tonight's programme, which can be kept as a playlist.
- Playlists. Save the queue as a playlist, or add a song to one, named without a keyboard.
- Scan to save. Details shows a QR code that opens the playing song on your phone, on the streaming service it came from.
- Check my setup. A pass/fail list (Music Assistant, sign-in, the TV's speaker, the MilkDrop Visualizer plugin, online lyrics, the preset scan), each failure with one plain next step.
- Presets. 395 MilkDrop presets (through Music Assistant's fork of Butterchurn), driven by the waveform Music Assistant streams a few seconds ahead, so the picture lands on the beat. Scan presets measures each one on your TV and keeps a list of the ones it runs smoothly. Presets can take their colours from the artwork. Favourites are shared with Music Assistant's own MilkDrop favourites and between your TVs.
- Remote keys. Play/pause, Stop (pauses), fast-forward and rewind (next and previous track), plus the colour keys; see Settings and remote keys.
- Play on this TV. Optionally the TV is a Music Assistant speaker through Sendspin, so one app both sounds and draws.
- Kind to OLEDs. Holds the screensaver off only while music plays and drifts the picture against burn-in.
Requirements
- An LG webOS TV with WebGL2 (2020 models onward, webOS 5 or later; tested on an LG OLED C1, webOS 6), either rooted with the Homebrew Channel or in Developer Mode.
- Music Assistant 2.10 or newer on the same network, with the MilkDrop Visualizer plugin added (Settings → Plugins): it streams the waveform the visuals are drawn from.
- For the visuals, speakers Music Assistant streams to itself (Sonos, Chromecast, AirPlay, Squeezelite, ...). A speaker playing on its own, such as Spotify straight from the Spotify app, carries nothing to draw.
Status: Afterglow runs every day on a rooted 2021 LG C1 (webOS 6). The Homebrew Channel listing and installs on other TVs and webOS versions haven't been tried yet. Long sessions on the C1 have shown native memory growing in an aged web runtime, which is under investigation (see Performance). Reports either way are very welcome.
Install
Download io.github.haydengriffin.afterglow_<version>_all.ipk from the
releases, or build it
(below). Then either:
- Homebrew Channel (rooted TV): install the
.ipkfrom a URL. From a checkout,npm run serve-ipkservesdist/and prints the URL to enter. - Developer Mode:
npx ares-install --device <name> dist/io.github.haydengriffin.afterglow_<version>_all.ipk.
Open Afterglow and sign in with your Music Assistant address, username and password. The TV keeps its own long-lived token, named after the TV, which you can revoke in Music Assistant or with Log out; the password is not stored. Then run Scan presets once. The setup guide walks through every step.
Settings
Press OK for the playback controls: a transport row with Display and Details, and a top strip with Browse, Now playing, Queue and Settings (sound and sync, display, presets, performance, account). Per-TV settings live on the TV; favourites and shared preferences sync through your Music Assistant account. See Settings and remote keys, The preset scan and Performance.
Privacy
Afterglow talks to your Music Assistant server. Artwork comes through Music Assistant's image proxy, falling back to the image's own address when the proxy has none. The other exception is lyrics. They come from Music Assistant; when it has none for a song, the TV asks lrclib.net directly, sending the song's title and artist (the album and length are only used on the TV to pick the best match). Choose other lyrics sends the same search, and a song whose lyrics you chose is fetched by that LRCLIB record's id. LRCLIB sees the request coming from your network. Turn Online lyrics off (OK → Display → Lyrics, shown in the Lyrics view) to stop it; it is on by default and synced with your other TVs.
Check my setup asks lrclib.net for one fixed record (no song, nothing about you) to see that it answers, only when you run it and Online lyrics is on. The Scan to save code in Details is drawn on the TV from the link Music Assistant already has; nothing is sent.
The TV stores its Music Assistant token in the app's own storage, never your password. There is no analytics or telemetry. The browser demo requests nothing but its own files.
Development
npm install
npm test
npm run package # dist/io.github.haydengriffin.afterglow_<version>_all.ipk
# and dist/io.github.haydengriffin.afterglow.manifest.jsonnpm run dev serves the app in a desktop browser; ?mock=1 runs it on demo data without Music Assistant, which is
what the browser demo is (built by
.github/workflows/pages.yml). The README images are rendered from the demo by
scripts/showcase.mjs with Playwright. See Development and the
changelog.
Support
Afterglow is free and open source. If it made your setup better, you can buy me a coffee. Bug reports and pull requests are just as welcome.
Credits
- viz-man by Michael Nestrud (MIT), the project Afterglow grew from.
- Butterchurn by Jordan Berg, in Music Assistant's fork (MIT), with the code its build inlines: eel-wasm by Jordan Eldredge (MIT), ecma-proposal-math-extensions by Rick Waldron (MIT) and @assemblyscript/loader (Apache-2.0).
- butterchurn-presets (MIT), and the MilkDrop preset authors.
- sendspin-js (Apache-2.0).
- QR Code generator by Project Nayuki (MIT), for Scan to save.
- Archivo typeface (SIL OFL 1.1).
- Lyrics fallback by LRCLIB.
Full notices are in NOTICE and app/THIRD_PARTY.md.
Licence
MIT, by Hayden Griffin. See LICENSE.


