From ada81dddd0b8efd4e608490337c58d7cf69b070e Mon Sep 17 00:00:00 2001 From: cottongin Date: Wed, 18 Mar 2026 11:13:16 -0400 Subject: [PATCH] docs: add design doc for heavy blur background replacement Replace Cloudy with Coil BlurTransformation for unblurred album art issue. Made-with: Cursor --- ...2026-03-18-heavy-blur-background-design.md | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 docs/plans/2026-03-18-heavy-blur-background-design.md diff --git a/docs/plans/2026-03-18-heavy-blur-background-design.md b/docs/plans/2026-03-18-heavy-blur-background-design.md new file mode 100644 index 0000000..4fa140c --- /dev/null +++ b/docs/plans/2026-03-18-heavy-blur-background-design.md @@ -0,0 +1,48 @@ +# Design: Heavy Blur Background via Coil BlurTransformation + +**Date:** 2026-03-18 +**Status:** Approved + +## Problem + +The player screen's blurred album art background uses the Cloudy library at its maximum radius of 25. This is insufficient — album art with text remains legible and fine details are still visible, breaking the intended "washed out background" aesthetic. + +## Solution + +Replace Cloudy with a self-contained Stackblur `BlurTransformation` applied via Coil's image loading pipeline. Blur is baked into the decoded bitmap on a background thread, producing a heavily smeared result with no legible text or sharp edges. + +## Changes + +### 1. Add `BlurTransformation.kt` + +Create `app/src/main/java/xyz/cottongin/radio247/ui/util/BlurTransformation.kt`. + +A ~130-line pure Kotlin + Android bitmap Stackblur implementation (no new library dependency). Accepts: +- `radius: Int` — blur radius (25 is already very aggressive at low scale) +- `scale: Float` — downsample factor applied before blurring (0.1f = 10% of original size) + +### 2. Update `BlurredBackground` in `NowPlayingScreen.kt` + +- Remove `.cloudy(radius = 25)` modifier +- Remove `size(10, 10)` from the `ImageRequest` (scale parameter in the transformation handles downsampling) +- Add `transformations(BlurTransformation(radius = 25, scale = 0.1f))` to the `ImageRequest` +- Remove Cloudy import + +### 3. Remove Cloudy dependency + +- Remove `implementation(libs.cloudy)` from `app/build.gradle.kts` +- Remove `cloudy` version and library entries from `gradle/libs.versions.toml` + +## Parameters + +| Parameter | Value | Rationale | +|-----------|-------|-----------| +| `radius` | 25 | Maximum effective Stackblur radius before diminishing returns | +| `scale` | 0.1f | Downsamples to 10% before blurring, destroying fine detail and text | + +## Trade-offs + +- **No new dependency** — implementation is inlined as a project file +- **All API levels** — pure bitmap manipulation, no RenderEffect/RenderScript +- **Background thread** — blur computed by Coil pipeline, zero per-frame GPU cost +- **Not animatable** — blur is baked at load time; cannot be animated at runtime (acceptable for this use case)