fix: crossfade now-playing background instead of hard flash

Two-layer opacity crossfade replaces the broken background-image transition.
New image loads on the hidden layer, then both opacity values swap smoothly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-04-28 09:29:54 +02:00
1 parent e75d90e165
commit 97a4cc756d
3 files changed
+17 -5

No files matched your search

+2 -1
View File
@@ -613,7 +613,8 @@
<!-- NOW PLAYING OVERLAY --> <!-- NOW PLAYING OVERLAY -->
<div class="np-overlay" id="np-overlay"> <div class="np-overlay" id="np-overlay">
<div class="np-bg" id="np-bg"></div> <div class="np-bg" id="np-bg-a"></div>
<div class="np-bg" id="np-bg-b" style="opacity:0"></div>
<div class="np-inner"> <div class="np-inner">
<div class="np-topbar"> <div class="np-topbar">
<button class="np-close" onclick="closeNowPlaying()" title="Schließen"> <button class="np-close" onclick="closeNowPlaying()" title="Schließen">
+13 -2
View File
@@ -57,17 +57,28 @@ export function updatePlayerUI(s) {
_syncNpDirect(s); _syncNpDirect(s);
} }
let _npBgCurr = 'a';
function _crossfadeNpBg(cv) {
const currEl = document.getElementById(`np-bg-${_npBgCurr}`);
const nextId = _npBgCurr === 'a' ? 'b' : 'a';
const nextEl = document.getElementById(`np-bg-${nextId}`);
if (!currEl || !nextEl) return;
nextEl.style.backgroundImage = cv ? `url('${cv}')` : 'none';
nextEl.style.opacity = '1';
currEl.style.opacity = '0';
_npBgCurr = nextId;
}
export function _syncNpDirect(s) { export function _syncNpDirect(s) {
if(!S.npOpen || !s) return; if(!S.npOpen || !s) return;
const cv = coverUrl(s.coverArt, 400); const cv = coverUrl(s.coverArt, 400);
const cover = document.getElementById('np-cover'); const cover = document.getElementById('np-cover');
const bg = document.getElementById('np-bg');
if (cover) { if (cover) {
const existingImg = cover.querySelector('img'); const existingImg = cover.querySelector('img');
if (cv && existingImg) existingImg.src = cv; if (cv && existingImg) existingImg.src = cv;
else if (cover) cover.innerHTML = cv ? `<img src="${cv}" style="width:100%;height:100%;object-fit:cover">` : '<div class="no-art">♪</div>'; else if (cover) cover.innerHTML = cv ? `<img src="${cv}" style="width:100%;height:100%;object-fit:cover">` : '<div class="no-art">♪</div>';
} }
if(bg) bg.style.backgroundImage = cv ? `url('${cv}')` : 'none'; _crossfadeNpBg(cv);
const t = document.getElementById('np-title'); if(t) t.textContent = s.title || '—'; const t = document.getElementById('np-title'); if(t) t.textContent = s.title || '—';
const an = document.getElementById('np-artist-name'); const an = document.getElementById('np-artist-name');
if(an) { if(an) {
+2 -2
View File
@@ -508,13 +508,13 @@ nav{flex:1;overflow-y:auto;padding:4px 10px}
} }
.np-overlay.open{transform:translateY(0)} .np-overlay.open{transform:translateY(0)}
/* Blurred album art as background */ /* Blurred album art as background — two layers for crossfade */
.np-bg{ .np-bg{
position:absolute;inset:-40px; position:absolute;inset:-40px;
background-size:cover;background-position:center; background-size:cover;background-position:center;
filter:blur(60px) brightness(.35) saturate(1.4); filter:blur(60px) brightness(.35) saturate(1.4);
transform:scale(1.1); transform:scale(1.1);
transition:background-image .6s ease; transition:opacity .55s ease;
z-index:0; z-index:0;
} }