shreyask commited on
Commit
3af292e
·
verified ·
1 Parent(s): 99e9fca

Fix spinner: CSS rotate on compositor thread, not setInterval

Browse files
Files changed (1) hide show
  1. index.html +15 -24
index.html CHANGED
@@ -317,7 +317,7 @@
317
  .doc-card.ranked-3 .doc-score-num { color: #60A5FA; }
318
  .doc-card.ranked-3 .doc-score-bar { background: #60A5FA; }
319
 
320
- /* Active card being scored — amber left-border pulse + dim overlay */
321
  .doc-card.computing {
322
  border-color: var(--amber-dim);
323
  box-shadow: inset 3px 0 0 var(--amber), 0 0 12px rgba(245,158,11,0.08);
@@ -329,21 +329,20 @@
329
  50% { box-shadow: inset 3px 0 0 var(--amber), 0 0 18px rgba(245,158,11,0.18); }
330
  }
331
 
 
332
  .doc-card.computing .doc-score-num {
 
333
  color: var(--amber);
334
- font-size: 0.72rem;
335
- letter-spacing: 0.05em;
336
- animation: score-spin-text 1s linear infinite;
337
  }
338
 
339
- @keyframes score-spin-text {
340
- 0% { content: '⠋'; }
341
- /* CSS content animation doesn't work on non-pseudo-elements — use JS instead */
342
- 0%, 100% { opacity: 1; }
343
- 50% { opacity: 0.35; }
344
  }
345
 
346
- /* Spinner ring in score bar while computing */
347
  .doc-card.computing .doc-score-bar {
348
  background: var(--amber);
349
  width: 100% !important;
@@ -352,9 +351,9 @@
352
  }
353
 
354
  @keyframes bar-indeterminate {
355
- 0% { transform: scaleX(0); opacity: 0.6; }
356
- 50% { transform: scaleX(1); opacity: 1; }
357
- 100% { transform: scaleX(0); opacity: 0.6; }
358
  }
359
 
360
  /* ── Unscored doc (has text but wasn't in last rank run) ── */
@@ -761,17 +760,11 @@
761
  rankBtn.classList.add("running");
762
  rankBtn.textContent = "⟳ Ranking…";
763
 
764
- const SPINNER = ["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];
765
- const spinners = new Map(); // card intervalId
766
-
767
  toScore.forEach(({ card }) => {
768
  card.classList.add("computing");
769
- const numEl = card.querySelector(".doc-score-num");
770
- numEl.textContent = SPINNER[0];
771
- let i = 0;
772
- spinners.set(card, setInterval(() => {
773
- numEl.textContent = SPINNER[++i % SPINNER.length];
774
- }, 80));
775
  });
776
 
777
  const scored = [];
@@ -797,7 +790,6 @@
797
  const en = Math.exp(ln - m);
798
  const score = ey / (ey + en);
799
 
800
- clearInterval(spinners.get(card));
801
  card.classList.remove("computing");
802
  animateScore(
803
  card.querySelector(".doc-score-num"),
@@ -808,7 +800,6 @@
808
 
809
  } catch (err) {
810
  console.error("Inference error on doc", id, err);
811
- clearInterval(spinners.get(card));
812
  card.classList.remove("computing");
813
  card.querySelector(".doc-score-num").textContent = "err";
814
  setStatus("error", `Error: ${err?.message ?? String(err)}`);
 
317
  .doc-card.ranked-3 .doc-score-num { color: #60A5FA; }
318
  .doc-card.ranked-3 .doc-score-bar { background: #60A5FA; }
319
 
320
+ /* Active card being scored — amber left-border + glow pulse */
321
  .doc-card.computing {
322
  border-color: var(--amber-dim);
323
  box-shadow: inset 3px 0 0 var(--amber), 0 0 12px rgba(245,158,11,0.08);
 
329
  50% { box-shadow: inset 3px 0 0 var(--amber), 0 0 18px rgba(245,158,11,0.18); }
330
  }
331
 
332
+ /* CSS-only spinner — works even when WASM blocks the JS event loop */
333
  .doc-card.computing .doc-score-num {
334
+ display: inline-block; /* required for transform */
335
  color: var(--amber);
336
+ font-size: 1.2rem;
337
+ animation: spin 0.7s linear infinite;
338
+ transform-origin: center;
339
  }
340
 
341
+ @keyframes spin {
342
+ to { transform: rotate(360deg); }
 
 
 
343
  }
344
 
345
+ /* Indeterminate progress bar (also CSS-only) */
346
  .doc-card.computing .doc-score-bar {
347
  background: var(--amber);
348
  width: 100% !important;
 
351
  }
352
 
353
  @keyframes bar-indeterminate {
354
+ 0% { transform: scaleX(0); opacity: 0.6; }
355
+ 50% { transform: scaleX(1); opacity: 1; }
356
+ 100% { transform: scaleX(0); opacity: 0.6; }
357
  }
358
 
359
  /* ── Unscored doc (has text but wasn't in last rank run) ── */
 
760
  rankBtn.classList.add("running");
761
  rankBtn.textContent = "⟳ Ranking…";
762
 
763
+ // Set once — CSS rotates it on the compositor thread,
764
+ // so it spins even while WASM inference blocks the JS event loop.
 
765
  toScore.forEach(({ card }) => {
766
  card.classList.add("computing");
767
+ card.querySelector(".doc-score-num").textContent = "⟳";
 
 
 
 
 
768
  });
769
 
770
  const scored = [];
 
790
  const en = Math.exp(ln - m);
791
  const score = ey / (ey + en);
792
 
 
793
  card.classList.remove("computing");
794
  animateScore(
795
  card.querySelector(".doc-score-num"),
 
800
 
801
  } catch (err) {
802
  console.error("Inference error on doc", id, err);
 
803
  card.classList.remove("computing");
804
  card.querySelector(".doc-score-num").textContent = "err";
805
  setStatus("error", `Error: ${err?.message ?? String(err)}`);