diff --git a/plugins/radiant-lyrics-luna/README.md b/plugins/radiant-lyrics-luna/README.md deleted file mode 100644 index 978446d..0000000 --- a/plugins/radiant-lyrics-luna/README.md +++ /dev/null @@ -1,83 +0,0 @@ -# Radiant Lyrics Luna Plugin - -A plugin for Luna (Tidal Desktop) that adds enhanced lyrics styling, cover art backgrounds, and UI management features. - -## Features - -### ✨ Lyrics Glow Effect -- Beautiful glowing effect for lyrics with custom font styling -- Can be toggled on/off in settings - -### 🎨 Cover Everywhere (Performance Optimized) -- Apply spinning cover art background to the entire app -- **NEW: Ultra-performance mode** with significant optimizations: - - Reduced blur effects (max 20px in performance mode) - - Smaller image sizes (640x640 vs 1280x1280) - - Static backgrounds (no animations) - - Optimized GPU usage with hardware acceleration - - DOM element reuse to prevent memory leaks - - Throttled updates (max once per 500ms) - - Adaptive polling for track changes - -### 🔧 Performance Mode Features -When enabled, Performance Mode provides: -- **Blur Reduction**: Caps blur at 20px instead of up to 200px -- **Image Optimization**: Uses 640x640 resolution instead of 1280x1280 -- **Animation Disable**: Removes all CSS animations for static backgrounds -- **Memory Optimization**: Better DOM element management and cleanup -- **GPU Optimization**: Reduces `will-change` properties and backdrop-filter effects -- **Size Reduction**: Smaller background image dimensions (120vw vs 150vw for global, 80vw vs 90vw for Now Playing) - -### 🎛️ UI Management -- Hide/unhide UI functionality with smooth transitions -- Player bar visibility control when UI is hidden -- Customizable background effects (blur, brightness, contrast, spin speed) - -## Technical Improvements - -### Performance Optimizations (Latest Update) -1. **DOM Element Reuse**: Background elements are created once and reused instead of being recreated on every track change -2. **Update Throttling**: Cover art updates are throttled to prevent excessive DOM manipulation -3. **Adaptive Polling**: Track change detection starts fast and slows down when no changes occur -4. **Hardware Acceleration**: Added GPU acceleration hints for smoother animations -5. **Memory Management**: Proper cleanup of cached DOM elements -6. **CSS Optimizations**: Better use of `transform3d` and `backface-visibility` for GPU rendering - -### Normal Mode Performance Enhancements -Even without Performance Mode enabled, the plugin now includes significant optimizations: -- **Optimized Filter Order**: Reordered CSS filters for better GPU performance (`contrast` → `brightness` → `blur`) -- **CSS Custom Properties**: Dynamic filter updates use CSS variables to avoid style recalculation -- **Transform3D**: All transforms use `translate3d()` for better GPU acceleration -- **Image Caching**: LRU cache for cover art images (max 10 images) for instant loading -- **Preloading**: Smart image preloading with cache checking for smoother transitions -- **Enhanced GPU Layers**: Better use of `transform-style: preserve-3d` and `isolation: isolate` -- **Optimized Animations**: Improved keyframe animations with `cubic-bezier` timing -- **Backdrop-Filter Optimization**: More efficient backdrop-filter usage with hardware acceleration -- **Compositing Hints**: Added `contain: layout style paint` for better rendering isolation - -### Browser Compatibility -- Respects `prefers-reduced-motion` for accessibility -- Optimized for modern browsers with hardware acceleration support - -## Settings - -- **Lyrics Glow Effect**: Toggle the enhanced lyrics styling -- **Hide UI Feature**: Enable hide/show UI functionality -- **Player Bar Visibility**: Keep player bar visible when UI is hidden -- **Cover Everywhere**: Apply cover art background to entire app -- **Performance Mode**: Enable ultra-light performance optimizations -- **Background Controls**: Adjust contrast (0-200), blur (0-200), brightness (0-100) -- **Spin Speed**: Control rotation speed (10-120 seconds per rotation) -- **Settings Affect Now Playing**: Apply background settings to Now Playing view - -## Performance Recommendations - -- Enable **Performance Mode** if you experience lag or high GPU usage -- Reduce **Background Blur** setting for better performance -- Use lower **Background Contrast** values on slower systems -- Consider disabling **Cover Everywhere** on very low-end systems - -## Credits - -- Heavily inspired by Cover-Theme by @Inrixia -- Thanks to the Luna development team for the plugin framework \ No newline at end of file diff --git a/plugins/radiant-lyrics-luna/src/Settings.tsx b/plugins/radiant-lyrics-luna/src/Settings.tsx index beba782..b0029ef 100644 --- a/plugins/radiant-lyrics-luna/src/Settings.tsx +++ b/plugins/radiant-lyrics-luna/src/Settings.tsx @@ -77,7 +77,7 @@ export const Settings = () => { /> { console.log("Performance Mode:", checked ? "enabled" : "disabled"); diff --git a/plugins/radiant-lyrics-luna/src/cover-everywhere.css b/plugins/radiant-lyrics-luna/src/cover-everywhere.css index 14c12b3..a22d42a 100644 --- a/plugins/radiant-lyrics-luna/src/cover-everywhere.css +++ b/plugins/radiant-lyrics-luna/src/cover-everywhere.css @@ -9,10 +9,9 @@ z-index: -3; pointer-events: none; overflow: hidden; - /* Enhanced hardware acceleration */ - transform: translate3d(0, 0, 0); + /* Hardware acceleration */ + transform: translateZ(0); backface-visibility: hidden; - perspective: 1000px; } .global-spinning-black-bg { @@ -24,35 +23,29 @@ background: #000; z-index: -2; pointer-events: none; - /* Force GPU layer */ - transform: translateZ(0); } .global-spinning-image { position: absolute; left: 50%; top: 50%; - transform: translate3d(-50%, -50%, 0); + transform: translate(-50%, -50%); width: 150vw; height: 150vh; object-fit: cover; z-index: -1; filter: blur(80px) brightness(0.4) contrast(1.2) saturate(1); opacity: 1; - animation: spinGlobalOptimized 45s cubic-bezier(0, 0, 1, 1) infinite; + animation: spinGlobal 45s linear infinite; will-change: transform; - /* Enhanced hardware acceleration for smooth animations */ + /* Hardware acceleration */ transform-origin: center center; backface-visibility: hidden; - /* Optimized compositing */ - contain: layout style paint; } -/* Performance mode optimizations */ +/* Performance mode optimizations - keep spinning but optimize other aspects */ .global-spinning-image.performance-mode-static { - animation: none !important; - transform: translate3d(-50%, -50%, 0) !important; - will-change: auto !important; + /* Keep animation enabled in performance mode */ /* Lighter blur for performance */ filter: blur(20px) brightness(0.4) contrast(1.2) saturate(1) !important; /* Smaller size for performance */ @@ -61,9 +54,7 @@ } .now-playing-background-image.performance-mode-static { - animation: none !important; - transform: translate3d(-50%, -50%, 0) !important; - will-change: auto !important; + /* Keep animation enabled in performance mode */ /* Optimized size and effects for performance */ width: 80vw !important; height: 80vh !important; @@ -79,38 +70,19 @@ z-index: -3; pointer-events: none; overflow: hidden; - /* Enhanced hardware acceleration */ - transform: translate3d(0, 0, 0); - backface-visibility: hidden; - perspective: 1000px; -} - -/* OPTIMIZED keyframe animations with better GPU acceleration */ -@keyframes spinGlobalOptimized { - 0% { - transform: translate3d(-50%, -50%, 0) rotate(0deg); - } - 100% { - transform: translate3d(-50%, -50%, 0) rotate(360deg); - } -} - -@keyframes spin { - 0% { - transform: translate3d(-50%, -50%, 0) rotate(0deg); - } - 100% { - transform: translate3d(-50%, -50%, 0) rotate(360deg); - } -} - -/* Optimized backdrop-filter usage for better performance */ -.optimized-backdrop { - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - /* Force GPU acceleration for backdrop filters */ + /* Hardware acceleration */ transform: translateZ(0); - will-change: backdrop-filter; + backface-visibility: hidden; +} + +/* Optimized keyframe animations with GPU acceleration */ +@keyframes spinGlobal { + from { + transform: translate(-50%, -50%) rotate(0deg); + } + to { + transform: translate(-50%, -50%) rotate(360deg); + } } /* Reduced motion for users who prefer it */ @@ -118,35 +90,16 @@ .global-spinning-image, .now-playing-background-image { animation: none !important; - transform: translate3d(-50%, -50%, 0) !important; + transform: translate(-50%, -50%) !important; will-change: auto !important; } } -/* Performance mode: disable heavy effects */ +/* Performance mode: optimize effects but keep spinning */ .performance-mode .global-spinning-image, .performance-mode .now-playing-background-image { + /* Keep animations but optimize filter effects */ filter: blur(10px) brightness(0.4) contrast(1.1) !important; - animation: none !important; - will-change: auto !important; -} - -/* OPTIMIZED Normal mode styles for better performance without quality loss */ -body:not(.performance-mode) .global-spinning-image { - /* Use optimized filter order for better GPU performance */ - filter: contrast(var(--bg-contrast, 1.2)) brightness(var(--bg-brightness, 0.4)) blur(var(--bg-blur, 80px)) saturate(1); - /* Enhanced GPU acceleration */ - transform-style: preserve-3d; - /* Optimized compositing layer */ - isolation: isolate; -} - -body:not(.performance-mode) .now-playing-background-image { - /* Use optimized filter order */ - filter: contrast(var(--bg-contrast, 1.2)) brightness(var(--bg-brightness, 0.4)) blur(var(--bg-blur, 80px)); - /* Enhanced GPU acceleration */ - transform-style: preserve-3d; - isolation: isolate; } /* Make Notification Feed sidebar transparent */ @@ -171,7 +124,7 @@ main, background: unset !important; } -/* OPTIMIZED sidebar and player bar with better backdrop-filter performance */ +/* Make sidebar and player bar semi-transparent with optimized backdrop-filter */ [data-test="footer-player"], [data-test="main-layout-sidebar-wrapper"], [class^="_bar"], @@ -179,9 +132,6 @@ main, background-color: rgba(0, 0, 0, 0.3) !important; backdrop-filter: blur(10px) !important; -webkit-backdrop-filter: blur(10px) !important; - /* Force GPU acceleration for backdrop filters */ - transform: translateZ(0); - will-change: backdrop-filter; } /* Performance mode: reduce backdrop blur */ @@ -193,14 +143,11 @@ main, -webkit-backdrop-filter: blur(5px) !important; } -/* OPTIMIZED Feed sidebar panel */ +/* Feed sidebar panel - black tint background for readability */ [data-test="feed-sidebar"] { background-color: rgba(0, 0, 0, 0.5) !important; backdrop-filter: blur(10px) !important; -webkit-backdrop-filter: blur(10px) !important; - /* Enhanced GPU acceleration */ - transform: translateZ(0); - will-change: backdrop-filter; } /* Performance mode: reduce sidebar backdrop blur */ diff --git a/plugins/radiant-lyrics-luna/src/index.ts b/plugins/radiant-lyrics-luna/src/index.ts index 467a2d6..b3c34e5 100644 --- a/plugins/radiant-lyrics-luna/src/index.ts +++ b/plugins/radiant-lyrics-luna/src/index.ts @@ -30,10 +30,6 @@ let currentGlobalCoverSrc: string | null = null; let lastUpdateTime = 0; const UPDATE_THROTTLE = 500; // Throttle updates to max once per 500ms -// Image cache for better performance -const imageCache = new Map(); -const MAX_CACHE_SIZE = 10; // Limit cache size to prevent memory leaks - // Apply lyrics glow styles if enabled if (settings.lyricsGlowEnabled) { lyricsGlowStyleTag.css = lyricsGlow; @@ -193,60 +189,30 @@ const applyGlobalSpinningBackground = (coverArtImageSrc: string): void => { globalBackgroundContainer.appendChild(globalBackgroundImage); } - // Update image source efficiently with caching for smoother transitions + // Update image source efficiently if (globalBackgroundImage && globalBackgroundImage.src !== coverArtImageSrc) { - // Check cache first - if (imageCache.has(coverArtImageSrc)) { - globalBackgroundImage.src = coverArtImageSrc; - } else { - // Preload and cache the new image - const preloadImg = new Image(); - preloadImg.onload = () => { - // Add to cache (with size limit) - if (imageCache.size >= MAX_CACHE_SIZE) { - const firstKey = imageCache.keys().next().value; - if (firstKey) { - imageCache.delete(firstKey); - } - } - imageCache.set(coverArtImageSrc, preloadImg); - - if (globalBackgroundImage && globalBackgroundImage.src !== coverArtImageSrc) { - globalBackgroundImage.src = coverArtImageSrc; - } - }; - preloadImg.src = coverArtImageSrc; - } + globalBackgroundImage.src = coverArtImageSrc; } // Apply performance-optimized settings if (globalBackgroundImage) { // Performance mode optimizations if (settings.performanceMode) { - // Ultra-light performance mode + // Performance mode with spinning enabled globalBackgroundImage.style.width = '120vw'; globalBackgroundImage.style.height = '120vh'; globalBackgroundImage.style.filter = `blur(${Math.min(settings.backgroundBlur, 20)}px) brightness(${settings.backgroundBrightness / 100}) contrast(${Math.min(settings.backgroundContrast, 150)}%)`; - globalBackgroundImage.style.animation = 'none'; - globalBackgroundImage.style.transform = 'translate(-50%, -50%)'; - globalBackgroundImage.classList.add('performance-mode-static'); - // Remove will-change for better memory usage - globalBackgroundImage.style.willChange = 'auto'; + globalBackgroundImage.style.animation = `spinGlobal ${settings.spinSpeed}s linear infinite`; + globalBackgroundImage.classList.remove('performance-mode-static'); + globalBackgroundImage.style.willChange = 'transform'; } else { - // OPTIMIZED Normal mode - Better performance while maintaining quality + // Normal mode globalBackgroundImage.style.width = '150vw'; globalBackgroundImage.style.height = '150vh'; - // Use CSS custom properties for dynamic updates without style recalculation - globalBackgroundImage.style.setProperty('--bg-contrast', `${settings.backgroundContrast}%`); - globalBackgroundImage.style.setProperty('--bg-brightness', `${settings.backgroundBrightness / 100}`); - globalBackgroundImage.style.setProperty('--bg-blur', `${settings.backgroundBlur}px`); - globalBackgroundImage.style.animation = `spinGlobalOptimized ${settings.spinSpeed}s linear infinite`; + globalBackgroundImage.style.filter = `blur(${settings.backgroundBlur}px) brightness(${settings.backgroundBrightness / 100}) contrast(${settings.backgroundContrast}%)`; + globalBackgroundImage.style.animation = `spinGlobal ${settings.spinSpeed}s linear infinite`; globalBackgroundImage.classList.remove('performance-mode-static'); - // Use transform3d for better GPU acceleration globalBackgroundImage.style.willChange = 'transform'; - globalBackgroundImage.style.transformOrigin = 'center center'; - // Force GPU layer creation for smoother animations - globalBackgroundImage.style.transform = 'translate3d(-50%, -50%, 0)'; } } }; @@ -312,25 +278,19 @@ const updateRadiantLyricsNowPlayingBackground = function(): void { // Performance mode optimizations if (settings.performanceMode) { - // Reduce blur and effects for better performance + // Reduce blur and effects for better performance, but keep spinning blur = Math.min(blur, 20); contrast = Math.min(contrast, 150); - imgElement.style.animation = 'none'; - imgElement.style.transform = 'translate3d(-50%, -50%, 0)'; - imgElement.classList.add('performance-mode-static'); - imgElement.style.willChange = 'auto'; - imgElement.style.filter = `blur(${blur}px) brightness(${brightness / 100}) contrast(${contrast}%)`; - } else { - // OPTIMIZED Normal mode updates using CSS custom properties imgElement.style.animation = `spin ${spinSpeed}s linear infinite`; imgElement.classList.remove('performance-mode-static'); imgElement.style.willChange = 'transform'; - imgElement.style.transform = 'translate3d(-50%, -50%, 0)'; - // Use CSS custom properties for efficient updates - imgElement.style.setProperty('--bg-contrast', `${contrast}%`); - imgElement.style.setProperty('--bg-brightness', `${brightness / 100}`); - imgElement.style.setProperty('--bg-blur', `${blur}px`); + } else { + imgElement.style.animation = `spin ${spinSpeed}s linear infinite`; + imgElement.classList.remove('performance-mode-static'); + imgElement.style.willChange = 'transform'; } + + imgElement.style.filter = `blur(${blur}px) brightness(${brightness / 100}) contrast(${contrast}%)`; }); }; @@ -756,62 +716,32 @@ const updateCoverArtBackground = function (method: number = 0): void { nowPlayingBackgroundContainer.appendChild(nowPlayingGradientOverlay); } - // Update image source efficiently with caching + // Update image source efficiently if (nowPlayingBackgroundImage && nowPlayingBackgroundImage.src !== coverArtImageSrc) { - // Check cache first - if (imageCache.has(coverArtImageSrc)) { - nowPlayingBackgroundImage.src = coverArtImageSrc; - currentNowPlayingCoverSrc = coverArtImageSrc; - } else { - // Preload and cache the new image - const preloadImg = new Image(); - preloadImg.onload = () => { - // Add to cache (with size limit) - if (imageCache.size >= MAX_CACHE_SIZE) { - const firstKey = imageCache.keys().next().value; - if (firstKey) { - imageCache.delete(firstKey); - } - } - imageCache.set(coverArtImageSrc, preloadImg); - - if (nowPlayingBackgroundImage && nowPlayingBackgroundImage.src !== coverArtImageSrc) { - nowPlayingBackgroundImage.src = coverArtImageSrc; - currentNowPlayingCoverSrc = coverArtImageSrc; - } - }; - preloadImg.src = coverArtImageSrc; - } + nowPlayingBackgroundImage.src = coverArtImageSrc; + currentNowPlayingCoverSrc = coverArtImageSrc; } // Apply performance-optimized settings if (nowPlayingBackgroundImage) { if (settings.performanceMode) { - // Ultra-light performance mode + // Performance mode with spinning enabled nowPlayingBackgroundImage.style.width = '80vw'; nowPlayingBackgroundImage.style.height = '80vh'; const blur = Math.min(settings.backgroundBlur, 20); const contrast = Math.min(settings.backgroundContrast, 150); nowPlayingBackgroundImage.style.filter = `blur(${blur}px) brightness(${settings.backgroundBrightness / 100}) contrast(${contrast}%)`; - nowPlayingBackgroundImage.style.animation = 'none'; - nowPlayingBackgroundImage.style.transform = 'translate(-50%, -50%)'; - nowPlayingBackgroundImage.classList.add('performance-mode-static'); - nowPlayingBackgroundImage.style.willChange = 'auto'; - } else { - // OPTIMIZED Normal mode - Better performance while maintaining quality - nowPlayingBackgroundImage.style.width = '90vw'; - nowPlayingBackgroundImage.style.height = '90vh'; - // Use CSS custom properties for efficient dynamic updates - nowPlayingBackgroundImage.style.setProperty('--bg-contrast', `${settings.backgroundContrast}%`); - nowPlayingBackgroundImage.style.setProperty('--bg-brightness', `${settings.backgroundBrightness / 100}`); - nowPlayingBackgroundImage.style.setProperty('--bg-blur', `${settings.backgroundBlur}px`); nowPlayingBackgroundImage.style.animation = `spin ${settings.spinSpeed}s linear infinite`; nowPlayingBackgroundImage.classList.remove('performance-mode-static'); - // Enhanced GPU acceleration for smoother animations nowPlayingBackgroundImage.style.willChange = 'transform'; - nowPlayingBackgroundImage.style.transformOrigin = 'center center'; - // Force hardware acceleration with transform3d - nowPlayingBackgroundImage.style.transform = 'translate3d(-50%, -50%, 0)'; + } else { + // Normal mode + nowPlayingBackgroundImage.style.width = '90vw'; + nowPlayingBackgroundImage.style.height = '90vh'; + nowPlayingBackgroundImage.style.filter = `blur(${settings.backgroundBlur}px) brightness(${settings.backgroundBrightness / 100}) contrast(${settings.backgroundContrast}%)`; + nowPlayingBackgroundImage.style.animation = `spin ${settings.spinSpeed}s linear infinite`; + nowPlayingBackgroundImage.classList.remove('performance-mode-static'); + nowPlayingBackgroundImage.style.willChange = 'transform'; } } @@ -864,15 +794,10 @@ if (settings.performanceMode) { } updateCoverArtBackground(1); + // Add cleanup to unloads unloads.add(() => { cleanUpDynamicArt(); - - // Clean up spin animation style - const spinAnimationStyle = document.querySelector('#spinAnimation'); - if (spinAnimationStyle && spinAnimationStyle.parentNode) { - spinAnimationStyle.parentNode.removeChild(spinAnimationStyle); - } // Clean up auto-fade timeout if (unhideButtonAutoFadeTimeout) { @@ -891,9 +816,12 @@ unloads.add(() => { unhideButton.parentNode.removeChild(unhideButton); } + // Clean up spin animations + const spinAnimationStyle = document.querySelector('#spinAnimation'); + if (spinAnimationStyle && spinAnimationStyle.parentNode) { + spinAnimationStyle.parentNode.removeChild(spinAnimationStyle); + } + // Clean up global spinning backgrounds cleanUpGlobalSpinningBackground(); - - // Clear image cache - imageCache.clear(); }); \ No newline at end of file