From 14b078290431ea29df0edacd359e54c98e9d8204 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Wed, 18 Mar 2026 21:41:17 +0300 Subject: [PATCH] refactor(web-test): replace fade transitions with auto-cleanup of overlays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CSS fade transitions don't work well with CDP screencast (causes desktop flash between slides). Instead, showImage/showTitleSlide now automatically remove the other overlay type — no need to call hide before showing next. Pattern for consecutive slides: showTitleSlide(...) → showImage(...) → showImage(...) → hideImage() No hideTitleSlide() needed between title and first image. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/skills/web-test/scripts/browser.mjs | 49 +++++++-------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/.claude/skills/web-test/scripts/browser.mjs b/.claude/skills/web-test/scripts/browser.mjs index a4dff8ad..dc175f50 100644 --- a/.claude/skills/web-test/scripts/browser.mjs +++ b/.claude/skills/web-test/scripts/browser.mjs @@ -4213,8 +4213,7 @@ export async function showTitleSlide(text, opts = {}) { await page.evaluate(({ text, subtitle, background, color, fontSize }) => { let div = document.getElementById('__web_test_title'); - const isNew = !div; - if (isNew) { + if (!div) { div = document.createElement('div'); div.id = '__web_test_title'; document.body.appendChild(div); @@ -4224,15 +4223,16 @@ export async function showTitleSlide(text, opts = {}) { `background:${background}`, 'display:flex', 'align-items:center', 'justify-content:center', 'z-index:999999', 'pointer-events:none', - 'transition:opacity 0.3s ease', isNew ? 'opacity:0' : '' ].join(';'); + // Remove other overlays to prevent flash between slides + const img = document.getElementById('__web_test_image'); + if (img) img.remove(); const esc = s => s.replace(/&/g, '&').replace(/'); let html = `
${esc(text)}
`; if (subtitle) { html += `
${esc(subtitle)}
`; } div.innerHTML = `
${html}
`; - if (isNew) requestAnimationFrame(() => { div.style.opacity = '1'; }); }, { text, subtitle, background, color, fontSize }); // Smart TTS wait (same pattern as showCaption/showImage) @@ -4248,22 +4248,13 @@ export async function showTitleSlide(text, opts = {}) { } } -/** Remove the title slide overlay (with fade-out). */ +/** Remove the title slide overlay. */ export async function hideTitleSlide() { ensureConnected(); - const exists = await page.evaluate(() => { + await page.evaluate(() => { const el = document.getElementById('__web_test_title'); - if (!el) return false; - el.style.opacity = '0'; - return true; + if (el) el.remove(); }); - if (exists) { - await page.waitForTimeout(350); - await page.evaluate(() => { - const el = document.getElementById('__web_test_title'); - if (el) el.remove(); - }); - } } /** @@ -4337,18 +4328,20 @@ export async function showImage(imagePath, opts = {}) { await page.evaluate(({ dataUrl, fit, bg, useBlur, shadow, maxSize, isFull }) => { let div = document.getElementById('__web_test_image'); - const isNew = !div; - if (isNew) { + if (!div) { div = document.createElement('div'); div.id = '__web_test_image'; document.body.appendChild(div); } + // Remove other overlays to prevent flash between slides + const title = document.getElementById('__web_test_title'); + if (title) title.remove(); + div.style.cssText = [ 'position:fixed', 'top:0', 'left:0', 'width:100%', 'height:100%', `background:${bg}`, 'display:flex', 'align-items:center', 'justify-content:center', - 'z-index:999999', 'pointer-events:none', 'overflow:hidden', - 'transition:opacity 0.3s ease', isNew ? 'opacity:0' : '' + 'z-index:999999', 'pointer-events:none', 'overflow:hidden' ].join(';'); let html = ''; @@ -4366,7 +4359,6 @@ export async function showImage(imagePath, opts = {}) { html += ``; div.innerHTML = html; - if (isNew) requestAnimationFrame(() => { div.style.opacity = '1'; }); }, { dataUrl, fit, bg, useBlur, shadow, maxSize, isFull }); // Smart TTS wait (same pattern as showCaption) @@ -4382,22 +4374,13 @@ export async function showImage(imagePath, opts = {}) { } } -/** Remove the image overlay (with fade-out). */ +/** Remove the image overlay. */ export async function hideImage() { ensureConnected(); - const exists = await page.evaluate(() => { + await page.evaluate(() => { const el = document.getElementById('__web_test_image'); - if (!el) return false; - el.style.opacity = '0'; - return true; + if (el) el.remove(); }); - if (exists) { - await page.waitForTimeout(350); - await page.evaluate(() => { - const el = document.getElementById('__web_test_image'); - if (el) el.remove(); - }); - } } /**