Make screen capture work in Firefox

Firefox has no tab capture, so preferCurrentTab is silently dropped and the
operator can only share a window or a screen. Neither maps onto the viewport
the way the crop assumes, so screenshots came out offset by the browser chrome
— and every failure was swallowed by a bare catch, leaving no way to tell why.

Check the shared surface and only crop when the viewport covers it: exact for
Chrome's tab capture, true for a screen while the page is fullscreen. Test that
by dimensions rather than document.fullscreenElement, which F11 leaves null.
Start now requests fullscreen, after getDisplayMedia so the click's transient
activation goes to the fragile call. Reasons surface in a corner notice and the
console, and the check reruns per grab so leaving fullscreen says so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H9v2Xoa6eoeGYpK6gp95k9
This commit is contained in:
simon
2026-08-10 21:36:58 +02:00
co-authored by Claude Opus 5
parent d3c0268c48
commit cc6ea58c7c
5 changed files with 151 additions and 20 deletions
+29 -2
View File
@@ -50,8 +50,16 @@ async function start() {
started = true;
// Before any await: getDisplayMedia needs the click's transient activation,
// which is gone the moment this function yields.
const capturing = requestCapture();
// which is gone the moment this function yields. It goes first for the same
// reason — it is the call that must not lose the activation to another API.
const capturing = requestCapture({ onIssue: showNotice });
// Screenshots only line up while the viewport covers the whole captured
// surface. Firefox cannot share a bare tab, so the operator shares the screen
// and this makes the page match it. Harmless on the tab-capture path.
document.documentElement.requestFullscreen?.().catch(() => {
showNotice('Could not go fullscreen — press F11 so screenshots line up.');
});
gate.classList.add('hidden');
@@ -330,6 +338,25 @@ function onStatus(status) {
document.getElementById('status').hidden = status === 'online';
}
// --- notices ------------------------------------------------------------
// Capture problems used to be swallowed silently, which left a broken
// screenshot and no way to tell why. They are advisory, never fatal, so the
// notice fades itself out rather than sitting over the party all night.
const NOTICE_MS = 12000;
let noticeTimer = null;
function showNotice(message) {
console.warn('[player]', message);
const notice = document.getElementById('notice');
notice.textContent = message;
notice.hidden = false;
clearTimeout(noticeTimer);
noticeTimer = setTimeout(() => {
notice.hidden = true;
}, NOTICE_MS);
}
updateGate();
// Debug helper used when verifying the crossfade without waiting out a track.