From 8fe3c73c0988835175fe440289148e68c7c182dd Mon Sep 17 00:00:00 2001 From: alikia2x Date: Wed, 5 Feb 2025 03:24:48 +0800 Subject: [PATCH] improve: performance - using interpolation for spring animtion --- .../core/components/lyrics/lyricLine.svelte | 74 ++++++++++++++----- .../core/components/lyrics/newLyrics.svelte | 4 +- 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/packages/core/components/lyrics/lyricLine.svelte b/packages/core/components/lyrics/lyricLine.svelte index 55317aa..f111fcc 100644 --- a/packages/core/components/lyrics/lyricLine.svelte +++ b/packages/core/components/lyrics/lyricLine.svelte @@ -37,19 +37,57 @@ let springX: Spring | undefined = undefined; let isCurrentLyric = false; + let prevRealY: number | undefined = undefined; + let prevRealTime: number | undefined = undefined; + let lastRealY: number | undefined = undefined; + let lastRealTime: number | undefined = undefined; + const INTERVAL = 1; // 可调节的插值间隔(0-1) + function updateY(timestamp: number) { if (stopped) return; - if (lastUpdateY === undefined) { - lastUpdateY = new Date().getTime(); + + // 记录真实帧信息 + const currentTime = new Date().getTime(); + const isRealFrame = INTERVAL === 0 || Math.random() < INTERVAL; + + if (isRealFrame) { + // 真实物理帧 + if (lastUpdateY === undefined) { + lastUpdateY = currentTime; + } + if (springY === undefined) return; + + // 保存前一次的真实帧数据 + prevRealY = lastRealY; + prevRealTime = lastRealTime; + + // 更新物理状态 + time = (currentTime - lastUpdateY) / 1000; + springY.update(time); + positionY = springY.getCurrentPosition(); + + // 记录当前真实帧数据 + lastRealY = positionY; + lastRealTime = currentTime; + lastUpdateY = currentTime; + } else if ( + prevRealY !== undefined && + prevRealTime !== undefined && + lastRealY !== undefined && + lastRealTime !== undefined + ) { + // 插值帧 + const timeSinceLastReal = currentTime - lastRealTime; + const deltaT = timeSinceLastReal / 1000; + const velocity = (lastRealY - prevRealY) / ((lastRealTime - prevRealTime) / 1000); + + positionY = lastRealY + velocity * deltaT; } - if (springY === undefined) return; - time = (new Date().getTime() - lastUpdateY) / 1000; - springY.update(time); - positionY = springY.getCurrentPosition(); - if (!springY.arrived() && !stopped && !we_are_scrolling) { + + // 无论是否真实帧都继续请求动画帧(保持动画流畅) + if (!springY?.arrived() && !stopped && !we_are_scrolling) { requestAnimationFrame(updateY); } - lastUpdateY = new Date().getTime(); } function updateX(timestamp: number) { @@ -98,7 +136,7 @@ } if (scrolling) blurRadius = 0; if ($userAdjustingProgress) blurRadius = 0; - blur = blurRadius + blur = blurRadius; } } @@ -137,11 +175,10 @@ we_are_scrolling = false; }; - export const syncSpringWithDelta = (deltaY: number) => { const target = positionY + deltaY; springY!.setPosition(target); - } + }; export const getInfo = () => { return { @@ -169,9 +206,7 @@ // Calculate if the current character should be highlighted based on progress const isCharacterHighlighted = (line: ScriptItem, word: LyricWord, charIndex: number, progress: number) => { const charProgress = getCharacterProgress(word, charIndex); - return line.start <= progress && - progress <= line.end && - progress > charProgress; + return line.start <= progress && progress <= line.end && progress > charProgress; }; // Get the progress timing for a specific character in a word @@ -210,7 +245,7 @@ const getCharacterStyle = (line: ScriptItem, word: LyricWord, charIndex: number, progress: number) => { const duration = getTransitionDuration(word, charIndex); const progressAtCurrentLine = progress <= line.end; - return (duration && progressAtCurrentLine) ? `transition-duration: ${duration}s;` : 'transition-duration: 200ms;'; + return duration && progressAtCurrentLine ? `transition-duration: ${duration}s;` : 'transition-duration: 200ms;'; }; @@ -276,9 +311,10 @@ diff --git a/packages/core/components/lyrics/newLyrics.svelte b/packages/core/components/lyrics/newLyrics.svelte index 45d5644..15ee72a 100644 --- a/packages/core/components/lyrics/newLyrics.svelte +++ b/packages/core/components/lyrics/newLyrics.svelte @@ -280,12 +280,12 @@ progress: {progress.toFixed(2)}, nextUpdate: {nextUpdate}, scrolling: {scrolling}, current: {currentLyricIndex}, uap: {$userAdjustingProgress} -
-
+ --> {/if} {#if originalLyrics && originalLyrics.scripts}