diff --git a/README.md b/README.md
index d658d3ba..c65c9e2a 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,8 @@
A cross-platform extensible open-source music streaming platform.
-Bring your own music metadata/playlist/audio-source with plugins created by community or by yourself. A small step towards the decentralized music streaming era!
+Bring your own music metadata/playlist/audio-source with plugins created by community or by
+yourself. A small step towards the decentralized music streaming era!
@@ -17,16 +18,15 @@ Bring your own music metadata/playlist/audio-source with plugins created by comm
---

-

-
+****
## π Features
- π§© Plugin powered, supports any platform or custom music service through plugins.
- πΊοΈ Community driven plugins for popular platforms or create your own.
-- β¬οΈ Freely downloadable tracks with tagged metadata.
+- β¬οΈ Freely downloadable tracks with tagged **metadata**.
- π₯οΈ π± Cross-platform support.
- πͺΆ Small size & less data usage.
- π Time synced lyrics regardless of the plugin support.
@@ -41,132 +41,183 @@ Download Spotube from the Official Website: https://spotube.cc
### π Nightly Builds
-Grab the latest nightly builds of Spotube [from the Offical Website](https://spotube.cc/downloads/nightly).
-
-## π³οΈ Building from source
+Grab the latest nightly builds of
+Spotube [from the Offical Website](https://spotube.cc/downloads/nightly).
+
+
+π³οΈ Building from source [Click to expand]
+
-Spotube is a Kotlin Multiplatform + Compose Multiplatform app. The desktop app is built with the [Nucleus](https://nucleusframework.dev) Gradle plugin and released as a **GraalVM native image**: an ahead-of-time compiled binary that needs no JVM installed.
+Spotube is a Compose Multiplatform app.
-### Prerequisites
+### 1. Prerequisites
-- **JDK 21** to run Gradle. The Gradle daemon JDK and the GraalVM toolchain are provisioned automatically.
-- **Rust** (`rustup` + `cargo`). The `composeApp` Rust library is built through [Gobley](https://gobley.dev).
+- **JDK 21** to run Gradle (the Gradle daemon JDK and GraalVM are provisioned automatically).
+- **Rust** (`rustup` + `cargo`), for the `composeApp` library built
+ through [Gobley](https://gobley.dev).
- **Android SDK**, only for Android builds.
-- **Unpublished dependency.** One dependency isn't on Maven Central yet. Clone it and run `./gradlew publishToMavenLocal` in it:
- - [kdroidFilter/ComposeNativeWebview](https://github.com/kdroidFilter/ComposeNativeWebview), at the commit pinned in [`spotube-release-binary.yml`](.github/workflows/spotube-release-binary.yml) (`COMPOSE_WEBVIEW_COMMIT`)
-- **Linux runtime libraries** (needed to run the app, including `:composeApp:run`). The `.deb`/`.rpm` install these as dependencies from your distro. For a source build, install them yourself, **including VLC**. Only the `.AppImage` is self-contained (it bundles VLC, GTK 3 and WebKitGTK, and uses just the host's glibc, graphics, X11 and sound libraries):
+- **[ComposeNativeWebview](https://github.com/kdroidFilter/ComposeNativeWebview)**, which isn't on
+ Maven Central yet. Clone it at the commit pinned as `COMPOSE_WEBVIEW_COMMIT` in [
+ `spotube-release-binary.yml`](.github/workflows/spotube-release-binary.yml) and run
+ `./gradlew publishToMavenLocal` in it.
+- **Linux only: runtime libraries, including VLC.** Needed to run the app, including
+ `:composeApp:run`:
- | Distro | Command |
- |---|---|
- | Debian/Ubuntu | `sudo apt-get install libvlc5 vlc-plugin-base libwebkit2gtk-4.1-0 libgtk-3-0 libasound2 libgl1 libxtst6 libxi6 libxrender1` |
- | Fedora | `sudo dnf install vlc-libs webkit2gtk4.1 gtk3 alsa-lib mesa-libGL libXtst libXi libXrender`. `vlc-libs` is only in [RPM Fusion](https://rpmfusion.org/Configuration), so enable it first. |
- | Arch / CachyOS / Manjaro | `sudo pacman -S vlc webkit2gtk-4.1 gtk3 alsa-lib libglvnd libxtst libxi libxrender` |
- | openSUSE | `sudo zypper install libvlc5 libwebkit2gtk-4_1-0 libgtk-3-0 libasound2 Mesa-libGL1 libXtst6 libXi6 libXrender1` (for wide codec support, switch to the [Packman](https://en.opensuse.org/Additional_package_repositories#Packman) repo's VLC) |
+ | Distro | Command |
+ | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+ | Debian/Ubuntu | `sudo apt-get install libvlc5 vlc-plugin-base libwebkit2gtk-4.1-0 libgtk-3-0 libasound2 libgl1 libxtst6 libxi6 libxrender1` |
+ | Fedora | `sudo dnf install vlc-libs webkit2gtk4.1 gtk3 alsa-lib mesa-libGL libXtst libXi libXrender` (`vlc-libs` needs [RPM Fusion](https://rpmfusion.org/Configuration)) |
+ | Arch / CachyOS / Manjaro | `sudo pacman -S vlc webkit2gtk-4.1 gtk3 alsa-lib libglvnd libxtst libxi libxrender` |
+ | openSUSE | `sudo zypper install libvlc5 libwebkit2gtk-4_1-0 libgtk-3-0 libasound2 Mesa-libGL1 libXtst6 libXi6 libXrender1` |
- Arch-based distros and openSUSE have no native package here. Use the `.AppImage`. The `.rpm` is built with Fedora package names, so it won't resolve on openSUSE.
+ On Ubuntu 24.04+/Debian 13, `libgtk-3-0` and `libasound2` are `libgtk-3-0t64` and `libasound2t64`;
+ apt resolves this itself.
- On Ubuntu 24.04+/Debian 13 `libgtk-3-0` and `libasound2` are named `libgtk-3-0t64` and `libasound2t64`; apt resolves this automatically.
-
-Always use the Gradle wrapper (`./gradlew`, or `gradlew.bat` on Windows).
-
-### Development
+### 2. Run in development
+Desktop (JVM), fastest edit/run loop
```bash
-./gradlew :composeApp:run # desktop (JVM), fastest edit/run loop
-./gradlew :composeApp:assembleStableDebug # Android debug APK (or assembleNightlyDebug)
+./gradlew :composeApp:run
```
-Development builds stay fast. The release-only optimizations (the Rust release profile with LTO and symbol stripping, the native image, native-library pruning) are only applied when you build something to ship. See [Production vs development builds](#production-vs-development-builds).
+Android debug APK
+```bash
+./gradlew :composeApp:assembleStableDebug
+```
+> Use `./gradlew :composeApp:assembleNightlyDebug` for the nightly channel.
-### Building the desktop app (GraalVM native image)
+Development builds stay fast: the release-only optimizations below are skipped.
-#### Native toolchain
+### 3. Build the desktop app
-[Nucleus downloads and caches GraalVM CE](https://nucleusframework.dev/en/docs/performance/graalvm/) under `~/.gradle/nucleus/graalvm` on the first native build. Set `GRAALVM_HOME` to use your own GraalVM instead. Each OS also needs a native C toolchain:
+A native build takes **about 10 minutes**, uses **every CPU core** and peaks at **~15 GB of RAM**.
+It only happens for the tasks below, never for `run`.
-| OS | Requirements |
-|---|---|
-| Linux | `gcc`, `zlib` headers, `patchelf`; plus `rpm` for `.rpm` packages, `fuse` for `.AppImage`, and, for the AppImage's bundled libraries, `zstd` (plus `ar`/`tar` and `readelf`, from binutils). Debian/Ubuntu: `sudo apt-get install build-essential zlib1g-dev patchelf rpm fuse zstd`. Fedora: `sudo dnf install gcc zlib-devel patchelf rpm-build fuse zstd` (also install the [Linux runtime libraries](#prerequisites) to run what you build) |
-| macOS | Xcode Command Line Tools (`xcode-select --install`) |
-| Windows | Visual Studio Build Tools with the "Desktop development with C++" workload. Build from an "x64 Native Tools" prompt if `native-image` can't find MSVC. |
+**Native toolchain** (Nucleus downloads GraalVM CE on the first build; set `GRAALVM_HOME` to use
+your own):
-A native build is a whole-program compile. It takes **about 10 minutes**, uses **every CPU core**, and peaks at roughly **15 GB of RAM** (it gets slower, not broken, with less). That only happens for the native tasks below, never for `run`.
+| OS | Requirements |
+| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Linux | `gcc`, `zlib` headers, `patchelf`; `rpm` for `.rpm`, `fuse` + `zstd` for `.AppImage`.
Debian/Ubuntu: `sudo apt-get install build-essential zlib1g-dev patchelf rpm fuse zstd`.
Fedora: `sudo dnf install gcc zlib-devel patchelf rpm-build fuse zstd` |
+| macOS | Xcode Command Line Tools (`xcode-select --install`) |
+| Windows | Visual Studio Build Tools with "Desktop development with C++" (use an "x64 Native Tools" prompt if `native-image` can't find MSVC) |
-#### Build and run
+**Build and run the app folder:**
```bash
-# App folder: binary + its native libs, in composeApp/build/compose/binaries/main/graalvm-app/
./gradlew :composeApp:createGraalvmNativeDistributable
+```
+> Output folder: composeApp/build/compose/binaries/main/graalvm-app/
-# Run that folder's binary directly
-./composeApp/build/compose/binaries/main/graalvm-app/org.spotube.spotube/spotube
-
-# Or build and launch in one step
+Build and launch in one step
+```bash
./gradlew :composeApp:runGraalvmNativeDistributable
```
-Keep the `spotube` binary next to the `.so`/`.dll`/`lib/` files it was built with; it loads them from its own folder.
+Keep the `spotube` binary next to the libraries it was built with; it loads them from its own
+folder.
-#### Installers
+**Installers** (each OS builds only its own):
-Each OS can only build its own installers:
+| OS | Command |
+| ---------------- | ----------------------------------------------------------------------- |
+| Linux | `./gradlew :composeApp:packageGraalvmDeb :composeApp:packageGraalvmRpm` |
+| Linux (AppImage) | `./gradlew :composeApp:packageGraalvmAppImage -PappImage=true` |
+| Windows | `./gradlew :composeApp:packageGraalvmExe` (or `packageGraalvmMsi`) |
+| macOS | `./gradlew :composeApp:packageGraalvmDmg` |
+> Output folder: `composeApp/build/compose/binaries/main/graalvm-How the Linux AppImage bundle works
-The `.deb` and `.rpm` use your distro's shared libraries and declare them as dependencies, so the package manager installs them (on Fedora, `vlc-libs` needs RPM Fusion enabled). The `.AppImage` is the self-contained one: it bundles VLC, GTK 3 and WebKitGTK (see [What the AppImage bundles](#what-the-appimage-bundles)).
+- [`DownloadLinuxGtkBundleTask`](buildSrc/src/main/kotlin/org/spotube/gradle/DownloadLinuxGtkBundleTask.kt)
+ downloads the Ubuntu 24.04 packages (audio-only VLC via
+ [vlcj-bundler](https://github.com/team-spotube/vlcj-bundler-gradle-plugin), GTK 3, WebKitGTK 4.1,
+ glib-networking), keeps only what GTK/WebKit reach and relocates the libraries with `patchelf`.
+ Needs `ar`, `tar`, `zstd`, `readelf`, `patchelf`.
+- WebKitGTK has its helper-process path compiled in, so
+ [`AppImageEnvironment`](composeApp/src/jvmMain/kotlin/org/spotube/spotube/core/appimage/AppImageEnvironment.kt)
+ patches it to a relative path and moves to that directory at startup. It also sets
+ `GIO_EXTRA_MODULES` and `WEBKIT_DISABLE_DMABUF_RENDERER=1` (the bundled WebKitGTK 2.44 never
+ paints against a newer host Mesa).
+- `main()` must call `GraalVmInitializer.initialize()` first: the VLC loader and the environment
+ setup read `compose.application.resources.dir`.
-#### What the AppImage bundles
+