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 id="fullscreen-cover-overlay" style="display: none">
<div class="fullscreen-cover-content"> <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"> <button id="toggle-ui-btn" class="fullscreen-ui-toggle" title="Toggle UI">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -3743,6 +3745,31 @@
> >
</div> </div>
</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 --> <!-- Butterchurn Settings -->
<div class="setting-item" id="butterchurn-cycle-setting" style="display: none"> <div class="setting-item" id="butterchurn-cycle-setting" style="display: none">
<div class="info"> <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 // Visualizer Smart Intensity
const smartIntensityToggle = document.getElementById('smart-intensity-toggle'); const smartIntensityToggle = document.getElementById('smart-intensity-toggle');
if (smartIntensityToggle) { if (smartIntensityToggle) {

View file

@ -763,6 +763,7 @@ export const visualizerSettings = {
MODE_KEY: 'visualizer-mode', // 'solid' or 'blended' MODE_KEY: 'visualizer-mode', // 'solid' or 'blended'
PRESET_KEY: 'visualizer-preset', PRESET_KEY: 'visualizer-preset',
BUTTERCHURN_CYCLE_KEY: 'butterchurn-cycle-duration', BUTTERCHURN_CYCLE_KEY: 'butterchurn-cycle-duration',
DIM_AMOUNT_KEY: 'visualizer-dim-amount',
getPreset() { getPreset() {
try { try {
@ -828,6 +829,20 @@ export const visualizerSettings = {
localStorage.setItem(this.SMART_INTENSITY_KEY, enabled); 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 // Butterchurn preset cycle duration in seconds
getButterchurnCycleDuration() { getButterchurnCycleDuration() {
try { try {

View file

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

View file

@ -51,6 +51,12 @@ export class Visualizer {
this._resizeBound = () => this.resize(); 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() { get activePreset() {
return this.presets[this.activePresetKey] || this.presets['lcd']; return this.presets[this.activePresetKey] || this.presets['lcd'];
} }
@ -150,6 +156,8 @@ export class Visualizer {
this.audioContext.resume(); this.audioContext.resume();
} }
this.updateDimming();
// Set canvas dimensions before preset init so WebGL framebuffers are created at correct size // Set canvas dimensions before preset init so WebGL framebuffers are created at correct size
this.resize(); this.resize();
window.addEventListener('resize', this._resizeBound); window.addEventListener('resize', this._resizeBound);

View file

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