feat(visualizer): visualizer dimming

This commit is contained in:
Samidy 2026-03-08 02:55:51 +03:00
parent 3685e33b48
commit 4762dea607
6 changed files with 83 additions and 2 deletions

View file

@ -119,7 +119,9 @@
<div id="fullscreen-cover-overlay" style="display: none">
<div class="fullscreen-cover-content">
<canvas id="visualizer-canvas"></canvas>
<div id="visualizer-container">
<canvas id="visualizer-canvas"></canvas>
</div>
<button id="toggle-ui-btn" class="fullscreen-ui-toggle" title="Toggle UI">
<svg
xmlns="http://www.w3.org/2000/svg"
@ -3743,6 +3745,31 @@
>
</div>
</div>
<div class="setting-item" id="visualizer-dimming-setting">
<div class="info">
<span class="label">Visualizer Brightness</span>
<span class="description"
>Adjust the brightness of the visualizer. Lower this if the visualizer
is too bright for you.</span
>
</div>
<div style="display: flex; align-items: center; gap: 10px">
<input
type="range"
id="visualizer-dimming-slider"
min="0.1"
max="1.0"
step="0.05"
value="1.0"
style="width: 100px"
/>
<span
id="visualizer-dimming-value"
style="font-size: 0.9rem; min-width: 3em; text-align: right"
>100%</span
>
</div>
</div>
<!-- Butterchurn Settings -->
<div class="setting-item" id="butterchurn-cycle-setting" style="display: none">
<div class="info">

View file

@ -2110,6 +2110,23 @@ export function initializeSettings(scrobbler, player, api, ui) {
});
}
const visualizerDimmingSlider = document.getElementById('visualizer-dimming-slider');
const visualizerDimmingValue = document.getElementById('visualizer-dimming-value');
if (visualizerDimmingSlider && visualizerDimmingValue) {
const currentDimming = visualizerSettings.getDimAmount();
visualizerDimmingSlider.value = currentDimming;
visualizerDimmingValue.textContent = `${(currentDimming * 100).toFixed(0)}%`;
visualizerDimmingSlider.addEventListener('input', (e) => {
const newDimming = parseFloat(e.target.value);
visualizerSettings.setDimAmount(newDimming);
visualizerDimmingValue.textContent = `${(newDimming * 100).toFixed(0)}%`;
window.dispatchEvent(
new CustomEvent('visualizer-dim-change', { detail: { dimAmount: newDimming } })
);
});
}
// Visualizer Smart Intensity
const smartIntensityToggle = document.getElementById('smart-intensity-toggle');
if (smartIntensityToggle) {

View file

@ -763,6 +763,7 @@ export const visualizerSettings = {
MODE_KEY: 'visualizer-mode', // 'solid' or 'blended'
PRESET_KEY: 'visualizer-preset',
BUTTERCHURN_CYCLE_KEY: 'butterchurn-cycle-duration',
DIM_AMOUNT_KEY: 'visualizer-dim-amount',
getPreset() {
try {
@ -828,6 +829,20 @@ export const visualizerSettings = {
localStorage.setItem(this.SMART_INTENSITY_KEY, enabled);
},
getDimAmount() {
try {
const val = localStorage.getItem(this.DIM_AMOUNT_KEY);
if (val === null) return 1.0;
return parseFloat(val);
} catch {
return 1.0;
}
},
setDimAmount(value) {
localStorage.setItem(this.DIM_AMOUNT_KEY, value);
},
// Butterchurn preset cycle duration in seconds
getButterchurnCycleDuration() {
try {

View file

@ -120,6 +120,12 @@ export class UIRenderer {
window.addEventListener('theme-changed', () => {
this.updateGlobalTheme();
});
window.addEventListener('visualizer-dim-change', () => {
if (this.visualizer) {
this.visualizer.updateDimming();
}
});
}
// Helper for Heart Icon

View file

@ -51,6 +51,12 @@ export class Visualizer {
this._resizeBound = () => this.resize();
}
updateDimming() {
if (!this.canvas || !this.canvas.parentElement) return;
const dimAmount = visualizerSettings.getDimAmount();
this.canvas.parentElement.style.opacity = dimAmount.toString();
}
get activePreset() {
return this.presets[this.activePresetKey] || this.presets['lcd'];
}
@ -150,6 +156,8 @@ export class Visualizer {
this.audioContext.resume();
}
this.updateDimming();
// Set canvas dimensions before preset init so WebGL framebuffers are created at correct size
this.resize();
window.addEventListener('resize', this._resizeBound);

View file

@ -3483,13 +3483,21 @@ input:checked + .slider::before {
transition: background-image var(--transition);
}
#visualizer-canvas {
#visualizer-container {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
z-index: 0;
pointer-events: none;
transition: opacity 0.3s ease;
}
#visualizer-canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.fullscreen-cover-content {