fix(live): screenshot overlay no longer flashes solid black during loading

Same alpha-string trap pattern as the recent detectPageTheme fix, on a
different code path. resolveCanvasBackground walks parents looking for
an opaque background; on a page that doesn't set its own bg the loop
runs out and fell through to:

  return getComputedStyle(document.body).backgroundColor
    || getComputedStyle(document.documentElement).backgroundColor
    || '#ffffff';

`getComputedStyle(body).backgroundColor` for a default-bg page returns
the literal string "rgba(0, 0, 0, 0)" — non-empty, truthy — so the `||`
chain short-circuits to transparent-black instead of falling through to
'#ffffff'. modern-screenshot then composites the capture onto a black
canvas; the WebGL shader overlay flashes solid black until the shader
finishes loading.

Fix: drop the buggy fallback. The while-loop already covered <body> and
<html>; if neither is opaque the only sensible answer is the browser's
default canvas color (white).

Test coverage:
- New tests/live-browser-regression.test.mjs pins the anti-pattern
  with a static-source check (live-browser.js is an IIFE with no module
  exports, so this is the cheapest reliable regression guard). Also
  pins the equivalent guard for detectPageTheme's readOpaque helper
  added in the prior commit.
- Wired the new test file into `bun run test`'s explicit list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-04-28 15:40:24 -07:00
co-authored by Claude Opus 4.7
parent 9ec904302b
commit fdb9e7c6f8
15 changed files with 176 additions and 66 deletions
@@ -2622,11 +2622,15 @@
if (!isTransparentColor(cs.backgroundColor)) return cs.backgroundColor;
node = node.parentElement;
}
return (
getComputedStyle(document.body).backgroundColor ||
getComputedStyle(document.documentElement).backgroundColor ||
'#ffffff'
);
// The walk already passed through <body> and <html>; if they had been
// opaque we would have returned. Falling through with the previous
// `getComputedStyle(body).backgroundColor || …` chain is a trap: that
// call returns the literal string `"rgba(0, 0, 0, 0)"` for a page that
// never set its own bg, which is truthy and short-circuits the chain to
// transparent-black — modern-screenshot then renders the capture on a
// black canvas and the shader overlay flashes solid black during load.
// The browser canvas defaults to white, so we do too.
return '#ffffff';
}
// Capture the element (with current annotations baked in) and return a PNG