杨帆 发表于 2026-8-4 20:36

义字最难写 情字最难收

本帖最后由 杨帆 于 2026-8-4 22:57 编辑 <br /><br /><!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="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" rel="stylesheet">
<title>义字最难写 情字最难收</title>
<style>
:root {--color-1:#fff887;--color-2:#fc89e5;--color-3:#fd27d2;--color-4:#9cf9fc;--color-5:#0dd7de;--color-6:#fbcb6d;}
#papa {margin:30px 0;left:calc(50% - 81px);transform:translateX(-50%);width:1280px;height:750px;background: skyblue;box-shadow:2px 2px 8px #000;z-index:1;overflow:hidden;position:relative;--state:running;--begin1:0px;--begin2:0px;display:grid;place-items:center;}
#papa::before, #papa::after {position:absolute;content:'';inset:0;background:url('https://pic.imgdb.cn/item/66ab97d2d9c307b7e9734c2d.jpg') no-repeat 0 0 / 100% 100%;z-index:-2;}
#papa::before {background-position:var(--begin1) 0;}
#papa::after {transform:scale(-1,1);background-position:var(--begin2) 0;}
#lyricDisplay {position:absolute;top:15%;height:100%;letter-spacing:2px;display:flex;align-items:center;justify-content:center;overflow:hidden;position:relative;padding:0 1em;width:100%;font-weight:bold;font-family:'Long Cang','ZCOOL KuaiLe','Ma Shan Zheng','华文琥珀',STLiti,cursive;will-change:transform,opacity,color;transition:none;font-size:clamp(2em,3.5vw,5em);--state:running;}
.lyrichar {display:inline-block;opacity:0;text-shadow:1px 1px 2px #000,-1px -1px 2px #000;animation:charAppear 0.5s forwards,hue-rotate 1.5s linear infinite var(--state);margin:0 2px;}
@keyframes charAppear {to {opacity:1;transform:translate(0%);}}
@keyframes hue-rotate {50% {filter:hue-rotate(360deg);}}
.vid1,.vid2 {position:absolute;z-index:1;pointer-events:none;object-fit:cover;object-position:center;}
.vid1 {left:-10%;top:-10%;width:120%;height:120%;mask:linear-gradient(to bottom,red 35%,transparent 58%);-webkit-mask:linear-gradient(to bottom,red 35%,transparent 58%);}
.vid2 {left:0%;top:0%;width:100%;height:100%;mix-blend-mode:screen;mask:linear-gradient(to bottom,transparent 55%,transparent 75%,red 80%);-webkit-mask:linear-gradient(to bottom,transparent 55%,transparent 75%,red 80%);}
#fullscreen {position:absolute;border-radius:4px;color:#00F5FF;background:#0000;box-shadow:0px 0px 0px 0px #fff;padding:8px 8px;z-index:9;font-size:25px;font-weight:100;opacity:0;border:none;cursor:pointer;top:20px;right:2%;}
#statusDisplay {position:absolute;z-index:8;font-size:1.5em;font-weight:50;left:35%;top:15%;color:#fff;}
#stage {position:absolute;width:350px;height:350px;top:-45px;left:-25px;transform:translateX(-50%);z-index:18;overflow:hidden;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:16px;transform:scale(0.7);}
#cp {position:relative;width:250px;height:250px;flex-shrink:0;}
#cd {border:2px solid gold;z-index:10;position:absolute;top:40px;left:0px;width:200px;height:200px;border-radius:50%;background:url('https://pic.imgdb.cn/item/6430f89c0d2dde57770c848e.png') no-repeat center/cover;animation:spin 10s infinite linear;}
#mplayer {z-index:18;position:absolute;width:250px;height:250px;top:0;left:10px;opacity:1;transition:.2s;--disp1:0;--disp2:1;}
#mplayer::before, #mplayer::after {position:absolute;content:'';cursor:pointer;transition:.2s;width:250px;height:250px;}
#mplayer::before {background:url(https://pic.imgdb.cn/item/65f5104b9f345e8d03c1d60f.png)no-repeat center/cover;opacity:var(--disp1);}
#mplayer::after {background:url(https://pic.imgdb.cn/item/65f5103d9f345e8d03c17eca.png)no-repeat center/cover;opacity:var(--disp2);}
#tmsg {font:normal 18px sans-serif;color:#ffffff;}
#prog {width:50%;height:5px;cursor:pointer;box-shadow:0px 0px 0.1px 0.1px #666;border-radius:3px;}
@keyframes spin {100% {transform:rotate(360deg);}}
#papa:hover #fullscreen {opacity:.8;}
#fullscreen:hover {font-style:italic;}
.plane {width:200px;height:90px;z-index:5;position:absolute;top:0;left:0;offset-anchor:center;offset-rotate:auto 20deg;animation:fly 12s linear infinite;animation-play-state:running;}
@keyframes fly {0% {offset-distance:100%;}100% {offset-distance:0%;}}
.pause {animation-play-state:paused !important;}
</style>
</head>
<body>
<div id="papa">
        <div id="fullscreen">全屏欣赏</div>
        <div id="lyricDisplay"></div>
        <img class="plane" src="https://s3.bmp.ovh/2026/08/04/4iJpVuPh.png" />
        <div id="statusDisplay">加载中……</div>
        <div id="stage">
                <div id="cp">
                        <div id="cd"></div>
                        <div id="mplayer"></div>
                </div>
                <div id="tmsg">00:00 | 00:00</div>
                <div id="prog" title="调节进度"></div>
        </div>
        <audio id="aud" src="https://www.joy127.com/url/151508.mp3" autoplay loop preload="auto" playsinline></audio>
        <video class="vid1" src="https://img2.tukuppt.com/video_show/2418175/00/02/04/5b5085d637d83.mp4" loop preload="auto" playsinline autoplay muted></video>
        <video class="vid2" src="https://www.llz123.net/llz/llz/mulu/tongnian/yu.mp4" loop preload="auto" playsinline muted></video>
</div>
<script>
const papa = document.getElementById("papa");
const stage = document.getElementById('stage');
const mplayer = document.getElementById('mplayer');
const aud = document.getElementById("aud");
const vids = document.querySelectorAll('video');
const cd = document.getElementById("cd");
const prog = document.getElementById("prog");
const tmsg = document.getElementById("tmsg");
const statusDisplay = document.getElementById('statusDisplay');
const fullscreen = document.getElementById('fullscreen');
const lyricDisplay = document.getElementById('lyricDisplay');
const plane = document.querySelector('.plane');
const PathObserver = new ResizeObserver(entries => {
    entries.forEach(entry => {
      const { width, height } = entry.contentRect;
      const startX = -150, startY = 150;
      const endX = width + startX, endY = startY;   
      plane.style.setProperty('offset-path', `path('M ${startX} ${startY} C${180} ${80} ${380} ${50} ${480} ${50} S${720} ${60} ${endX} ${endY}')`);
    });
});
PathObserver.observe(papa);
let lrcText = `
义字最难写 情字最难收
义字最难写 情字最难收
义字最难写 情字最难收
常言说好人难做好路难修
却不见深情之人少泪流
问苍天为何真心难长久
原来是人心善变人情难留
义字最难写
情字最难收
忍字心头一把刀
孝字最难求
红尘路慢慢
苦乐自己受
人间万般不由己
善恶终有头
常言说好人难做好路难修
却不见深情之人少泪流
问苍天为何真心难长久
原来是人心善变人情难留
义字最难写
情字最难收
忍字心头一把刀
孝字最难求
红尘路慢慢
苦乐自己受
人间万般不由己
善恶终有头
义字最难写
情字最难收
忍字心头一把刀
孝字最难求
红尘路慢慢
苦乐自己受
人间万般不由己
善恶终有头
善恶终有头
`;
function parseLrc(lrc) {
    const lyrics = [];
    const lines = lrc.trim().split('\n');
    const lrcRegex = /\[(\d{2}):(\d{2})\.(\d{2})\](.*)/;
    for (let line of lines) {
      const match = line.match(lrcRegex);
      if (match) {
            const minutes = parseInt(match);
            const seconds = parseInt(match);
            const ms = parseInt(match);
            const totalSeconds = minutes * 60 + seconds + ms / 100;
            const text = match.trim();
            lyrics.push({ time: totalSeconds, text });
      }
    }
    return lyrics;
}
function displayLyricCharByChar(text) {
    lyricDisplay.innerHTML = '';
    const chars = text.split('');
    const colorList = ['var(--color-1)', 'var(--color-2)', 'var(--color-3)',
                     'var(--color-4)', 'var(--color-5)', 'var(--color-6)'];
    chars.forEach((char, i) => {
      const span = document.createElement('span');
      span.className = 'lyrichar';
      span.style.color = colorList;
      if (char === ' ') {
            span.innerHTML = '&nbsp;';
      } else {
            span.textContent = char;
      }
      const offset = i === 0 ? 0 : i * 30;
      span.style.transform = `translateY(${offset}px)`;
      span.style.animationDelay = `${i * 0.08}s`;
      if (/[,。!?,.!?]/.test(char)) {
            span.style.animationDelay = `${i * 0.08 + 0.08}s`;
      }
      lyricDisplay.appendChild(span);
    });
}
let lyrics = parseLrc(lrcText);
let currentLyricIndex = -1;
let isUpdating = false;
function resetLyrics() {
    currentLyricIndex = -1;
    lyricDisplay.innerHTML = '';
}
function syncLyricByTime(ct) {
    if (isUpdating) return;
    isUpdating = true;
    setTimeout(() => isUpdating = false, 100);
    for (let i = 0; i < lyrics.length; i++) {
      const start = lyrics.time;
      const end = (i < lyrics.length - 1) ? lyrics.time : Infinity;
      if (ct >= start - 0.3 && ct < end + 0.3) {
            if (currentLyricIndex !== i) {
                currentLyricIndex = i;
                displayLyricCharByChar(lyrics.text);
            }
            break;
      }
    }
}
function syncAnimationState() {
    const paused = aud.paused;
    lyricDisplay.style.setProperty('--state', paused ? 'paused' : 'running');
}
aud.addEventListener('timeupdate', () => {
    syncLyricByTime(aud.currentTime);
});
aud.addEventListener('ended', resetLyrics);
aud.addEventListener('playing', syncAnimationState);
aud.addEventListener('pause', syncAnimationState);
var raf = null;
var begin1 = 0, begin2 = 0, speed = 0.35;
var isAnimating = false;
function stopScroll() {
    if (raf) {
      cancelAnimationFrame(raf);
      raf = null;
    }
    isAnimating = false;
}
function moving() {
    var ww = papa.offsetWidth;
    begin1 += speed;
    if (speed > 0) {
      if (begin1 >= ww) begin1 = -ww;
    } else {
      if (begin1 <= -ww) begin1 = ww;
    }
    begin2 = begin1 >= 0
      ? -1 * (begin1 - ww + 1)
      : -1 * (begin1 + ww - 1);
    papa.style.setProperty('--begin1', begin1 + 'px');
    papa.style.setProperty('--begin2', begin2 + 'px');

    if (!aud.paused) {
      raf = requestAnimationFrame(moving);
    } else {
      stopScroll();
    }
}
function startScroll() {
    if (isAnimating) return;
    isAnimating = true;
    moving();
}
window.addEventListener('resize', function () {
    stopScroll();
    if (!aud.paused) {
      startScroll();
    }
});
const mState = () => {
    if(aud.paused){
      mplayer.style.setProperty('--disp1','1');
      mplayer.style.setProperty('--disp2','0');
      cd.style.animationPlayState = 'paused';
      mplayer.title = "播放";
      plane.classList.add('pause');
      stopScroll();
      vids.forEach(vid => vid.pause());
      statusDisplay.innerHTML = `<span style="color:#CC00FF">已暂停</span>`;
    }else{
      mplayer.style.setProperty('--disp1','0');
      mplayer.style.setProperty('--disp2','1');
      cd.style.animationPlayState = 'running';
      mplayer.title = "暂停";
      plane.classList.remove('pause');
      startScroll();
      vids.forEach(vid => vid.play());
    }
};
mplayer.addEventListener('click', () => aud.paused ? aud.play() : aud.pause());
aud.addEventListener('play', mState);
aud.addEventListener('pause', mState);
mState();
prog.onclick = (e) => {
    if(!aud.play()) return;
    if(aud.duration) aud.currentTime = aud.duration * e.offsetX / prog.offsetWidth;
}
const toMin = (val) => {
    if (!val || isNaN(val)) return '00:00';
    val = Math.floor(val);
    let min = Math.floor(val / 60);
    let sec = Math.floor(val % 60);
    min = min < 10 ?'0' + min : min;
    sec = sec < 10 ?'0' + sec : sec;
    return min + ':' + sec;
}
function renderPlayTime() {
      if(!aud.duration) return;
      const rem = aud.duration - aud.currentTime;
      statusDisplay.innerHTML = `<span style="color:#CC00FF">播放中:</span><span style="color:#FF0088">-${toMin(rem)}</span>`;
}
aud.addEventListener('timeupdate', () => {
    if(!aud.paused && aud.duration) renderPlayTime();      
    let percent = aud.currentTime / aud.duration * 100;
    percent = Math.max(0, Math.min(percent, 100));   
    prog.style.background = `linear-gradient(90deg, #FFFF66 ${percent}%, #0066CC ${percent}%)`;
    tmsg.innerText = toMin(aud.currentTime) + ' | ' + toMin(aud.duration);
});
aud.addEventListener('loadedmetadata', ()=>{
    if (isNaN(aud.duration)) return;
    tmsg.innerText = toMin(aud.currentTime) + ' | ' + toMin(aud.duration);
})
let fs = true;
fullscreen.onclick = () => {
if (fs) {
    fullscreen.innerText = '退出全屏';
    papa.requestFullscreen();
} else {
    fullscreen.innerText = '全屏欣赏';
    document.exitFullscreen();
}
fs = !fs;
};
['contextmenu', 'dragstart','selectstart'].forEach(type =>
document.getElementById('papa').addEventListener(type, e => e.preventDefault()));
</script>
</body>
</html>

杨帆 发表于 2026-8-4 20:37

代码来自马黑黑老师分享教程与作品,在此表示感谢{:4_180:}

霜染枫丹 发表于 2026-8-4 21:16

扬帆晚上好!您的作品技能展示的很漂亮,很赞佩!欣赏学习,祝制作愉快!{:4_204:}{:4_190:}

红影 发表于 2026-8-4 22:23

制作漂亮,只是这飞机路径有点奇怪,往下的不好,还不如让它斜飞直接出画面的好{:4_173:}

红影 发表于 2026-8-4 22:24

制作很漂亮,欣赏杨帆好帖。我分数用光了,等明天攒出来了再加哦{:4_187:}

杨帆 发表于 2026-8-4 22:59

霜染枫丹 发表于 2026-8-4 21:16
扬帆晚上好!您的作品技能展示的很漂亮,很赞佩!欣赏学习,祝制作愉快!

鼓捣着玩呢,谢谢枫丹老师鼓励,祝夏安{:4_187:}

杨帆 发表于 2026-8-4 23:00

红影 发表于 2026-8-4 22:23
制作漂亮,只是这飞机路径有点奇怪,往下的不好,还不如让它斜飞直接出画面的好

有道理,刚调整了路径,谢谢影子{:4_187:}

杨帆 发表于 2026-8-4 23:02

本帖最后由 杨帆 于 2026-8-4 23:03 编辑

红影 发表于 2026-8-4 22:24
制作很漂亮,欣赏杨帆好帖。我分数用光了,等明天攒出来了再加哦
谢谢鼓励~问好影子,分数不分数并没啥呀,开心最重要{:4_204:}

红影 发表于 2026-8-4 23:14

杨帆 发表于 2026-8-4 23:00
有道理,刚调整了路径,谢谢影子

嗯嗯,现在的路径好了很多,杨帆辛苦{:4_187:}

红影 发表于 2026-8-4 23:15

杨帆 发表于 2026-8-4 23:02
谢谢鼓励~问好影子,分数不分数并没啥呀,开心最重要

我今天不知怎么回事把分数都用没了,要等明天才能攒出来呢{:4_173:}
正好再来欣赏一遍帖子,也回思好事呢。

杨帆 发表于 2026-8-4 23:53

红影 发表于 2026-8-4 23:15
我今天不知怎么回事把分数都用没了,要等明天才能攒出来呢
正好再来欣赏一遍帖子,也回思好事 ...

是,一切皆是好事,勤劳的小蜜蜂您辛苦了{:4_187:}

梦江南 发表于 2026-8-5 11:16

看杨帆的音画是一种享受,这么多元素都溶合在一起太精彩了!{:4_187:}

杨帆 发表于 2026-8-5 11:19

梦江南 发表于 2026-8-5 11:16
看杨帆的音画是一种享受,这么多元素都溶合在一起太精彩了!

问好江南,谢谢鼓励,祝开心天天{:4_204:}

梦江南 发表于 2026-8-5 11:24

杨帆 发表于 2026-8-5 11:19
问好江南,谢谢鼓励,祝开心天天

这首歌曲很好听呢。{:4_180:}

偶然~ 发表于 2026-8-5 14:20

来欣赏杨帆老师的精品佳作

偶然~ 发表于 2026-8-5 14:20

制作大气磅礴,辛苦了,愿杨帆老师快乐像泡泡茶,越喝越甜,烦恼全消

杨帆 发表于 2026-8-5 14:38

偶然~ 发表于 2026-8-5 14:20
来欣赏杨帆老师的精品佳作

欢迎偶然~,谢谢鼓励,祝夏安{:4_190:}

偶然~ 发表于 2026-8-5 19:10

杨帆 发表于 2026-8-5 14:38
欢迎偶然~,谢谢鼓励,祝夏安

感谢杨帆老师带来的精彩,辛苦了!祝您和家人岁岁安康,幸福吉祥!

红影 发表于 2026-8-5 20:45

杨帆 发表于 2026-8-4 23:53
是,一切皆是好事,勤劳的小蜜蜂您辛苦了

哪里,你做帖子更辛苦啊{:4_187:}
页: [1]
查看完整版本: 义字最难写 情字最难收