小辣椒 发表于 2026-2-24 20:27

枫叶歌曲二首 TO:亚纶

<!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>

      @import url("https://fonts.googleapis.com/css2?family=Ma+Shan+Zheng&display=swap");

      

      #bj {

            position: relative;

            width: 1300px;

            height: 750px;

             margin: 130px 0 20px calc(50% - 731px);

            overflow: hidden;

            z-index: 1;

            background: #55aa55 url(https://wj1.zp68.com:812/lxx/yunhua/2025/11/23/9F.gif ) no-repeat center/cover;

            border-radius: 0px;

            box-shadow: 0 15px 0px rgba(0, 0, 0, 0);

            font-family: "Ma Shan Zheng","华文行楷","SimHei", "Arial", "sans-serif";

      }

      

      .song-info {

            animation: flash 2s linear infinite;

            position: absolute;

            top: 20px;

            left: 0;

            width: 100%;

            text-align: center;

            z-index: 5;

            padding: 10px;

      }

      

      .song-title {

            font-size: 38px;

            font-weight: 300;

            color: #00ff00;

            text-shadow: 0 0px 0px rgba( );

            margin-bottom: 5px;

      }

      

      .song-artist {

            font-size: 28px;

            color: #00ff00;

      }

      

      canvas {

            animation: flash 1s linear infinite;

            position: absolute;

            z-index: 2;

            width: 120%;

            height: 100%;

            display: block;

            cursor: pointer;

            transition: transform 0.3s ease;

            margin-top: -100px;

            margin-left: -66px;

            pointer-events: none;

      }

      

      canvas:hover {

            transform: scale(1.05);

      }

      

      .lyric-preview {

            display: none;

            opacity: 1;

            position: absolute;

            top: 50px;

            left: 50%;

            transform: translateX(-50%);

            color: #00ff00;

            font-size: 16px;

            text-align: center;

            width: 70%;

            z-index: 3;

            cursor: pointer;

            padding: 12px;

            border-radius: 10px;

            background: rgba(0, 0, 0, 0);

            backdrop-filter: blur(10px);

            transition: all 0.3s ease;

      }

      

      @keyframes flash {

            to { filter: hue-rotate(360deg)brightness(260%); }

      }

      

      .lyric-preview:hover {

            display: none;

            background: rgba(0, 0, 0, 0);

            transform: translateX(-50%) scale(1.02);

      }

      

      .prev-lyric {

            opacity: 1;

            margin-bottom: 6px;

            transition: opacity 0.2s ease;

            color: #00ff00;

            font-size: 14px;

      }

      

      .current-lyric {

            font-size: 18px;

            font-weight: bold;

            color: #00ff00;

            transition: opacity 0.2s ease;

      }

      

      .next-lyric {

            opacity: 1;

            margin-top: 6px;

            transition: opacity 0.2s ease;

            color: #00ff00;

            font-size: 14px;

      }

      

      .lyric-preview:active .current-lyric {

            opacity: 1;

      }

      

      /* 播放按钮样式 */

      #player {

            animation: flash 3s linear infinite;

            position: absolute;

            z-index: 10;

            left: 5%;

            bottom: 120px;

            width: 120px;

            height: 120px;

            opacity: 1;

            transition: .4s;

            display: grid;

            place-items: center;

            cursor: pointer;

            background: rgba(255, 255, 255, 0.);

            border-radius: 50%;

            box-shadow: 0 0px 0px rgba(0, 0, 0, 0.0);

      }

      

      #player::before {

            position: absolute;

            z-index: 1;

            content: '';

            width: 120px;

            height: 120px;

            background: url(https://wj1.zp68.com:812/lxx/yunhua/2025/11/23/ann.png) no-repeat center/cover;

            border-radius: 50%;

            transition: transform 0.3s ease;

      }

      

      @keyframes rotate {

            from { transform: rotate(0deg); }

            to { transform: rotate(360deg); }

      }

      

      #player.playing::before {

            animation: rotate 5s linear infinite;

      }

      

      #player.playing:hover::before {

            animation-duration: 5s;

      }

      

      #player:hover {

            transform: scale(1.01);

            background: rgba(255, 255, 255, 0);

      }

      

       #bgVideo {

            position: absolute;

            z-index: 1;

            left: 0;

            top: 0;

            width: 100%;

            height: 100%;

            filter: brightness(0.7);

            object-fit: cover;

            opacity: 1;

      }

      

      /* 进度条容器 */

      .progress-container {

            position: absolute;

            bottom: 40px;

            left: 32%;

            width: 33%;

            z-index: 10;

            background: #444;

            height: 6px;

            border-radius: 3px;

            cursor: pointer;

      }

      

      .progress-bar {

            height: 100%;

            width: 0%;

            background:#cc9b97;

            border-radius: 3px;

            transition: width 0.1s linear;

            position: relative;

      }

      

      .progress-bar::after {

            content: '';

            position: absolute;

            right: -8px;

            top: 50%;

            transform: translateY(-50%);

            width: 16px;

            height: 16px;

            background: #222;

            border-radius: 50%;

            box-shadow: 0 0 10px rgba(233, 69, 96, 0.8);

            opacity: 0;

            transition: opacity 0.2s;

      }

      

      .progress-container:hover .progress-bar::after {

            opacity: 1;

      }

      

      .time-display {

            display: flex;

            justify-content: space-between;

            margin-top: -24px;

            font-size: 14px;

            color: #222;

      }

      

      .controls {

            position: absolute;

            bottom: 70px;

            right: 5%;

            display: flex;

            align-items: center;

            gap: 15px;

            z-index: 10;

      }

      

      .control-btn {

            background:rgba(255, 255, 255, 0) ;

            border: none;

            color: #222;

            width: 40px;

            height: 40px;

            border-radius: 50%;

            display: flex;

            align-items: center;

            justify-content: center;

            cursor: pointer;

            transition: all 0.3s;

            font-size: 12px;

      }

      

      .control-btn:hover {

            background: rgba(255, 255, 255, 0);

            transform: scale(1);

      }

      

      .volume-container {

            display: flex;

            align-items: center;

            gap: 10px;

      }

      

      .volume-slider {

            width: 0px;

            height: 0px;

            background: rgba(255, 255, 255, 0);

            border-radius: 0px;

            position: relative;

      }

      

      .volume-level {

            height: 100%;

            width: 80%;

            background: #e94560;

            border-radius: 2px;

      }



      /* 加载进度显示 */

      .loading {

            position: absolute;

            top: 50%;

            left: 50%;

            transform: translate(-50%, -50%);

            font-size: 20px;

            color: #fff;

            z-index: 20;

            background: rgba(0, 0, 0, 0.7);

            padding: 20px 40px;

            border-radius: 10px;

            display: none;

      }

      

      /* 播放列表样式 */

      .playlist-container {

            position: absolute;

            top: 20px;

            right: 30px;

            z-index: 10;

            width: 40px;

            height: 40px;

            transition: all 0.3s ease;

      }



      .playlist-trigger {

            width: 40px;

            height: 40px;

            background: rgba(0, 0, 0, 0);

            border-radius: 50%;

            display: flex;

            align-items: center;

            justify-content: center;

            cursor: pointer;

            transition: all 0.3s;

            backdrop-filter: blur(5px);

            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);

      }



      .playlist-trigger:hover {

            background: rgba(233, 69, 96, 1);

            transform: scale(1.1);

      }



      .playlist-trigger::before {

    content: "≡";

    color: Sienna;

    font: 200 20px/15px ;

}



      .playlist {

            position: absolute;

            top: 50px;

            right: 0;

            background: rgba(220,220,220, 0);

            border-radius: 10px;

            padding: 10px;

            height: 150px;

            overflow: hidden;

            width: 300px;

            transition: all 0.3s ease;

            backdrop-filter: blur(10px);

            opacity: 0;

            visibility: hidden;

            display: flex;

            flex-direction: column;

      }



      .playlist-container:hover .playlist {

            opacity: 1;

            visibility: visible;

      }



      .playlist-header {

            margin-bottom: 10px;

            color: #fff555;

            text-align: center;

            border-bottom: 1px solid rgba(128,0,0, 0.5);

            padding-bottom: 8px;

            flex-shrink: 0;

      }



      .playlist-items {

            flex: 1;

            overflow-y: auto;

            padding-right: 5px;

      }



      .playlist-item {

            padding: 8px 12px;

            margin: 5px 0;

            line-height: 0.7;

            border-radius: 5px;

            cursor: pointer;

            transition: all 0.3s;

            font-size: 14px;

            flex-shrink: 0;

      }



      .playlist-item:hover {

            background: rgba(233, 69, 96, 0.3);

      }



      .playlist-item.active {

            background: rgba(233, 69, 96, 0.5);

            color: white;

      }



      /* 滚动条样式 */

      .playlist-items::-webkit-scrollbar {

            width: 6px;

      }



      .playlist-items::-webkit-scrollbar-track {

            background: rgba(255, 255, 255, 0.1);

            border-radius: 3px;

      }



      .playlist-items::-webkit-scrollbar-thumb {

            background: rgba(233, 69, 96, 0.8);

            border-radius: 3px;

            transition: background 0.3s;

      }



      .playlist-items::-webkit-scrollbar-thumb:hover {

            background: rgba(233, 69, 96, 0.8);

      }

    </style>

</head>

<body>

    <div id="bj">

      <!-- 歌曲信息 -->

      <div class="song-info">

            <div class="song-title">《秋天的枫叶》</div>

            <div class="song-artist">演唱:王爱华 </div>

      </div>

      

      <div class="lyric-preview" id="lyricPreview">

            <div class="prev-lyric" id="prevLyric"></div>

            <div class="current-lyric" id="currentLyric"></div>

            <div class="next-lyric" id="nextLyric"></div>

      </div>

      

      <div id="player" title="暂停/播放"></div>

      

      <div class="progress-container" id="progressContainer">

            <div class="progress-bar" id="progressBar"></div>

            <div class="time-display">

                <span id="currentTime">0:00</span>

                <span id="duration">0:00</span>

            </div>

      </div>



      <!-- 控制按钮 -->

      <div class="controls">

            <button class="control-btn" id="prevBtn" title="上一曲">◀◀</button>

            <button class="control-btn" id="nextBtn" title="下一曲">▶▶</button>

            <div class="volume-container">

                <button class="control-btn" id="volumeBtn" title="静音"></button>

                <div class="volume-slider" id="volumeSlider">

                  <div class="volume-level" id="volumeLevel"></div>

                </div>

            </div>

      </div>



       <!-- 播放列表 -->

       <div class="playlist-container">

            <div class="playlist-trigger" title="播放列表"></div>

            <div class="playlist" id="playlist">

                <h3 class="playlist-header">歌曲列表</h3>

                <div class="playlist-items">

                  <div class="playlist-item active" data-index="0">《秋天的枫叶》演唱:王爱华</div>

                  <div class="playlist-item" data-index="1">《枫叶情》 歌手:林淑容</div>

                </div>

            </div>

      </div>

      

      <div class="loading" id="loading">加载中...</div>

      

      <canvas id="glcanvas" width="900" height="420"></canvas>

      <video id="bgVideo" src="" muted loop></video>



      <!-- 音频播放器 -->

      <audio id="audio"></audio>

    </div>



    <script>

      // 歌曲数据

      const songs = [

            {

                title: "《秋天的枫叶》",

                artist: "演唱:王爱华 ",

                audioUrl: "https://wj1.zp68.com:812/lxx/yunhua/2025/11/23/01.mp3",

                videoUrl: "",

                lyrics: `

《秋天的枫叶》

美景与痴情的演绎

演唱:王爱华         

谁给画里藏进香味

让人陶醉

谁与恋人结伴成对

把彩云追

谁用太阳的色彩把梦描绘

梦中依偎

谁用一生选择了无悔

风雨相随

枫叶红哟枫叶美

浓妆艳抹要嫁谁

嫁给层层的山

潺潺的水

未了痴情最珍贵

枫叶红哟

枫叶美

浓妆艳抹要爱谁

明知明天即将离去

为梦沉醉

LRC编辑:小辣椒

谁给画里藏进香味

让人陶醉

谁与恋人结伴成对

把彩云追

谁用太阳的色彩把梦描绘

梦中依偎

谁用一生选择了无悔

风雨相随

枫叶红哟枫叶美

浓妆艳抹要嫁谁

嫁给层层的山

潺潺的水

未了痴情最珍贵

枫叶红哟

枫叶美

浓妆艳抹要爱谁

明知明天即将离去

为梦沉醉

为梦沉醉

谢谢欣赏



                `

            },

            {

                title: "枫叶情",

                artist: "林淑容",

                audioUrl: "https://wj1.zp68.com:812/lxx/yunhua/2026/02/07/01.mp3",

                videoUrl: "",

                lyrics: `

枫叶情

歌手:林淑容

作词 : Traditional

作曲 : Traditional      

一年容易又秋天

又见到枫叶一片片

你那红红的笑脸

要比枫叶还更娇艳

叫我对你又爱又怜

我们常在枫林里流连流连

爱在你我心里缠绵缠绵

一片枫叶一片情

片片都有我爱和怜

朝朝暮暮直到永远

LRC编辑:小辣椒

我爱美丽的秋天

我更爱枫叶一片片

要在片片的枫叶上

写下我俩的心愿

但愿俩情永远不变

你带给我柔情万千万千

我带给你爱意无限无限

一片枫叶一片情

愿你常记在心田

岁岁年年天上人间

~Music~

我们常在枫林里流连流连

爱在你我心里缠绵缠绵

一片枫叶一片情

片片都有我爱和怜

朝朝暮暮直到永远

谢谢欣赏



                `

            }

      ];



      const state = {

            currentSongIndex: 0,

            currentLyricIndex: 0,

            isAudioEnabled: true,

            isPlaying: false,

            mouseX: 0,

            mouseY: 0,

            isHovering: false,

            lyrics: [],

            hoverValue: 0,

            hoverSpeed: 0.005,

            lastMouseMoveTime: 0,

            throttleDelay: 100,

            userInteracted: false,

            animationId: null,

            isAnimating: false,

            isDragging: false,

            volume: 0.8,

            isMuted: false,

            staticBgImage: "https://wj1.zp68.com:812/lxx/yunhua/2025/11/23/9F.jpg"

      };



      const elements = {

            canvas: document.getElementById('glcanvas'),

            audio: document.getElementById('audio'),

            lyricPreview: document.getElementById('lyricPreview'),

            prevLyric: document.getElementById('prevLyric'),

            currentLyric: document.getElementById('currentLyric'),

            nextLyric: document.getElementById('nextLyric'),

            player: document.getElementById('player'),

            bgVideo: document.getElementById('bgVideo'),

            progressContainer: document.getElementById('progressContainer'),

            progressBar: document.getElementById('progressBar'),

            currentTime: document.getElementById('currentTime'),

            duration: document.getElementById('duration'),

            prevBtn: document.getElementById('prevBtn'),

            nextBtn: document.getElementById('nextBtn'),

            volumeBtn: document.getElementById('volumeBtn'),

            volumeSlider: document.getElementById('volumeSlider'),

            volumeLevel: document.getElementById('volumeLevel'),

            loading: document.getElementById('loading'),

            songTitle: document.querySelector('.song-title'),

            songArtist: document.querySelector('.song-artist'),

            playlist: document.getElementById('playlist'),

            playlistItems: document.querySelectorAll('.playlist-item')

      };



      // ===================== 初始化检测 =====================

      function initCheck() {

            const gl = elements.canvas.getContext('webgl') || elements.canvas.getContext('experimental-webgl');

            if (!gl) {

                state.isAudioEnabled = false;

                return null;

            }

            return gl;

      }



      // ===================== LRC歌词解析 =====================

      function parsePureLRC(lrcText) {

            const lines = [];

            const lrcLines = lrcText.split('\n')

                .map(line => line.trim())

                .filter(line => line && !line.includes('●') && !line.includes('谢谢欣赏'));



            for (const line of lrcLines) {

                const timeRegex = /\[(\d{2}):(\d{2})(?:\.(\d{1,3}))?\]/g;

                const text = line.replace(timeRegex, '').trim();

                let timeMatch;



                while ((timeMatch = timeRegex.exec(line)) !== null) {

                  const minutes = parseInt(timeMatch);

                  const seconds = parseInt(timeMatch);

                  const ms = timeMatch ? parseInt(timeMatch.padEnd(3, '0')) : 0;

                  const time = minutes * 60 + seconds + ms / 1000;



                  if (text) {

                        lines.push({ time, text });

                  }

                }

            }



            return lines.sort((a, b) => a.time - b.time);

      }



      // ===================== 歌词跳转 =====================

      function jumpToLyricByText(clickText) {

            if (!clickText.trim()) return;

            const targetLyric = state.lyrics.find(lyric => lyric.text === clickText.trim());

            if (!targetLyric) return;

            elements.audio.currentTime = targetLyric.time;

            const targetIndex = state.lyrics.findIndex(lyric => lyric.text === clickText.trim());

            if (targetIndex !== -1) {

                state.currentLyricIndex = targetIndex;

                elements.prevLyric.textContent = state.lyrics?.text || '';

                elements.currentLyric.textContent = state.lyrics.text;

                elements.nextLyric.textContent = state.lyrics?.text || '';

                if (window.render && window.render.updateTextTexture) {

                  window.render.updateTextTexture(state.lyrics.text);

                }

            }

      }



      // ===================== WebGL渲染 =====================

      function initWebGL(gl) {

            function compileShader(src, type) {

                const shader = gl.createShader(type);

                gl.shaderSource(shader, src);

                gl.compileShader(shader);

                if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {

                  console.error('Shader compilation error:', gl.getShaderInfoLog(shader));

                  return null;

                }

                return shader;

            }

            

            const vertexShaderSource = `

                attribute vec2 a_pos;

                attribute vec2 a_uv;

                varying vec2 v_uv;

                void main() {

                  v_uv = a_uv;

                  gl_Position = vec4(a_pos, 0.9, 1.0);

                }

            `;

            

            const fragmentShaderSource = `

                precision highp float;

                varying vec2 v_uv;

                uniform sampler2D u_text;

                uniform float u_time;

                uniform vec2 u_mouse;

                uniform float u_hover;



                float random(vec2 st) {

                  return fract(sin(dot(st.xy, vec2(12.9898,78.233)))*43758.5453123);

                }



                float noise(vec2 st) {

                  vec2 i = floor(st);

                  vec2 f = fract(st);

                  float a = random(i);

                  float b = random(i + vec2(1.0,0.0));

                  float c = random(i + vec2(0.0,1.0));

                  float d = random(i + vec2(1.0,1.0));

                  vec2 u = f*f*(3.0-2.0*f);

                  return mix(a,b,u.x) + (c-a)*u.y*(1.0-u.x) + (d-b)*u.x*u.y;

                }



                void main() {

                  vec2 correctedUV = vec2(v_uv.x, 1.0-v_uv.y);

                  float strength = smoothstep(0.2,1.0,correctedUV.y);

                  float noiseTime = u_time * 0.3;

                  float n = noise(vec2(correctedUV.x*5.0, (correctedUV.y*2.0 - noiseTime)*2.0));

                  

                  float melt = n * 0.4 * (correctedUV.y);

                  float dist = distance(correctedUV, u_mouse);

                  

                  float hoverWave = 0.0;

                  if (u_hover > 0.1) {

                        hoverWave = sin(dist*12.0 - u_time*6.0)*0.08*u_hover*exp(-dist*3.5) +

                                 sin(dist*20.0 - u_time*10.0)*0.04*u_hover*exp(-dist*5.0);

                  }

                        

                  vec2 hoverDistort = normalize(correctedUV - u_mouse) * hoverWave * (1.0 + sin(u_time*2.0)*0.1);

                  vec2 finalUV = vec2(

                        correctedUV.x + melt*0.3 + hoverDistort.x,

                        correctedUV.y - melt*0.8 + hoverDistort.y

                  );



                  vec4 col = texture2D(u_text, finalUV);

                  if (col.a > 0.1) {

                        float glow = smoothstep(0.8,1.0,col.a);

                        vec3 spectrumColor = vec3(correctedUV.y, abs(sin(u_time + correctedUV.x*5.0)), 1.0-correctedUV.y);

                        

                        if (u_hover > 0.1) {

                            float hoverIntensity = 1.0 - smoothstep(0.0,0.1,dist);

                            float pulseEffect = 0.99 + 0.1*sin(u_time*4.0 + dist*8.0);

                            vec3 goldColor = vec3(0.99, 0.99+0.8*pulseEffect, 0.2+0.2*sin(u_time*3.0));

                            vec3 blueColor = vec3(0.99+0.99*sin(u_time*2.0 + dist*6.0), 0.99+0.8*pulseEffect, 0.5);

                            spectrumColor = mix(spectrumColor, mix(goldColor, blueColor, 0.99), hoverIntensity*u_hover*0.99);

                            glow += hoverIntensity*u_hover*0.99;

                        }

                        

                        col.rgb = mix(col.rgb, spectrumColor, 0.99*glow);

                        

                        // 优化粒子效果

                     if (u_hover > 0.1 && dist < 0.2) {

                            float particles = noise(correctedUV*15.0 + u_time*2.0);

                            if (particles > 0.85) col.rgb += vec3(1.0,0.8,0.4)*(particles-0.85)*8.0*u_hover;

                           

                            float sparkles = noise(correctedUV*30.0 + u_time*4.0);

                            if (sparkles > 0.92 && dist < 0.15) col.rgb += vec3(0.9,0.9,1.0)*(sparkles-0.92)*6.0*u_hover;

                        }

                  }

                        

                  if (u_hover > 0.1) {

                        float ambientGlow = 1.0 - smoothstep(0.0,0.4,dist);

                        float auraEffect = sin(dist*6.0 - u_time*3.0)*0.2 + 0.8;

                        vec3 auraColor = vec3(

                            0.15+0.1*sin(u_time*1.5),

                            0.1+0.1*sin(u_time*2.0+1.0),

                            0.2+0.15*sin(u_time*1.2+2.0)

                        );

                        col.rgb += auraColor*ambientGlow*u_hover*auraEffect;

                        

                        float outerHalo = 1.0 - smoothstep(0.2,0.5,dist);

                        col.rgb += vec3(0.08,0.04,0.12)*outerHalo*u_hover*0.3;

                  }

                  

                  gl_FragColor = col;

                }

            `;

            

            const vs = compileShader(vertexShaderSource, gl.VERTEX_SHADER);

            const fs = compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER);

            const program = gl.createProgram();

            gl.attachShader(program, vs);

            gl.attachShader(program, fs);

            gl.linkProgram(program);

            

            const quad = new Float32Array([

                -1, -1, 0, 0,

                1, -1, 1, 0,

                -1, 1, 0, 1,

                1, 1, 1, 1

            ]);

            const buf = gl.createBuffer();

            gl.bindBuffer(gl.ARRAY_BUFFER, buf);

            gl.bufferData(gl.ARRAY_BUFFER, quad, gl.STATIC_DRAW);

            

            const a_pos = gl.getAttribLocation(program, 'a_pos');

            const a_uv = gl.getAttribLocation(program, 'a_uv');

            gl.enableVertexAttribArray(a_pos);

            gl.vertexAttribPointer(a_pos, 2, gl.FLOAT, false, 16, 0);

            gl.enableVertexAttribArray(a_uv);

            gl.vertexAttribPointer(a_uv, 2, gl.FLOAT, false, 16, 8);

            

            const uniforms = {

                u_time: gl.getUniformLocation(program, 'u_time'),

                u_text: gl.getUniformLocation(program, 'u_text'),

                u_mouse: gl.getUniformLocation(program, 'u_mouse'),

                u_hover: gl.getUniformLocation(program, 'u_hover')

            };

            

            const textCanvas = document.createElement('canvas');

            const tctx = textCanvas.getContext('2d');

            textCanvas.width = elements.canvas.width;

            textCanvas.height = elements.canvas.height;



            const textTex = gl.createTexture();

            gl.bindTexture(gl.TEXTURE_2D, textTex);

            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);

            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

            

            function updateTextTexture(text) {

                tctx.clearRect(0, 0, textCanvas.width, textCanvas.height);

                tctx.fillStyle = '#000000';

                tctx.font = 'bold 35px "Ma Shan Zheng","华文行楷","SimHei", "Arial", "sans-serif"';

                tctx.textAlign = 'center';

                tctx.textBaseline = '';

                tctx.fillText(text || '', textCanvas.width / 2, textCanvas.height / 2);

               

                gl.bindTexture(gl.TEXTURE_2D, textTex);

                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textCanvas);

            }



            // 绘制函数

            function draw(t) {

                if (!state.isAudioEnabled || !state.isAnimating) return;

               

                if (state.isHovering && state.hoverValue < 1.0) {

                  state.hoverValue = Math.min(1.0, state.hoverValue + state.hoverSpeed);

                } else if (!state.isHovering && state.hoverValue > 0.0) {

                  state.hoverValue = Math.max(0.0, state.hoverValue - state.hoverSpeed);

                }

               

                gl.viewport(0, 0, elements.canvas.width, elements.canvas.height);

                gl.clear(gl.COLOR_BUFFER_BIT);

                gl.useProgram(program);

                const time = t * 0.0005;

                gl.uniform1f(uniforms.u_time, time);

                gl.uniform2f(uniforms.u_mouse, state.mouseX, state.mouseY);

                gl.uniform1f(uniforms.u_hover, state.hoverValue);

               

                gl.activeTexture(gl.TEXTURE0);

                gl.bindTexture(gl.TEXTURE_2D, textTex);

                gl.uniform1i(uniforms.u_text, 0);



                gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);



                state.animationId = requestAnimationFrame(draw);

            }



            return { updateTextTexture, draw};

      }



      // ===================== 歌词同步 =====================

      function updateLyric() {

            if (!state.isAudioEnabled || !state.lyrics.length || !state.isPlaying) return;

            

            const currentTime = elements.audio.currentTime;

            const { lyrics } = state;

            

            for (let i = 0; i < lyrics.length; i++) {

                const currentLyricTime = lyrics.time;

                const nextLyricTime = i < lyrics.length - 1 ? lyrics.time : Infinity;

               

                if (currentTime >= currentLyricTime && currentTime < nextLyricTime && state.currentLyricIndex !== i) {

                  state.currentLyricIndex = i;

                  

                  if (window.render && window.render.updateTextTexture) {

                        window.render.updateTextTexture(lyrics.text);

                  }

                  

                  elements.prevLyric.textContent = lyrics?.text || '';

                  elements.currentLyric.textContent = lyrics.text;

                  elements.nextLyric.textContent = lyrics?.text || '';

                  break;

                }

            }



            if (state.isPlaying) {

                requestAnimationFrame(updateLyric);

            }

      }



      // ===================== 进度条更新 =====================

      function updateProgress() {

            if (!state.isAudioEnabled || !state.isPlaying) return;

            

            const currentTime = elements.audio.currentTime;

            const duration = elements.audio.duration;

            

            if (duration) {

                const progressPercent = (currentTime / duration) * 100;

                elements.progressBar.style.width = `${progressPercent}%`;

               

                elements.currentTime.textContent = formatTime(currentTime);

                elements.duration.textContent = formatTime(duration);

            }

            

            if (state.isPlaying) {

                requestAnimationFrame(updateProgress);

            }

      }



      // ===================== 时间格式化 =====================

      function formatTime(seconds) {

            const mins = Math.floor(seconds / 60);

            const secs = Math.floor(seconds % 60);

            return `${mins}:${secs < 10 ? '0' : ''}${secs}`;

      }



      // ===================== 音量控制 =====================

      function updateVolume() {

            elements.audio.volume = state.volume;

            elements.volumeLevel.style.width = `${state.volume * 100}%`;

            

            if (state.volume === 0 || state.isMuted) {

                elements.volumeBtn.textContent = '';

            } else if (state.volume < 0.5) {

                elements.volumeBtn.textContent = '';

            } else {

                elements.volumeBtn.textContent = '';

            }

      }



      // ===================== 切换歌曲 =====================

      function switchSong(index) {

            if (index === state.currentSongIndex) return;

            

            if (state.isPlaying) {

                elements.audio.pause();

            }

            

            state.currentSongIndex = index;

            

            elements.playlistItems.forEach((item, i) => {

                if (i === index) {

                  item.classList.add('active');

                } else {

                  item.classList.remove('active');

                }

            });

            

            const currentSong = songs;

            elements.songTitle.textContent = currentSong.title;

            elements.songArtist.textContent = `演唱:${currentSong.artist}`;

            

            elements.audio.src = currentSong.audioUrl;

            elements.bgVideo.src = currentSong.videoUrl;

            

            state.lyrics = parsePureLRC(currentSong.lyrics);

            state.currentLyricIndex = 0;

            

            if (state.lyrics.length > 0) {

                window.render.updateTextTexture(state.lyrics.text);

                elements.prevLyric.textContent = '';

                elements.currentLyric.textContent = state.lyrics.text;

                elements.nextLyric.textContent = state.lyrics?.text || '';

            }

            

            elements.progressBar.style.width = '0%';

            elements.currentTime.textContent = '0:00';

            elements.duration.textContent = '0:00';

            

            elements.audio.load();

            attemptAutoPlay();

      }



      // ===================== 事件绑定 =====================

      function bindEvents(gl) {

            window.addEventListener('resize', () => {

                if (!gl) return;

                const width = elements.canvas.parentElement.clientWidth * 0.95;

                const height = elements.canvas.parentElement.clientHeight * 0.6;

                elements.canvas.width = width;

                elements.canvas.height = height;

            });

            

            elements.canvas.addEventListener('mousemove', (e) => {

                const now = Date.now();

                if (now - state.lastMouseMoveTime < state.throttleDelay) return;

                state.lastMouseMoveTime = now;



                if (state.isAudioEnabled) {

                  const rect = elements.canvas.getBoundingClientRect();

                  state.mouseX = (e.clientX - rect.left) / rect.width;

                  state.mouseY = 1.0 - (e.clientY - rect.top) / rect.height;

                  state.isHovering = true;

                }

            });

            

            elements.canvas.addEventListener('mouseleave', () => {

                state.isHovering = false;

            });

            

            elements.lyricPreview.addEventListener('click', (e) => {

                const target = e.target;

                if (target.classList.contains('prev-lyric') ||

                  target.classList.contains('current-lyric') ||

                  target.classList.contains('next-lyric')) {

                  const clickText = target.textContent;

                  jumpToLyricByText(clickText);

                }

            });

            

            elements.player.addEventListener('click', function(e) {

                console.log('播放按钮被点击');

                e.stopPropagation();

                togglePlayback();

            });

            

            elements.progressContainer.addEventListener('click', (e) => {

                if (!state.isAudioEnabled) return;

               

                const rect = elements.progressContainer.getBoundingClientRect();

                const percent = (e.clientX - rect.left) / rect.width;

                elements.audio.currentTime = percent * elements.audio.duration;

            });

            

            elements.progressContainer.addEventListener('mousedown', (e) => {

                state.isDragging = true;

                const rect = elements.progressContainer.getBoundingClientRect();

                const percent = (e.clientX - rect.left) / rect.width;

                elements.audio.currentTime = percent * elements.audio.duration;

            });

            

            document.addEventListener('mousemove', (e) => {

                if (state.isDragging) {

                  const rect = elements.progressContainer.getBoundingClientRect();

                  const percent = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));

                  elements.audio.currentTime = percent * elements.audio.duration;

                }

            });

            

            document.addEventListener('mouseup', () => {

                state.isDragging = false;

            });

            

            elements.prevBtn.addEventListener('click', () => {

                const prevIndex = state.currentSongIndex > 0 ? state.currentSongIndex - 1 : songs.length - 1;

                switchSong(prevIndex);

            });

            

            elements.nextBtn.addEventListener('click', () => {

                const nextIndex = state.currentSongIndex < songs.length - 1 ? state.currentSongIndex + 1 : 0;

                switchSong(nextIndex);

            });

            

            elements.playlistItems.forEach((item, index) => {

                item.addEventListener('click', () => {

                  switchSong(index);

                });

            });

            

            document.addEventListener('keydown', (e) => {

                if (e.code === 'Space') {

                  e.preventDefault();

                  togglePlayback();

                } else if (e.code === 'ArrowLeft') {

                  elements.audio.currentTime = Math.max(0, elements.audio.currentTime - 5);

                } else if (e.code === 'ArrowRight') {

                  elements.audio.currentTime = Math.min(elements.audio.duration, elements.audio.currentTime + 5);

                } else if (e.code === 'ArrowUp') {

                  state.volume = Math.min(1, state.volume + 0.1);

                  updateVolume();

                } else if (e.code === 'ArrowDown') {

                  state.volume = Math.max(0, state.volume - 0.1);

                  updateVolume();

                }

            });

            

            document.addEventListener('click', () => {

                state.userInteracted = true;

            });

      }



      // ===================== 播放控制函数 =====================

      function togglePlayback() {

            console.log('togglePlayback 被调用,当前状态:', elements.audio.paused ? '暂停' : '播放');

            

            if (elements.audio.paused) {

                elements.audio.play().catch(error => {

                  console.error('播放失败:', error);

                });

            } else {

                elements.audio.pause();

            }

            updatePlayerState();

      }



      // ===================== 更新播放状态(包含背景切换) =====================

      function updatePlayerState() {

            const bgContainer = document.getElementById('bj');

            

            if (elements.audio.paused) {

                // 暂停状态

                elements.player.classList.remove('playing');

                state.isPlaying = false;

                state.isAnimating = false;

               

                elements.bgVideo.pause();

               

                if (state.animationId) {

                  cancelAnimationFrame(state.animationId);

                  state.animationId = null;

                }

               



                bgContainer.style.background = `#55aa55 url(${state.staticBgImage}) no-repeat center/cover`;

                bgContainer.style.animationPlayState = 'paused';

                elements.canvas.style.animationPlayState = 'paused';

                elements.player.style.animationPlayState = 'paused';

               

            } else {

                // 播放状态

                elements.player.classList.add('playing');

                state.isPlaying = true;

                state.isAnimating = true;

               

                elements.bgVideo.play().catch(e => {

                  console.log('背景视频播放失败:', e);

                });

               

            

                bgContainer.style.background = "#55aa55 url(https://wj1.zp68.com:812/lxx/yunhua/2025/11/23/9F.gif) no-repeat center/cover";

                bgContainer.style.animationPlayState = 'running';

                elements.canvas.style.animationPlayState = 'running';

                elements.player.style.animationPlayState = 'running';

               

                if (window.render && window.render.draw) {

                  state.animationId = requestAnimationFrame(window.render.draw);

                }

               

                updateLyric();

                updateProgress();

            }

            console.log('播放状态更新:', state.isPlaying ? '播放中' : '已暂停');

      }



      // ===================== 自动播放 =====================

      function attemptAutoPlay() {

            elements.loading.style.display = 'block';

            

            const playPromise = elements.audio.play();

            

            if (playPromise !== undefined) {

                playPromise.then(() => {

                  elements.loading.style.display = 'none';

                  updatePlayerState();

                }).catch(error => {

                  console.log('自动播放被阻止,等待用户交互');

                  elements.loading.style.display = 'none';

                  

                  const hint = document.createElement('div');

                  hint.textContent = '无法播放,请更换链接或稍后再试';

                  hint.style.position = 'absolute';

                  hint.style.top = '50%';

                  hint.style.left = '50%';

                  hint.style.transform = 'translate(-50%, -50%)';

                  hint.style.background = 'rgba(0,0,0,1)';

                  hint.style.padding = '15px 30px';

                  hint.style.borderRadius = '10px';

                  hint.style.zIndex = '20';

                  hint.style.cursor = 'pointer';

                  document.getElementById('bj').appendChild(hint);

                  

                  const startPlayback = () => {

                        elements.audio.play().then(() => {

                            updatePlayerState();

                            hint.remove();

                            document.removeEventListener('click', startPlayback);

                        });

                  };

                  

                  hint.addEventListener('click', startPlayback);

                  document.addEventListener('click', startPlayback);

                });

            }

      }



      // ===================== 初始化 =====================

      async function init() {

            const currentSong = songs;

            

            elements.audio.src = currentSong.audioUrl;

            elements.bgVideo.src = currentSong.videoUrl;

            

            state.lyrics = parsePureLRC(currentSong.lyrics);

            const gl = initCheck();

            

            if (!gl) {

                console.error('WebGL不支持,播放器将无法正常工作');

                elements.loading.textContent = 'WebGL不支持,播放器无法正常工作';

                return;

            }

            

            window.render = initWebGL(gl);

            bindEvents(gl);

            

            if (state.lyrics.length > 0) {

                window.render.updateTextTexture(state.lyrics.text);

                elements.prevLyric.textContent = '';

                elements.currentLyric.textContent = state.lyrics.text;

                elements.nextLyric.textContent = state.lyrics?.text || '';

            }

            

            updateVolume();

            

            elements.audio.addEventListener('play', updatePlayerState);

            elements.audio.addEventListener('pause', updatePlayerState);

            

            elements.audio.addEventListener('ended', () => {

                const nextIndex = state.currentSongIndex < songs.length - 1 ? state.currentSongIndex + 1 : 0;

                switchSong(nextIndex);

            });

            

            attemptAutoPlay();

            

            console.log('播放器初始化完成');

      }



      if (document.readyState === 'loading') {

            document.addEventListener('DOMContentLoaded', init);

      } else {

            init();

      }

    </script>

</body>

</html>

小辣椒 发表于 2026-2-24 20:28

@亚纶音乐工作室

学习亚纶的代码套用玩一个

小辣椒 发表于 2026-2-24 20:31

因为是现成的图片,进度条我修改了一下,一键停止是背景,上面的标题字我修改后不漂亮了,就这样了

这个是偷懒制作,你看了就懂的{:4_170:}

红影 发表于 2026-2-24 20:59

好奇妙的歌词效果。欣赏亲爱的好帖,亚伦老师收礼开心{:4_187:}

红影 发表于 2026-2-24 21:04

这枫叶制作好像还是岁月的帖子里的吧,亲爱的加了人物。
标题字还会变色呢,小播也漂亮。给亲爱的点赞{:4_187:}

樵歌 发表于 2026-2-24 21:31

选的歌都是好听的,可我还是套都套不来{:4_198:}

也曾年轻 发表于 2026-2-25 09:41

https://5b0988e595225.cdn.sohucs.com/images/20200409/db39fb96f8534ea6a6583d3e35f6721e.gif

梦油 发表于 2026-2-25 10:27

变形的字幕很吸引人哦。

梦江南 发表于 2026-2-25 13:02

整体画面太引人入胜了!赞哦!{:4_187:}

杨帆 发表于 2026-2-25 20:45

谢谢小辣椒精彩制作,祝亚伦老师收礼开心{:4_176:}
页: [1]
查看完整版本: 枫叶歌曲二首 TO:亚纶