Compare commits

...

10 Commits

8 changed files with 1291 additions and 1534 deletions
+1 -1
View File
@@ -494,7 +494,7 @@
// 模式0:频谱柱状图(居中对称 + 镜像)
function drawSpectrum() {
const barCount = bufferLength / 2;
const barCount = bufferLength; // 使用全部频段 bin,保留高频
const barWidth = (width * 0.8) / barCount;
const gap = 2;
const maxBarHeight = height * 0.35;
File diff suppressed because it is too large Load Diff
-17
View File
@@ -205,17 +205,6 @@
margin: 0 4px;
}
/* 震动效果 */
.shake {
animation: shake 0.15s ease-out;
}
@keyframes shake {
0%, 100% { transform: translate(0, 0); }
25% { transform: translate(-3px, 2px); }
50% { transform: translate(2px, -3px); }
75% { transform: translate(-2px, -1px); }
}
</style>
</head>
<body>
@@ -738,12 +727,6 @@
hue: hue
}));
}
// 屏幕微震
if (bass > 0.5) {
document.body.classList.add('shake');
setTimeout(() => document.body.classList.remove('shake'), 150);
}
}
// 更新和绘制流星
-53
View File
@@ -792,47 +792,8 @@
}
}
// ==================== 扫描环(速度感环) ====================
let rings = [];
function spawnRing() {
rings.push({
radius: 10,
maxRadius: Math.max(width, height) * 0.8,
life: 1,
decay: 0.008,
hue: 200 + Math.random() * 20,
width: 2 + Math.random() * 2
});
}
function updateAndDrawRings(bass) {
for (let i = rings.length - 1; i >= 0; i--) {
const r = rings[i];
r.radius += 8 + bass * 15;
r.life -= r.decay;
if (r.life <= 0 || r.radius > r.maxRadius) {
rings.splice(i, 1);
continue;
}
ctx.save();
ctx.globalAlpha = r.life * 0.3;
ctx.strokeStyle = `hsl(${r.hue}, 15%, 70%)`;
ctx.lineWidth = r.width * r.life;
ctx.shadowBlur = 15;
ctx.shadowColor = 'rgba(255, 255, 255, 0.4)';
ctx.beginPath();
ctx.arc(cx, cy, r.radius, 0, Math.PI * 2);
ctx.stroke();
ctx.restore();
}
}
// ==================== 主渲染循环 ====================
let lastTime = 0;
let ringTimer = 0;
let warpLineTimer = 0;
let speedValue = 0;
@@ -899,20 +860,6 @@
}
updateAndDrawWarpLines(bass, treble);
// 生成和绘制扫描环(无声音时不生成)
if (avg > 0.03) {
ringTimer += dt;
const ringInterval = Math.max(200, 800 - avg * 500 - bass * 300);
if (ringTimer > ringInterval) {
ringTimer = 0;
spawnRing();
}
if (isBeat && bass > 0.4) {
spawnRing();
}
}
updateAndDrawRings(bass);
// 节拍粒子爆发
if (isBeat && bass > 0.3) {
spawnParticles(0.5 + bass);
+1 -1
View File
@@ -895,7 +895,7 @@ function drawFreqBars(high) {
const gap = W / barCount * 0.4;
for (let i = 0; i < barCount; i++) {
const freqIdx = Math.floor(i / barCount * (freqData.length * 0.6));
const freqIdx = Math.floor(i / barCount * (freqData.length - 1)); // 覆盖全部频段,保留高频
const val = freqData[freqIdx] / 255;
const barH = val * H * 0.35;
const x = i * (barWidth + gap) + gap * 0.5;
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -360,7 +360,7 @@ function drawGrid(time) {
function drawSkyline() {
if (!freqArray) return;
const binCount = analyser.frequencyBinCount;
const usable = Math.floor(binCount * 0.6);
const usable = binCount; // 覆盖全部频段,保留高频
const barCount = 80;
const barW = W / barCount;
const baseY = H * 0.9;
+111
View File
@@ -0,0 +1,111 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>音频可视化</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
width: 100%;
height: 100%;
background: #111;
overflow: hidden;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: 4px;
width: 100vw;
height: 100vh;
background: #000;
}
.cell {
position: relative;
background: #111;
overflow: hidden;
}
.cell iframe {
width: 100%;
height: 100%;
border: 0;
display: block;
}
.cell select {
position: absolute;
top: 8px;
left: 8px;
z-index: 10;
background: rgba(0, 0, 0, 0.6);
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 4px;
padding: 2px 6px;
font-size: 12px;
cursor: pointer;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s, visibility 0.2s;
}
.cell:hover select {
opacity: 1;
visibility: visible;
}
</style>
</head>
<body>
<div class="grid" id="grid"></div>
<script>
// 可供选择的页面列表
const pages = [
'1.html', '2.html', '3.html', '4.html',
'5.html', '6.html', '7.html', '8.html',
];
// 4 个格子默认显示的页面
const defaults = ['2.html', '6.html', '7.html', '8.html'];
const grid = document.getElementById('grid');
defaults.forEach((current) => {
const cell = document.createElement('div');
cell.className = 'cell';
const iframe = document.createElement('iframe');
iframe.src = current;
const select = document.createElement('select');
pages.forEach((p) => {
const opt = document.createElement('option');
opt.value = p;
opt.textContent = p;
if (p === current) opt.selected = true;
select.appendChild(opt);
});
// 切换时更新对应 iframe
select.addEventListener('change', () => { iframe.src = select.value; });
cell.appendChild(select);
cell.appendChild(iframe);
grid.appendChild(cell);
});
</script>
</body>
</html>