diff --git a/static/js/app.js b/static/js/app.js index a5e05a1..3ab4dfb 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -2240,13 +2240,10 @@ document.addEventListener('keydown', e => { const continuousKeys = {'j': 1, 'k': -1}; if (continuousKeys[e.key] !== undefined && !e.repeat) { e.preventDefault(); - const dir = continuousKeys[e.key]; - const now = performance.now(); - if (_readerScrollDir !== dir) _readerScrollStartTs = now; - _readerScrollDir = dir; - _readerScrollLastTs = now; - if (!_readerScrollRaf) { - _readerScrollRaf = requestAnimationFrame(_readerScrollTick); + _readerScrollDir = continuousKeys[e.key]; + if (!_readerScrollInterval) { + _readerScrollLastTs = performance.now(); + _readerScrollInterval = setInterval(_readerScrollTick, READER_SCROLL_TICK_MS); } } if (e.key === 'd') { e.preventDefault(); contentEl.scrollBy({top: large / 2, behavior: 'smooth'}); } @@ -2266,8 +2263,8 @@ document.addEventListener('keydown', e => { document.addEventListener('keyup', e => { if (e.key === 'j' || e.key === 'k') { - if (_readerScrollRaf) cancelAnimationFrame(_readerScrollRaf); - _readerScrollRaf = null; + clearInterval(_readerScrollInterval); + _readerScrollInterval = null; _readerScrollDir = 0; } }); @@ -3189,21 +3186,21 @@ let pdfTotalPages = 0; let _pdfPageTextBoxCache = {}; let _pdfRenderGen = 0; let _touchStartX = 0; -let _readerScrollRaf = null; +let _readerScrollInterval = null; let _readerScrollDir = 0; -let _readerScrollStartTs = 0; let _readerScrollLastTs = 0; -const READER_SCROLL_MIN_SPEED = 700; // px/s right as j/k is pressed -const READER_SCROLL_MAX_SPEED = 1800; // px/s once ramped up -const READER_SCROLL_RAMP_MS = 300; // time to reach max speed -function _readerScrollTick(ts) { - const dt = ts - _readerScrollLastTs; - _readerScrollLastTs = ts; - const held = ts - _readerScrollStartTs; - const t = Math.min(held / READER_SCROLL_RAMP_MS, 1); - const speed = READER_SCROLL_MIN_SPEED + (READER_SCROLL_MAX_SPEED - READER_SCROLL_MIN_SPEED) * t; - $('reader-content')?.scrollBy({top: _readerScrollDir * speed * dt / 1000}); - _readerScrollRaf = requestAnimationFrame(_readerScrollTick); +const READER_SCROLL_SPEED = 1200; // constant px/s, no ramp-up +const READER_SCROLL_TICK_MS = 20; // fixed cadence, independent of the + // display's refresh rate — rAF runs at + // that rate (120/144/165Hz on plenty of + // laptops), which was driving 2-3x more + // scrollBy + scroll-listener work per + // second than intended and read as lag. +function _readerScrollTick() { + const now = performance.now(); + const dt = now - _readerScrollLastTs; + _readerScrollLastTs = now; + $('reader-content')?.scrollBy({top: Math.round(_readerScrollDir * READER_SCROLL_SPEED * dt / 1000)}); } let _pinchStartDist = 0; let _pinchStartZoom = 100; diff --git a/static/js/sw.js b/static/js/sw.js index 4ff96cd..cf4db2c 100644 --- a/static/js/sw.js +++ b/static/js/sw.js @@ -2,7 +2,7 @@ * diora service worker — caches the app shell for offline use. */ -const CACHE = 'diora-v33'; +const CACHE = 'diora-v34'; const PODCAST_CACHE = 'diora-podcast-v1'; const SHELL = [ '/static/css/app.css',