From 5f297c4c2166293a4cbae15a893d44aab9adcf7a Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 1 Jun 2026 20:03:48 -0400 Subject: [PATCH] feat(web): dominant-color accent strip on PlayerBar + bigger Home tiles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #9 — new lib/media/dominantColor.ts: load cover image, downsample to 1x1 canvas, read pixel. Approximates the dominant tone via the browser's bilinear mean — close enough for an ambient accent without the 5KB ColorThief dependency. Same-origin cover URLs so no CORS dance. Result cached by URL so revisits are free. PlayerBar samples the current track's cover and pipes the resulting rgb into a 2px accent strip above both the compact and desktop variants. Transparent until the first resolve; 300ms transition on colour change so track-skips fade rather than snap. #10 — slight bump to Home tile widths so a typical viewport shows roughly 5-6 across instead of cramming 8-9: Playlists w-56, all remaining AlbumCard rows w-48 (Recently Added + both Rediscover album scrollers). Replaces the wave-2 sizes that were still showing 7-8 across on wider screens. --- web/src/lib/components/PlayerBar.svelte | 36 +++++++++++++++++ web/src/lib/media/dominantColor.ts | 53 +++++++++++++++++++++++++ web/src/routes/+page.svelte | 7 ++-- 3 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 web/src/lib/media/dominantColor.ts diff --git a/web/src/lib/components/PlayerBar.svelte b/web/src/lib/components/PlayerBar.svelte index 68caddcf..fc9bdc0a 100644 --- a/web/src/lib/components/PlayerBar.svelte +++ b/web/src/lib/components/PlayerBar.svelte @@ -13,6 +13,7 @@ } from '$lib/player/store.svelte'; import { formatDuration } from '$lib/media/duration'; import { FALLBACK_COVER, coverUrl } from '$lib/media/covers'; + import { dominantColorFromUrl, rgbToCssString } from '$lib/media/dominantColor'; import LikeButton from './LikeButton.svelte'; import TrackMenu from './TrackMenu.svelte'; @@ -44,6 +45,24 @@ function onCoverError(e: Event) { (e.currentTarget as HTMLImageElement).src = FALLBACK_COVER; } + + // #9 — dominant-color accent. Sample the current track's cover and + // pipe it into a CSS custom property; a 2px strip above the bar + // takes on the colour, so the page subtly tracks what's playing. + // Cache-backed in dominantColorFromUrl so revisits are free. + // Default ('') keeps the strip transparent until the first cover + // resolves. + let accentRgb = $state(''); + $effect(() => { + const cover = current?.album_id ? coverUrl(current.album_id) : null; + if (!cover) { + accentRgb = ''; + return; + } + dominantColorFromUrl(cover).then((rgb) => { + if (rgb) accentRgb = rgbToCssString(rgb); + }); + }); {#if current} @@ -59,6 +78,16 @@ Play controls maintain 40/48/40 size; like+kebab and column-3 sub-rows are shorter so column 2's bottom edge aligns with column 3's bottom. --> + +
+ +