醉美水芙蓉 发表于 2026-5-28 22:03:47

只为你绽放

<meta charset="utf-8">
<style>
#papa{margin:130px 0 20px calc(50% - 781px);width:1400px;height:850px;background:lightblue url('https://cccimg.com/view.php/2c2334bf5d7804d9ca358b78bbe921e0.gif') no-repeat center/cover;box-shadow:3px 3px 6px gray;z-index:1;overflow:hidden;user-select:none;display:grid;place-items:center;position:relative;--state:running;border-radius:32px;}
zxx-slide{display:block;width:100%;height:100%;position:absolute;}
.zxx-slide-a{width:100%;height:110%;position:absolute;bottom:-50px;display:none;}
.zxx-slide-a.in{z-index:1;}
.zxx-slide-img{width:100%;height:100%;object-fit:cover;pointer-events:none;display:block;}
.zxx-slide-index-x{position:absolute;left:0px;right:0;bottom:0px;text-align:center;font-size:0;z-index:1;}
@keyframes seed{0%{--seed:0}1%{--seed:1}2%{--seed:2}3%{--seed:3}4%{--seed:4}5%{--seed:5}6%{--seed:6}7%{--seed:7}8%{--seed:8}9%{--seed:9}10%{--seed:10}11%{--seed:11}12%{--seed:12}13%{--seed:13}14%{--seed:14}15%{--seed:15}16%{--seed:16}17%{--seed:17}18%{--seed:18}19%{--seed:19}20%{--seed:20}21%{--seed:21}22%{--seed:22}23%{--seed:23}24%{--seed:24}25%{--seed:25}26%{--seed:26}27%{--seed:27}28%{--seed:28}29%{--seed:29}30%{--seed:30}31%{--seed:31}32%{--seed:32}33%{--seed:33}34%{--seed:34}35%{--seed:35}36%{--seed:36}37%{--seed:37}38%{--seed:38}39%{--seed:39}40%{--seed:40}41%{--seed:41}42%{--seed:42}43%{--seed:43}44%{--seed:44}45%{--seed:45}46%{--seed:46}47%{--seed:47}48%{--seed:48}49%{--seed:49}50%{--seed:50}51%{--seed:51}52%{--seed:52}53%{--seed:53}54%{--seed:54}55%{--seed:55}56%{--seed:56}57%{--seed:57}58%{--seed:58}59%{--seed:59}60%{--seed:60}61%{--seed:61}62%{--seed:62}63%{--seed:63}64%{--seed:64}65%{--seed:65}66%{--seed:66}67%{--seed:67}68%{--seed:68}69%{--seed:69}70%{--seed:70}71%{--seed:71}72%{--seed:72}73%{--seed:73}74%{--seed:74}75%{--seed:75}76%{--seed:76}77%{--seed:77}78%{--seed:78}79%{--seed:79}80%{--seed:80}81%{--seed:81}82%{--seed:82}83%{--seed:83}84%{--seed:84}85%{--seed:85}86%{--seed:86}87%{--seed:87}88%{--seed:88}89%{--seed:89}90%{--seed:90}91%{--seed:91}92%{--seed:92}93%{--seed:93}94%{--seed:94}95%{--seed:95}96%{--seed:96}97%{--seed:97}98%{--seed:98}99%{--seed:99}100%{--seed:100}}
.zxx-slide-a.effect-round{-webkit-mask:radial-gradient(#000 calc(1% * var(--seed)), transparent calc(1% * var(--seed)));-webkit-mask-size:50px 50px;mask:radial-gradient(#000 calc(1% * var(--seed)), transparent calc(1% * var(--seed)));mask-size:50px 50px;animation:seed 1s ease-out;}
.zxx-slide-a.effect-topdown{-webkit-mask:linear-gradient(to bottom, #000 calc(1% * var(--seed)), transparent calc(1% * var(--seed)));mask:linear-gradient(to bottom, #000 calc(1% * var(--seed)), transparent calc(1% * var(--seed)));-webkit-mask-size:100% 100%;mask-size:100% 100%;animation:seed 1s ease-out;}
@keyframes fadeIn{0%{opacity:0;}100%{opacity:1;}}
.zxx-slide-a.effect-fade{mask:none;-webkit-mask:none;animation:fadeIn 1s ease-out forwards;}
@keyframes blurToClear{from{filter:blur(20px);opacity:0;}to{filter:blur(0);opacity:1;}}
.zxx-slide-a.effect-clear{mask:none;-webkit-mask:none;animation:blurToClear 1.5s ease-out forwards;}
.block-effect-wrapper{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;display:grid;pointer-events:none;}
.dissolve-wrapper{grid-template-columns:repeat(30, 1fr);grid-template-rows:repeat(20, 1fr);}
.pixelate-wrapper{grid-template-columns:repeat(40, 1fr);grid-template-rows:repeat(30, 1fr);}
.mosaic-wrapper{grid-template-columns:repeat(15, 1fr);grid-template-rows:repeat(10, 1fr);}
.block-piece{background-color:#006400;transition:all 1.2s;opacity:0.6;border-radius:2%;transform:scale(1);box-shadow:0px 0px 0px 2px #ffffff;}
.shatter-wrapper{perspective:1500px;position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;pointer-events:none;}
.shatter-piece{position:absolute;background:no-repeat center/cover;transition:transform 1.4s, opacity 1s;transform-origin:center;opacity:1;}
@keyframes blockHide{to{transform:scale(0);opacity:0;}}
.zxx-slide-a.effect-dissolve .block-piece,.zxx-slide-a.effect-pixelate .block-piece,.zxx-slide-a.effect-mosaic .block-piece{animation:blockHide 1.2s ease-out forwards;}
.zxx-slide-a.effect-shatter .shatter-piece{transform:translate3d(100px, -100px, -500px) rotate(180deg);opacity:0;}
.lyrics{margin:0;z-index:20;top:92%;left:50%;transform:translate(-50%, -50%);height:100px;text-align:center;position:absolute;}
.lyric-line{width:100%;position:relative;height:60px;overflow:visible;font:300 50px '华文行楷', sans-serif;line-height:60px;text-align:left;white-space:nowrap;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);}
.lyric-mask{position:absolute;color:transparent;background:linear-gradient(90deg,cyan,teal);background-clip:text;-webkit-background-clip:text;text-shadow:1px 1px 1px rgba(0,0,0,.45);white-space:nowrap;}
.lyric-original{color:#ADFF2F;white-space:nowrap;}
#fullscreen{position:absolute;top:30px;left: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;}
.spectrum-player{position:absolute;top:4%;right:2%;z-index:30;width:110px;height:110px;cursor:pointer;user-select:none;filter:none;box-shadow:none;}
.progress-ring-svg{position:absolute;top:0;left:0;width:100%;height:100%;transform:rotate(-90deg);filter:none;}
.progress-ring-circle{fill:none;stroke:#ffd700;stroke-width:2.5;stroke-linecap:round;stroke-dasharray:238.76;stroke-dashoffset:238.76;transition:stroke-dashoffset 0.08s linear;}
#fireworksCanvas{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:31;}
.spectrum-dots{position:absolute;width:100%;height:100%;top:0;left:0;pointer-events:none;transform:translate(-3px, -3px);}
.spectrum-dot{position:absolute;width:6px;height:6px;border-radius:50%;background:#ffaa33;box-shadow:0 0 4px #ffcc55, 0 0 2px #ffaa44;transform-origin:center;transition:transform 0.05s linear, background 0.05s linear, box-shadow 0.05s ease;will-change:transform, background, box-shadow;}
.center-btn{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);width:70px;height:70px;border-radius:50%;background:rgba(0, 0, 0, 0.45);backdrop-filter:blur(8px);border:1px solid rgba(255, 215, 0, 0.9);display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all 0.2s;z-index:5;font-family:'Microsoft YaHei', monospace;text-align:center;color:#ffd700;text-shadow:0 0 2px #ff0000;line-height:1.2;box-shadow:none;}
.center-btn:hover{background:rgba(0, 0, 0, 0.8);border-color:#ffaa00;transform:translate(-50%, -50%) scale(1.02);box-shadow:none;}
.time-remain{font-size:18px;font-family:monospace;margin-top:2px;}
@media (max-width:1000px){.spectrum-player{width:95px;height:95px;}.center-btn{width:60px;height:60px;}.time-remain{font-size:10px;}}
</style>
<div id="papa">
<div class="spectrum-player" id="spectrumPlayer">
<canvas id="fireworksCanvas"></canvas>
<svg class="progress-ring-svg" viewBox="0 0 110 110">
<circle class="progress-ring-circle" cx="55" cy="55" r="38"></circle>
</svg>
<div class="spectrum-dots" id="spectrumDots"></div>
<div class="center-btn" id="centerBtn">
<div class="time-remain" id="btnTimeRemain">-00:00</div>
</div>
</div>
<zxx-slide>
<div class="zxx-slide-x">
<p class="zxx-slide-a">      
<video class="zxx-slide-img" src="https://img-baofun.zhhainiao.com/pcwallpaper_ugc/preview/701485d0b5bfae8158342acdccd271c1_preview.mp4" loop muted autoplay preload="auto" playsinline></video>
<p class="zxx-slide-a">
<video class="zxx-slide-img" src="https://img-baofun.zhhainiao.com/pcwallpaper_ugc/preview/53b4e149ea039f14fded82e4e9a04f27_preview.mp4" loop muted autoplay preload="auto" playsinline></video></p>
<p class="zxx-slide-a">
<video class="zxx-slide-img" src="https://img-baofun.zhhainiao.com/pcwallpaper_ugc/preview/d6df4b8d6c0474b2290825fdce256825_preview.mp4" loop muted autoplay preload="auto" playsinline></video></p>
</div>
</zxx-slide>
<span id="fullscreen">全屏欣赏</span>
<div class="lyrics">
<div class="lyric-line">
<div class="lyric-mask"></div>
<div class="lyric-original"></div>
</div>
</div>
</div>
<audio id="audio" src="https://www.joy127.com/url/151698.mp3" autoplay loop></audio>
<script>
var eleZxxSlides = document.querySelectorAll('zxx-slide');
const effectList = ['effect-round','effect-topdown','effect-fade','effect-clear','effect-dissolve','effect-pixelate','effect-mosaic','effect-shatter'];
[].slice.call(eleZxxSlides).forEach(function (container) {
    var timerSlide = null;
    var indexSlide = 0;
    var ANIMATION_DURATION = 1200;
    var WAIT_DURATION = 8800;
    var TOTAL_INTERVAL = ANIMATION_DURATION + WAIT_DURATION;       
    var eleSlides = [].slice.call(container.querySelectorAll('p'));
    function getRandomEffect(){
      let ran = Math.floor(Math.random() * effectList.length);
      return effectList;
    }
    function createEffectLayer(slide, effect) {
      let oldLayer = slide.querySelector('.block-effect-wrapper, .shatter-wrapper');
      if(oldLayer) oldLayer.remove();
      let imgSrc = slide.querySelector('.zxx-slide-img')?.poster || '';
      let video = slide.querySelector('.zxx-slide-img');
      if(video && video.poster) imgSrc = video.poster;
      if(effect === 'effect-dissolve' || effect === 'effect-pixelate' || effect === 'effect-mosaic'){
            let wrapper = document.createElement('div');
            wrapper.className = `block-effect-wrapper ${effect.replace('effect-','')}-wrapper`;
            let cols = wrapper.classList.contains('dissolve-wrapper') ? 30 : wrapper.classList.contains('pixelate-wrapper') ? 40 : 15;
            let rows = wrapper.classList.contains('dissolve-wrapper') ? 20 : wrapper.classList.contains('pixelate-wrapper') ? 30 : 10;
            let total = cols * rows;
            for(let i=0; i<total; i++){
                let piece = document.createElement('div');
                piece.className = 'block-piece';
                wrapper.appendChild(piece);
            }
            slide.appendChild(wrapper);
      }
      else if(effect === 'effect-shatter'){
            let wrapper = document.createElement('div');
            wrapper.className = 'shatter-wrapper';
            let cols = 8, rows = 5;
            let w = 100/cols, h = 100/rows;
            for(let y=0; y<rows; y++){
                for(let x=0; x<cols; x++){
                  let piece = document.createElement('div');
                  piece.className = 'shatter-piece';
                  piece.style.width = w+'%';
                  piece.style.height = h+'%';
                  piece.style.left = x*w+'%';
                  piece.style.top = y*h+'%';
                  piece.style.backgroundImage = `url(${imgSrc})`;
                  piece.style.backgroundPosition = `${-x*w}% ${-y*h}%`;
                  wrapper.appendChild(piece);
                }
            }
            slide.appendChild(wrapper);
      }
    }
    function showCurrentSlide(){
      eleSlides.forEach(function (slide, index) {       
            if (indexSlide == index) {
                effectList.forEach(eff=>slide.classList.remove(eff));
                let randEff = getRandomEffect();
                createEffectLayer(slide, randEff);
                slide.classList.add('in', randEff);
                slide.style.display = 'block';
            } else {
                slide.classList.remove('in');
                effectList.forEach(eff=>slide.classList.remove(eff));
                slide.style.display = 'none';
            }
      });
    }
    function nextSlide(){
      indexSlide++;
      if (indexSlide >= eleSlides.length) indexSlide = 0;
      showCurrentSlide();
      if(!audio.paused){
            timerSlide = setTimeout(nextSlide, TOTAL_INTERVAL);
      }
    }
    showCurrentSlide();
    function startLoop(){
      clearTimeout(timerSlide);
      timerSlide = setTimeout(nextSlide, TOTAL_INTERVAL);
    }
    function stopLoop(){
      clearTimeout(timerSlide);
    }
    audio.addEventListener('play', startLoop);
    audio.addEventListener('pause', stopLoop);
    if(!audio.paused){
      startLoop();
    }
});
</script>
<script>
const lrc = `只为你绽放
Hmmm
Mmmm
Mmmm
        LRC编辑:醉美水芙蓉
Comparing you to a flower that blooms
Blooms only once
When I have only that your beauty stands
Will you forget each other?
After a long time
Will there be someone else crossing our line
I hope you are still here
Just want to know how are you?
And how is your life today?
I traveled to meet you
I just want to see
Your face that's all I need
It's okay
I understand the miles we've grown
I just want to keep the story
Keep the smile we've known
Deep down in case in the end we don't meet
I want you to know that I just want that so sweet
I hope you are still here
Just want to know how are you?
And how is your life today?
I traveled to meet you
I just want to see
Your face that's all I need
Sometimes we open our eyes wake up and forget
Hmmm
Something's missing deep inside a feeling unmet
Hmmm
But in the quiet of the night your memory stays
Guiding me through the shadows lighting up my days
I hope you are still here
Just want to know how are you?
And how is your life today?
I traveled to meet you
I just want to see
Your face that's all I need
谢谢欣赏!
`;
const audio = document.getElementById('audio');
const lyrics = parseLyrics(lrc);
const lyricMask = document.querySelector('.lyric-mask');
const lyricOriginal = document.querySelector('.lyric-original');
let currentIndex = -1;
let currentLyric = null;
function parseLyrics(lrcText) {
    const lyrics = [];
    const lines = lrcText.split('\n').filter(line => line.trim());
    lines.forEach((line, index) => {
      const timeMatch = line.match(/\[(\d+:\d+\.\d+)\]/);
      if (timeMatch) {
            const timeStr = timeMatch;
            const text = line.replace(/\[.*?\]/g, '').trim();
            if (text) {
                const startTime = timeToMs(timeStr);
                const nextLine = lines;
                const nextTimeMatch = nextLine ? nextLine.match(/\[(\d+:\d+\.\d+)\]/) : null;
                const endTime = nextTimeMatch ? timeToMs(nextTimeMatch) : startTime + 5000;
                lyrics.push({
                  startTime,
                  endTime,
                  text,
                  durations: calculateCharDurations(text, startTime, endTime)
                });
            }
      }
    });
    return lyrics;
}
function calculateCharDurations(text, startTime, endTime) {
    const totalDuration = endTime - startTime;
    const charCount = text.length;
    const baseDur = Math.floor(totalDuration / charCount);
    const durations = new Array(charCount).fill(baseDur);
    const remainder = totalDuration % charCount;
    for (let i = 0; i < remainder; i++) {
      durations++;
    }
    return durations;
}
function timeToMs(timeStr) {
    const parts = timeStr.split(':');
    const minutes = parseInt(parts, 10);
    const secondsAndMs = parts.split('.');
    const seconds = parseInt(secondsAndMs, 10);
    const ms = parseInt(secondsAndMs || 0, 10);
    return minutes * 60 * 1000 + seconds * 1000 + ms;
}
function getCurrentLyricIndex(lyrics, currentTimeMs) {
    for (let i = 0; i < lyrics.length; i++) {
      if (currentTimeMs >= lyrics.startTime && currentTimeMs <= lyrics.endTime) {
            return i;
      }
    }
    return -1;
}
function updateLyricDisplay(index) {
    if (index < 0 || index >= lyrics.length) return;
    currentIndex = index;
    currentLyric = lyrics;
    lyricOriginal.textContent = currentLyric.text;
    lyricMask.textContent = currentLyric.text;
    lyricMask.style.width = '0';
}
function updateLyricMask(currentTimeMs) {
    if (!currentLyric) return;
    const elapsed = currentTimeMs - currentLyric.startTime;
    const totalDuration = currentLyric.durations.reduce((a, b) => a + b, 0);
    let charIndex = 0;
    let accumulated = 0;
    for (let i = 0; i < currentLyric.durations.length; i++) {
      accumulated += currentLyric.durations;
      if (elapsed <= accumulated) {
            charIndex = i + 1;
            break;
      }
    }
    if (elapsed >= totalDuration) charIndex = currentLyric.text.length;
    charIndex = Math.min(charIndex, currentLyric.text.length);
    const temp = document.createElement('span');
    temp.style.cssText = 'visibility:hidden;position:absolute;font:300 50px "华文隶书"';
    document.body.appendChild(temp);
    temp.textContent = currentLyric.text.substring(0, charIndex);
    lyricMask.style.width = temp.offsetWidth + 'px';
    document.body.removeChild(temp);
}
audio.addEventListener('timeupdate', () => {
    const now = audio.currentTime * 1000;
    const idx = getCurrentLyricIndex(lyrics, now);
    if (idx !== currentIndex) updateLyricDisplay(idx);
    updateLyricMask(now);
});
updateLyricDisplay(0);
let state = { isPlaying: false, isDragging: false };
const dom = {
    spectrumPlayer: document.getElementById('spectrumPlayer'),
    progressCircle: document.querySelector('.progress-ring-circle'),
    centerBtn: document.getElementById('centerBtn'),
    btnTimeRemain: document.getElementById('btnTimeRemain'),
    fireworksCanvas: document.getElementById('fireworksCanvas'),
    audio: document.getElementById('audio')
};
const innerRadius = 38;
const circumference = 2 * Math.PI * innerRadius;
let spectrumAnimationId = null, spectrumDots = [];
const totalDots = 24;
let globalRotationRad = 0;
const ROTATION_SPEED = 0.0068;
let originalAngles = [];
let dotRadius = 0;
let dotCenter = { x: 0, y: 0 };
const fwCtx = dom.fireworksCanvas.getContext('2d');
let particles = [];
let fwWidth, fwHeight, fwCenterX, fwCenterY;
function resizeFireworksCanvas() {
    fwWidth = dom.spectrumPlayer.clientWidth;
    fwHeight = dom.spectrumPlayer.clientHeight;
    dom.fireworksCanvas.width = fwWidth;
    dom.fireworksCanvas.height = fwHeight;
    fwCenterX = fwWidth / 2;
    fwCenterY = fwHeight / 2;
}
resizeFireworksCanvas();
window.addEventListener('resize', resizeFireworksCanvas);
class Particle {
    constructor(angle, speed, color) {
      this.x = fwCenterX;
      this.y = fwCenterY;
      this.vx = Math.cos(angle) * speed;
      this.vy = Math.sin(angle) * speed;
      this.alpha = 1;
      this.life = 1;
      this.radius = Math.random() * 2 + 1;
      this.color = color;
    }
    update() {
      this.x += this.vx;
      this.y += this.vy;
      this.life -= 0.02;
      this.alpha = this.life;
    }
    draw(ctx) {
      ctx.save();
      ctx.globalAlpha = this.alpha;
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
      ctx.fillStyle = this.color;
      ctx.fill();
      ctx.restore();
    }
}
function emitFireworks(intensity) {
    const count = Math.floor(intensity * 8);
    const baseSpeed = 1.5 + intensity * 2;
    const colors = ['#ffdd00', '#ff8800', '#ff4444', '#ffffff'];
    for (let i = 0; i < count; i++) {
      const angle = Math.random() * Math.PI * 2;
      const speed = baseSpeed * (0.5 + Math.random() * 0.5);
      const color = colors;
      particles.push(new Particle(angle, speed, color));
    }
}
function animateFireworks() {
    fwCtx.clearRect(0, 0, fwWidth, fwHeight);
    particles = particles.filter(p => p.life > 0);
    particles.forEach(p => {
      p.update();
      p.draw(fwCtx);
    });
    if (state.isPlaying) {
      requestAnimationFrame(animateFireworks);
    } else {
      fwCtx.clearRect(0, 0, fwWidth, fwHeight);
    }
}
function updateDotGeometry() {
    const w = dom.spectrumPlayer.clientWidth;
    const h = dom.spectrumPlayer.clientHeight;
    dotCenter.x = w / 2;
    dotCenter.y = h / 2;
    dotRadius = Math.min(w, h) * 0.52;
}
function rebuildSpectrumDots() {
    const container = document.getElementById('spectrumDots');
    if (!container) return;
    container.innerHTML = '';
    spectrumDots = [];
    originalAngles = [];
    updateDotGeometry();
    for (let i = 0; i < totalDots; i++) {
      const angle = (i / totalDots) * 2 * Math.PI;
      originalAngles.push(angle);
      const dot = document.createElement('div');
      dot.className = 'spectrum-dot';
      const x = dotCenter.x + dotRadius * Math.cos(angle);
      const y = dotCenter.y + dotRadius * Math.sin(angle);
      dot.style.left = `${x}px`;
      dot.style.top = `${y}px`;
      container.appendChild(dot);
      spectrumDots.push(dot);
    }
}
function updateDotsPosition() {
    for (let i = 0; i < spectrumDots.length; i++) {
      const dot = spectrumDots;
      const rawAngle = originalAngles;
      const finalAngle = rawAngle + globalRotationRad;
      const px = dotCenter.x + dotRadius * Math.cos(finalAngle);
      const py = dotCenter.y + dotRadius * Math.sin(finalAngle);
      dot.style.left = `${px}px`;
      dot.style.top = `${py}px`;
    }
}
let resizeTimeout;
function handleResize() {
    if (resizeTimeout) clearTimeout(resizeTimeout);
    resizeTimeout = setTimeout(() => {
      if (!dom.spectrumPlayer) return;
      const wasPlaying = state.isPlaying;
      if (wasPlaying && spectrumAnimationId) {
            cancelAnimationFrame(spectrumAnimationId);
            spectrumAnimationId = null;
      }
      updateDotGeometry();
      rebuildSpectrumDots();
      updateDotsPosition();
      if (wasPlaying) startSpectrumAnimation();
    }, 100);
}
window.addEventListener('resize', handleResize);
function formatNegativeTime(seconds) {
    if (isNaN(seconds) || !isFinite(seconds) || seconds <= 0) return "-00:00";
    const mins = Math.floor(seconds / 60), secs = Math.floor(seconds % 60);
    return `-${mins}:${secs < 10 ? '0' : ''}${secs}`;
}
function updateProgressCircle() {
    if (!dom.audio.duration) return;
    const progress = dom.audio.currentTime / dom.audio.duration;
    dom.progressCircle.style.strokeDashoffset = circumference * (1 - progress);
    dom.btnTimeRemain.textContent = formatNegativeTime(dom.audio.duration - dom.audio.currentTime);
    dom.progressCircle.style.stroke = `hsl(${40 + progress * 20}, 100%, 55%)`;
}
function generateSpectrum() {
    const t = Date.now() / 250;
    let maxVal = 0;
    const data = [];
    for (let i = 0; i < totalDots; i++) {
      let val = 0.4 + Math.sin(t + i * 0.3) * 0.4 + Math.random() * 0.3;
      val = Math.min(1.0, Math.max(0.3, val));
      data.push(val);
      if(val > maxVal) maxVal = val;
    }
    return {data, intensity: maxVal};
}
function startSpectrumAnimation() {
    if (spectrumAnimationId) cancelAnimationFrame(spectrumAnimationId);
    if (!state.isPlaying) return;
    animateFireworks();
    function animate() {
      if (!state.isPlaying) return;
      globalRotationRad += ROTATION_SPEED;
      if (globalRotationRad > Math.PI * 2) globalRotationRad -= Math.PI * 2;
      updateDotsPosition();
      const {data, intensity} = generateSpectrum();
      if (intensity > 0.68) emitFireworks(intensity);
      for (let i = 0; i < spectrumDots.length; i++) {
            const dot = spectrumDots;
            const val = data;
            const scale = 0.7 + val * 0.9;
            dot.style.transform = `scale(${scale})`;
            const hue = 35 + val * 45;
            const sat = 95;
            const light = 58 + val * 28;
            dot.style.background = `hsl(${hue}, ${sat}%, ${light}%)`;
            const glowIntensity = 4 + val * 12;
            const shadowColor = `hsl(${hue + 10}, 100%, 65%)`;
            dot.style.boxShadow = `0 0 ${glowIntensity}px ${shadowColor}, 0 0 3px #ffcc88`;
            if (val > 0.85) {
                dot.style.boxShadow = `0 0 ${glowIntensity + 6}px #fff5b0, 0 0 6px #ffaa44`;
            }
      }
      spectrumAnimationId = requestAnimationFrame(animate);
    }
    animate();
}
function togglePlayback() {
    if (dom.audio.paused) {
      dom.audio.play().catch(e => {});
    } else {
      dom.audio.pause();
    }
    updatePlayerUI();
}
function updatePlayerUI() {   
    state.isPlaying = !dom.audio.paused;
    const vids = document.querySelectorAll('.zxx-slide-img');
    var mState = () => {
         vids.forEach(vid => audio.paused ? vid.pause(): vid.play() );
    };
audio.onplaying = audio.onpause = () => mState();
    if (state.isPlaying) {
      startSpectrumAnimation();
      updateProgressCircle();
      centerBtn.title = "暂停";
    } else {
      if (spectrumAnimationId) cancelAnimationFrame(spectrumAnimationId);
      spectrumAnimationId = null;
      centerBtn.title = "播放";
    }
}
function getAngleFromEvent(e, rect) {
    const cx = rect.left + rect.width / 2, cy = rect.top + rect.height / 2;
    let clientX = e.touches ? e.touches.clientX : e.clientX, clientY = e.touches ? e.touches.clientY : e.clientY;
    const dx = clientX - cx, dy = clientY - cy;
    let angle = Math.atan2(dy, dx);
    if(angle < 0) angle += 2 * Math.PI;
    let progressAngle = angle - Math.PI/2;
    if(progressAngle < 0) progressAngle += 2 * Math.PI;
    return progressAngle / (2 * Math.PI);
}
function seekByEvent(e, rect) {
    const progress = getAngleFromEvent(e, rect);
    if(!dom.audio.duration) return;
    dom.audio.currentTime = progress * dom.audio.duration;
    updateProgressCircle();
}
function bindCircularProgressEvents() {
    const p = dom.spectrumPlayer;
    let d = false;
    const m = (e) => { if(!d) return; e.preventDefault(); seekByEvent(e, p.getBoundingClientRect()); };
    const u = () => { d = false; document.removeEventListener('mousemove', m); document.removeEventListener('mouseup', u); };
    p.addEventListener('mousedown', (e) => {
      if(e.target === dom.centerBtn || dom.centerBtn.contains(e.target)) return;
      e.preventDefault(); d = true;
      seekByEvent(e, p.getBoundingClientRect());
      document.addEventListener('mousemove', m);
      document.addEventListener('mouseup', u);
    });
    p.addEventListener('touchstart', (e) => {
      if(e.target === dom.centerBtn || dom.centerBtn.contains(e.target)) return;
      e.preventDefault(); d = true;
      seekByEvent(e, p.getBoundingClientRect());
      document.addEventListener('touchmove', m);
      document.addEventListener('touchend', u);
    });
    p.addEventListener('click', (e) => {
      if(e.target === dom.centerBtn || dom.centerBtn.contains(e.target)) return;
      seekByEvent(e, p.getBoundingClientRect());
    });
}
function initPlayer() {
    dom.progressCircle.style.strokeDashoffset = circumference;
    updateDotGeometry();
    rebuildSpectrumDots();
    bindCircularProgressEvents();
    dom.centerBtn.addEventListener('click', (e) => { e.stopPropagation(); togglePlayback(); });
    dom.audio.addEventListener('timeupdate', updateProgressCircle);
    dom.audio.addEventListener('play', updatePlayerUI);
    dom.audio.addEventListener('pause', updatePlayerUI);   
}
initPlayer();
papa.oncontextmenu = (e) => e.preventDefault();
let fs = true;
let fsTimer;
fullscreen.onclick = () => {
    if(fs){
      fullscreen.innerText = '退出全屏';
      papa.requestFullscreen();
    }else{
      fullscreen.innerText = '全屏欣赏';
      document.exitFullscreen();
    }
    fs = !fs;
};
papa.addEventListener('mousemove', () => {
    clearTimeout(fsTimer);
    fullscreen.style.opacity = '1';
    fsTimer = setTimeout(() => {
      fullscreen.style.opacity = '0';
    }, 3000);
});
</script>

klxf 发表于 2026-5-28 23:21:03

漂亮,谢谢分享

夕阳西下 发表于 2026-5-29 08:28:30

欣赏精美佳作!向醉美老师学习!

醉美水芙蓉 发表于 2026-5-29 21:11:42

klxf 发表于 2026-5-28 23:21
漂亮,谢谢分享

谢谢友友分享!

醉美水芙蓉 发表于 2026-5-29 21:11:59

夕阳西下 发表于 2026-5-29 08:28
欣赏精美佳作!向醉美老师学习!

夕阳友友客气了!
页: [1]
查看完整版本: 只为你绽放