醉美水芙蓉 发表于 2026-6-26 21:35:52

【水芙蓉播放器】望你

<meta charset="utf-8">
<style>
@import url("https://fonts.googleapis.com/css2?family=Liu+Jian+Mao+Cao&family=Long+Cang&family=Ma+Shan+Zheng&family=ZCOOL+KuaiLe&family=ZCOOL+QingKe+HuangYou&display=swap");
.pa{position:relative;display:grid;place-items:center;margin:30px 0;width:1280px;height:750px;left:calc(50% - 81px);transform:translateX(-50%);box-shadow:3px 3px 6px gray;overflow:hidden;z-index:1;background:#000 url('https://mpimg.cn/view.php/b5000bc190158ec5cb87ac7da7b02101.gi') no-repeat center/cover;font-family:"ZCOOL KuaiLe","Ma Shan Zheng","Long Cang","华文行楷","SimHei","Arial","sans-serif";--state:running;}
.bg-layer{position:absolute;inset:0;background-image:url("");background-repeat:no-repeat;background-position:center;background-size:100% 100%;z-index:0;transition:background-image 0.2s ease;}
.pa.play .bg-layer{background-image:url("https://mpimg.cn/view.php/b5000bc190158ec5cb87ac7da7b02101.gif");}
#svgObj{position:absolute;left:50%;top:15%;transform:translateX(-50%);width:100vw;height:40vw;z-index:5;fill:none;stroke:url(#grdWave);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:2 4;stroke-dashoffset:0;opacity:.45;animation:pMove 8s ease-in-out infinite alternate var(--state);}
@keyframes pMove{to{stroke-dashoffset:-180;}}
.vid{position:absolute;z-index:2;left:-10%;top:-10%;width:120%;height:120%;object-fit:cover;pointer-events:none;object-position:center;mix-blend-mode:screen;mask:linear-gradient(to bottom,red 20%,transparent 58%);-webkit-mask:linear-gradient(to bottom,red 20%,transparent 58%);}
#msvg{position:absolute;z-index:12;right:50px;top:50px;width:120px;height:120px;display:block;cursor:pointer;animation:rotate 4s 0.5s linear infinite var(--state);}
#msvg:hover { filter: unset !important; }
@keyframes rotate{to{transform:rotate(360deg);}}
#lyricCanvas{position:absolute;left:20%;top:5%;width:900px;height:180px;transform:perspective(800px) rotateY(20deg);background:transparent;z-index:5;filter:drop-shadow(0 var(--shadow-offset) 0 rgba(189,183,107,.75));--shadow-offset:clamp(580px, 45vh, 680px);}
#wrapper{position:absolute;left:20%;bottom:30px;font:500 60px/0px "Long Cang","Ma Shan Zheng","STKaiti";letter-spacing:4px;color:#ff0000;white-space:pre;width:860px;height:70px;text-align:center;filter:drop-shadow(#fff 1px 0 0) drop-shadow(#fff 0 1px 0) drop-shadow(#fff -1px 0 0) drop-shadow(#fff 0 -1px 0);z-index:6;}
.char{display:inline-block;padding:0px 2px;opacity:0;transform:translate(var(--x), var(--y)) rotate(270deg);animation:fadeIn 1.5s var(--delay) forwards var(--state),flas 0.5s linear infinite var(--state);}
@keyframes fadeIn{100%{transform:translate(0, 0%);opacity:1;}}
@keyframes flas{100%{filter:hue-rotate(360deg);}}
#fullscreen{border-radius:4px;position:absolute;color:DarkGray;padding:4px 8px;z-index:12;font-size:25px;border:none;cursor:pointer;top:25px;left:25px;background:transparent;}
#fullscreen:hover{font-style:italic;}
#statusDisplay{position:absolute;z-index:3;font-size:1.5em;font-weight:50;left:65%;top:25%;color:#fff;}
</style>
</head>
<body>
<div id="pa" class="pa">
<div id="wrapper"></div>
<div id="fullscreen">全屏欣赏</div>
<div id="statusDisplay">播放中: -2:20</div>
<canvas id="lyricCanvas" width="900" height="180"></canvas>
<audio id="aud" src="https://www.joy127.com/url/154096.mp3" loop autoplay></audio>
<video class="vid" src="https://img2.tukuppt.com/video_show/2418175/01/04/62/614ade273f6d1.mp4" autoplay loop muted></video>
<div class="bg-layer"></div>
<svg id="svgObj" viewBox="0 0 160 90">
<defs>
<linearGradient id="grdWave">
<stop offset="0" stop-color="#072afc"></stop>
<stop offset="0.15" stop-color="#1976D2"></stop>
<stop offset="1" stop-color="#2196F3"></stop>
</linearGradient>
</defs>
<symbol id="pb">
<path d='M0 45 C40 0 120 90 160 45'></path>
</symbol>
<use href="#pb" x="-5" y="0"></use>
<use href="#pb" x="0" y="5"></use>
<use href="#pb" x="5" y="10"></use>
</svg>
<svg id="msvg" width="400" height="400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><title id="svgTip">暂停</title>
<defs id="defs">
<radialGradient id="grd" cx="0.25" cy="0.25" r="0.25">
<stop offset="5%" stop-color="red"/>
<stop offset="30%" stop-color="lightgreen"/>
<stop offset="100%" stop-color="darkred"/>
</radialGradient>
<symbol id="sy" viewBox="0 0 400 400">
<circle cx="150" cy="20" r="20" fill="url(#grd)" stroke="pink" stroke-width="2"/>
<circle cx="150" cy="100" r="20" fill="url(#grd)" stroke="pink" stroke-width="2"/>
<circle cx="150" cy="180" r="20" fill="url(#grd)" stroke="pink" stroke-width="2"/>
</symbol>
</defs>
<use href="#sy"/>
<use href="#sy" transform="rotate(60, 200 200)"/>
<use href="#sy" transform="rotate(120, 200 200)"/>
<use href="#sy" transform="rotate(180, 200 200)"/>
<use href="#sy" transform="rotate(240, 200 200)"/>
<use href="#sy" transform="rotate(300, 200 200)"/>
</svg>
</div>
<script>
const msvg = document.getElementById('msvg');
const wave = document.getElementById('svgObj');
const paBox = document.getElementById('pa');
const vid = document.querySelector('.vid');
const statusDisplay = document.getElementById('statusDisplay');
const audioPlayer = document.getElementById('aud');
const svgTip = document.getElementById('svgTip');

let isPaused = true;

function togglePlayPause() {
if (isPaused) {
    isPaused =false ;
    paBox.style.animationPlayState = 'running';   
    vid.play();
    audioPlayer.play();
    paBox.classList.add('play');
    statusDisplay.innerHTML = `<span style="color:#CC00FF">播放中:</span><span style="color:#FF0088">${formatTime(-(audioPlayer.duration-audioPlayer.currentTime))}</span>`;
} else {
    isPaused = true;
    paBox.style.animationPlayState = 'paused';
    vid.pause();
    audioPlayer.pause();
    paBox.classList.remove('play');
    statusDisplay.textContent = '已暂停';
}
   paBox.style.setProperty('--state', isPaused ? 'paused' : 'running');
   svgTip.textContent = isPaused ? "播放" : "暂停";
   
}

msvg.addEventListener('click', (e) => {
      e.stopPropagation();
      togglePlayPause();
               
    });

function formatTime(seconds) {
const abs = Math.abs(seconds);
const m = Math.floor(abs/60);
const s = Math.floor(abs%60);
return `${seconds<0?'-':''}${m}:${s<10?'0':''}${s}`;
}

function renderPlayTime() {
      if(!audioPlayer.duration) return;
      const rem = audioPlayer.duration - audioPlayer.currentTime;
      statusDisplay.innerHTML = `<span style="color:#CC00FF">播放中:</span><span style="color:#FF0088">${formatTime(-rem)}</span>`;
}

(function() {
    const lyricCanvas = document.getElementById('lyricCanvas');
    const toggleBtn = document.getElementById('msvg');

    let gl = null;
    let webglProgram = null;
    let webglTexture = null;
    let webglUniforms = {};
    let webglTimeAcc = 0;
    let lyricRenderId = null;

    letisPaused = true;
    const waveSpeed = 1.0;

    let showText = " ";

    function initWebGLLyric() {
      gl = lyricCanvas.getContext('webgl') || lyricCanvas.getContext('experimental-webgl');
      if (!gl) {
            alert("浏览器不支持WebGL,无法展示水波文字");
            return null;
      }

      const vsSource = `
            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 fsSource = `
            precision highp float;
            varying vec2 v_uv;
            uniform sampler2D u_text;
            uniform float u_time;
            uniform vec2 u_mouse;
            uniform float u_hover;
            uniform float u_speed;
            void main() {
                vec2 uv = vec2(v_uv.x, 1.0 - v_uv.y);
                float t = u_time * u_speed;
                float waveX = sin(uv.y * 10.0 + t * 1.2) * 0.008;
                float waveY = cos(uv.x * 8.0 - t * 1.0) * 0.006;
                vec2 distorted = uv + vec2(waveX, waveY);

                float dist = distance(distorted, u_mouse);
                if (u_hover > 0.1 && dist < 0.25) {
                  float off = sin(dist * 15.0 - t * 6.0) * 0.008 * u_hover;
                  distorted += normalize(distorted - u_mouse) * off;
                }

                vec4 col = texture2D(u_text, distorted);
                if (col.a < 0.05) discard;

                float glow = smoothstep(0.3, 0.9, col.a);
                col.rgb = mix(col.rgb, vec3(1.0, 0.96, 0.88), glow * 0.6);

                if (u_hover > 0.1 && dist < 0.2) {
                  float halo = (1.0 - smoothstep(0.0,0.2,dist)) * u_hover * 0.5;
                  col.rgb += vec3(0.5, 0.3, 0.1) * halo;
                }
                gl_FragColor = col;
            }
      `;

      function compileShader(src, type) {
            const shader = gl.createShader(type);
            gl.shaderSource(shader, src);
            gl.compileShader(shader);
            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) return null;
            return shader;
      }

      const vs = compileShader(vsSource, gl.VERTEX_SHADER);
      const fs = compileShader(fsSource, gl.FRAGMENT_SHADER);
      const prog = gl.createProgram();
      gl.attachShader(prog, vs);
      gl.attachShader(prog, fs);
      gl.linkProgram(prog);
      webglProgram = prog;

      const vertices = new Float32Array([
            -1, -1, 0, 0,
            1, -1, 1, 0,
            -1,1, 0, 1,
            1,1, 1, 1
      ]);
      const vbo = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
      gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

      const a_pos = gl.getAttribLocation(prog, 'a_pos');
      const a_uv = gl.getAttribLocation(prog, '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);

      webglUniforms = {
            u_time: gl.getUniformLocation(prog, 'u_time'),
            u_text: gl.getUniformLocation(prog, 'u_text'),
            u_mouse: gl.getUniformLocation(prog, 'u_mouse'),
            u_hover: gl.getUniformLocation(prog, 'u_hover'),
            u_speed: gl.getUniformLocation(prog, 'u_speed')
      };

      webglTexture = gl.createTexture();
      gl.bindTexture(gl.TEXTURE_2D, webglTexture);
      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);

      const textCanvas = document.createElement('canvas');
      textCanvas.width = lyricCanvas.width;
      textCanvas.height = lyricCanvas.height;
      const tctx = textCanvas.getContext('2d');

      function updateTextTexture(text) {
            tctx.clearRect(0, 0, textCanvas.width, textCanvas.height);
            tctx.letterSpacing = "6px";
            tctx.font = '72px "Long Cang","Ma Shan Zheng","ZCOOL KuaiLe",KaiTi,SimHei,cursive';
            tctx.textAlign = 'center';
            tctx.textBaseline = 'middle';
            tctx.lineWidth = 2;
            tctx.strokeStyle = '#F8F3EB';
            tctx.shadowColor = "#00BBFF";
            tctx.shadowBlur = 2;
            tctx.strokeText(text, textCanvas.width / 2, textCanvas.height / 2);
            tctx.fillStyle = '#BBFF00';
            tctx.fillText(text, textCanvas.width / 2, textCanvas.height / 2);
            gl.bindTexture(gl.TEXTURE_2D, webglTexture);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textCanvas);
      }

      let mouseX = 0.5, mouseY = 0.5, hoverValue = 0;
      lyricCanvas.addEventListener('mousemove', (e) => {
            const rect = lyricCanvas.getBoundingClientRect();
            mouseX = (e.clientX - rect.left) / rect.width;
            mouseY = 1.0 - (e.clientY - rect.top) / rect.height;
            hoverValue = Math.min(1.0, hoverValue + 0.06);
      });
      lyricCanvas.addEventListener('mouseleave', () => { hoverValue = 0; });

      let startTime = performance.now() / 1000;
      function renderLoop() {
            if (!gl || !webglProgram) return;
            const now = performance.now() / 1000;
            const delta = now - startTime;
            if(isPaused){
                webglTimeAcc += delta * waveSpeed;
            }
            startTime = now;

            gl.viewport(0, 0, lyricCanvas.width, lyricCanvas.height);
            gl.clearColor(0, 0, 0, 0);
            gl.clear(gl.COLOR_BUFFER_BIT);
            gl.useProgram(webglProgram);

            gl.uniform1f(webglUniforms.u_time, webglTimeAcc);
            gl.uniform1f(webglUniforms.u_speed, isPaused ? waveSpeed : 0);
            gl.uniform2f(webglUniforms.u_mouse, mouseX, mouseY);
            gl.uniform1f(webglUniforms.u_hover, hoverValue);
            gl.activeTexture(gl.TEXTURE0);
            gl.bindTexture(gl.TEXTURE_2D, webglTexture);
            gl.uniform1i(webglUniforms.u_text, 0);

            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
            lyricRenderId = requestAnimationFrame(renderLoop);
      }
      renderLoop();

      return { updateTextTexture };
    }

    function bindControlButtons(){
      toggleBtn.onclick = ()=>{      
            isPaused = !isPaused;
         
      };
    }

    function init() {      
      const webglUpdater = initWebGLLyric();
      bindControlButtons();
      if (webglUpdater) {
            webglUpdater.updateTextTexture(showText);
      }
    }
    init();
   
})();

window.addEventListener('load', ()=>{
    togglePlayPause();
})

const gc = `望你
演唱:齐丹布
LRC编辑:醉美水芙蓉
我多想亲吻那天上的星辰
因为那就是你灵动的眼睛
就算今生不能与你相爱
你仍是我眼中最美的风景
望啊望 天上的星辰
闪啊闪 是你的眼睛
梦中有你给我一片柔情
我要打马走进你的心门
我多想拥抱那风中的彩云
因为那就是你飘逸的身影
就算今生不能与你同行
我也要成为守护你的绿荫
望啊望 风中的彩云
飘啊飘 是你的身影
在心上刻下你那深深的烙印
我要驰骋天涯把你追寻
望啊望 风中的彩云
飘啊飘 是你的身影
在心上刻下你那深深的烙印
我要驰骋天涯把你追寻
我要驰骋天涯把你追寻
把你追寻
谢谢欣赏!

`;
const gcAr = lrc2HC(gc);
let curkey = 1, isSeeking = false;
aud.ontimeupdate = () => {
const currentTime = audioPlayer.currentTime;
if(!audioPlayer.paused && audioPlayer.duration) renderPlayTime();
if(curkey > gcAr.length - 1) return;
if(aud.currentTime >= gcAr) {
const gap = gcAr?. ?? 0 - gcAr;
showLrc(gcAr, wrapper, gap);
}
};
aud.onended = () => {
curkey = 1;
aud.play();
}
aud.onseeked = () => calcKey();
function lrc2HC(text) {
let lrcAr = [];
let ar = text.trim().split('\n');
ar.sort();
let reg = /\[(\d+)[.:](\d+)[.:](\d+)\](.*)/;
ar.forEach(item => {
if(reg.test(item)) {
let result = item.match(reg);
let tmsg = parseInt(result) * 60 + parseInt(result) + parseInt(result) / 1000;
lrcAr.push(.trim()]);
}
});
return lrcAr ? lrcAr : ;
};
function calcKey() {
for (let j = 0; j < gcAr.length; j++) {
if (aud.currentTime <= gcAr) {
curkey = j - 1;
break;
}
}
if (curkey < 0) curkey = 0;
if (curkey > gcAr.length - 1) curkey = gcAr.length - 1;
let time = gcAr?. ?? 0 - gcAr;
isSeeking = false;
showLrc(gcAr, wrapper, time);
}
function showLrc(str, targetElm, time) {
if(isSeeking) return;
targetElm.innerHTML = '';
const chars = str.split('').map(c => c === ' ' ? ' ' : c);
const frg = document.createDocumentFragment();
chars.forEach((char, idx) => {
const span = document.createElement('span');
span.innerHTML = char;
span.classList.add('char');
const x = Math.random() * (Math.random() > 0.5 ? -600 : 600);
const y = Math.random() * (Math.random() > 0.5 ? 0 : 0);
span.style.cssText += `
color: #${Math.random().toString(11).substring(2,8)};
--x: ${x}px;
--y: ${y}px;
--delay: ${Math.random() * 0.5}s;
`;
frg.appendChild(span);
});
targetElm.appendChild(frg);
curkey ++;
setTimeout(() =>isSeeking = false, time);
}
let fs = true,fsTimer;
fullscreen.onclick = ()=>{
if(fs){
    fullscreen.innerText = '退出全屏';
    pa.requestFullscreen();
}else{
    fullscreen.innerText = '全屏欣赏';
    document.exitFullscreen();
}
fs = !fs;
};
pa.addEventListener('mousemove', () => {
clearTimeout(fsTimer);
fullscreen.style.opacity = '1';
fsTimer = setTimeout(() => fullscreen.style.opacity = '0', 2500);
});
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
    if (!aud.paused) aud.pause();
} else {
    if (aud.paused && !aud.ended) aud.play().catch(()=>{});
}
});

['contextmenu', 'dragstart', 'selectstart'].forEach(ev =>
pa.addEventListener(ev, (e) => { e.preventDefault(); })
);
msvg.onanimationiteration = () => {
msvg.style.setProperty('filter', `hue-rotate(${60 + Math.random() * 300}deg)`);
};
</script>

云端漫步 发表于 2026-6-26 21:39:27

芙蓉的播放器设计创意棒,做工满含匠心很细腻,好作品,好制作,狠狠点赞喝彩,

绿蔷薇 发表于 2026-6-26 22:54:04

手机模式也能看到特效呢,漂亮~{:4_123:}

绿蔷薇 发表于 2026-6-26 22:54:51

明天爬电脑再来细赏,问好芙蓉~{:9_269:}

游侠 发表于 2026-6-27 07:11:16

漂亮的播放器

欧阳风刀 发表于 2026-6-27 10:02:41

这张带播放器的特效音画,元素丰富,效果惊艳。

欧阳风刀 发表于 2026-6-27 10:03:26

歌曲节奏带劲,感谢水芙蓉精心制作分享!

欧阳风刀 发表于 2026-6-27 10:03:35

祝周末愉快!

念若莲 发表于 2026-6-27 10:52:35

播放器美极了,动感音乐+特效,画面感一级棒{:9_285:}

念若莲 发表于 2026-6-27 10:53:00

欣赏点赞赞,问好芙蓉姑娘{:9_286:}
页: [1] 2 3
查看完整版本: 【水芙蓉播放器】望你