aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-15 12:05:11 -0700
committerAdam Soltys <[email protected]>2026-08-15 12:05:11 -0700
commiteae1a256de6316fb3619e8757cf8dc6f6f9e572f (patch)
treec2a0c84217f2f3bda67ca79827576e38755bfdb3
parent89ee463e94727d0bb605d956cd5c61a33a426a4a (diff)
downloadcoinosv3-eae1a256de6316fb3619e8757cf8dc6f6f9e572f.tar.gz
coinosv3-eae1a256de6316fb3619e8757cf8dc6f6f9e572f.zip
Background repaints breathe at 200ms instead of strobing at frame rate — a resting cursor keeps its hover through a boot burst
Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_014tE4U5nEjGTQy8PwYqamfv
-rw-r--r--src/app.js19
1 files changed, 12 insertions, 7 deletions
diff --git a/src/app.js b/src/app.js
index e6e8e9b..6c867c9 100644
--- a/src/app.js
+++ b/src/app.js
@@ -330,8 +330,9 @@ function animatedAmount(key, sat) {
function render() {
// A direct render subsumes any coalesced one queued by a background emit, so
- // drop the pending frame (a user action must not trigger a second rebuild).
- if (_renderRaf) { cancelAnimationFrame(_renderRaf); _renderRaf = 0; }
+ // drop the pending one (a user action must not trigger a second rebuild).
+ if (_renderRaf) { clearTimeout(_renderRaf); _renderRaf = 0; }
+ _lastRender = Date.now();
// Preserve focus + caret across the rebuild, so a background update (poll, a
// payment push, an SP scan) can't kick the user out of a field they're editing.
const a = document.activeElement;
@@ -393,14 +394,18 @@ function render() {
// after being backgrounded. Rendering synchronously on each one rebuilds the
// whole screen dozens of times in a row and starves user input, so the app
// feels frozen for a second or two. Coalesce those into at most one render per
-// animation frame. Direct user actions still call render() synchronously, and
-// the browser dispatches input events ahead of the queued frame, so a tap or
-// navigation always takes priority over background repaints. (rAF also skips
-// rendering entirely while the tab is hidden, and fires once on refocus.)
+// 200ms: one-per-frame still meant a visible strobe during boot bursts (every
+// rebuild swaps the node under the cursor, dropping its :hover until the next
+// mouse move — buttons flashed under a resting pointer). Direct user actions
+// still call render() synchronously and always take priority; render() itself
+// stamps the throttle, so a user render pushes the next background one out.
let _renderRaf = 0;
+let _lastRender = 0;
+const BG_RENDER_MIN_MS = 200;
function scheduleRender() {
if (_renderRaf) return;
- _renderRaf = requestAnimationFrame(() => { _renderRaf = 0; render(); });
+ const wait = Math.max(0, BG_RENDER_MIN_MS - (Date.now() - _lastRender));
+ _renderRaf = setTimeout(() => { _renderRaf = 0; render(); }, wait);
}
wallet.subscribe(scheduleRender);