7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

手書き風アニメーションでプレゼンする【Excalidraw animate + HTML】

7
Last updated at Posted at 2025-06-18

Excalidraw

animateさせることもできる。

draw.io以外でAWSアーキテクチャ図を書く方法がないか調べているうちに知った。

しかし、 GIFでの出力ができなくて、Google Slideに添付できない。

そのほかの方法を調べると、
Reveal.jsなど色々なOSSがあった。
しかし、この程度なら自力でHTMLで作れるということで、vibe coding で作成。

せっかくなのでインフォーマルめ、軽めのプレゼンなどに活用する予定。

これ。


<!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 ボタン(左下) ─ */
  .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{
    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>
(() => {
  /* ===== 設定 ===== */
  const NUM_SLIDES = 20;
  const FILE_PREFIX = 'frame';   // frame01.svg など
  const PAD_LENGTH  = 2;         // 01, 02 …

  /* ===== スライド生成 ===== */
  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);
  }

  /* ===== ページ送り & カウンタ更新 ===== */
  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>

使い方

・Excalidraw animateで手書き風のアニメートされたSVGファイルを作る(frame01.svg 〜 frame20.svgの名前にする)。
・index.htmlに上記コードをペースト。
・同じフォルダに frame01.svg 〜 frame20.svg を置く
この index.html をブラウザで開きフルスクリーン
← / → でページ移動、左下の ↺ でそのページだけリプレイ
右下に薄く 「現在枚数 / 総枚数」 が常に表示される

追記

6末の社内の成果発表会で活用した。

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?