杨帆 发表于 2026-5-7 17:07

难忘今宵

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>难忘今宵</title>   
</head>
<body>
<style>
@import url("https://fonts.googleapis.cn/css2?family=Ma+Shan+Zheng&display=swap");
.stage{margin: 130px 0 20px calc(50% - 781px);width: 1400px;height: 780px;background: #000;box-shadow: 3px 3px 6px gray;z-index: 1;overflow: hidden;user-select: none;position: relative;--state: running;border-radius: 32px;}
.heroes-show{position: absolute;top: 145px;left: 0;width: 100%;display: flex;align-items: center;justify-content: space-around;flex-wrap: nowrap;z-index: 8;transform: perspective(1em) rotateX(1deg);transform-origin:center;}
.worker-card{width: 160px;height: 160px;background: transparent;opacity: 0;cursor: pointer;animation: gentleBreathing 16s ease-in-out infinite,flash 1s infinite alternate,rotating 6s infinite linear;}
.worker-card img{width: 100%;height: 100%;object-fit: contain;display: block;backdrop-filter:lighten;}
.worker-card:nth-child(1){animation-delay: 0s;}
.worker-card:nth-child(2){animation-delay: 2s;}
.worker-card:nth-child(3){animation-delay: 4s;}
.worker-card:nth-child(4){animation-delay: 6s;}
@keyframes gentleBreathing {0%{opacity: 0;}15%{opacity: 1;}85%{opacity: 1;}100%{opacity: 0;}}
@keyframes flash {to{filter: hue-rotate(360deg);}}
@keyframes rotating{0%{transform:rotate(-90deg);}25%{transform:rotate(0deg);}50%{transform:rotate(90deg);}75%{transform:rotate(0deg);}100%{transform:rotate(-90deg);}}
.bg-video{position: absolute;top: 0;left: 0;width: 100%;height: 100%;object-fit: fill;pointer-events: none;z-index: 3;mask: linear-gradient(to right top, red 70%, transparent 90%);-webkit-mask: linear-gradient(to right top, red 70%, transparent 90%);}
.bg-video:nth-child(2){top: -10%;left: -10%;width: 120%;height: 120%;opacity: 0.6;mix-blend-mode: screen;mask: linear-gradient(to bottom, red 20%, transparent 60%);-webkit-mask: linear-gradient(to bottom, red 20%, transparent 60%);}
.song-info-vertical, .song-info-vertical2, .song-info-vertical3, .song-info-vertical4{position: absolute;writing-mode: vertical-rl;text-orientation: mixed;font-size: 1rem;font-weight: bold;font-family: YouYuan, '华文琥珀', 'Segoe UI', cursive;color: transparent;letter-spacing: 6px;z-index: 8;pointer-events: none;filter: drop-shadow(0 0 8px rgba(255,200,0,0.7));white-space: nowrap;}
.song-info-vertical{left:46.03%;top: 43%;transform: perspective(1em) rotateY(6deg);}
.song-info-vertical2{left: 44.03%;top: 43%;transform: perspective(1em) rotateY(-6deg);}
.song-info-vertical3{left: 91.2%;top: 57%;transform: perspective(1em) rotateY(6deg);}
.song-info-vertical4{left: 89.2%;top: 57%;transform: perspective(1em) rotateY(-6deg);}
.song-info-vertical::before, .song-info-vertical2::before,.song-info-vertical3::before, .song-info-vertical4::before{position: absolute;content: attr(data-text);top: 0;left: 0;width: 100%;height: 0%;color: #FFD966;background: linear-gradient(to bottom, #FFBF00, #FF7F00, #FFD966);background-clip: text;-webkit-background-clip: text;overflow: hidden;white-space: nowrap;filter: drop-shadow(0 0 5px #ffaa44);animation: textFillVertical 5.2s infinite alternate ease-in-out;text-shadow: 0 0 2px darkorange;writing-mode: vertical-rl;text-orientation: mixed;}
.song-info-vertical3::before, .song-info-vertical4::before{color: #98FB98;filter: drop-shadow(0 0 5px #7CFC00);}
.song-info-vertical.pause-animation::before,.song-info-vertical2.pause-animation::before,.song-info-vertical3.pause-animation::before,.song-info-vertical4.pause-animation::before{animation-play-state: paused !important;}
@keyframes textFillVertical {0%{height: 0%;letter-spacing: 8px;opacity: 0.7;}40%{letter-spacing: 2px;}100%{height: 100%;letter-spacing: 1px;opacity: 1;}}
#lrc{position: absolute;left: 0;right: 0;bottom: 25px;text-align: center;z-index: 8;font: normal 2.5rem STSong,'华文琥珀', 'Segoe UI', cursive;filter: drop-shadow(0 4px 12px rgba(0,0,0,0.6)) drop-shadow(0 0 6px #ffcc55);letter-spacing: 3px;pointer-events: none;display: flex;flex-wrap: wrap;justify-content: center;align-items: baseline;padding: 0 20px;transform: perspective(2em) rotateX(18deg);transform-origin: bottom center;}
.lrc-char{display: inline-block;color: #FFE484;font-size: 1.2em;font-weight: bold;text-shadow: 0 0 8px #ff9900, 2px 2px 5px #000;transform-origin: center center;margin: 0 2px;}
.lrc-space{display: inline-block;width: 0.56em;}
.lrc-char.spin{animation: spinOnce 2s cubic-bezier(0.4, 0.4, 0.4, 0.4) forwards;}
@keyframes spinOnce {0%{transform: rotate(0deg) scale(1);filter: brightness(1);color: #fff6c0;}50%{transform: rotate(180deg) scale(1.15);filter: brightness(2);color: #fff9c8;}100%{transform: rotate(360deg) scale(1);filter: brightness(1);color: #FFE484;}}
.independent-progress{position: absolute;top: 12%;left:calc(50% - 20px);transform:translateX(-50%);background: transparent;backdrop-filter: none;padding: 6px 15px;border-radius: 40px;display: flex;justify-content:space-between;align-items: center;z-index: 10;}
.independent-progress input{display: flex;justify-content:space-between;align-items:center;width: 180px;height: 3px;-webkit-appearance: none;background:#ffecb3;border-radius: 4px;outline: none;cursor: pointer;}
.independent-progress input::-webkit-slider-thumb{-webkit-appearance: none;width: 10px;height: 10px;background: Lime;border-radius: 50%;cursor: pointer;box-shadow: 0 0 5px gold;}
.time-indicator,#buttonTime{font-family: monospace;font-size: 15px;color: #ffecb3;background: transparent;padding: 2px 8px;border-radius: 20px;}
#bgCanvas {position: absolute;left: 31%;top: 51%;display: flex; align-items: center;justify-content: center; width: 50%;height: 50%;object-fit: cover;z-index: 6;pointer-events: none;opacity: 0.8;}
.dancer {mix-blend-mode: screen;mask: radial-gradient(circle at center, black 30%,transparent 50%,);-webkit-mask: radial-gradient(circle at center, black 30%,transparent 50% );}
.playback-btn{position: absolute;top: 67.5%;left:51.5%;width:5%;height: 5%;cursor: pointer;z-index: 15;filter: drop-shadow(0 5px 12px rgba(0,0,0,0.4));transition: transform 0.2s ease;transform: perspective(2em) rotateX(18deg);transform-origin: bottom center;},
.playback-btn:hover{transform: perspective(2em) rotateX(18deg) scale(1.05);}
.playback-btn:active{transform: perspective(2em) rotateX(18deg) scale(0.96);}
@keyframes discRotate {0%{transform: rotate(0deg);}100%{transform: rotate(360deg);}}
.spin-group{animation: discRotate 4s linear infinite;transform-origin: 50px 50px;}
#h4{position: absolute;top: 5%;left: 50%;transform: translateX(-50%);padding: 5px;letter-spacing: 20px;font-weight: 600;font-size: 3.8em;font-family:"Ma Shan Zheng",STXingkai, "华文行楷",STSong,'华文琥珀', 'Segoe UI', cursive;z-index: 10;}
#h4 span{position: relative;animation: my-words 1.5s infinite var(--state);}
#h4 span:nth-child(1){animation-delay: 0.2s;color: #6495ED;text-shadow: 0 0 1px #6495ED, 0 0 3px #87CEFA;}
#h4 span:nth-child(2){animation-delay: 0.4s;color: #98FB98;text-shadow: 0 0 1px #98FB98, 0 0 3px #B4EEB4;}
#h4 span:nth-child(3){animation-delay: 0.25s;color: #FF6B81;text-shadow: 0 0 1px #FF6B81, 0 0 3px #FF9AAA;}
#h4 span:nth-child(4){animation-delay: 0.35s;color: #FFD700;text-shadow: 0 0 1px #FFD700, 0 0 3px #FFEC8B;}
@keyframes my-words {0%{top: 0;}50%{top: -15px;}100%{top: 0;}}
#fullscreen{position:absolute;top:30px;right:30px;font:normal 1.5em 楷体;color:#fff;text-shadow:0 0 3px #000;opacity:1;cursor:pointer;user-select:none;z-index:8;}
#fullscreen:hover{font-style:italic;}
</style>
<div class="stage">   
    <video class="bg-video" muted playsinline autoplay loop>
      <source src="https://img.tukuppt.com/video_show/3657157/00/02/08/5b504416e276b.mp4" type="video/mp4">
    </video>
    <video class="bg-video" muted playsinline autoplay loop>
      <source src="https://img.tukuppt.com/video_show/15653652/01/59/07/63806a6eb7241.mp4" type="video/mp4">
    </video>   
    <div id="h4"><span>难</span><span>忘</span><span>今</span><span>宵</span></div>   
    <div class="heroes-show">
      <div class="worker-card"><img src="https://pic1.imgdb.cn/item/69874ced07b0859037cea432.png" alt="春" draggable="false"></div>
      <div class="worker-card"><img src="https://s3.bmp.ovh/imgs/2025/12/18/8267fead3dbb8e27.png" alt="夏" draggable="false"></div>
      <div class="worker-card"><img src="https://pic.imgdb.cn/item/67205f9dd29ded1a8cdba766.png" alt="秋" draggable="false"></div>
      <div class="worker-card"><img src="https://s3.bmp.ovh/imgs/2025/12/18/7338334170436de4.png" alt="冬" draggable="false"></div>
    </div>
    <div class="song-info-vertical" data-text="无论天涯与海角神州万里同怀抱">无论天涯与海角神州万里同怀抱</div>
    <div class="song-info-vertical2" data-text="无论天涯与海角神州万里同怀抱">无论天涯与海角神州万里同怀抱</div>
    <div class="song-info-vertical3" data-text="青山在人未老共祝愿祖国好">青山在人未老共祝愿祖国好</div>
    <div class="song-info-vertical4" data-text="青山在人未老共祝愿祖国好">青山在人未老共祝愿祖国好</div>
    <div id="lrc" data-lrc="难忘今宵">难忘今宵</div>
   <span id="fullscreen">全屏欣赏</span>
    <div class="independent-progress">
      <span id="buttonTime" class="time-indicator"> - 00:00</span>
      <input type="range" id="progress" min="0" max="100" value="0" step="any" title="调节进度">
      <span id="timeDisplay" class="time-indicator">00:00 | 00:00</span>      
    </div>   
    <canvas id="bgCanvas" class="dancer"></canvas>
    <div class="playback-btn" id="playBtn">
      <svg viewBox="0 0 100 100" style="display:block;">
            <defs>
                <radialGradient id="bgGrad" cx="50%" cy="50%" r="50%">
                  <stop offset="0%" stop-color="#FFE89A"/>
                  <stop offset="70%" stop-color="#FFB347"/>
                  <stop offset="100%" stop-color="#CC7A00"/>
                </radialGradient>
                <radialGradient id="innerGrad" cx="50%" cy="50%" r="50%">
                  <stop offset="0%" stop-color="#FFF7CC"/>                  
                  <stop offset="100%" stop-color="#FFD966"/>
                </radialGradient>
                <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
                  <feDropShadow dx="0" dy="3" stdDeviation="3" flood-color="#000000" flood-opacity="0.5"/>
                </filter>
            </defs>
            <circle cx="50" cy="50" r="45" fill="url(#bgGrad)" stroke="#FFDD99" stroke-width="2" filter="url(#shadow)"/>
            <circle cx="50" cy="50" r="42" fill="none" stroke="#E6A817" stroke-width="1.5" stroke-dasharray="8 6"/>
            <g id="rotatingGroup">
                <circle cx="50" cy="50" r="30" fill="url(#innerGrad)" stroke="#FFAA33" stroke-width="1.5"/>
                <text x="50" y="51" text-anchor="middle" dominant-baseline="central" font-size="28" font-weight="900" fill="#D32F2F" stroke="#8B0000" stroke-width="1.2" font-family="Arial, sans-serif">开心</text>
            </g>
      </svg>
    </div>
   <audio id="aud" src="https://music.163.com/song/media/outer/url?id=395334.mp3" preload="auto" loop autoplay></audio>
</div>
<script>
(function(){
    const audio = document.getElementById('aud');
    const stage = document.querySelector('.stage');
    const playbackBtn = document.querySelector('.playback-btn');
    const bgVideo = document.querySelectorAll('.bg-video');
    const progressBar = document.getElementById('progress');
    const timeDisplaySpan = document.getElementById('timeDisplay');
    const playBtn = document.getElementById('playBtn');
    const buttonTime = document.getElementById('buttonTime');
    const rotatingGroup = document.getElementById('rotatingGroup');
    const songInfo1 = document.querySelector('.song-info-vertical');
    const songInfo2 = document.querySelector('.song-info-vertical2');
    const songInfo3 = document.querySelector('.song-info-vertical3');
    const songInfo4 = document.querySelector('.song-info-vertical4');
    const h4 = document.getElementById('h4');
    const workers = document.querySelectorAll('.worker-card');
    function collectAnimatedElements() {
      const lrcChars = document.querySelectorAll('#lrc .lrc-char');
      const elements = [...workers, ...lrcChars];
      if (rotatingGroup) elements.push(rotatingGroup);
      return elements;
    }
    function pauseAllAnimations() {
      collectAnimatedElements().forEach(el => {
            el.style.animationPlayState = 'paused';
      });
      if (songInfo1) songInfo1.classList.add('pause-animation');
      if (songInfo2) songInfo2.classList.add('pause-animation');
      if (songInfo3) songInfo3.classList.add('pause-animation');
      if (songInfo4) songInfo4.classList.add('pause-animation');
    }
    function resumeAllAnimations() {
      collectAnimatedElements().forEach(el => {
            el.style.animationPlayState = '';
      });
      if (songInfo1) songInfo1.classList.remove('pause-animation');
      if (songInfo2) songInfo2.classList.remove('pause-animation');
      if (songInfo3) songInfo3.classList.remove('pause-animation');
      if (songInfo4) songInfo4.classList.remove('pause-animation');
    }
    function formatTime(seconds) {
      if (isNaN(seconds)) return "00:00";
      const mins = Math.floor(seconds / 60);
      const secs = Math.floor(seconds % 60);
      return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
    }
    function updateProgressAndTime() {
      if (audio.duration) {
            progressBar.value = (audio.currentTime / audio.duration) * 100;
            timeDisplaySpan.innerText = `${formatTime(audio.currentTime)} | ${formatTime(audio.duration)}`;
            let difference = audio.duration - audio.currentTime;                              
            document.getElementById('buttonTime').textContent =`- ${formatTime(difference)}`;
      }
    }
    function setPlayingVisual(isPlaying) {
      if (isPlaying) {
            rotatingGroup.classList.add('spin-group');
      } else {
            rotatingGroup.classList.remove('spin-group');
      }
    }
    function togglePlayPause() {
      if (audio.paused) {
            audio.play().catch(e => console.warn("播放失败:", e));
      } else {
            audio.pause();
      }      
    }
    playBtn.addEventListener('click', (e) => {
      e.stopPropagation();
      togglePlayPause();
    });
    workers.forEach(card => {
      card.addEventListener('click', (e) => {
            e.stopPropagation();
            togglePlayPause();
      });
    });
    progressBar.addEventListener('input', () => {
      if (!audio.duration) return;
      audio.currentTime = (progressBar.value / 100) * audio.duration;
      updateProgressAndTime();
    });
    audio.addEventListener('play', () => {
      setPlayingVisual(true);
      h4.style.setProperty('--state', 'running');
      bgVideo.forEach(vid => vid.play().catch(e => console.warn("视频播放失败:", e)));
      resumeAllAnimations();
      workers.forEach(card => card.title = "暂停");
      playBtn.title = "暂停";
    });
    audio.addEventListener('pause', () => {
      setPlayingVisual(false);
      h4.style.setProperty('--state', 'paused');
      bgVideo.forEach(vid => vid.pause());
      pauseAllAnimations();
      workers.forEach(card => card.title = "播放");
      playBtn.title = "播放";
    });
    audio.addEventListener('timeupdate', () => {
      updateProgressAndTime();
      updateLrcIndex();
    });
    audio.addEventListener('loadedmetadata', () => {
      updateProgressAndTime();
      setPlayingVisual(!audio.paused);
    });
    audio.addEventListener('ended', () => {
      audio.currentTime = 0;
      audio.play().catch(console.warn);
    });
    let mKey = 0, lastActiveCount = 0, played = [], lrcAr = [];
    const geci = `
难忘今宵
李谷一 - 难忘今宵
难忘今宵难忘今宵
无论天涯与海角
神州万里同怀抱
共祝愿祖国好祖国好
难忘今宵难忘今宵
无论天涯与海角
神州万里同怀抱
共祝愿祖国好祖国好
共祝愿祖国好
共祝愿祖国好
告别今宵告别今宵
无论新友与故交
明年春来再相邀
青山在人未老人未老
青山在人未老
青山在人未老
共祝愿祖国好
共祝愿祖国好
`;
    function parseLrc(text) {
      const arr = [];
      const lines = text.split('\n');
      for (const line of lines) {
            const match = line.match(/\[(\d+):(\d+)\.(\d+)\]/);
            if (match) {
                const time = parseInt(match)*60 + parseInt(match) + parseInt(match)/100;
                const lyric = line.replace(/\[.*?\]/, '').trim();
                if (lyric) arr.push({ time, lyric });
            }
      }
      arr.sort((a,b)=>a.time-b.time);
      for (let i=0; i<arr.length-1; i++) {
            arr.duration = arr.time - arr.time;
      }
      if(arr.length) arr.duration = 4;
      return arr;
    }
    lrcAr = parseLrc(geci);
    function renderLrc(text) {
      const lrcDiv = document.getElementById('lrc');
      lrcDiv.innerHTML = '';
      let visCount = 0;
      for(const ch of text) {
            if(ch.trim() === '') {
                const sp = document.createElement('span');
                sp.className = 'lrc-space';
                lrcDiv.appendChild(sp);
            } else {
                const span = document.createElement('span');
                span.className = 'lrc-char';
                span.textContent = ch;
                lrcDiv.appendChild(span);
                visCount++;
            }
      }
      played = new Array(visCount).fill(false);
      lastActiveCount = 0;
    }
    function spinChar(idx) {
      const chars = document.querySelectorAll('#lrc .lrc-char');
      if(idx >= chars.length || played) return;
      const span = chars;
      span.classList.remove('spin');
      void span.offsetHeight;
      span.classList.add('spin');
      played = true;
    }
    function updateCharActivation() {
      if(mKey < 0 || mKey >= lrcAr.length) return;
      const chars = document.querySelectorAll('#lrc .lrc-char');
      const total = chars.length;
      if(total === 0) return;
      const now = audio.currentTime;
      const start = lrcAr.time;
      const duration = lrcAr.duration || 2.8;
      const progress = Math.max(0, Math.min(1, (now - start) / duration));
      const active = Math.ceil(progress * total);
      for(let i = lastActiveCount; i < active; i++) spinChar(i);
      lastActiveCount = active;
    }
    function showLrc() {
      renderLrc(lrcAr.lyric);
      updateCharActivation();
    }
    function updateLrcIndex() {
      const cur = audio.currentTime;
      let newKey = 0;
      for(let i=0; i<lrcAr.length; i++) {
            if(cur >= lrcAr.time) newKey = i;
      }
      if(newKey !== mKey) {
            mKey = newKey;
            showLrc();
      } else {
            updateCharActivation();
      }
    }
    audio.addEventListener('seeked', updateLrcIndex);
    if(lrcAr.length) showLrc();
    stage.oncontextmenu = e => e.preventDefault();   
   
    let fs = true;
    const fullscreen = document.getElementById('fullscreen');
    let fsTimer;
    fullscreen.onclick = () => {
      if(fs) {
            fullscreen.innerText = '退出全屏';
            stage.requestFullscreen();
      } else {
            fullscreen.innerText = '全屏欣赏';
            document.exitFullscreen();
      }
      fs = !fs;
    };
    stage.addEventListener('mousemove', () => {
      clearTimeout(fsTimer);
      fullscreen.style.opacity = '1';
      fsTimer = setTimeout(() => fullscreen.style.opacity = '0', 3000);
    });
    playBtn.onanimationiteration = () => {
      playBtn.style.filter = `hue-rotate(${60 + Math.random() * 240}deg)`;
    };      
})();

const TOTAL_FRAMES = 29;
const FRAME_DURATION_MS = 100;
let frames = [];
let framesLoaded = false;
let animationId = null;
let isPlaying = true;
const canvas = document.getElementById('bgCanvas');
const ctx = canvas.getContext('2d');
const audio = document.getElementById('aud');
const playBtn = document.getElementById('playBtn');
function getFrameUrl(index) {
    const list = [
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_00_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_01_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_02_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_03_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_04_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_05_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_06_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_07_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_08_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_09_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_10_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_11_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_12_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_13_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_14_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_15_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_16_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_17_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_18_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_19_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_20_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_21_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_22_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_23_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_24_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_25_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_26_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_27_delay-0.1s.gif",
      "https://xlaj.cn/upfile/2026/05/06/frame/frame_28_delay-0.1s.gif"
    ];
    return list;
}
function loadFrames() {
    let loadedCount = 0;
    for (let i = 0; i < TOTAL_FRAMES; i++) {
      const img = new Image();
      img.src = getFrameUrl(i);
      frames.push(img);
      img.onload = () => {
            loadedCount++;
            if (loadedCount === TOTAL_FRAMES) {
                framesLoaded = true;
                canvas.width = 1300;
                canvas.height = 762;
                drawFrame(0);
                requestAnimationFrame(updateFrame);
            }
      };
    }
}
function drawFrame(index) {
    if (!framesLoaded || !frames) return;
    ctx.clearRect(0,0,canvas.width,canvas.height);
    ctx.drawImage(frames,0,0,canvas.width,canvas.height);
}
let frameIndex = 0;
function updateFrame() {
    if (!framesLoaded) { requestAnimationFrame(updateFrame); return; }
    if (isPlaying) {
      drawFrame(frameIndex);
      frameIndex = (frameIndex + 1) % TOTAL_FRAMES;
    }
    setTimeout(()=>{
      requestAnimationFrame(updateFrame);
    }, FRAME_DURATION_MS);
}
function pauseAnimation() { isPlaying = false; }
function resumeAnimation() { isPlaying = true; }
function syncAllAnimations() {
    const paused = audio.paused;
    paused ? pauseAnimation() : resumeAnimation();   
}
playBtn.onclick = (e) => {
    e.stopPropagation();
    syncAllAnimations();
};
audio.onplay = () => {
    resumeAnimation();
};
audio.onpause = () => {
    pauseAnimation();
};
loadFrames();
</script>
</body>
</html>

杨帆 发表于 2026-5-7 17:08

代码来自了了子老师、小辣椒管理员分享作品,在此表示感谢{:4_190:}

也曾年轻 发表于 2026-5-7 17:48

https://img1.oldkids.cn/upload/2021/12/01/blog_260844733_20211201053404192.gif

梦江南 发表于 2026-5-7 18:20

高难度音画作品,这么多元素融合在一起,厉害了!{:4_187:}

梦江南 发表于 2026-5-7 18:22

谢谢杨帆精彩音画分享!{:4_204:}{:4_199:}

霜染枫丹 发表于 2026-5-7 19:34

感谢杨帆的精彩分享,祝您制作愉快~~{:4_204:}{:4_190:}

马黑黑 发表于 2026-5-7 19:45

{:4_199:}

梦油 发表于 2026-5-7 19:57

现在,这样的词曲作者和歌唱演员太难找了。

小辣椒 发表于 2026-5-7 21:36

连回个帖都没有,已经用在你帖上了

小辣椒 发表于 2026-5-7 21:37

欣赏杨帆好制作{:4_187:}

杨帆 发表于 2026-5-7 21:44

也曾年轻 发表于 2026-5-7 17:48


谢谢年轻老师鼓励,请多指导{:4_190:}

杨帆 发表于 2026-5-7 21:45

梦江南 发表于 2026-5-7 18:22
谢谢杨帆精彩音画分享!

谢谢江南老师鼓励,祝开心{:4_204:}

杨帆 发表于 2026-5-7 21:46

霜染枫丹 发表于 2026-5-7 19:34
感谢杨帆的精彩分享,祝您制作愉快~~

谢谢枫丹老师鼓励,祝开心{:4_187:}

杨帆 发表于 2026-5-7 21:47

马黑黑 发表于 2026-5-7 19:45


谢谢马老师鼓励,请多指导{:4_190:}

杨帆 发表于 2026-5-7 21:48

梦油 发表于 2026-5-7 19:57
现在,这样的词曲作者和歌唱演员太难找了。

是啊,祝梦兄欣赏愉快{:4_190:}

杨帆 发表于 2026-5-7 21:52

梦江南 发表于 2026-5-7 18:20
高难度音画作品,这么多元素融合在一起,厉害了!

鼓捣着玩呢,音频用的是你的呦,谢谢江南{:4_204:}

杨帆 发表于 2026-5-7 22:12

小辣椒 发表于 2026-5-7 21:36
连回给帖都没有,已经用在你帖上了

只顾着欣赏学习了,你的逐帧动画制作很漂亮,迟复为歉{:4_180:}

杨帆 发表于 2026-5-7 22:13

小辣椒 发表于 2026-5-7 21:37
欣赏杨帆好制作

谢谢小辣椒鼓励,请多指导{:4_187:}

红影 发表于 2026-5-7 22:22

好漂亮的制作,精彩纷呈。
欣赏杨帆好帖{:4_199:}

杨帆 发表于 2026-5-7 22:23

红影 发表于 2026-5-7 22:22
好漂亮的制作,精彩纷呈。
欣赏杨帆好帖

谢谢影子鼓励,请多指导{:4_204:}
页: [1] 2
查看完整版本: 难忘今宵