refactor: better lyric scroll with requestAnimationFrame algo

This commit is contained in:
Harshad 2026-02-06 01:06:36 +05:30
parent 03a6952287
commit 7b2e35dab5
2 changed files with 42 additions and 20 deletions

View file

@ -13,6 +13,7 @@ document.addEventListener('alpine:init', () => {
isPlaying: false,
countdown: 180,
isDownloadReady: false,
scrollAnimationId: null,
async init() {
this.sessionId = this.getSessionId();
@ -178,25 +179,41 @@ document.addEventListener('alpine:init', () => {
}, 100);
},
updateLyricsScroll() {
const player = document.getElementById('audio-player');
initScrollLogic(player) {
const container = document.getElementById('lyrics-container');
const update = () => {
if (!player.duration || player.duration === Infinity || !container) {
this.scrollAnimationId = requestAnimationFrame(update);
return;
}
if (!player || !container || !player.duration || player.duration === Infinity) {
return;
}
const maxScroll = container.scrollHeight - container.clientHeight;
const progress = player.currentTime / player.duration;
// We use direct assignment for performance within the rAF loop
container.scrollTop = progress * maxScroll;
// Calculate how far through the song we are (0 to 1)
const playbackPercentage = player.currentTime / player.duration;
if (!player.paused) {
this.scrollAnimationId = requestAnimationFrame(update);
}
};
// Calculate the total scrollable area
// scrollHeight (total content) - clientHeight (visible area)
const maxScroll = container.scrollHeight - container.clientHeight;
player.addEventListener('play', () => {
cancelAnimationFrame(this.scrollAnimationId);
update();
});
// Set the scroll position
container.scrollTo({
top: maxScroll * playbackPercentage,
behavior: 'smooth' // Gives it a nice fluid feel
player.addEventListener('pause', () => {
cancelAnimationFrame(this.scrollAnimationId);
});
player.addEventListener('seeking', () => {
// Snap the scroll immediately when the user drags the seek bar
if (player.duration && player.duration !== Infinity) {
const maxScroll = container.scrollHeight - container.clientHeight;
container.scrollTop = (player.currentTime / player.duration) * maxScroll;
}
});
},

View file

@ -40,10 +40,9 @@
id="audio-player"
:src="$store.songApp.audioUrl"
preload="metadata"
x-init="$store.songApp.initScrollLogic($el)"
@play="$store.songApp.isPlaying = true"
@pause="$store.songApp.isPlaying = false"
@timeupdate="$store.songApp.updateLyricsScroll()"
@loadedmetadata="$store.songApp.updateLyricsScroll()"
>
Your browser does not support the audio element.
</audio>
@ -59,10 +58,16 @@
<div
class="song-lyrics"
id="lyrics-container"
x-show="$store.songApp.lyrics"
x-text="$store.songApp.lyrics"
></div>
id="lyrics-container"
style="overflow: hidden; position: relative;"
x-show="$store.songApp.lyrics"
>
<div
id="lyrics-content"
style="transition: transform 0.4s linear; will-change: transform;"
x-text="$store.songApp.lyrics">
</div>
</div>
<div class="share-container">
<div class="share-title">Share the love.</div>