Content is user-generated and unverified.
class ViewportCapture { constructor() { this.stream = null; this.isInitialized = false; } // Initialize capture stream - requires user interaction async initialize() { try { this.stream = await navigator.mediaDevices.getDisplayMedia({ video: { mediaSource: 'browser', // Hints at browser content displaySurface: 'browser', // Specifically requests browser surface logicalSurface: true, // Requests logical surface (tab content) cursor: 'never', // Excludes cursor width: { ideal: window.innerWidth }, // Match viewport dimensions height: { ideal: window.innerHeight }, // Match viewport dimensions frameRate: { ideal: 1, max: 5 } }, audio: false, preferCurrentTab: true // Non-standard but some browsers may respect it }); this.isInitialized = true; } catch (error) { this.stop(); throw new Error(`Failed to initialize screen capture: ${error.message}`); } } // Capture single frame from initialized stream async captureFrame() { if (!this.isInitialized) { throw new Error('Screen capture not initialized. Call initialize() first.'); } const video = document.createElement('video'); video.muted = true; video.srcObject = this.stream; await video.play(); // Wait for current frame await new Promise((resolve) => { const checkVideo = () => { if (video.readyState >= video.HAVE_CURRENT_DATA) { resolve(); } else { requestAnimationFrame(checkVideo); } }; checkVideo(); }); // Capture single frame const canvas = document.createElement('canvas'); canvas.width = video.videoWidth; canvas.height = video.videoHeight; const ctx = canvas.getContext('2d'); ctx.drawImage(video, 0, 0); // Clean up video element (stream stays alive) video.srcObject = null; return { dataURL: canvas.toDataURL('image/png'), blob: await new Promise(resolve => canvas.toBlob(resolve, 'image/png')), canvas: canvas }; } stop() { if (this.stream) { this.stream.getTracks().forEach(track => track.stop()); this.stream = null; this.isInitialized = false; } } } // Usage Example const capturer = new ViewportCapture(); // Step 1: User interaction required for initialization document.getElementById('enableButton').addEventListener('click', async () => { try { await capturer.initialize(); document.getElementById('status').textContent = 'Screen capture ready!'; } catch (error) { console.error('Failed to initialize capture:', error); } }); // Step 2: Any trigger can capture frames (clap detection, timer, etc.) handleClap(async () => { try { const result = await capturer.captureFrame(); // Download the screenshot const link = document.createElement('a'); link.download = `screenshot-${Date.now()}.png`; link.href = result.dataURL; link.click(); console.log('Frame captured!'); } catch (error) { console.error('Frame capture failed:', error); } }); // Could also be triggered by other events: // document.addEventListener('keydown', (e) => { // if (e.key === ' ') capturer.captureFrame(); // });
Content is user-generated and unverified.
    Enhanced ViewportCapture with Better Constraints | Claude