From 91ce68a1050ca628760c3ef601b9c899571bd1fc Mon Sep 17 00:00:00 2001 From: Mustafa Senoglu Date: Fri, 7 Aug 2026 12:13:54 +0300 Subject: [PATCH 1/3] fix(convert/html): fix flickering on slide change with --one-file When using --one-file mode, base64-encoded video data URIs are split into multiple elements by RevealJS. The existing fix only ran on the 'ready' event, so dynamically created video elements (when navigating to slides outside the initial viewDistance) were never fixed. This adds a 'slidechanged' handler that re-runs the fix on slide transitions, using a WeakSet to avoid duplicate processing of already-fixed backgrounds. Closes #426 --- manim_slides/templates/revealjs.html | 51 ++++++++++++++++------------ 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/manim_slides/templates/revealjs.html b/manim_slides/templates/revealjs.html index 0fa6b8b3..bb39204b 100644 --- a/manim_slides/templates/revealjs.html +++ b/manim_slides/templates/revealjs.html @@ -313,33 +313,42 @@ }); } - function fixBase64VideoBackground(event) { - // Analyze all slides backgrounds - for (const slide of Reveal.getBackgroundsElement().querySelectorAll('.slide-background')) { - // Get the slide video and its sources for each background - const video = slide.querySelector('video'); - if (video) { - setVideoBase64(video); - } else { - // Listen to the creation of the video element - const observer = new MutationObserver((mutationsList) => { - for (const mutation of mutationsList) { - if (mutation.type === 'childList') { - for (const addedNode of mutation.addedNodes) { - if (addedNode.tagName === 'VIDEO') { - setVideoBase64(addedNode); - observer.disconnect(); // Stop observing once the video is handled - } + var _observedBgSlides = new WeakSet(); + + function fixSlideBackground(bg) { + if (_observedBgSlides.has(bg)) return; + _observedBgSlides.add(bg); + const video = bg.querySelector('video'); + if (video) { + setVideoBase64(video); + } else { + const observer = new MutationObserver((mutationsList) => { + for (const mutation of mutationsList) { + if (mutation.type === 'childList') { + for (const addedNode of mutation.addedNodes) { + if (addedNode.tagName === 'VIDEO') { + setVideoBase64(addedNode); + observer.disconnect(); + return; } } } - }); - observer.observe(slide, { childList: true, subtree: true }); - } + } + }); + observer.observe(bg, { childList: true, subtree: true }); } } - // Setup base64 videos + + function fixBase64VideoBackground() { + const backgroundsEl = Reveal.getBackgroundsElement(); + if (!backgroundsEl) return; + for (const bg of backgroundsEl.querySelectorAll('.slide-background')) { + fixSlideBackground(bg); + } + } + Reveal.on( 'ready', fixBase64VideoBackground ); + Reveal.on( 'slidechanged', fixBase64VideoBackground ); {% endif %} {% if env['READTHEDOCS'] %} From ebf66a25ec98afd62b65d5a22353d78f9579e28d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 09:15:07 +0000 Subject: [PATCH 2/3] chore(fmt): auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- manim_slides/templates/firebase_sync.html | 51 +++++++++++++---------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/manim_slides/templates/firebase_sync.html b/manim_slides/templates/firebase_sync.html index c0f1dacb..14f5d7df 100644 --- a/manim_slides/templates/firebase_sync.html +++ b/manim_slides/templates/firebase_sync.html @@ -502,33 +502,42 @@ }); } - function fixBase64VideoBackground(event) { - // Analyze all slides backgrounds - for (const slide of Reveal.getBackgroundsElement().querySelectorAll('.slide-background')) { - // Get the slide video and its sources for each background - const video = slide.querySelector('video'); - if (video) { - setVideoBase64(video); - } else { - // Listen to the creation of the video element - const observer = new MutationObserver((mutationsList) => { - for (const mutation of mutationsList) { - if (mutation.type === 'childList') { - for (const addedNode of mutation.addedNodes) { - if (addedNode.tagName === 'VIDEO') { - setVideoBase64(addedNode); - observer.disconnect(); // Stop observing once the video is handled - } + var _observedBgSlides = new WeakSet(); + + function fixSlideBackground(bg) { + if (_observedBgSlides.has(bg)) return; + _observedBgSlides.add(bg); + const video = bg.querySelector('video'); + if (video) { + setVideoBase64(video); + } else { + const observer = new MutationObserver((mutationsList) => { + for (const mutation of mutationsList) { + if (mutation.type === 'childList') { + for (const addedNode of mutation.addedNodes) { + if (addedNode.tagName === 'VIDEO') { + setVideoBase64(addedNode); + observer.disconnect(); + return; } } } - }); - observer.observe(slide, { childList: true, subtree: true }); - } + } + }); + observer.observe(bg, { childList: true, subtree: true }); } } - // Setup base64 videos + + function fixBase64VideoBackground() { + const backgroundsEl = Reveal.getBackgroundsElement(); + if (!backgroundsEl) return; + for (const bg of backgroundsEl.querySelectorAll('.slide-background')) { + fixSlideBackground(bg); + } + } + Reveal.on( 'ready', fixBase64VideoBackground ); + Reveal.on( 'slidechanged', fixBase64VideoBackground ); {% endif %} {% if env['READTHEDOCS'] %} From d2820eeb6039461b750435946ccfa332fbb1bd59 Mon Sep 17 00:00:00 2001 From: Mustafa Senoglu Date: Fri, 7 Aug 2026 15:36:05 +0300 Subject: [PATCH 3/3] fix: apply same flickering fix to all templates and docs - firebase_sync.html: same WeakSet + slidechanged handler - docs/source/_static/template.html: sync with main template - docs/source/_static/firebase_sync_demo.html: sync with firebase template - revealjs.html: var -> const (review feedback) --- docs/source/_static/firebase_sync_demo.html | 51 ++++++++++++--------- docs/source/_static/template.html | 51 ++++++++++++--------- manim_slides/templates/firebase_sync.html | 2 +- manim_slides/templates/revealjs.html | 2 +- 4 files changed, 62 insertions(+), 44 deletions(-) diff --git a/docs/source/_static/firebase_sync_demo.html b/docs/source/_static/firebase_sync_demo.html index ff6db344..acf6c03f 100644 --- a/docs/source/_static/firebase_sync_demo.html +++ b/docs/source/_static/firebase_sync_demo.html @@ -820,33 +820,42 @@ }); } - function fixBase64VideoBackground(event) { - // Analyze all slides backgrounds - for (const slide of Reveal.getBackgroundsElement().querySelectorAll('.slide-background')) { - // Get the slide video and its sources for each background - const video = slide.querySelector('video'); - if (video) { - setVideoBase64(video); - } else { - // Listen to the creation of the video element - const observer = new MutationObserver((mutationsList) => { - for (const mutation of mutationsList) { - if (mutation.type === 'childList') { - for (const addedNode of mutation.addedNodes) { - if (addedNode.tagName === 'VIDEO') { - setVideoBase64(addedNode); - observer.disconnect(); // Stop observing once the video is handled - } + const _observedBgSlides = new WeakSet(); + + function fixSlideBackground(bg) { + if (_observedBgSlides.has(bg)) return; + _observedBgSlides.add(bg); + const video = bg.querySelector('video'); + if (video) { + setVideoBase64(video); + } else { + const observer = new MutationObserver((mutationsList) => { + for (const mutation of mutationsList) { + if (mutation.type === 'childList') { + for (const addedNode of mutation.addedNodes) { + if (addedNode.tagName === 'VIDEO') { + setVideoBase64(addedNode); + observer.disconnect(); + return; } } } - }); - observer.observe(slide, { childList: true, subtree: true }); - } + } + }); + observer.observe(bg, { childList: true, subtree: true }); } } - // Setup base64 videos + + function fixBase64VideoBackground() { + const backgroundsEl = Reveal.getBackgroundsElement(); + if (!backgroundsEl) return; + for (const bg of backgroundsEl.querySelectorAll('.slide-background')) { + fixSlideBackground(bg); + } + } + Reveal.on( 'ready', fixBase64VideoBackground ); + Reveal.on( 'slidechanged', fixBase64VideoBackground ); diff --git a/docs/source/_static/template.html b/docs/source/_static/template.html index adf1c20f..4dc932f2 100644 --- a/docs/source/_static/template.html +++ b/docs/source/_static/template.html @@ -311,33 +311,42 @@ }); } - function fixBase64VideoBackground(event) { - // Analyze all slides backgrounds - for (const slide of Reveal.getBackgroundsElement().querySelectorAll('.slide-background')) { - // Get the slide video and its sources for each background - const video = slide.querySelector('video'); - if (video) { - setVideoBase64(video); - } else { - // Listen to the creation of the video element - const observer = new MutationObserver((mutationsList) => { - for (const mutation of mutationsList) { - if (mutation.type === 'childList') { - for (const addedNode of mutation.addedNodes) { - if (addedNode.tagName === 'VIDEO') { - setVideoBase64(addedNode); - observer.disconnect(); // Stop observing once the video is handled - } + const _observedBgSlides = new WeakSet(); + + function fixSlideBackground(bg) { + if (_observedBgSlides.has(bg)) return; + _observedBgSlides.add(bg); + const video = bg.querySelector('video'); + if (video) { + setVideoBase64(video); + } else { + const observer = new MutationObserver((mutationsList) => { + for (const mutation of mutationsList) { + if (mutation.type === 'childList') { + for (const addedNode of mutation.addedNodes) { + if (addedNode.tagName === 'VIDEO') { + setVideoBase64(addedNode); + observer.disconnect(); + return; } } } - }); - observer.observe(slide, { childList: true, subtree: true }); - } + } + }); + observer.observe(bg, { childList: true, subtree: true }); } } - // Setup base64 videos + + function fixBase64VideoBackground() { + const backgroundsEl = Reveal.getBackgroundsElement(); + if (!backgroundsEl) return; + for (const bg of backgroundsEl.querySelectorAll('.slide-background')) { + fixSlideBackground(bg); + } + } + Reveal.on( 'ready', fixBase64VideoBackground ); + Reveal.on( 'slidechanged', fixBase64VideoBackground ); {% endif %} diff --git a/manim_slides/templates/firebase_sync.html b/manim_slides/templates/firebase_sync.html index 14f5d7df..6c2cca2c 100644 --- a/manim_slides/templates/firebase_sync.html +++ b/manim_slides/templates/firebase_sync.html @@ -502,7 +502,7 @@ }); } - var _observedBgSlides = new WeakSet(); + const _observedBgSlides = new WeakSet(); function fixSlideBackground(bg) { if (_observedBgSlides.has(bg)) return; diff --git a/manim_slides/templates/revealjs.html b/manim_slides/templates/revealjs.html index bb39204b..44bcc280 100644 --- a/manim_slides/templates/revealjs.html +++ b/manim_slides/templates/revealjs.html @@ -313,7 +313,7 @@ }); } - var _observedBgSlides = new WeakSet(); + const _observedBgSlides = new WeakSet(); function fixSlideBackground(bg) { if (_observedBgSlides.has(bg)) return;