【水芙蓉播放器】望你
<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> 芙蓉的播放器设计创意棒,做工满含匠心很细腻,好作品,好制作,狠狠点赞喝彩,
手机模式也能看到特效呢,漂亮~{:4_123:} 明天爬电脑再来细赏,问好芙蓉~{:9_269:} 漂亮的播放器 这张带播放器的特效音画,元素丰富,效果惊艳。 歌曲节奏带劲,感谢水芙蓉精心制作分享! 祝周末愉快! 播放器美极了,动感音乐+特效,画面感一级棒{:9_285:} 欣赏点赞赞,问好芙蓉姑娘{:9_286:}