Add real-time CAVA audio visualizer for VU bars
CAVA runs in background via cava-start.sh, writing bar values to /tmp/skeledance_bars. A new QML DataSource polls that file at 80ms and calls updateBars() in JS. Falls back to rest state when not playing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b2df95ed10
commit
5876701a64
4 changed files with 61 additions and 17 deletions
|
|
@ -873,33 +873,30 @@ const VU_PALETTE = [
|
|||
'#00eebb','#00ddaa','#00cc99','#00bb88',
|
||||
];
|
||||
|
||||
const MAX_BAR_H = 70;
|
||||
|
||||
for (let i = 0; i < VU_COUNT; i++) {
|
||||
const bar = document.createElement('div');
|
||||
bar.className = 'vu-bar';
|
||||
bar.style.background = VU_PALETTE[i % VU_PALETTE.length];
|
||||
bar.style.boxShadow = `0 0 4px ${VU_PALETTE[i % VU_PALETTE.length]}`;
|
||||
bar._maxH = 15 + Math.random() * 55;
|
||||
bar._phase = Math.random() * Math.PI * 2;
|
||||
bar._speed = 1.5 + Math.random() * 4;
|
||||
bar.style.height = '3px';
|
||||
bar.style.opacity = '0.15';
|
||||
vuMeter.appendChild(bar);
|
||||
vuBars.push(bar);
|
||||
}
|
||||
|
||||
function animateVU(ts) {
|
||||
const t = ts * 0.001;
|
||||
vuBars.forEach(bar => {
|
||||
if (isPlaying) {
|
||||
const h = bar._maxH * Math.abs(Math.sin(t * bar._speed + bar._phase));
|
||||
bar.style.height = Math.max(3, h) + 'px';
|
||||
bar.style.opacity = 0.55 + 0.45 * (h / bar._maxH);
|
||||
} else {
|
||||
bar.style.height = '3px';
|
||||
bar.style.opacity = '0.15';
|
||||
}
|
||||
// Called by QML with semicolon-separated CAVA values (0–100 per bar)
|
||||
function updateBars(raw) {
|
||||
if (!isPlaying) return;
|
||||
const vals = raw.split(';');
|
||||
vuBars.forEach((bar, i) => {
|
||||
const v = Math.min(100, parseInt(vals[i] || 0, 10));
|
||||
const h = Math.max(3, (v / 100) * MAX_BAR_H);
|
||||
bar.style.height = h + 'px';
|
||||
bar.style.opacity = 0.3 + 0.7 * (v / 100);
|
||||
});
|
||||
requestAnimationFrame(animateVU);
|
||||
}
|
||||
requestAnimationFrame(animateVU);
|
||||
|
||||
/* ============================================================
|
||||
FLOATING MUSIC NOTES
|
||||
|
|
@ -943,8 +940,9 @@ function updateMusic(artist, title) {
|
|||
: (title || artist || '— —');
|
||||
const playing = !!(artist || title);
|
||||
isPlaying = playing;
|
||||
document.querySelector('.robot-wrap').style.opacity = playing ? '1' : '0';
|
||||
document.querySelector('.robot-wrap').style.opacity = playing ? '1' : '0';
|
||||
document.querySelector('.music-ticker').style.opacity = playing ? '1' : '0';
|
||||
if (!playing) vuBars.forEach(b => { b.style.height = '3px'; b.style.opacity = '0.15'; });
|
||||
if (el.textContent === text) return;
|
||||
el.textContent = text;
|
||||
if (playing) pickSkeleton();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue