醉美水芙蓉 发表于 4 天前

抹去泪水 - 韩宝仪

<meta charset="utf-8">
<style> @import url("https://fonts.googleapis.com/css2?family=Ma+Shan+Zheng&display=swap");
    #bj {
      position: relative;
      width: 1300px;
      height: 867px;
      margin-left: -300px;
      margin-top: 0;
       overflow: hidden;z-index:12345;
            background:url(https://bbs.cnzv.cc/up/upload/pic/12/20260309-9094c8233ef3f417b6e373bf33d73b9d.jpg)no-repeat center/cover;
           --state: running;font-family: "Ma Shan Zheng","仿宋体","SimHei", "Arial", "sans-serif";
    }
    canvas {animation: flash 2s linear infinite ;
position: absolute;
      width: 100%;
      height: 100%;z-index: 7;
      display: block;
      cursor: pointer; pointer-events: none;
      transition: transform 0.3s ease;
      margin-top: -80px;margin-left: -120px;
    }
    canvas:hover {
      transform: scale(1.05);
    }
@keyframes flash {
                to { filter: hue-rotate(360deg)brightness(260%); }
        }
    .lyric-preview { display: none;
      position: absolute;
      top: 240px;
      left: 35%;
      transform: translateX(-50%);
      color: #ff0000;
      font-size: 45px;
      text-align: center;
      width: 80%;
      z-index: 7;
      cursor: pointer; /**/
      padding: 10px;
      border-radius: 0px;
      transition: background-color 0.2s ease;
    }
    .lyric-preview:hover {
   color: #fff000;
    }
    .prev-lyric {
      opacity: 0.8;color: #fff000;
      margin-bottom: 8px;
      transition: opacity 0.2s ease;
    }
    .current-lyric {
      font-size: 55px;
      font-weight: 300;
      color: #ff0000
      transition: opacity 0.2s ease;
    }
   .prev-lyric:hover {
      transform: scale(1.15);
    }
    .next-lyric {
      opacity: 0.8;color: #fff000;
      margin-top: 8px;
      transition: opacity 0.2s ease;
    }
    .lyric-preview:active .current-lyric {
      opacity: 0.9;
    }
#mdiv {top:12%; left:85%;cursor: pointer;width:120px;height: 120px;animation:rot 10s linear infinite var(--state);position: absolute;filter:drop-shadow(#000 0px 0 1px);z-index: 40;}
@keyframes rot { to { transform: rotate(2turn);} }

#toggleButton{position: absolute;margin-top: 30px; margin-left: 1050px;color:#ff0000; width:180px; height:80px; font-size:25px;cursor:pointer; text-align: center;z-index:1235;}
       #toggleButton:hover { color:#fff;}
#canv {display: block; position: absolute;width:1300px; height:250px; bottom: 0px; left: 100px;z-index:6; animation: sp 60s linear infinite;}
@keyframes sp {
      0% { filter:hue-rotate(360deg)contrast(250%)brightness(120%); }
}
</style>

<div id="bj">
    <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>
<img id="mdiv"src="https://pic1.imgdb.cn/item/690c41ba3203f7be00db7fed.png">
   <div id="toggleButton">多行歌词</div>
    <canvas id="glcanvas" width="900" height="420"></canvas>

<canvas id='canv'width="1300" height="250"></canvas>

    <audio id="audio" src="https://aod.cos.tx.xmcdn.com/storages/88c2-audiofreehighqps/2D/16/GKwRIDoIHq0BABsn0QIUAUEq.m4a" loop autoplay crossOrigin="anonymous"></audio>
</div>
<script>
const state = {
      currentLyricIndex: 0,
      isAudioEnabled: true,
      isPlaying: false,
      mouseX: 0,
      mouseY: 0,
      isHovering: false,
      lyrics: [],
      hoverValue: 0,
      hoverSpeed: 0.05, // 降低hover动画速度,更流畅
      lastMouseMoveTime: 0,
      throttleDelay: 100 // 鼠标事件节流延迟
    };

    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')
    };

    // ===================== 初始化检测 =====================
    function initCheck() {
      // WebGL兼容性检测
      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('着色器错误:', 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.0, 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.5,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.3,dist);
                        float pulseEffect = 0.7 + 0.3*sin(u_time*4.0 + dist*8.0);
                        vec3 goldColor = vec3(0.9, 0.6+0.3*pulseEffect, 0.2+0.2*sin(u_time*3.0));
                        vec3 blueColor = vec3(0.3+0.4*sin(u_time*2.0 + dist*6.0), 0.6+0.3*pulseEffect, 0.9);
                        spectrumColor = mix(spectrumColor, mix(goldColor, blueColor, 0.5), hoverIntensity*u_hover*0.8);
                        glow += hoverIntensity*u_hover*0.8;
                  }
                  
                  col.rgb = mix(col.rgb, spectrumColor, 0.6*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 = '#000';
            tctx.font = '600 42px "Ma Shan Zheng","仿宋体","SimHei", "Arial"';
            tctx.textAlign = 'center';
            tctx.textBaseline = 'middle';
            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) 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.001;
            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);
   requestAnimationFrame(draw);
            
      }
   
         return { updateTextTexture, draw };
    }

    // ===================== 歌词同步 =====================
    function updateLyric() {
      if (!state.isAudioEnabled || !state.lyrics.length ) 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;
            }
      }

                  requestAnimationFrame(updateLyric);
            
   
    }

    // ===================== 事件绑定 =====================
    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);
            }
      });
    }

    // ==========================================
    async function init() {
      // LRC
      const pureLRCText = `
抹去泪水 - 韩宝仪
词:卡斯
曲:陈宏
LRC编辑:醉美水芙蓉
爱情常遇暴风雨
人生难免不如意
泪与欢笑成对比
冬去春来是温馨
人生的旅途喜与悲
风风雨雨会过去
命运握在你手里
成功更要靠自己
抹去眼中的泪滴
爱情常遇暴风雨
人生难免不如意
泪与欢笑成对比
冬去春来是温馨
人生的旅途喜与悲
风风雨雨会过去
命运握在你手里
成功更要靠自己
抹去眼中的泪滴
人生的旅途喜与悲
风风雨雨会过去
命运握在你手里
成功更要靠自己
抹去眼中的泪滴
谢谢欣赏!

      `;
      state.lyrics = parsePureLRC(pureLRCText);
      const gl = initCheck();
      if (!gl) return;
      window.render = initWebGL(gl);
      bindEvents(gl);
      requestAnimationFrame(window.render.draw);
      updateLyric();
      window.render.updateTextTexture(state.lyrics?.text || '');
      elements.prevLyric.textContent = '';
      elements.currentLyric.textContent = state.lyrics?.text || '';
      elements.nextLyric.textContent = state.lyrics?.text || '';
    }
    window.addEventListener('load', init);
mdiv.onclick = () => audio.paused ?audio.play(): audio.pause();
mState = () => {bj.style.setProperty('--state', audio.paused ?'paused' : 'running');

};
audio.onplaying = audio.onpause = () => mState();;



      
let fss = true;toggleButton.innerText = '多行歌词';
      toggleButton.onclick = () => {
            if (fss) {toggleButton.innerText = '多行歌词';
               lyricPreview.style.display = 'none';
            glcanvas.style.display = 'block';
      
            }else {toggleButton.innerText = '特效歌词';
               lyricPreview.style.display = 'block';
               glcanvas.style.display = 'none';
            }
            fss = !fss;
      };

</script>
<script>
(function () {

        let Act = new AudioContext();

        let audSrc = Act.createMediaElementSource(audio);

        let analyser = Act.createAnalyser();

        audSrc.connect(analyser);

        analyser.connect(Act.destination);

        let ctx = canv.getContext('2d');

        let width = canv.width;

        let height = canv.height;

        let ppColor = ctx.createLinearGradient(250,200,250,0);

        ppColor.addColorStop(0.98, '#ffaa00');

        let ppNum = 1300;

        let voiceHeight = new Uint8Array(analyser.frequencyBinCount);

            (function draw() {

                analyser.getByteFrequencyData(voiceHeight);

                let step = Math.round(voiceHeight.length / ppNum);

                ctx.clearRect(0, 0, width, height);

                for (let j = 0; j < ppNum; j++) {

                        let audiheighteight = voiceHeight;

                        ctx.fillStyle = ppColor;

                                ctx.fillRect(width / 2+ (j * 4), height, 3, -audiheighteight);

                        ctx.fillRect(width / 2- (j * 4), height, 3, -audiheighteight);

                }

                window.requestAnimationFrame(draw);

        })();
})();
</script>

klxf 发表于 3 天前

漂亮~谢谢友友精彩分享

醉美水芙蓉 发表于 3 天前

klxf 发表于 2026-3-10 12:11
漂亮~谢谢友友精彩分享

谢谢友友支持!

武朝歌 发表于 3 天前

好作品,欣赏,学习了。赞!

醉美水芙蓉 发表于 3 天前

武朝歌 发表于 2026-3-10 20:19
好作品,欣赏,学习了。赞!

谢谢老师光临!
页: [1]
查看完整版本: 抹去泪水 - 韩宝仪