diff --git a/src/web/public/app.js b/src/web/public/app.js index 3817b42e..872d35f3 100644 --- a/src/web/public/app.js +++ b/src/web/public/app.js @@ -1368,8 +1368,9 @@ class CodemanApp { this.terminal.write(chunk); offset += chunkSize; - // Schedule next chunk on next frame - requestAnimationFrame(writeChunk); + // Double-RAF: yields to both the browser's layout/paint AND the WebGL renderer's + // GPU flush. Single RAF can still block if ReadPixels is synchronous. + requestAnimationFrame(() => requestAnimationFrame(writeChunk)); }; // Start writing @@ -3436,12 +3437,15 @@ class CodemanApp { // belt-and-suspenders guard for any edge cases. this._restoringFlushedState = true; try { - // Instant cache restore — show previous buffer immediately while network fetch runs + // Instant cache restore — show previous buffer via chunked write to avoid WebGL GPU stalls. + // Direct terminal.write() of large cached buffers (256KB+) can block the main thread + // for 5+ seconds while the WebGL renderer processes ReadPixels synchronously. const cachedBuffer = this.terminalBufferCache.get(sessionId); if (cachedBuffer) { this.terminal.clear(); this.terminal.reset(); - this.terminal.write(cachedBuffer); + await this.chunkedTerminalWrite(cachedBuffer); + if (selectGen !== this._selectGeneration) { this._restoringFlushedState = false; return; } this.terminal.scrollToBottom(); } diff --git a/src/web/public/constants.js b/src/web/public/constants.js index 080001f0..cc8f80a4 100644 --- a/src/web/public/constants.js +++ b/src/web/public/constants.js @@ -52,7 +52,7 @@ const TITLE_FLASH_INTERVAL_MS = 1500; // Title flash rate const BROWSER_NOTIF_RATE_LIMIT_MS = 3000; // Rate limit for browser notifications const AUTO_CLOSE_NOTIFICATION_MS = 8000; // Auto-close browser notifications const THROTTLE_DELAY_MS = 100; // General UI throttle delay -const TERMINAL_CHUNK_SIZE = 128 * 1024; // 128KB chunks for terminal data +const TERMINAL_CHUNK_SIZE = 32 * 1024; // 32KB chunks for terminal data (smaller to avoid WebGL GPU stalls) const TERMINAL_TAIL_SIZE = 256 * 1024; // 256KB tail for initial load const SYNC_WAIT_TIMEOUT_MS = 50; // Wait timeout for terminal sync const STATS_POLLING_INTERVAL_MS = 2000; // System stats polling