frontend-slides について
このスキルは非推奨で、デザイナー以外の人がブラウザーで動くアニメーション付きHTMLプレゼンテーションを作成するためのものです。スタイル選びを支援し、各スライドが画面内に収まる単体のデッキを生成します。
主な機能
- 01CSSとJavaScriptを含む単一HTMLファイル
- 02ビジュアルプレビューによるスタイル選択
- 03プリセットを使ったスライドデザイン
- 04スライド内スクロールのない画面フィット
- 05PowerPoint変換とHTMLプレゼンテーションの改善
活用シーン
- 01ブラウザーで表示するピッチデッキの作成
- 02ラフなメモからプレゼン資料を構成
- 03PowerPointファイルをHTMLスライドに変換
- 04既存のHTMLプレゼンテーションを改善
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ gooseworks-ai/ goose-skills --skill frontend-slidesインストール後、Claude Code で/frontend-slidesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mdskill.meta.jsonSTYLE_PRESETS.md詳細
非推奨: このスキルは
goose-graphicsに置き換えられました。skills/composites/goose-graphics/をご覧ください(npx goose-skills install goose-graphicsでインストールできます)。スライド形式は新しいスキルに含まれる7つの形式の1つで、36種類のスタイルプリセットに加え、画像の取得とPNGエクスポートに対応しています。このスキルは、削除まで1リリースサイクルの間、引き続き提供されます。
フロントエンドスライドスキル
ブラウザー上で完全に動作する、依存関係ゼロでアニメーション豊富なHTMLプレゼンテーションを作成します。このスキルでは、ビジュアルを見て選ぶ(「言葉で説明するより、実際に見せる」)ことで、デザインの専門家でない人が好みのスタイルを見つけ、その後、プロダクション品質のスライドデッキを生成できます。
基本理念
- 依存関係ゼロ — CSSとJSをインラインで記述した単一のHTMLファイルです。npmもビルドツールも必要ありません。
- 言葉で説明するより、実際に見せる — 人は実際に見るまで、自分が何を求めているのか分かりません。抽象的な選択肢ではなく、ビジュアルプレビューを生成します。
- 独自性のあるデザイン — ありきたりな「AIが生成したような」見た目を避けます。どのプレゼンテーションも、オーダーメイドのように仕上げます。
- プロダクション品質 — コードには適切なコメントを付け、アクセシビリティとパフォーマンスに配慮します。
- ビューポートへの収まり(重要) — すべてのスライドをビューポート内に正確に収める必要があります。スライド内のスクロールは一切禁止です。これは譲れない要件です。
重要:ビューポートへの収まりに関する要件
このセクションは、すべてのプレゼンテーションで必須です。どの画面サイズでも、すべてのスライドをスクロールせずに完全に表示できるようにしてください。
黄金律
Each slide = exactly one viewport height (100vh/100dvh)
Content overflows? → Split into multiple slides or reduce content
Never scroll within a slide.
コンテンツ密度の上限
ビューポート内に収めるため、スライドごとに以下の上限を適用してください。
| スライドの種類 | コンテンツの上限 |
|---|---|
| タイトルスライド | 見出し1つ+サブタイトル1つ+任意のキャッチコピー |
| コンテンツスライド | 見出し1つ+箇条書き4~6項目、または見出し1つ+段落2つ |
| 機能グリッド | 見出し1つ+カード最大6枚(2×3または3×2のグリッド) |
| コードスライド | 見出し1つ+コード最大8~10行 |
| 引用スライド | 引用1つ(最大3行)+出典 |
| 画像スライド | 見出し1つ+画像1枚(高さ最大60vh) |
コンテンツがこの上限を超える場合 → 複数のスライドに分割します
必須のCSS構成
すべてのプレゼンテーションに、ビューポート内に収めるための以下の基本CSSを含めてください。
/* ===========================================
VIEWPORT FITTING: MANDATORY BASE STYLES
These styles MUST be included in every presentation.
They ensure slides fit exactly in the viewport.
=========================================== */
/* 1. Lock html/body to viewport */
html, body {
height: 100%;
overflow-x: hidden;
}
html {
scroll-snap-type: y mandatory;
scroll-behavior: smooth;
}
/* 2. Each slide = exact viewport height */
.slide {
width: 100vw;
height: 100vh;
height: 100dvh; /* Dynamic viewport height for mobile browsers */
overflow: hidden; /* CRITICAL: Prevent ANY overflow */
scroll-snap-align: start;
display: flex;
flex-direction: column;
position: relative;
}
/* 3. Content container with flex for centering */
.slide-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
max-height: 100%;
overflow: hidden; /* Double-protection against overflow */
padding: var(--slide-padding);
}
/* 4. ALL typography uses clamp() for responsive scaling */
:root {
/* Titles scale from mobile to desktop */
--title-size: clamp(1.5rem, 5vw, 4rem);
--h2-size: clamp(1.25rem, 3.5vw, 2.5rem);
--h3-size: clamp(1rem, 2.5vw, 1.75rem);
/* Body text */
--body-size: clamp(0.75rem, 1.5vw, 1.125rem);
--small-size: clamp(0.65rem, 1vw, 0.875rem);
/* Spacing scales with viewport */
--slide-padding: clamp(1rem, 4vw, 4rem);
--content-gap: clamp(0.5rem, 2vw, 2rem);
--element-gap: clamp(0.25rem, 1vw, 1rem);
}
/* 5. Cards/containers use viewport-relative max sizes */
.card, .container, .content-box {
max-width: min(90vw, 1000px);
max-height: min(80vh, 700px);
}
/* 6. Lists auto-scale with viewport */
.feature-list, .bullet-list {
gap: clamp(0.4rem, 1vh, 1rem);
}
.feature-list li, .bullet-list li {
font-size: var(--body-size);
line-height: 1.4;
}
/* 7. Grids adapt to available space */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
gap: clamp(0.5rem, 1.5vw, 1rem);
}
/* 8. Images constrained to viewport */
img, .image-container {
max-width: 100%;
max-height: min(50vh, 400px);
object-fit: contain;
}
/* ===========================================
RESPONSIVE BREAKPOINTS
Aggressive scaling for smaller viewports
=========================================== */
/* Short viewports (< 700px height) */
@media (max-height: 700px) {
:root {
--slide-padding: clamp(0.75rem, 3vw, 2rem);
--content-gap: clamp(0.4rem, 1.5vw, 1rem);
--title-size: clamp(1.25rem, 4.5vw, 2.5rem);
--h2-size: clamp(1rem, 3vw, 1.75rem);
}
}
/* Very short viewports (< 600px height) */
@media (max-height: 600px) {
:root {
--slide-padding: clamp(0.5rem, 2.5vw, 1.5rem);
--content-gap: clamp(0.3rem, 1vw, 0.75rem);
--title-size: clamp(1.1rem, 4vw, 2rem);
--body-size: clamp(0.7rem, 1.2vw, 0.95rem);
}
/* Hide non-essential elements */
.nav-dots, .keyboard-hint, .decorative {
display: none;
}
}
/* Extremely short (landscape phones, < 500px height) */
@media (max-height: 500px) {
:root {
--slide-padding: clamp(0.4rem, 2vw, 1rem);
--title-size: clamp(1rem, 3.5vw, 1.5rem);
--h2-size: clamp(0.9rem, 2.5vw, 1.25rem);
--body-size: clamp(0.65rem, 1vw, 0.85rem);
}
}
/* Narrow viewports (< 600px width) */
@media (max-width: 600px) {
:root {
--title-size: clamp(1.25rem, 7vw, 2.5rem);
}
/* Stack grids vertically */
.grid {
grid-template-columns: 1fr;
}
}
/* ===========================================
REDUCED MOTION
Respect user preferences
=========================================== */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.2s !important;
}
html {
scroll-behavior: auto;
}
}
はみ出し防止チェックリスト
プレゼンテーションを生成する前に、以下を念頭に置いて確認してください。
- ✅ すべての
.slideにheight: 100vh; height: 100dvh; overflow: hidden;がある - ✅ すべてのフォントサイズに
clamp(min, preferred, max)を使用している - ✅ すべての余白に
clamp()またはビューポート単位を使用している - ✅ コンテンツコンテナに
max-heightの制約がある - ✅ 画像に
max-height: min(50vh, 400px)などを設定している - ✅ グリッドのレスポンシブな列に
auto-fitとminmax()を使用している - ✅ 高さ700px、600px、500pxに対応するブレークポイントがある
- ✅ コンテンツ要素に固定のピクセル高を指定していない
- ✅ 各スライドのコンテンツ量が密度の上限を守っている
コンテンツが収まらない場合
コンテンツが多すぎる場合:
すること:
- 複数のスライドに分割する
- 箇条書きの数を減らす(スライドごとに最大5~6項目)
- テキストを短くする(各項目は1~2行を目安にする)
- コードスニペットを短くする
- 「続き」のスライドを作成する
しないこと:
- 読みやすさを損なうほどフォントサイズを小さくする
- パディングや余白を完全になくす
- スクロールを許可する
- コンテンツを無理に詰め込む
ビューポートへの収まりをテストする
生成後、以下のサイズでテストするようユーザーに勧めてください。
- デスクトップ:1920×1080、1440×900、1280×720
- タブレット:1024×768、768×1024(縦向き)
- モバイル:375×667、414×896
- 横向きのスマートフォン:667×375、896×414
フェーズ0:モードの判定
まず、ユーザーが何をしたいのかを判断します。
モードA:新しいプレゼンテーション
- ユーザーはゼロからスライドを作成したい
- フェーズ1(コンテンツの把握)に進む
モードB:PPTの変換
- ユーザーは変換対象のPowerPointファイル(.ppt、.pptx)を持っている
- フェーズ4(PPTの抽出)に進む
モードC:既存のプレゼンテーションの改善
- ユーザーはHTMLプレゼンテーションを持っており、改善したい
- 既存のファイルを読み、構成を把握してから改善する
フェーズ1:コンテンツの把握(新しいプレゼンテーション)
デザインを始める前に、コンテンツを把握します。AskUserQuestionを使って質問します。
ステップ 1.1:プレゼンテーションの背景
質問 1:目的
- 見出し:「目的」
- 質問:「このプレゼンテーションの目的は何ですか?」
- 選択肢:
- 「ピッチデッキ」 — 投資家や顧客にアイデア、製品、または会社を売り込む
- 「授業/チュートリアル」 — 概念、手順ガイド、教育コンテンツを説明する
- 「カンファレンストーク」 — イベント、技術講演、基調講演で話す
- 「社内プレゼンテーション」 — チームの近況報告、戦略会議、会社の近況報告
質問 2:スライド枚数
- 見出し:「長さ」
- 質問:「スライドはおよそ何枚ですか?」
- 選択肢:
- 「短め(5~10枚)」 — 手短なピッチ、ライトニングトーク
- 「中程度(10~20枚)」 — 標準的なプレゼンテーション
- 「長め(20枚以上)」 — 詳細な解説、包括的な講演
質問 3:コンテンツ
- 見出し:「コンテンツ」
- 質問:「コンテンツはすでに用意されていますか?それとも構成を考えるサポートが必要ですか?」
- 選択肢:
- 「コンテンツはすべて用意できています」 — プレゼンテーションのデザインだけが必要
- 「大まかなメモがあります」 — スライドにまとめるサポートが必要
- 「テーマだけ決まっています」 — 全体のアウトラインを作成するサポートが必要
ユーザーにコンテンツがある場合は、テキスト、箇条書き、画像などを共有してもらいます。
フェーズ 2:スタイルの探求(ビジュアルの確認)
重要:このフェーズでは「説明より実物を見せる」ことが大切です。
多くの人は、デザインの好みを言葉で説明できません。「ミニマルなものと大胆なもののどちらがよいですか?」と尋ねる代わりに、ミニプレビューを作成し、見た人の反応を確認します。
プリセットの選び方
ユーザーは2つの方法でスタイルを選べます。
オプション A:ガイド付きの選択(デフォルト)
- ユーザーが雰囲気に関する質問に回答する
- スキルが回答をもとにプレビューファイルを 3 つ生成する
- ユーザーがブラウザーでプレビューを確認し、気に入ったものを選ぶ
- 特定のスタイルが決まっていないユーザーに最適です
オプション B:直接選択
- 希望するスタイルがすでに決まっている場合は、名前を指定してプリセットを選べます
- 例:「Bold Signal スタイルを使って」や「Dark Botanical のようなものがほしい」
- すぐにフェーズ 3 に進みます
利用可能なプリセット:
| プリセット | 雰囲気 | おすすめの用途 |
|---|---|---|
| Bold Signal | 自信に満ちた、インパクトの強い | ピッチデッキ、基調講演 |
| Electric Studio | 洗練された、プロフェッショナルな | 代理店のプレゼンテーション |
| Creative Voltage | エネルギッシュな、レトロモダンな | クリエイティブなピッチ |
| Dark Botanical | エレガントな、洗練された | プレミアムブランド |
| Notebook Tabs | エディトリアルな、整理された | レポート、レビュー |
| Pastel Geometry | 親しみやすい、気軽に接しやすい | 製品概要 |
| Split Pastel | 遊び心のある、モダンな | クリエイティブエージェンシー |
| Vintage Editorial | ウィットに富んだ、個性を感じる | パーソナルブランド |
| Neon Cyber | 未来的な、テクノロジー感のある | テック系スタートアップ |
| Terminal Green | 開発者向けの | 開発ツール、API |
| Swiss Modern | ミニマルな、精密な | 企業向け、データ |
| Paper & Ink | 文学的な、思慮深い | ストーリーテリング |
ステップ 2.0:スタイルの選択方法
まず、スタイルの選び方をユーザーに尋ねます。
質問:スタイルの選択方法
- 見出し:「スタイル」
- 質問:「プレゼンテーションのスタイルをどのように選びますか?」
- 選択肢:
- 「選択肢を見せてください」— ニーズに合わせてプレビューを 3 つ生成します(ほとんどのユーザーにおすすめ)
- 「希望するスタイルが決まっています」— プリセットの一覧から直接選べます
- 「クライアントのブランドを使用する」— クライアントのブランドカラー、フォント、雰囲気を適用します
「選択肢を見せてください」の場合 → ステップ 2.1(ムードの選択)に進みます
「希望するスタイルが決まっています」の場合 → プリセット選択画面を表示します。
質問:プリセットを選択
- 見出し:「プリセット」
- 質問:「使用するスタイルを選んでください。」
- 選択肢:
- 「Bold Signal」— 暗い背景に鮮やかなカードを配した、自信に満ちた力強いスタイル
- 「Dark Botanical」— 柔らかな抽象図形をあしらった、エレガントなダークスタイル
- 「Notebook Tabs」— カラフルなセクションタブを配した、エディトリアルな紙のようなスタイル
- 「Pastel Geometry」— 装飾的なピルをあしらった、親しみやすいパステルスタイル
(ユーザーがいずれかを選んだら、フェーズ 3 に進みます。さらに選択肢を見たい場合は、追加のプリセットを表示するか、ガイド付きの選択に進みます。)
「クライアントのブランドを使用する」の場合 → クライアントのビジュアルアイデンティティを読み込みます。
- このプレゼンテーションの対象となるクライアントを尋ねます(または、文脈から推測します)。
clients/<client-name>/brand/visual-identity.mdがあるか確認します。- ファイルがある場合:「Slide Preset」セクションを読み込みます。CSS の
:rootカスタムプロパティをプレゼンテーションのテーマ変数として、タイポグラフィをフォントの組み合わせとして、フォント読み込み用の<link>タグをそのまま使用し、シグネチャー要素を装飾用 CSS のデザイン指針として使用します。 - ファイルがない場合: ユーザーに次のように伝えます。「[client] のビジュアルアイデンティティはまだ抽出されていません。今すぐ抽出しますか?クライアントのウェブサイト URL を入力してください。」続いて、
visual-brand-extractorスキルを実行してファイルを生成し、そのまま続行します。 - クライアントのプリセットを読み込んだ状態でフェーズ 3 に進みます。
ステップ 2.1:ムードの選択(ガイド付きの選択)
質問 1:印象
- 見出し:「雰囲気」
- 質問:「スライドを見た人に、どのような印象を持ってほしいですか?」
- 選択肢:
- 「感銘/自信」— プロフェッショナルで信頼でき、チームが仕事を熟知している印象
- 「興奮/活気」— 革新的で大胆、未来を感じさせる印象
- 「落ち着き/集中」— 明快で思慮深く、内容を追いやすい印象
- 「ひらめき/感動」— 感情に訴え、ストーリー性があり、記憶に残る印象
- multiSelect: true(最大 2 つまで選択可能)
ステップ 2.2:スタイルのプレビューを生成
選択されたムードに基づき、一時ディレクトリに単一のタイトルスライドを表示するミニ HTML ファイルとして、異なるスタイルのプレビューを 3 つ生成します。各プレビューには、次の内容を含めます。
- タイポグラフィ(フォントの選択、見出しと本文の階層)
- カラーパレット(背景色、アクセントカラー、テキストカラー)
- アニメーションのスタイル(要素の表示方法)
- 全体的な美的印象
検討するプレビュースタイル(ムードに応じて 3 つ選択):
| ムード | スタイルの選択肢 |
|---|---|
| 感銘/自信 | 「Bold Signal」、「Electric Studio」、「Dark Botanical」 |
| 興奮/活気 | 「Creative Voltage」、「Neon Cyber」、「Split Pastel」 |
| 落ち着き/集中 | 「Notebook Tabs」、「Paper & Ink」、「Swiss Modern」 |
| ひらめき/感動 | 「Dark Botanical」、「Vintage Editorial」、「Pastel Geometry」 |
重要:次のような一般的なパターンは使用しないでください。
- 白い背景に紫のグラデーション
- Inter、Roboto、システムフォント
- 標準的なブルーのプライマリーカラー
- ありきたりなヒーローレイアウト
代わりに、個性が際立つ選択をしてください。
- 個性的なフォントの組み合わせ(Clash Display、Satoshi、Cormorant Garamond、DM Sans など)
- 個性のある統一感の取れたカラーテーマ
- 雰囲気のある背景(グラデーション、控えめなパターン、奥行き)
- 印象的なアニメーションの演出
Step 2.3: プレビューを提示する
プレビューを次の場所に作成します:.claude-design/slide-previews/
.claude-design/slide-previews/
├── style-a.html # First style option
├── style-b.html # Second style option
├── style-c.html # Third style option
└── assets/ # Any shared assets
各プレビューファイルは、次の条件を満たす必要があります。
- 単体で動作する(CSS/JSをインラインで記述)
- 美しさを伝える単一の「タイトルスライド」である
- 動きのスタイルを示すアニメーションがある
- 約50~100行で、プレゼンテーション全体にはしない
ユーザーに提示します。
I've created 3 style previews for you to compare:
**Style A: [Name]** — [1 sentence description]
**Style B: [Name]** — [1 sentence description]
**Style C: [Name]** — [1 sentence description]
Open each file to see them in action:
- .claude-design/slide-previews/style-a.html
- .claude-design/slide-previews/style-b.html
- .claude-design/slide-previews/style-c.html
Take a look and tell me:
1. Which style resonates most?
2. What do you like about it?
3. Anything you'd change?
次に、AskUserQuestion を使用します。
質問:スタイルを選んでください
- ヘッダー:「スタイル」
- 質問:「どのスタイルのプレビューがお好みですか?」
- 選択肢:
- 「スタイルA:[名前]」 — [簡単な説明]
- 「スタイルB:[名前]」 — [簡単な説明]
- 「スタイルC:[名前]」 — [簡単な説明]
- 「要素を組み合わせる」 — 異なるスタイルの要素を組み合わせます
「要素を組み合わせる」を選んだ場合は、具体的な内容を尋ねます。
Phase 3: プレゼンテーションを生成する
次の内容に基づいて、プレゼンテーション全体を生成します。
- Phase 1 のコンテンツ
- Phase 2 のスタイル
ファイル構成
単一のプレゼンテーションの場合:
presentation.html # Self-contained presentation
assets/ # Images, if any
複数のプレゼンテーションを含むプロジェクトの場合:
[presentation-name].html
[presentation-name]-assets/
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 rel="stylesheet" href="https://api.fontshare.com/v2/css?f[]=...">
<style>
/* ===========================================
CSS CUSTOM PROPERTIES (THEME)
Easy to modify: change these to change the whole look
=========================================== */
:root {
/* Colors */
--bg-primary: #0a0f1c;
--bg-secondary: #111827;
--text-primary: #ffffff;
--text-secondary: #9ca3af;
--accent: #00ffcc;
--accent-glow: rgba(0, 255, 204, 0.3);
/* Typography - MUST use clamp() for responsive scaling */
--font-display: 'Clash Display', sans-serif;
--font-body: 'Satoshi', sans-serif;
--title-size: clamp(2rem, 6vw, 5rem);
--subtitle-size: clamp(0.875rem, 2vw, 1.25rem);
--body-size: clamp(0.75rem, 1.2vw, 1rem);
/* Spacing - MUST use clamp() for responsive scaling */
--slide-padding: clamp(1.5rem, 4vw, 4rem);
--content-gap: clamp(1rem, 2vw, 2rem);
/* Animation */
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
--duration-normal: 0.6s;
}
/* ===========================================
BASE STYLES
=========================================== */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
scroll-snap-type: y mandatory;
height: 100%;
}
body {
font-family: var(--font-body);
background: var(--bg-primary);
color: var(--text-primary);
overflow-x: hidden;
height: 100%;
}
/* ===========================================
SLIDE CONTAINER
CRITICAL: Each slide MUST fit exactly in viewport
- Use height: 100vh (NOT min-height)
- Use overflow: hidden to prevent scroll
- Content must scale with clamp() values
=========================================== */
.slide {
width: 100vw;
height: 100vh; /* EXACT viewport height - no scrolling */
height: 100dvh; /* Dynamic viewport height for mobile */
padding: var(--slide-padding);
scroll-snap-align: start;
display: flex;
flex-direction: column;
justify-content: center;
position: relative;
overflow: hidden; /* Prevent any content overflow */
}
/* Content wrapper that prevents overflow */
.slide-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
max-height: 100%;
overflow: hidden;
}
/* ===========================================
RESPONSIVE BREAKPOINTS
Adjust content for different screen sizes
=========================================== */
@media (max-height: 600px) {
:root {
--slide-padding: clamp(1rem, 3vw, 2rem);
--content-gap: clamp(0.5rem, 1.5vw, 1rem);
}
}
@media (max-width: 768px) {
:root {
--title-size: clamp(1.5rem, 8vw, 3rem);
}
}
@media (max-height: 500px) and (orientation: landscape) {
/* Extra compact for landscape phones */
:root {
--title-size: clamp(1.25rem, 5vw, 2rem);
--slide-padding: clamp(0.75rem, 2vw, 1.5rem);
}
}
/* ===========================================
ANIMATIONS
Trigger via .visible class (added by JS on scroll)
=========================================== */
.reveal {
opacity: 0;
transform: translateY(30px);
transition: opacity var(--duration-normal) var(--ease-out-expo),
transform var(--duration-normal) var(--ease-out-expo);
}
.slide.visible .reveal {
opacity: 1;
transform: translateY(0);
}
/* Stagger children */
.reveal:nth-child(1) { transition-delay: 0.1s; }
.reveal:nth-child(2) { transition-delay: 0.2s; }
.reveal:nth-child(3) { transition-delay: 0.3s; }
.reveal:nth-child(4) { transition-delay: 0.4s; }
/* ... more styles ... */
</style>
</head>
<body>
<div class="progress-bar"></div>
<nav class="nav-dots">
</nav>
<section class="slide title-slide">
<h1 class="reveal">Presentation Title</h1>
<p class="reveal">Subtitle or author</p>
</section>
<section class="slide">
<h2 class="reveal">Slide Title</h2>
<p class="reveal">Content...</p>
</section>
<script>
/* ===========================================
SLIDE PRESENTATION CONTROLLER
Handles navigation, animations, and interactions
=========================================== */
class SlidePresentation {
constructor() {
// ... initialization
}
// ... methods
}
// Initialize
new SlidePresentation();
</script>
</body>
</html>
必須の JavaScript 機能
すべてのプレゼンテーションに、次の機能を含めます。
-
SlidePresentation クラス — メインコントローラー
- キーボード操作(矢印キー、スペースキー)
- タッチ/スワイプ対応
- マウスホイールによる操作
- プログレスバーの更新
- ナビゲーションドット
-
Intersection Observer — スクロールに応じたアニメーション用
- スライドがビューポートに入ったときに
.visibleクラスを追加 - CSS アニメーションを効率的に実行
- スライドがビューポートに入ったときに
-
任意の拡張機能(スタイルに応じて)
- トレイル付きカスタムカーソル
- パーティクルシステムの背景(canvas)
- 視差効果
- ホバー時の3Dチルト
- マグネティックボタン
- カウンターアニメーション
コード品質要件
コメント: 各セクションには、次の内容を説明する明確なコメントを付けます。
- 処理内容
- 存在する理由
- 変更方法
/* ===========================================
CUSTOM CURSOR
Creates a stylized cursor that follows mouse with a trail effect.
- Uses lerp (linear interpolation) for smooth movement
- Grows larger when hovering over interactive elements
=========================================== */
class CustomCursor {
constructor() {
// ...
}
}
アクセシビリティ:
- セマンティック HTML(
<section>、<nav>、<main>) - キーボード操作に対応
- 必要に応じて ARIA ラベルを使用
- 動きを抑制する設定に対応
@media (prefers-reduced-motion: reduce) {
.reveal {
transition: opacity 0.3s ease;
transform: none;
}
}
レスポンシブ対応とビューポートへの適合(重要):
完全な CSS とガイドラインについては、上記の「重要:ビューポートへの適合要件」セクションを参照してください。
簡単な確認項目:
- すべての
.slideにheight: 100vh; height: 100dvh; overflow: hidden;を指定する - すべての文字サイズと余白に
clamp()を使用する - コンテンツ量の上限を守る(箇条書きは最大4~6項目、カードは最大6枚など)
- 高さ700px、600px、500pxのブレークポイントを含める
- コンテンツが収まらない場合は複数のスライドに分割し、スクロールは使用しない
Phase 4: PPT 変換
PowerPoint ファイルを変換する場合:
Step 4.1: コンテンツを抽出する
python-pptx を使って Python で次の内容を抽出します。
from pptx import Presentation
from pptx.util import Inches, Pt
import json
import os
import base64
def extract_pptx(file_path, output_dir):
"""
Extract all content from a PowerPoint file.
Returns a JSON structure with slides, text, and images.
"""
prs = Presentation(file_path)
slides_data = []
# Create assets directory
assets_dir = os.path.join(output_dir, 'assets')
os.makedirs(assets_dir, exist_ok=True)
for slide_num, slide in enumerate(prs.slides):
slide_data = {
'number': slide_num + 1,
'title': '',
'content': [],
'images': [],
'notes': ''
}
for shape in slide.shapes:
# Extract title
if shape.has_text_frame:
if shape == slide.shapes.title:
slide_data['title'] = shape.text
else:
slide_data['content'].append({
'type': 'text',
'content': shape.text
})
# Extract images
if shape.shape_type == 13: # Picture
image = shape.image
image_bytes = image.blob
image_ext = image.ext
image_name = f"slide{slide_num + 1}_img{len(slide_data['images']) + 1}.{image_ext}"
image_path = os.path.join(assets_dir, image_name)
with open(image_path, 'wb') as f:
f.write(image_bytes)
slide_data['images'].append({
'path': f"assets/{image_name}",
'width': shape.width,
'height': shape.height
})
# Extract notes
if slide.has_notes_slide:
notes_frame = slide.notes_slide.notes_text_frame
slide_data['notes'] = notes_frame.text
slides_data.append(slide_data)
return slides_data
Step 4.2: コンテンツの構成を確認する
抽出したコンテンツをユーザーに提示します。
I've extracted the following from your PowerPoint:
**Slide 1: [Title]**
- [Content summary]
- Images: [count]
**Slide 2: [Title]**
- [Content summary]
- Images: [count]
...
All images have been saved to the assets folder.
Does this look correct? Should I proceed with style selection?
Step 4.3: スタイルを選択する
抽出したコンテンツを考慮したうえで、Phase 2(スタイルの選定)に進みます。
Step 4.4: HTML を生成する
抽出したコンテンツを選択したスタイルに変換し、次の内容を保持します。
- すべてのテキストコンテンツ
- すべての画像(assets フォルダーを参照)
- スライドの順序
- スピーカーノート(HTML コメントまたは別ファイルとして保存)
Phase 5: 納品
最終出力
プレゼンテーションが完成したら:
-
一時ファイルを整理する
.claude-design/slide-previews/が存在する場合は削除する
-
プレゼンテーションを開く
open [filename].htmlを使ってブラウザーで開く
-
概要を提示する
Your presentation is ready!
📁 File: [filename].html
🎨 Style: [Style Name]
📊 Slides: [count]
**Navigation:**
- Arrow keys (← →) or Space to navigate
- Scroll/swipe also works
- Click the dots on the right to jump to a slide
**To customize:**
- Colors: Look for `:root` CSS variables at the top
- Fonts: Change the Fontshare/Google Fonts link
- Animations: Modify `.reveal` class timings
Would you like me to make any adjustments?
スタイルリファレンス:効果から印象への対応
このガイドを使って、意図する印象に合ったアニメーションを選びます。
ドラマチック/映画的
- ゆっくりしたフェードイン(1~1.5秒)
- 大きなスケールのトランジション(0.9 → 1)
- スポットライト効果を使った暗い背景
- 視差スクロール
- 画面いっぱいに表示する画像
テック/未来的
- ネオンの発光効果(アクセントカラーを使った box-shadow)
- パーティクルシステム(canvas の背景)
- グリッドパターン
- アクセントに等幅フォントを使用
- グリッチ効果または文字のスクランブル効果
- シアン、マゼンタ、エレクトリックブルーの配色
遊び心のある/親しみやすい
- 弾むイージング(バネの物理特性)
- 角丸(大きな半径)
- パステルカラーまたは明るい色
- 浮遊/上下に揺れるアニメーション
- 手描きまたはイラスト風の要素
プロフェッショナル/企業向け
- 控えめで素早いアニメーション(200-300ms)
- クリーンなサンセリフ体
- ネイビー、スレート、またはチャコールの背景
- 正確な余白と配置
- 装飾要素は最小限
- データビジュアライゼーションを重視
落ち着いた/ミニマル
- 非常にゆっくりとした控えめな動き
- 余白を多く取る
- 彩度を抑えたカラーパレット
- セリフ体のタイポグラフィ
- ゆとりのあるパディング
- コンテンツに集中し、気を散らすものを置かない
エディトリアル/雑誌風
- 明確なタイポグラフィの階層
- 引用文とコールアウト
- 画像とテキストの組み合わせ
- グリッドからはみ出すレイアウト
- 見出しはセリフ体、本文はサンセリフ体
- 黒と白にアクセントカラーを1色
アニメーションパターンのリファレンス
登場アニメーション
/* Fade + Slide Up (most common) */
.reveal {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.6s var(--ease-out-expo),
transform 0.6s var(--ease-out-expo);
}
.visible .reveal {
opacity: 1;
transform: translateY(0);
}
/* Scale In */
.reveal-scale {
opacity: 0;
transform: scale(0.9);
transition: opacity 0.6s, transform 0.6s var(--ease-out-expo);
}
/* Slide from Left */
.reveal-left {
opacity: 0;
transform: translateX(-50px);
transition: opacity 0.6s, transform 0.6s var(--ease-out-expo);
}
/* Blur In */
.reveal-blur {
opacity: 0;
filter: blur(10px);
transition: opacity 0.8s, filter 0.8s var(--ease-out-expo);
}
背景エフェクト
/* Gradient Mesh */
.gradient-bg {
background:
radial-gradient(ellipse at 20% 80%, rgba(120, 0, 255, 0.3) 0%, transparent 50%),
radial-gradient(ellipse at 80% 20%, rgba(0, 255, 200, 0.2) 0%, transparent 50%),
var(--bg-primary);
}
/* Noise Texture */
.noise-bg {
background-image: url("data:image/svg+xml,..."); /* Inline SVG noise */
}
/* Grid Pattern */
.grid-bg {
background-image:
linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);
background-size: 50px 50px;
}
インタラクティブエフェクト
/* 3D Tilt on Hover */
class TiltEffect {
constructor(element) {
this.element = element;
this.element.style.transformStyle = 'preserve-3d';
this.element.style.perspective = '1000px';
this.bindEvents();
}
bindEvents() {
this.element.addEventListener('mousemove', (e) => {
const rect = this.element.getBoundingClientRect();
const x = (e.clientX - rect.left) / rect.width - 0.5;
const y = (e.clientY - rect.top) / rect.height - 0.5;
this.element.style.transform = `
rotateY(${x * 10}deg)
rotateX(${-y * 10}deg)
`;
});
this.element.addEventListener('mouseleave', () => {
this.element.style.transform = 'rotateY(0) rotateX(0)';
});
}
}
トラブルシューティング
よくある問題
フォントが読み込まれない場合:
- Fontshare/Google Fonts の URL を確認してください
- CSS のフォント名が一致していることを確認してください
アニメーションが開始されない場合:
- Intersection Observer が動作していることを確認してください
.visibleクラスが追加されていることを確認してください
スクロールスナップが動作しない場合:
- html/body に
scroll-snap-typeが設定されていることを確認してください - 各スライドに
scroll-snap-align: startが必要です
モバイルでの問題:
- 768px のブレークポイントで負荷の高いエフェクトを無効にしてください
- タッチイベントをテストしてください
- パーティクル数を減らすか、キャンバスを無効にしてください
パフォーマンスの問題:
will-changeは控えめに使用してくださいtransformとopacityのアニメーションを優先してください- スクロール/mousemove のハンドラーをスロットルしてください
関連スキル
- learn — プレゼンテーション用の FORZARA.md ドキュメントを生成します
- frontend-design — スライド以外の、より複雑なインタラクティブページ向け
- design-and-refine:design-lab — コンポーネントのデザインを反復的に調整します
セッションの進行例
- ユーザー:「AI スタートアップ向けのピッチデッキを作成したいです」
- スキルが目的、長さ、コンテンツについて質問します
- ユーザーが箇条書きと重要なメッセージを共有します
- スキルが希望する印象(感動と期待)について質問します
- スキルがスタイルのプレビューを3種類生成します
- ユーザーがスタイル B(ネオン・サイバー)を選び、背景を暗くするよう依頼します
- スキルがすべてのスライドを含むプレゼンテーションを生成します
- スキルがブラウザーでプレゼンテーションを開きます
- ユーザーが特定のスライドの修正を依頼します
- 最終版のプレゼンテーションが納品されます
変換セッションの進行例
- ユーザー:「slides.pptx をウェブプレゼンテーションに変換してください」
- スキルが PPT からコンテンツと画像を抽出します
- スキルが抽出したコンテンツをユーザーに確認します
- スキルが希望する印象/スタイルについて質問します
- スキルがスタイルのプレビューを生成します
- ユーザーがスタイルを選びます
- スキルがアセットを保持した HTML プレゼンテーションを生成します
- 最終版のプレゼンテーションが納品されます