improve: performance by modifing template

This commit is contained in:
alikia2x (寒寒) 2025-02-05 04:57:09 +08:00
parent f27c290f39
commit b01cc47566
Signed by: alikia2x
GPG Key ID: 56209E0CCD8420C6
2 changed files with 59 additions and 73 deletions

View File

@ -41,17 +41,16 @@
let prevRealTime: number | undefined = undefined; let prevRealTime: number | undefined = undefined;
let lastRealY: number | undefined = undefined; let lastRealY: number | undefined = undefined;
let lastRealTime: number | undefined = undefined; let lastRealTime: number | undefined = undefined;
const INTERVAL = 1; // 可调节的插值间隔0-1 const INTERPOLATED_RATE = 0; // 可调节的插值间隔0-1
function updateY(timestamp: number) { function updateY(timestamp: number) {
if (stopped) return; if (stopped) return;
// 记录真实帧信息
const currentTime = new Date().getTime(); const currentTime = new Date().getTime();
const isRealFrame = INTERVAL === 0 || Math.random() < INTERVAL; const isRealFrame = Math.random() > INTERPOLATED_RATE;
if (isRealFrame) { if (isRealFrame) {
// 真实物理帧 // 真实物理帧处理
if (lastUpdateY === undefined) { if (lastUpdateY === undefined) {
lastUpdateY = currentTime; lastUpdateY = currentTime;
} }
@ -62,31 +61,35 @@
prevRealTime = lastRealTime; prevRealTime = lastRealTime;
// 更新物理状态 // 更新物理状态
time = (currentTime - lastUpdateY) / 1000; const deltaTime = (currentTime - lastUpdateY) / 1000;
springY.update(time); springY.update(deltaTime);
positionY = springY.getCurrentPosition(); positionY = springY.getCurrentPosition();
// 记录当前真实帧数据 // 记录当前真实帧数据
lastRealY = positionY; lastRealY = positionY;
lastRealTime = currentTime; lastRealTime = currentTime;
lastUpdateY = currentTime; lastUpdateY = currentTime;
// 无论是否真实帧都继续请求动画帧(保持动画流畅)
// 继续请求动画帧
if (!springY?.arrived() && !stopped && !we_are_scrolling) { if (!springY?.arrived() && !stopped && !we_are_scrolling) {
requestAnimationFrame(updateY); requestAnimationFrame(updateY);
} }
} else if ( } else {
prevRealY !== undefined && // 插值帧处理
prevRealTime !== undefined && if (lastRealY !== undefined && lastRealTime !== undefined) {
lastRealY !== undefined &&
lastRealTime !== undefined
) {
// 插值帧
const timeSinceLastReal = currentTime - lastRealTime; const timeSinceLastReal = currentTime - lastRealTime;
const deltaT = timeSinceLastReal / 1000; const deltaT = timeSinceLastReal / 1000;
const velocity = (lastRealY - prevRealY) / ((lastRealTime - prevRealTime) / 1000);
// 计算速度(如果有前一次真实帧数据)
let velocity = 0;
if (prevRealY !== undefined && prevRealTime !== undefined && lastRealTime !== prevRealTime) {
velocity = (lastRealY - prevRealY) / ((lastRealTime - prevRealTime) / 1000);
}
positionY = lastRealY + velocity * deltaT; positionY = lastRealY + velocity * deltaT;
// 无论是否真实帧都继续请求动画帧(保持动画流畅) }
// 无论是否成功插值都保持动画流畅
if (!stopped && !we_are_scrolling) { if (!stopped && !we_are_scrolling) {
requestAnimationFrame(updateY); requestAnimationFrame(updateY);
} }
@ -206,50 +209,19 @@
export const getRef = () => ref; export const getRef = () => ref;
// Calculate if the current character should be highlighted based on progress let processedChars = line.words?.flatMap((word) => {
const isCharacterHighlighted = (line: ScriptItem, word: LyricWord, charIndex: number, progress: number) => { const { startTime, endTime, word: text } = word;
const charProgress = getCharacterProgress(word, charIndex);
return line.start <= progress && progress <= line.end && progress > charProgress;
};
// Get the progress timing for a specific character in a word
const getCharacterProgress = (word: LyricWord, charIndex: number) => {
const { startTime, endTime } = word;
const wordDuration = endTime - startTime; const wordDuration = endTime - startTime;
return wordDuration * (charIndex / word.word.length) + startTime; return text.split('').map((chr, i) => {
}; const charProgress = startTime + wordDuration * (i / text.length);
const charDuration = wordDuration * ((i + 1) / text.length);
const transitionDur = charDuration < 0.6 ? null : charDuration / 1.6;
return { chr, charProgress, transitionDur };
});
});
// Calculate the transition duration for a character // 新增:缓存当前行状态
const getTransitionDuration = (word: LyricWord, charIndex: number) => { $: isActiveLine = line.start <= progress && progress <= line.end;
const { startTime, endTime } = word;
const wordDuration = endTime - startTime;
const charDuration = wordDuration * ((charIndex + 1) / word.word.length);
// If duration is less than 0.6s, we'll use CSS class with fixed duration
if (charDuration < 0.6) {
return null;
}
// Otherwise, calculate custom duration
return charDuration / 1.6;
};
// Generate the CSS classes for a character
const getCharacterClasses = (line: ScriptItem, word: LyricWord, charIndex: number, progress: number) => {
const baseClasses = 'inline-block';
const opacityClass = isCharacterHighlighted(line, word, charIndex, progress)
? 'opacity-100 text-glow'
: 'opacity-35';
return `${baseClasses} ${opacityClass}`.trim();
};
// Generate the style string for a character
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;';
};
</script> </script>
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
@ -282,18 +254,19 @@
{/if} {/if}
{#if line.words !== undefined && line.words.length > 0} {#if line.words !== undefined && line.words.length > 0}
<span class={`text-white text-[2rem] leading-9 lg:text-5xl lg:leading-[4rem] font-semibold mr-4 `}> <span class={`text-white text-[2rem] leading-9 lg:text-5xl lg:leading-[4rem] font-semibold mr-4 `}>
{#each line.words as word} {#each processedChars as char (char.charProgress)}
{#if word.word} {@const isHighlighted = line.start <= progress && progress <= line.end && progress > char.charProgress}
{#each word.word.split('') as chr, i} {@const useCustomTransition = char.transitionDur !== null && isActiveLine}
<span <span
class={getCharacterClasses(line, word, i, progress)} class="inline-block {isHighlighted ? 'opacity-100 text-glow' : 'opacity-35'}"
style={getCharacterStyle(line, word, i, progress)} style={useCustomTransition
? `transition-duration: ${char.transitionDur}s;`
: 'transition-duration: 200ms;'}
> >
{chr} {char.chr}
</span> </span>
{/each} {/each}
{/if}
{/each}
</span> </span>
{:else} {:else}
<span <span
@ -320,4 +293,17 @@
0 15px 30px rgba(0, 0, 0, 0.11), 0 15px 30px rgba(0, 0, 0, 0.11),
0 5px 15px rgba(0, 0, 0, 0.08); 0 5px 15px rgba(0, 0, 0, 0.08);
} }
/* 预定义过渡类 */
.char-transition {
transition-property: opacity;
transition-timing-function: ease-out;
}
.fast-transition {
transition-duration: 200ms;
}
.custom-transition {
transition-duration: var(--custom-duration);
}
</style> </style>

View File

@ -209,7 +209,7 @@
if (audioPlayer === null) return; if (audioPlayer === null) return;
if ($userAdjustingProgress === false) currentProgress = audioPlayer.currentTime; if ($userAdjustingProgress === false) currentProgress = audioPlayer.currentTime;
progressBarRaw.set(audioPlayer.currentTime); progressBarRaw.set(audioPlayer.currentTime);
}, 20); }, 70);
} }
onMount(() => { onMount(() => {