<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Аудио Визуализатор в стиле Windows XP</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            background: linear-gradient(135deg, #000046, #1CB5E0);
            height: 100vh;
            overflow: hidden;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            color: white;
        }
        
        .container {
            text-align: center;
            z-index: 10;
            background: rgba(0, 0, 0, 0.3);
            padding: 20px;
            border-radius: 15px;
            backdrop-filter: blur(5px);
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
            max-width: 90%;
        }
        
        h1 {
            margin-bottom: 20px;
            text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
            font-size: 2.5rem;
        }
        
        .file-upload {
            margin: 20px 0;
            padding: 15px;
            background: rgba(255, 255, 255, 0.1);
            border-radius: 10px;
            cursor: pointer;
            transition: all 0.3s ease;
            border: 2px dashed rgba(255, 255, 255, 0.3);
        }
        
        .file-upload:hover {
            background: rgba(255, 255, 255, 0.2);
        }
        
        #file-input {
            display: none;
        }
        
        #visualizer {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: 0;
        }
        
        #audio-player {
            width: 100%;
            margin-top: 20px;
            background: rgba(0, 0, 0, 0.5);
            border-radius: 10px;
        }
        
        .instructions {
            margin-top: 20px;
            font-size: 0.9rem;
            opacity: 0.8;
        }
    </style>
</head>
<body>
    <canvas id="visualizer"></canvas>
    
    <div class="container">
        <h1>Аудио Визуализатор</h1>
        <div class="file-upload" id="file-upload">
            📁 Загрузить аудиофайл
        </div>
        <input type="file" id="file-input" accept="audio/*">
        <audio id="audio-player" controls></audio>
        <div class="instructions">
            Загрузите любой аудиофайл (MP3, WAV и др.) и наслаждайтесь визуализацией
        </div>
    </div>

    <script>
        // Элементы DOM
        const fileUpload = document.getElementById('file-upload');
        const fileInput = document.getElementById('file-input');
        const audioPlayer = document.getElementById('audio-player');
        const canvas = document.getElementById('visualizer');
        const ctx = canvas.getContext('2d');
        
        // Настройка canvas
        function resizeCanvas() {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        }
        resizeCanvas();
        window.addEventListener('resize', resizeCanvas);
        
        // Аудио контекст и анализатор
        let audioContext;
        let analyser;
        let dataArray;
        let animationId;
        
        // Параметры визуализации
        const particles = [];
        const MAX_PARTICLES = 200;
        const PARTICLE_SPEED = 0.05;
        const DEPTH = 1000;
        
        // Инициализация частиц
        function initParticles() {
            particles.length = 0;
            for (let i = 0; i < MAX_PARTICLES; i++) {
                particles.push({
                    x: Math.random() * canvas.width,
                    y: Math.random() * canvas.height,
                    z: Math.random() * DEPTH,
                    color: `hsl(${Math.random() * 360}, 100%, 50%)`,
                    speed: PARTICLE_SPEED + Math.random() * PARTICLE_SPEED * 0.5,
                    history: []
                });
            }
        }
        
        // Загрузка аудио
        fileUpload.addEventListener('click', () => fileInput.click());
        fileInput.addEventListener('change', function(e) {
            const file = e.target.files[0];
            if (!file) return;
            
            const fileURL = URL.createObjectURL(file);
            audioPlayer.src = fileURL;
            
            initAudioVisualizer();
        });
        
        // Инициализация аудио визуализатора
        function initAudioVisualizer() {
            if (audioContext) return;
            
            // Создаем аудио контекст
            audioContext = new (window.AudioContext || window.webkitAudioContext)();
            analyser = audioContext.createAnalyser();
            analyser.fftSize = 512;
            
            // Подключаем анализатор к аудио элементу
            const source = audioContext.createMediaElementSource(audioPlayer);
            source.connect(analyser);
            analyser.connect(audioContext.destination);
            
            // Создаем массив для данных частот
            dataArray = new Uint8Array(analyser.frequencyBinCount);
            
            // Инициализируем частицы
            initParticles();
            
            // Запускаем визуализацию
            if (animationId) cancelAnimationFrame(animationId);
            visualize();
        }
        
        // Основная функция визуализации
        function visualize() {
            // Очищаем canvas с полупрозрачным фоном для эффекта шлейфа
            ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            
            // Получаем данные частот
            analyser.getByteFrequencyData(dataArray);
            
            // Вычисляем среднюю амплитуду
            let sum = 0;
            for (let i = 0; i < dataArray.length; i++) {
                sum += dataArray[i];
            }
            const avgAmplitude = sum / dataArray.length;
            
            // Обновляем и рисуем частицы
            particles.forEach(particle => {
                // Двигаем частицу "вперед" (к зрителю)
                particle.z -= particle.speed * (1 + avgAmplitude / 100);
                
                // Если частица вышла за пределы видимости, создаем новую
                if (particle.z < 1) {
                    resetParticle(particle);
                }
                
                // Рассчитываем 3D позицию
                const scale = DEPTH / (DEPTH + particle.z);
                const x2d = (particle.x - canvas.width / 2) * scale + canvas.width / 2;
                const y2d = (particle.y - canvas.height / 2) * scale + canvas.height / 2;
                
                // Сохраняем историю для рисования линии
                particle.history.push({ x: x2d, y: y2d });
                if (particle.history.length > 10) {
                    particle.history.shift();
                }
                
                // Рисуем линию (шлейф частицы)
                drawParticleTrail(particle, avgAmplitude);
            });
            
            // Создаем эффект переливающихся линий
            drawEnergyLines(avgAmplitude);
            
            animationId = requestAnimationFrame(visualize);
        }
        
        // Рисуем шлейф частицы
        function drawParticleTrail(particle, amplitude) {
            if (particle.history.length < 2) return;
            
            // Рассчитываем цвет на основе амплитуды
            const hue = (parseInt(particle.color.split(',')[0].split('(')[1]) + amplitude * 0.5) % 360;
            const color = `hsla(${hue}, 100%, ${50 + amplitude * 0.2}%, 0.8)`;
            
            ctx.beginPath();
            ctx.moveTo(particle.history[0].x, particle.history[0].y);
            
            // Рисуем кривую через все точки истории
            for (let i = 1; i < particle.history.length; i++) {
                ctx.lineTo(particle.history[i].x, particle.history[i].y);
            }
            
            // Настройки стиля линии
            ctx.strokeStyle = color;
            ctx.lineWidth = 0.5 + amplitude / 50;
            ctx.lineCap = 'round';
            ctx.lineJoin = 'round';
            ctx.stroke();
        }
        
        // Рисуем переливающиеся линии энергии
        function drawEnergyLines(amplitude) {
            const centerX = canvas.width / 2;
            const centerY = canvas.height / 2;
            const maxRadius = Math.min(centerX, centerY) * 1.5;
            
            ctx.beginPath();
            
            // Создаем спиралевидные линии
            for (let angle = 0; angle < Math.PI * 8; angle += 0.05) {
                const radius = maxRadius * (angle / (Math.PI * 8)) * (1 + amplitude / 255);
                const x = centerX + Math.cos(angle) * radius;
                const y = centerY + Math.sin(angle) * radius;
                
                if (angle === 0) {
                    ctx.moveTo(x, y);
                } else {
                    ctx.lineTo(x, y);
                }
            }
            
            // Градиент для линии
            const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
            gradient.addColorStop(0, `hsla(${(amplitude * 2) % 360}, 100%, 70%, 0.7)`);
            gradient.addColorStop(0.5, `hsla(${(amplitude * 2 + 120) % 360}, 100%, 70%, 0.9)`);
            gradient.addColorStop(1, `hsla(${(amplitude * 2 + 240) % 360}, 100%, 70%, 0.7)`);
            
            ctx.strokeStyle = gradient;
            ctx.lineWidth = 1 + amplitude / 50;
            ctx.stroke();
        }
        
        // Сброс частицы
        function resetParticle(particle) {
            particle.x = Math.random() * canvas.width;
            particle.y = Math.random() * canvas.height;
            particle.z = DEPTH;
            particle.color = `hsl(${Math.random() * 360}, 100%, 50%)`;
            particle.history = [];
        }
        
        // Инициализация при загрузке
        initParticles();
        
        // Базовая анимация до загрузки музыки
        function baseAnimation() {
            ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            
            particles.forEach(particle => {
                particle.z -= particle.speed;
                if (particle.z < 1) resetParticle(particle);
                
                const scale = DEPTH / (DEPTH + particle.z);
                const x2d = (particle.x - canvas.width / 2) * scale + canvas.width / 2;
                const y2d = (particle.y - canvas.height / 2) * scale + canvas.height / 2;
                
                particle.history.push({ x: x2d, y: y2d });
                if (particle.history.length > 5) particle.history.shift();
                
                if (particle.history.length > 1) {
                    ctx.beginPath();
                    ctx.moveTo(particle.history[0].x, particle.history[0].y);
                    for (let i = 1; i < particle.history.length; i++) {
                        ctx.lineTo(particle.history[i].x, particle.history[i].y);
                    }
                    ctx.strokeStyle = particle.color;
                    ctx.lineWidth = 0.5;
                    ctx.stroke();
                }
            });
            
            animationId = requestAnimationFrame(baseAnimation);
        }
        
        baseAnimation();
    </script>
</body>
</html>

Можешь подкорректировать этот код, чтобы:
сделать так, чтобы это выглядело как мы движемся в глубь этой бесконечной спирали и она крутилась от нас и всё в зависимости он скорости музыки?
И ты ещё какие-то разноцветные точки сделал на фоне. А можно интенсивность их появления и движения, а также количесво, тоже связать с скоростью и тактом музыки?