diff --git a/.claude/skills/web-test/scripts/browser.mjs b/.claude/skills/web-test/scripts/browser.mjs index a28b6337..a4dff8ad 100644 --- a/.claude/skills/web-test/scripts/browser.mjs +++ b/.claude/skills/web-test/scripts/browser.mjs @@ -4213,7 +4213,8 @@ export async function showTitleSlide(text, opts = {}) { await page.evaluate(({ text, subtitle, background, color, fontSize }) => { let div = document.getElementById('__web_test_title'); - if (!div) { + const isNew = !div; + if (isNew) { div = document.createElement('div'); div.id = '__web_test_title'; document.body.appendChild(div); @@ -4222,7 +4223,8 @@ export async function showTitleSlide(text, opts = {}) { 'position:fixed', 'top:0', 'left:0', 'width:100%', 'height:100%', `background:${background}`, 'display:flex', 'align-items:center', 'justify-content:center', - 'z-index:999999', 'pointer-events:none' + 'z-index:999999', 'pointer-events:none', + 'transition:opacity 0.3s ease', isNew ? 'opacity:0' : '' ].join(';'); const esc = s => s.replace(/&/g, '&').replace(/'); let html = `
${esc(text)}
`; @@ -4230,6 +4232,7 @@ export async function showTitleSlide(text, opts = {}) { 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) @@ -4245,13 +4248,22 @@ export async function showTitleSlide(text, opts = {}) { } } -/** Remove the title slide overlay. */ +/** Remove the title slide overlay (with fade-out). */ export async function hideTitleSlide() { ensureConnected(); - await page.evaluate(() => { + const exists = await page.evaluate(() => { const el = document.getElementById('__web_test_title'); - if (el) el.remove(); + if (!el) return false; + el.style.opacity = '0'; + return true; }); + if (exists) { + await page.waitForTimeout(350); + await page.evaluate(() => { + const el = document.getElementById('__web_test_title'); + if (el) el.remove(); + }); + } } /** @@ -4325,7 +4337,8 @@ export async function showImage(imagePath, opts = {}) { await page.evaluate(({ dataUrl, fit, bg, useBlur, shadow, maxSize, isFull }) => { let div = document.getElementById('__web_test_image'); - if (!div) { + const isNew = !div; + if (isNew) { div = document.createElement('div'); div.id = '__web_test_image'; document.body.appendChild(div); @@ -4334,7 +4347,8 @@ export async function showImage(imagePath, opts = {}) { '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' + 'z-index:999999', 'pointer-events:none', 'overflow:hidden', + 'transition:opacity 0.3s ease', isNew ? 'opacity:0' : '' ].join(';'); let html = ''; @@ -4352,6 +4366,7 @@ 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) @@ -4367,13 +4382,22 @@ export async function showImage(imagePath, opts = {}) { } } -/** Remove the image overlay from the page. */ +/** Remove the image overlay (with fade-out). */ export async function hideImage() { ensureConnected(); - await page.evaluate(() => { + const exists = await page.evaluate(() => { const el = document.getElementById('__web_test_image'); - if (el) el.remove(); + if (!el) return false; + el.style.opacity = '0'; + return true; }); + if (exists) { + await page.waitForTimeout(350); + await page.evaluate(() => { + const el = document.getElementById('__web_test_image'); + if (el) el.remove(); + }); + } } /**