mcpField
A
ai-vibe-slides

ai-vibe-slides

github.com/unclecatvnドキュメント148424 回インストール2 週間前に更新
リポジトリ

ai-vibe-slides について

ブラウザーでの発表や印刷・PDF出力に対応する、単一の HTML または React ファイル形式のスライドデッキを作るスキルです。構成案、デザイン方針、レイアウト、操作方法、レスポンシブ対応と印刷用スタイルを扱います。

主な機能

  1. 01単一ファイルのHTMLまたはReactデッキ生成
  2. 02対象者に合わせた構成案の作成
  3. 03一貫したビジュアル方針の選択
  4. 04キーボードとクリックでの操作
  5. 05印刷・PDF向けスタイルの準備

活用シーン

  1. 01短いテーマからプレゼンを作成
  2. 02ピッチ資料や学術発表の作成
  3. 03スライド内容と見た目の修正
  4. 04ブラウザーでの発表やファイル出力

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/unclecatvn/agent-skills --skill ai-vibe-slides

インストール後、Claude Code で/ai-vibe-slidesを入力して読み込まれたか確認します。

詳細

AI Vibe Slides — 美しいHTMLスライドデッキ、そのまま発表可能

目標

次のことができる、完成したスライドデッキを含む単一のHTMLまたはReactアーティファクトファイルを作成します。

  • ブラウザーで直接、全画面表示する
  • 矢印キー、スペースキー、クリックで移動する
  • プロフェッショナルで洗練され、スタイルに一貫性がある
  • 必要に応じて印刷またはPDFにエクスポートする

banana-slidesに着想を得た、アイデア → アウトライン → 完成スライドの3ステップのパイプラインですが、出力はフルスタックアプリケーションではなく、自己完結型のHTMLファイルです。


スライド作成パイプライン

ステップ1:リクエストを理解する → アウトラインを作成する

ユーザーがリクエストを提示したら、まず頭の中でアウトラインを作成します(ユーザーから求められない限り、表示する必要はありません)。

  1. メインテーマと対象読者(学生、ビジネスパーソン、技術系の講演参加者など)を特定します
  2. 論理的なセクションに分割します。
    • スライド1:表紙(タイトル+サブタイトル+作者)
    • スライド2〜3:導入/背景
    • 中盤のスライド:中心となる内容(1枚につき重要なアイデアは1つ)
    • 最終スライド:まとめ/行動喚起/謝辞
  3. 各スライドには、タイトル、2〜5個の箇条書きまたはビジュアルコンテンツ、レイアウトタイプを含めます

ユーザーの入力が短い一文(例:「医療におけるAIについてのスライドを作成」)だけの場合は、論理的な構成で8〜12枚のスライドに自動的に展開します。

ステップ2:デザインの方向性を選ぶ

コンテキストに基づいて、明確なデザインの方向性を1つ決めます。

コンテキスト推奨スタイル
スタートアップのピッチデッキ大胆なダークテーマ、グラデーションのアクセント、力強いサンセリフ体
学術/教育すっきりした明るいデザイン、図解を多用し、読みやすいフォント
技術系の講演/カンファレンスモダンなダークテーマ、コード風のタイポグラフィ、ネオンのアクセント
企業/レポートミニマルでプロフェッショナルなデザイン、ネイビー/ホワイト、セリフ体の見出し
クリエイティブ/マーケティングカラフルで非対称なレイアウト、大胆なタイポグラフィ
子ども/幼児教育パステルカラー、丸みのある角、遊び心のあるアイコン、大きな文字

一般的なルール:

  • メインカラーを2〜3色選び、デッキ全体で一貫して使用します
  • 見出し用フォントを1つ+本文用フォントを1つ(Google Fontsを使用)
  • テキストは最小限にし、余白を十分に取ります — 1枚あたり最大5〜6行
  • 明確な視覚的階層:大きなタイトル → 中くらいのコンテンツ → 小さな注記
ステップ3:HTML/Reactのスライドデッキを生成する

すべてを含む単一ファイル(.htmlまたは.jsx)を作成します。


HTMLスライドデッキの構造

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>{Presentation Title}</title>
    <link
      href="https://fonts.googleapis.com/css2?family={Font1}&family={Font2}&display=swap"
      rel="stylesheet"
    />
    <style>
      /* === RESET + BASE === */
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      /* === SLIDE CONTAINER === */
      .slide-deck {
        width: 100vw;
        height: 100vh;
        overflow: hidden;
        position: relative;
      }
      .slide {
        width: 100%;
        height: 100%;
        display: none;
        flex-direction: column;
        justify-content: center;
        padding: 60px 80px;
        position: absolute;
        top: 0;
        left: 0;
      }
      .slide.active {
        display: flex;
      }

      /* === TYPOGRAPHY === */
      h1 {
        font-family: "{Font1}", sans-serif;
        font-size: 3.2rem;
        margin-bottom: 1rem;
      }
      h2 {
        font-family: "{Font1}", sans-serif;
        font-size: 2.4rem;
        margin-bottom: 1.5rem;
      }
      p,
      li {
        font-family: "{Font2}", sans-serif;
        font-size: 1.4rem;
        line-height: 1.8;
      }

      /* === THEME COLORS === */
      :root {
        --bg-primary: #0f172a;
        --bg-slide: #1e293b;
        --text-primary: #f8fafc;
        --text-secondary: #94a3b8;
        --accent: #3b82f6;
        --accent-2: #8b5cf6;
      }

      /* === NAVIGATION UI === */
      .nav-hint {
        position: fixed;
        bottom: 20px;
        right: 30px;
        font-size: 0.8rem;
        color: var(--text-secondary);
        opacity: 0.5;
      }
      .slide-counter {
        position: fixed;
        bottom: 20px;
        left: 30px;
        font-size: 0.8rem;
        color: var(--text-secondary);
      }

      /* === TRANSITIONS === */
      .slide {
        animation: fadeIn 0.4s ease;
      }
      @keyframes fadeIn {
        from {
          opacity: 0;
          transform: translateY(10px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      /* === LAYOUT VARIANTS === */
      .slide.cover {
        justify-content: center;
        align-items: center;
        text-align: center;
      }
      .slide.two-column {
        flex-direction: row;
        gap: 60px;
        align-items: center;
      }
      .slide.two-column .col {
        flex: 1;
      }
      .slide.centered {
        align-items: center;
        text-align: center;
      }

      /* === VISUAL ELEMENTS === */
      .card {
        background: rgba(255, 255, 255, 0.05);
        border-radius: 12px;
        padding: 24px;
        margin: 8px 0;
      }
      .badge {
        display: inline-block;
        background: var(--accent);
        color: white;
        padding: 4px 14px;
        border-radius: 20px;
        font-size: 0.85rem;
      }
      .divider {
        width: 60px;
        height: 4px;
        background: var(--accent);
        border-radius: 2px;
        margin: 16px 0;
      }
      .icon-grid {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
        gap: 20px;
      }

      /* === PRINT / PDF EXPORT === */
      @media print {
        .slide {
          page-break-after: always;
          display: flex !important;
          position: relative;
        }
        .nav-hint,
        .slide-counter {
          display: none;
        }
      }
    </style>
  </head>
  <body>
    <div class="slide-deck" id="deck">
      
      <div
        class="slide cover active"
        style="background: linear-gradient(135deg, var(--bg-primary), #1a1a2e);"
      >
        <div class="badge">Topic</div>
        <h1 style="font-size: 3.8rem; margin-top: 20px;">Main Title</h1>
        <p
          style="color: var(--text-secondary); font-size: 1.3rem; margin-top: 12px;"
        >
          Short subtitle description
        </p>
        <div class="divider" style="margin: 20px auto;"></div>
        <p style="color: var(--text-secondary); font-size: 1rem;">
          Author — Date
        </p>
      </div>

      
      <div class="slide">
        <h2>Slide Title</h2>
        <div class="divider"></div>
        <ul>
          <li>Key point 1</li>
          <li>Key point 2</li>
          <li>Key point 3</li>
        </ul>
      </div>

      
    </div>

    <div class="slide-counter">
      <span id="current">1</span> / <span id="total"></span>
    </div>
    <div class="nav-hint">← → or click to navigate</div>

    <script>
      const slides = document.querySelectorAll(".slide");
      let currentSlide = 0;
      document.getElementById("total").textContent = slides.length;

      function showSlide(n) {
        slides[currentSlide].classList.remove("active");
        currentSlide = (n + slides.length) % slides.length;
        slides[currentSlide].classList.add("active");
        document.getElementById("current").textContent = currentSlide + 1;
      }

      document.addEventListener("keydown", (e) => {
        if (e.key === "ArrowRight" || e.key === " ")
          showSlide(currentSlide + 1);
        if (e.key === "ArrowLeft") showSlide(currentSlide - 1);
        if (e.key === "f") document.documentElement.requestFullscreen?.();
        if (e.key === "Escape") document.exitFullscreen?.();
      });

      document.querySelector(".slide-deck").addEventListener("click", (e) => {
        const x = e.clientX / window.innerWidth;
        x > 0.5 ? showSlide(currentSlide + 1) : showSlide(currentSlide - 1);
      });
    </script>
  </body>
</html>

スライドのレイアウトタイプ

各スライドでは、内容に最も適したレイアウトを使用します。

1. 表紙スライド
  • 中央揃えの特大フォント、グラデーション背景
  • トピックバッジ+メインタイトル+サブタイトル+作者
2. セクション区切り
  • セクションタイトル+番号のみ、アクセントカラーの背景
  • プレゼンテーションの主要なセクションを分けるために使用
3. コンテンツ+箇条書き
  • 左揃えのタイトル+重要なポイントのリスト
  • 通常のドットの代わりに、各箇条書きの先頭にアイコン/絵文字を使用
4. 2カラム
  • .two-columnレイアウト:左側にテキスト、右側にビジュアル/リスト/カード
  • 比較、ビフォーアフター、テキスト+イラストに最適
5. カードグリッド
  • 2〜3列のグリッド。各カードにはアイコン+タイトル+短い説明を含めます
  • 機能、メリット、チームメンバーの紹介に最適
6. 大きな数字/統計
  • 中央に大きな数字(font-size: 5rem以上)+その下に小さなラベル
  • データポイント、KPI、インパクトを示す数値に最適
7. 引用/ハイライト
  • 装飾的な引用符を添えた、大きな中央揃えのテキスト
  • 背景は別の色(淡いアクセントカラー)
8. タイムライン/手順
  • 各ステップをつなぐドットを配置した、横方向または縦方向のフレックスボックス
  • プロセス、ロードマップ、歴史の説明に最適
9. 謝辞/CTA
  • 中央揃えのシンプルなデザイン。連絡先情報または行動喚起を記載

必須のデザインルール

  1. 16:9 のアスペクト比:常に width: 100vw; height: 100vh を使用し、各スライドが画面全体に表示されるようにします
  2. テキストは最小限に:1 枚のスライドにつき最大 6 行です。内容が長い場合は、複数のスライドに分割します
  3. 大きなフォントサイズ:見出しは 2.4rem 以上、本文は 1.3rem 以上にします。プロジェクターでも読みやすいサイズにしてください
  4. 高いコントラスト:テキストが背景に対してはっきり読めるようにします。見た目を確認してください
  5. 一貫性:デッキ全体で、フォント、カラーパレット、余白を統一します
  6. プレースホルダー画像を使わない:<img src="placeholder"> は使用しないでください。代わりに CSS の図形、グラデーション、アイコン(絵文字または React 用 Lucide)、インライン SVG を使用します
  7. 控えめなアニメーション:スライド切り替え時の fadeIn のみを使用します。注意をそらす複雑なアニメーションは使いません
  8. 全画面表示に対応:あらゆる画面サイズで適切に動作するようにします
  9. 印刷対応:各スライドが印刷時に 1 ページになるよう、@media print ルールを含めます

HTML の代わりに React(.jsx)を使用する場合

React の成果物を作成する場合は、次のパターンを使用します。

import { useState, useEffect, useCallback } from "react";

const slides = [
  { type: "cover", title: "...", subtitle: "..." },
  { type: "content", title: "...", points: ["...", "..."] },
  { type: "twoColumn", title: "...", left: "...", right: "..." },
  // ...
];

export default function SlideDeck() {
  const [current, setCurrent] = useState(0);

  const next = useCallback(
    () => setCurrent((c) => (c + 1) % slides.length),
    [],
  );
  const prev = useCallback(
    () => setCurrent((c) => (c - 1 + slides.length) % slides.length),
    [],
  );

  useEffect(() => {
    const handleKey = (e) => {
      if (e.key === "ArrowRight" || e.key === " ") next();
      if (e.key === "ArrowLeft") prev();
      if (e.key === "f") document.documentElement.requestFullscreen?.();
    };
    window.addEventListener("keydown", handleKey);
    return () => window.removeEventListener("keydown", handleKey);
  }, [next, prev]);

  const renderSlide = (slide) => {
    switch (slide.type) {
      case "cover":
        return /* cover layout */;
      case "content":
        return /* content layout */;
      case "twoColumn":
        return /* two-column layout */;
      // ...
    }
  };

  return (
    <div
      className="w-screen h-screen overflow-hidden relative"
      onClick={(e) => (e.clientX > window.innerWidth / 2 ? next() : prev())}
      style={{ fontFamily: "'Outfit', sans-serif" }}
    >
      {renderSlide(slides[current])}
      <div className="fixed bottom-5 left-8 text-sm opacity-40">
        {current + 1} / {slides.length}
      </div>
    </div>
  );
}

React を使う利点:Tailwind CSS ユーティリティ、Lucide アイコン、より複雑なロジック、グラフ用の recharts。


納品前チェックリスト

  • スライドの枚数が正しい(表紙+内容+締め)
  • 矢印キー ← → が機能し、クリックで移動できる
  • カウンターに正しい「X / N」が表示される
  • F キーで全画面表示にできる
  • すべてのテキストが十分なコントラストで読みやすい
  • 画像の破損やプレースホルダーがない
  • Google Fonts が正しく読み込まれる(または適切な代替フォントが使われる)
  • 印刷/PDF に正しく出力される(@media print)
  • デッキ全体でスタイルが統一されている
  • 各スライドの要点は 1 つで、テキストを詰め込みすぎていない

自然言語による編集

初回作成後、ユーザーは変更を依頼できます。

  • 「ライトテーマに切り替えて」→ CSS 変数を更新します
  • 「事例研究についてのスライドを 2 枚追加して」→ 配列にスライドを挿入します
  • 「スライド 3 のテキストが多すぎるので、分割して」→ スライド間で内容を再構成します
  • 「フォントを Playfair Display に変更して」→ Google Fonts のリンクと CSS を更新します
  • 「スライド 5 にグラフを追加して」→ CSS のグラフまたは recharts(React)を使用します

編集のたびに、変更しないスライドはそのまま維持し、ユーザーが依頼した内容だけを更新します。

コメント