---
name: generate-pptx
description: スライドストーリーに基づき PptxGenJS コードを直接出力して PowerPoint（PPTX）ファイルを生成する。自由なレイアウト、カード、アイコン、図表等に対応。
allowed-tools:
  - web_search
---

# PPTX 生成スキル

PptxGenJS のコードを直接出力し、アプリがサーバーサイドで実行して PPTX を生成するスキルです。
JSON ではなく JavaScript コードを出力することで、カードレイアウト、マルチカラム、統計ハイライト等の自由なデザインが可能です。

## 出力フォーマット

` ```javascript ` コードブロックで PptxGenJS コードを出力すること。
コードは以下の変数がスコープに提供された状態で実行される：

- `pres` — PptxGenJS インスタンス（`layout: 'LAYOUT_WIDE'` 設定済み）
- `C` — カラー定数オブジェクト
- `F` — フォント定数（`F.JA`, `F.EN`）
- `SW`, `SH` — スライド幅(13.33)・高さ(7.5)
- `ML`, `MR` — 左右マージン(0.5)
- `CW` — コンテンツ幅(12.33)
- `HEADER_H` — ヘッダー帯高さ(0.45)

**重要**: コードでは `pres` にスライドを追加するだけでよい。`import`, `writeFile`, `new PptxGenJS()` は不要。

## スコープに提供される定数

### カラー定数 `C`（ベースパレット）

```javascript
C.BLUE       // '0078D4' — Microsoft Blue（プライマリ）
C.BLUE_DARK  // '005A9E'
C.BLUE_LIGHT // 'DEECF9' — 薄い青背景
C.BLUE_PALE  // 'EBF3FC' — 極薄い青背景
C.DARK       // '1B1B1B' — テキスト（メイン）
C.DARK_GRAY  // '2D2D2D' — テキスト（見出し）
C.MID_GRAY   // '505050' — テキスト（補足）
C.TEXT       // '3B3B3B' — テキスト（本文）
C.LIGHT_GRAY // 'F5F5F5' — カード背景
C.BORDER     // 'E1E1E1' — ボーダー
C.GREEN      // '107C10' — 成功・セキュリティ
C.GREEN_LIGHT// 'DFF6DD'
C.ORANGE     // 'D83B01' — 警告・重要
C.ORANGE_LIGHT // 'FFF4CE'
C.PURPLE     // '5C2D91' — セカンダリ
C.PURPLE_LIGHT // 'F0E6F6'
C.TEAL       // '008272'
C.WHITE      // 'FFFFFF'
```

**カラーの自由な使用**: `C` 定数はベースパレットとして用意しているが、**`#` なしの 6桁 HEX であれば自由にカスタムカラーを直書きしてよい。** `designBrief.colorMood` やプレゼンのテーマに合わせて、より表現力の高い配色を設計すること。

**カラームード別の推奨パレット例:**

| colorMood | アクセント | 背景 | テキスト | 補足 |
|-----------|----------|------|---------|------|
| warm / energetic | `E85D26`, `F59E0B`, `D94F04` | `FFF7ED`, `FFFBEB` | `1B1B1B` | オレンジ〜イエロー系 |
| cool / professional | `0078D4`, `2563EB`, `3B82F6` | `EFF6FF`, `F0F9FF` | `1E3A5F` | ブルー系 |
| nature / sustainable | `059669`, `10B981`, `047857` | `ECFDF5`, `F0FDF4` | `064E3B` | グリーン系 |
| premium / luxury | `7C3AED`, `6D28D9`, `A855F7` | `FAF5FF`, `F5F3FF` | `1E1B4B` | パープル系 |
| bold / startup | `DC2626`, `EF4444`, `F97316` | `FEF2F2`, `FFF7ED` | `1B1B1B` | レッド〜オレンジ系 |
| monochrome | `374151`, `6B7280`, `111827` | `F9FAFB`, `F3F4F6` | `111827` | グレー系 |

### フォント定数 `F`

```javascript
F.JA  // 'Noto Sans JP' — 日本語テキスト
F.EN  // 'Segoe UI'     — 英数字・ヘッダー
```

## コードの書き方ルール

1. **必ず** ` ```javascript ` で囲む（アプリがコードブロックを検出してダウンロードボタンを表示する）
2. `pres.addSlide()` でスライドを追加し、`addText`, `addShape` 等で要素を配置
3. `import` 文は書かない（サーバーが提供する変数のみ使用）
4. `new PptxGenJS()` は書かない（`pres` が既に提供されている）
5. `pres.writeFile()` は書かない（サーバーが自動で出力する）
6. PptxGenJS のカラー値は `#` なしの 6桁 HEX で指定する

## デザインガイドライン

## Design-led generation rules

- `set_scenario` で承認された **story と designBrief を最優先の入力**として扱う
- 各スライドの `layout` / `icon` は **固定命令ではなく creative hint** とみなす
- 全体のリズム、余白、視線誘導、情報階層が改善されるなら、レイアウトを積極的に再解釈してよい
- 連続するスライドで同じ構図が続く場合は、意図的にメリハリをつける
- ユーザーが承認したストーリーの主張は維持しつつ、見せ方はより大胆に設計してよい
- `designBrief.layoutApproach` が `design-led` の場合、ストーリーを壊さない範囲で最も表現力の高い構図を選ぶ
- `designBrief.layoutApproach` が `structured` の場合、scenario の layout を比較的強く尊重する

### アイコンの使用（重要）

`public/icons/` に 64x64 PNG アイコンが用意されている。**積極的に使用すること。**

```javascript
// アイコンの使い方
slide.addImage({
  path: 'public/icons/brain.png',
  x: 0.5, y: 1.0, w: 0.5, h: 0.5,
});
```

利用可能アイコン: `arrow-trending-up`, `brain`, `building`, `calendar`, `chart`, `checkmark-circle`, `cloud`, `code`, `data-trending`, `document`, `globe`, `lightbulb`, `link`, `lock-closed`, `money`, `people-team`, `rocket`, `search`, `settings`, `shield`, `sparkle`, `star`, `target`, `warning`

**アイコン使用ルール:**
- カードの左上にアイコンを配置してビジュアルアクセントにする
- タイトルスライドやセクション区切りでアイコンを大きめに使う
- 箇条書きの先頭にアイコンを使ってリッチな印象にする
- 単調な箇条書きスライドを避け、アイコン付きカードレイアウトを優先する

### McKinsey式レイアウト原則

1. **スライドタイトル = 主張**: シナリオの `keyMessage` をスライドタイトルとして使う
2. **レイアウト多様性**: 3枚連続で同じレイアウトを使わない
3. **データ重視**: 数値がある場合は統計ハイライトで大きく見せる
4. **比較は並列**: Before/After や選択肢はカードで横並び
5. **1スライド1テーマ**: 1つのテーマに対して複数のサブポイント・データ・図解を盛り込んでよい。余白が多すぎるスカスカなスライドは避け、情報が充実した構成にする

### シナリオとの連動

`set_scenario` ツールで事前にシナリオが設定されている場合:
- シナリオの `title`, `keyMessage`, `layout`, `icon` を参照してスライドを生成する
- `keyMessage` をスライドのメインタイトル（大きな文字）として使用する
- `layout` はそのまま適用してもよいが、designBrief や全体の流れに合わせて再解釈してよい
- `icon` で指定されたアイコンは優先候補としつつ、不要なら無理に使わなくてもよい

### bullets の解釈ルール（重要）

**`bullets` はデータソースであり、表示形式ではない。** シナリオの `bullets` 配列をそのまま箇条書きとして表示するのは `layout: bullets` のときだけ。それ以外の layout では、bullets の内容を解析し、最適なビジュアル表現に変換すること。

| layout | bullets の解釈 | 変換先ビジュアル |
|--------|---------------|----------------|
| `title` | サブタイトル・キャッチコピー | 大きな中央テキスト |
| `agenda` | アジェンダ項目 | 番号付きリスト or ステップカード |
| `section` | セクションの説明文 | 大きなテキスト + アクセント |
| `bullets` | **そのまま箇条書き** | 箇条書きリスト（唯一の例外） |
| `cards` | 各カードの内容 | 2-6枚の独立カードに分割 |
| `stats` | 数値データ（例: "市場規模: $15.7B"）| 大きな数値 + ラベルのハイライトカード |
| `comparison` | 比較項目（例: "Before: X → After: Y"）| 2-3列の比較表 or 対比カード |
| `timeline` | 時系列ステップ | 矢印で接続された横並びフロー |
| `diagram` | 構成要素・関係性 | 図解・マトリクス・ピラミッド |
| `summary` | 重要ポイント | 3つの強調カード or アイコン付きまとめ |

**禁止事項:** `layout: stats` なのに数値を箇条書きで表示する、`layout: cards` なのに全項目を1つのテキストボックスに入れる等は NG。bullets の文字列からデータを抽出し、layout に応じた最もインパクトのあるビジュアルに変換すること。

### フォントサイズ

| 用途               | サイズ  | 太さ    |
| ------------------ | ------- | ------- |
| スライドタイトル   | 24-32pt | Bold    |
| セクションタイトル | 32-44pt | Bold    |
| 本文               | 13-18pt | Regular |
| 箇条書き           | 12-16pt | Regular |
| カード内テキスト   | 11-14pt | Regular |
| カードタイトル     | 13-16pt | Bold    |
| 統計数値           | 28-48pt | Bold    |
| キャプション       | 9-11pt  | Regular |
| ヘッダー帯         | 8-10pt  | Regular |
| フッター           | 7-8pt   | Regular |

**密度の考え方**: `designBrief.density` が `dense` の場合はサイズ範囲の下限寄り、`airy` の場合は上限寄りを選ぶ。デフォルト（`balanced`）でも情報量を優先し、スカスカにならないよう注意する。

### Slide Master パターン

3種の Slide Master が用意されている。**これらは出発点であり、designBrief に応じてカスタマイズしてよい。** 例えばヘッダー帯の色を変えたり、背景にグラデーションを使ったりすることも可能。

#### CONTENT（コンテンツスライド）

```javascript
pres.defineSlideMaster({
  title: 'CONTENT',
  background: { color: C.WHITE },
  objects: [
    { rect: { x: 0, y: 0, w: '100%', h: HEADER_H, fill: { color: C.BLUE } } },
    { rect: { x: 0, y: 0, w: 0.06, h: HEADER_H, fill: { color: C.BLUE_DARK } } },
    { text: {
        text: 'プレゼンタイトル',
        options: { x: 0.3, y: 0.08, w: 11, h: 0.3, fontSize: 9, fontFace: F.EN, color: C.WHITE }
    }},
    { rect: { x: ML, y: SH - 0.35, w: CW, h: 0.005, fill: { color: C.BORDER } } },
  ],
  slideNumber: { x: SW - 1.2, y: SH - 0.33, w: 0.8, h: 0.28, fontSize: 7.5, fontFace: F.EN, color: C.MID_GRAY, align: 'right' },
});
```

#### TITLE（タイトルスライド）

```javascript
pres.defineSlideMaster({
  title: 'TITLE',
  background: { color: C.BLUE },
  objects: [],
});
```

#### SECTION（セクション区切り）

```javascript
pres.defineSlideMaster({
  title: 'SECTION',
  background: { color: C.DARK },
  objects: [
    { rect: { x: 0, y: 0, w: 0.1, h: '100%', fill: { color: C.BLUE } } },
    { rect: { x: 1.0, y: SH - 0.7, w: 5, h: 0.04, fill: { color: C.BLUE } } },
  ],
});
```

### レイアウト設計の自由度

以下のヘルパー関数は **参考パターン** として提供する。そのまま使ってもよいが、**ゼロからオリジナルのレイアウトを設計することを強く推奨する。**

考えられる構図バリエーション:
- **2カラム・3カラム分割**: 左に図解、右にテキスト等
- **グリッドレイアウト**: 2×3 や 3×3 のカード/アイコングリッド
- **フルブリード背景**: 濃い色の背景に白文字のインパクトスライド
- **左サイドバー + メインコンテンツ**: サイドにナビゲーション的な要素
- **ステップフロー**: 矢印で接続された横並びステップ
- **ピラミッド / マトリクス**: 階層構造や2軸の分類図
- **大きな数値 + 補足テキスト**: 統計をヒーロー要素にしたレイアウト
- **アイコン + テキストの交互配置**: リッチな箇条書きの代替

PptxGenJS の `addText`, `addShape`, `addImage` を自由に組み合わせて、表現力の高いスライドを作成すること。

### 参考: ヘルパー関数パターン

以下は **使用は任意** の参考実装。

#### スライドタイトル + アンダーバー

```javascript
function addSlideTitle(slide, title, opts = {}) {
  const { y = 0.6, fontSize = 26, color = C.DARK } = opts;
  slide.addText(title, {
    x: ML, y, w: CW, h: 0.6,
    fontSize, fontFace: F.JA, color, bold: true, valign: 'bottom',
  });
  slide.addShape(pres.ShapeType.rect, {
    x: ML, y: y + 0.62, w: 1.4, h: 0.04, fill: { color: C.BLUE },
  });
}
```

#### カード描画

```javascript
function drawCard(slide, x, y, w, h, opts = {}) {
  const { bg = C.LIGHT_GRAY, accentTop = null, title, body, bodyBullet = false } = opts;
  slide.addShape(pres.ShapeType.roundRect, {
    x, y, w, h, fill: { color: bg }, rectRadius: 0.08,
    shadow: { type: 'outer', blur: 4, offset: 2, color: '000000', opacity: 0.1 },
  });
  if (accentTop) {
    slide.addShape(pres.ShapeType.rect, {
      x: x + 0.12, y: y + 0.1, w: w - 0.24, h: 0.045, fill: { color: accentTop },
    });
  }
  let textY = y + (accentTop ? 0.22 : 0.15);
  if (title) {
    slide.addText(title, {
      x: x + 0.2, y: textY, w: w - 0.4, h: 0.4,
      fontSize: 15, fontFace: F.JA, color: C.DARK, bold: true, valign: 'middle',
    });
    textY += 0.42;
  }
  if (body) {
    const items = Array.isArray(body) ? body : [body];
    const textArr = items.map(t => ({
      text: t,
      options: {
        fontSize: 13, fontFace: F.JA, color: C.TEXT, breakLine: true,
        bullet: bodyBullet ? { type: 'bullet', color: C.MID_GRAY } : false,
        lineSpacingMultiple: 1.2,
      },
    }));
    slide.addText(textArr, {
      x: x + 0.2, y: textY, w: w - 0.4, h: h - (textY - y) - 0.15, valign: 'top',
    });
  }
}
```

#### 統計ハイライト

```javascript
function drawStat(slide, x, y, w, h, { value, label, color = C.BLUE }) {
  slide.addShape(pres.ShapeType.roundRect, {
    x, y, w, h, fill: { color: C.WHITE }, line: { color, width: 2 }, rectRadius: 0.08,
  });
  slide.addText(value, {
    x, y: y + 0.08, w, h: h * 0.55,
    fontSize: 28, fontFace: F.EN, color, bold: true, align: 'center', valign: 'middle',
  });
  slide.addText(label, {
    x: x + 0.1, y: y + h * 0.55, w: w - 0.2, h: h * 0.4,
    fontSize: 10, fontFace: F.JA, color: C.MID_GRAY, align: 'center', valign: 'top',
  });
}
```

#### 箇条書き

```javascript
function addBullets(slide, x, y, w, h, bullets, opts = {}) {
  const { fontSize = 15, color = C.TEXT, bulletColor = C.BLUE } = opts;
  const items = bullets.map(t => ({
    text: t,
    options: {
      fontSize, fontFace: F.JA, color,
      bullet: { type: 'bullet', color: bulletColor },
      breakLine: true, lineSpacingMultiple: 1.2,
    },
  }));
  slide.addText(items, { x, y, w, h, valign: 'top', paraSpaceAfter: 6 });
}
```

## コンテンツルール

- **絵文字を使用しない**: `💡` `🔄` `✅` 等は Noto Sans JP で表示崩れの原因になる
- **矢印は可**: テキストの `→` `↑` は使用可
- **チェックマーク**: 絵文字ではなく `✔`（U+2714）を使用
- **行間**: 日本語テキストは `lineSpacingMultiple: 1.2` を標準とする（情報量が多い場合は `1.1` も可）
- **最小フォント**: 7pt 未満は使用しない
- ユーザーの言語に合わせてスライドを作成する
- 専門用語は原語を併記（例:「検索拡張生成（RAG）」）

## 品質チェックリスト

- [ ] `import` 文を書いていない
- [ ] `new PptxGenJS()` を書いていない
- [ ] `writeFile` を書いていない
- [ ] カラーは `#` なしの 6桁 HEX
- [ ] 絵文字を使用していない
- [ ] フォントは `F.JA` または `F.EN` を使用
- [ ] タイトルスライドとまとめスライドが含まれている
- [ ] 各スライドにノートが設定されている（`slide.addNotes()`）

## ワークフロー

1. ユーザーのリクエストが曖昧な場合、トピック・対象者・目的を確認する
2. Web検索ツールが利用可能な場合、最新情報を収集する
3. Slide Master を定義する（CONTENT, TITLE, SECTION をベースに、designBrief に応じてカスタマイズ）
4. 必要に応じてヘルパー関数を定義する（参考パターンを使うか、オリジナルで書くかは自由）
5. スライドを順番に追加する（各スライドに十分な情報量を持たせ、スカスカにしない）
6. 各スライドに `slide.addNotes()` でスピーカーノートを追加する
7. コードの前に構成の簡単な説明を添える
