DEV Community

Cover image for Present with Hand-Drawn Style Animations Using Excalidraw Animate + HTML
pirothat
pirothat

Posted on

Present with Hand-Drawn Style Animations Using Excalidraw Animate + HTML

Excalidraw

https://excalidraw.com/

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>
Enter fullscreen mode Exit fullscreen mode

How to use

Steps

  1. Create animated SVG files with Excalidraw Animate (name them frame01.svg to frame20.svg).

  2. Paste the HTML code above into an index.html file.

  3. Put your SVG files in the same folder as index.html.

  4. 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)