From 7b2e35dab520a093035fe46bb232d9637140f969 Mon Sep 17 00:00:00 2001 From: Harshad Date: Fri, 6 Feb 2026 01:06:36 +0530 Subject: [PATCH] refactor: better lyric scroll with requestAnimationFrame algo --- assets/js/result2.js | 45 ++++++++++++++++++++++++++++++-------------- result.php | 17 +++++++++++------ 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/assets/js/result2.js b/assets/js/result2.js index bf4e6db..3355200 100644 --- a/assets/js/result2.js +++ b/assets/js/result2.js @@ -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; + } }); }, diff --git a/result.php b/result.php index 824b5c3..6f17efd 100644 --- a/result.php +++ b/result.php @@ -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. @@ -59,10 +58,16 @@
+ id="lyrics-container" + style="overflow: hidden; position: relative;" + x-show="$store.songApp.lyrics" + > +
+
+