Excalidraw
It turns out you can even animate your drawings:
https://dai-shi.github.io/excalidraw-animate/
I came across this while looking for alternatives to draw.io for creating AWS architecture diagrams.
The catch? You can’t export as GIF, which means you can’t directly attach it to Google Slides.
While researching workarounds, I found a bunch of open-source tools like Reveal.js.
But for something this simple, I figured I could just build my own in HTML — so I did, with a quick “vibe coding” session.
I’m planning to use it for informal or lightweight presentations.
Here’s the code
<!doctype html>
<meta charset="utf-8">
<title>Excalidraw Animate – 20 Slides with Replay & Counter</title>
<style>
html,body{margin:0;height:100%;background:#fff;font-family:sans-serif}
.slide{position:fixed;inset:0;display:none;justify-content:center;align-items:center}
.slide.active{display:flex}
object{max-width:90vw;max-height:90vh}
/* ─ Replay button (bottom-left) ─ */
.replay-btn{
position:absolute;bottom:14px;left:14px;
border:0;background:none;cursor:pointer;user-select:none;
font-size:22px;line-height:1;color:#555;
opacity:0.15;transition:opacity .2s,transform .2s;
}
.slide:hover .replay-btn,.replay-btn:hover{
opacity:0.85;transform:scale(1.15);
}
/* ─ Counter (bottom-right) ─ */
#counter{
position:fixed;bottom:16px;right:16px;
font-size:14px;color:#666;
opacity:0.4;transition:opacity .2s;
user-select:none;
}
#counter:hover{opacity:0.8}
</style>
<div id="deck"></div>
<div id="counter"></div>
<script>
(() => {
/* ===== Config ===== */
const NUM_SLIDES = 20;
const FILE_PREFIX = 'frame'; // frame01.svg, frame02.svg …
const PAD_LENGTH = 2; // 01, 02 …
/* ===== Create slides ===== */
const deck = document.getElementById('deck');
for (let i = 1; i <= NUM_SLIDES; i++) {
const slide = document.createElement('div');
slide.className = 'slide' + (i === 1 ? ' active' : '');
const obj = document.createElement('object');
obj.type = 'image/svg+xml';
obj.data = `${FILE_PREFIX}${String(i).padStart(PAD_LENGTH,'0')}.svg`;
slide.appendChild(obj);
const btn = document.createElement('button');
btn.className = 'replay-btn';
btn.textContent = '↺';
btn.onclick = () => { obj.data = obj.data; };
slide.appendChild(btn);
deck.appendChild(slide);
}
/* ===== Navigation & counter ===== */
const slides = [...document.querySelectorAll('.slide')];
const counter = document.getElementById('counter');
let idx = 0;
const updateCounter = () => { counter.textContent = `${idx+1} / ${slides.length}`; };
updateCounter();
const show = n => {
slides[idx].classList.remove('active');
idx = (n + slides.length) % slides.length;
slides[idx].classList.add('active');
updateCounter();
};
document.addEventListener('keydown', e => {
if (['ArrowRight','L',';'].includes(e.key)) show(idx + 1);
if (['ArrowLeft' ,'H',','].includes(e.key)) show(idx - 1);
});
})();
</script>
How to use
Steps
Create animated SVG files with Excalidraw Animate (name them frame01.svg to frame20.svg).
Paste the HTML code above into an index.html file.
Put your SVG files in the same folder as index.html.
Open index.html in your browser and go fullscreen.
Navigation
← / → keys to move between slides
Bottom-left ↺ button to replay the current slide
Bottom-right counter shows “current / total” at all times
Note
I used this setup for our internal presentation day at the end of June — it worked great!
Top comments (0)