この記事は、Claude Codeと一緒に作成しました。
はじめに
X(旧Twitter)に、素敵な技術記事を投稿して頂いている皆様に感謝します。
ただ、Xという場所の特性上、TLで見かけて、BookMarkしていても、検索が困難だったり、後から見ようとしても難しかったりして、情報が「ただの投稿記事」に終わってしまうのが惜しいと思ったので、「これをPDFかPPTXでストックして、NoteBookLMとかに食わせたら良くない?」と思いつき、こんなコマンドを作成していました。(現在も育成中なので)
余談ですが、似たような発想の記事として AIエージェントの作業結果、マークダウンで読むの辛くない? →「HTML共有くん」を作りました を見かけた時には、憧れもありました。AIエージェントの成果物をその場限りで流さず、後から扱いやすい形でストックしておきたい、という問題意識は近いものがあるのかもしれません。
なお、このコマンドは、著作権問題回避と個人使用が目的なため、公開はしていません。そのあたりが解決するならば、公開も考えますが……。あくまで自分がブックマークした記事を自分用にストックし直すためのツールであり、投稿者の方々への敬意を忘れず、著作権を侵害する意図がないことは事前にお伝えしておきたいと思います。
X(Twitter)のスレッドや一般的なWebページ、SpeakerDeckのようなスライド共有サービスの内容を、日次でまとめてPowerPoint(PPTX)化したいというニーズがあり、Claude(Claude Code / MCP環境)上に x_to_pptx という独自コマンド(MCPツール群を組み合わせたパイプライン)を構築しました。
本記事では、x_to_pptx というコマンドが実際に何をしているか、その処理内容と設計上のこだわりを整理します。
全体像
x_to_pptx は単一のツールではなく、複数のMCPツールをClaudeが順番に呼び出して連携させるパイプラインです。大まかな流れは以下の通りです。
-
x_to_pptx(Playwrightベースの取得ツール) — 対象URLから本文テキストとメディア画像を自動取得 - Claude自身による構成・要約 — 取得した本文を読み、スライド構成(見出し・段落・図解ブロック)に組み立てる
-
marp-md-generator— Claudeが組んだ構成をMarp記法のMarkdownとして書き出す -
marp_generate(Marp CLIラッパー) — Marp形式MarkdownをPPTX / PDF / HTMLに変換 -
qa-render— 生成物を全スライドPNG化して目視QA、体裁が崩れていれば3〜4を再実行 - (必要に応じて)HTML standalone化スクリプト — 配布用に画像をbase64埋め込みした単一HTMLを生成
つまり「スクレイピング」「スライド構成」「レンダリング」「QA」の4工程を1コマンドの呼び出し感覚で一気通貫にやる、という設計です。
使い方の例
実態はCLIコマンドというより、Claudeとのチャット内で自然文の指示として呼び出す形です。実際に使う際の指示文の例をいくつか挙げます。
基本形(1件をPPTX化)
このスレッドをPPTX化して
https://x.com/xxxxx/status/1234567890
出力先を指定する場合
https://x.com/xxxxx/status/1234567890 を
C:\Users\ysaka\Downloads\pptx_out\20260902\ai-agent-note\ に保存してPPTX化して
PDF・PPTXに加えてHTML版も欲しい場合
このURLをPPTX化して。HTML版も欲しい
https://x.com/xxxxx/status/1234567890
単体ファイルとして配布したい場合(standalone化まで)
このURLを配布用HTMLで
https://x.com/xxxxx/status/1234567890
Xのスレッド以外(一般的な技術ブログなど)を渡す場合
このブログ記事もPPTX化して
https://example.com/blog/2026/08/some-article
複数URLをまとめて日次バッチ的に処理する場合
以下をまとめてPPTX化して(1URL=1デッキで)
https://x.com/xxxxx/status/111
https://x.com/yyyyy/status/222
https://speakerdeck.com/zzzzz/some-deck
いずれの場合も、裏側では前述の「取得→構成設計→Marp変換→レンダリング→QA」のパイプラインが自動的に一気通貫で走り、途中で止まらずPPTX/PDF(必要ならHTML)の生成まで完了します。
1. コンテンツ取得: x_to_pptx ツール
入力は x_url(対象URL)と、任意で outdir(出力先ディレクトリ。未指定ならtemp)の2つだけです。
内部ではPlaywright(Chromium)を使い、以下を行います。
- Xのスレッド全体(主投稿+連投+リプライ)の本文テキストを取得
- 各ポストに含まれる
pbs.twimg.com/mediaの画像を、?name=largeを付与した高解像度URLでローカルに保存 - 本文テキストと保存した画像パスのリストを返す
なお、Xの「Article」形式(長文記事)は通常の tweetText が空になるケースがあるため、その場合は article.innerText を取得するようフォールバックする実装になっています。
重要なのは、Xのスレッド以外の一般的なWebページやSpeakerDeckのURLも同じ x_url パラメータにそのまま渡せば取得できるという点です。運用上「XのURLじゃないから対象外」と判断してはいけない、という点を明確なルールとして定めています。
2. スライド構成: Claude自身が行う要約・構成設計
取得した本文を読み、どこで区切ってスライド化するかの構成・要約はClaude自身が行います。ここはツールに任せず、あえて人(Claude)の判断を挟んでいるのがポイントです。
このとき厳守しているルールがいくつかあります。
- 表紙に作成日を入れる
- 最終スライドに引用元URL(
x_urlそのもの)を入れる - 「使う」「活用する」「試す」といった実践的な内容を含むスライドには、HOWTO(入力例・手順)を必ず明記する
これらは下書きのテキストを作る時点で盛り込むようにしており、後工程での漏れを防いでいます。
3. Marp記法への変換: marp-md-generator
そもそもMarpとは
Marp は、Markdownで書いた文章をそのままスライド(プレゼン資料)に変換できるオープンソースのフレームワークです。PowerPointのようにマウスで図形を配置していくのではなく、テキストエディタでMarkdownを書くだけでスライドが組み上がっていくのが特徴で、Marp CLIを使えばコマンドラインからPDF・PPTX・HTMLなどに書き出せます。
基本的な考え方はシンプルで、
- 先頭にYAMLフロントマター(
marp: trueやテーマ指定など)を書く - 本文はMarkdown記法(見出し・箇条書き・画像・コードブロックなど)でそのまま書ける
-
---(水平線)で区切った単位が1枚のスライドになる
というルールに従うだけで、Markdown一枚がそのままスライドデッキになります。コードや文章そのものを書く感覚でスライドが作れるため、Gitでの差分管理やテキストベースでの自動生成と非常に相性が良く、今回のように「AIがスクレイピングしてきた本文をスライド化する」用途に向いています。
独自記法ルール
x_to_pptx パイプラインでは、この素のMarp記法をさらに機械的に扱いやすくするため、marp-md-generator という専用ツールで以下のような独自の省略記法・拡張記法を定義しています。構成が固まったら、Claudeがこの記法に沿ってMarkdownを書き出します。
| 記法 | 意味 |
|---|---|
=== |
新しいスライドの開始 |
: |
h2見出し |
[左][右] |
2カラムレイアウト(枠付き) |
@flow / @matrix など |
図形ブロック(フローチャートやマトリクス表現) |
この機械的な変換ルールに沿ってMarkdownを生成することで、Claudeが都度自由記述するよりもレイアウトが安定します。
4. レンダリング: marp_generate
生成したMarp Markdownを、実際にPPTX/PDF/HTMLへ変換するのがこのツールです。主なパラメータは以下の通りです。
-
markdown/markdown_path:変換対象のMarp Markdown(文字列 or 既存ファイルパス) -
format:pptx/pdf/html/pptx-editable -
theme:内蔵テーマ名、同梱CSS名、またはCSS絶対パス
ここでのこだわりはテーマ指定の方法です。独自に用意した light-cream という配色テーマを使う際、テーマ名ではなくCSSの絶対パス(C:\...\marp-mcp\themes\light-cream.css)で指定する運用にしています。テーマ名指定だと反映されないケースがあったためです。
また、format=pptx-editable(テキスト編集可能なPPTX)はLibreOffice環境が必要なため、その環境がない場合は失敗します。その場合は後述の通り別経路でPPTXを作ります。
5. QAループ: qa-render
見た目の崩れ(文字はみ出し・画像重なりなど)を防ぐため、本番のPPTX/HTMLを1回で確定生成せず、まずPDFを生成して qa-render で全スライドをPNG画像化し、AIが目視確認するフローを挟んでいます。
問題があれば構成・Markdownを修正し、PDF再生成→再QAを繰り返し、体裁が確定してから初めてPPTX/HTMLを本生成する、という2段階方式です。これにより無駄なPPTX再生成を避けつつ、品質を担保しています。
6. 編集可能PPTXが必要な場合
前述の通り marp:marp_generate の pptx-editable はLibreOffice依存で失敗することがあるため、テキスト編集可能なPPTXが欲しい場合は、コンテナ内で python-pptx を使って直接PPTXを生成する経路を別途用意しています。配色は light-cream をハードコードし、生成後は present_files でユーザーにダウンロード提供します。
7. 配布用スタンドアロンHTML
「HTML版も欲しい」と言われた場合はPPTX・PDFに加えてHTMLも生成しますが、「配布用のHTMLで」と言われた場合はさらに一歩進めて、Embed-MarpHtmlImages.ps1 というPowerShellスクリプトで画像をbase64埋め込みしたstandalone HTMLに変換します。単体のHTMLファイルとして送付・共有できる状態にするための仕上げ工程です。
8. 出力デザイン: light-cream テーマの中身を公開
最後に、実際に使っている配色テーマ light-cream.css の中身をそのまま公開します。見やすく(目に優しいw)、そんなに派手ではない、シンプルなデザインは、私個人の趣味ですがw 参考になれば幸いです。
ベースは背景が明るいクリーム色(#FAF6EC)で、本文は黒に近い濃いグレー(#1A1A1A)。見出しはteal系(#00A896)とblue系(#1F5FA8)、強調文字だけorange(#E07B39)を差し色として使う、というシンプルな4色構成にしています。派手な装飾やグラデーションは入れず、長時間見ても疲れにくいことを優先しました。
/* @theme light-cream */
@import 'default';
:root {
--bg: #FAF6EC; /* 明るいクリーム色(目に優しい) */
--card: #E6E6E6; /* コードブロック灰色背景 */
--orange: #E07B39; /* 強調(変更なし) */
--teal: #00A896; /* h1 に使用(旧h2の色) */
--blue: #1F5FA8; /* h2 青色系統 */
--text: #1A1A1A; /* 本文 黒 */
--pagenum: #555555; /* ページ番号 暗い灰色 */
font-family: 'Noto Sans CJK JP', 'Noto Sans JP', sans-serif;
}
section {
background: var(--bg);
color: var(--text);
padding: 60px 60px 110px 60px; /* 下部は本文1行分の余白を確保 */
font-size: 28px;
box-sizing: border-box;
overflow: hidden;
}
/* 画像も下端に余白が残るよう上限高さを抑える+中央寄せ */
section img {
max-height: 60%;
display: block;
margin-left: auto;
margin-right: auto;
}
h1 {
color: var(--teal);
border-bottom: 4px solid var(--blue);
padding-bottom: 0.2em;
}
h2 {
color: var(--blue);
}
ul {
list-style: none;
padding-left: 0;
}
ul li {
margin: 0.4em 0;
padding-left: 1.4em;
position: relative;
}
ul li::before {
content: "";
position: absolute;
left: 0;
top: 0.45em;
border-style: solid;
border-width: 0.35em 0 0.35em 0.55em;
border-color: transparent transparent transparent var(--blue);
}
strong {
color: var(--orange);
}
code {
background: var(--card);
color: #1A1A1A;
padding: 2px 8px;
border-radius: 4px;
}
pre {
background: var(--card);
border-left: 4px solid var(--orange);
}
pre code {
background: transparent;
color: #1A1A1A;
}
section.title {
display: flex;
flex-flow: column nowrap;
justify-content: flex-start;
text-align: center;
}
section.center {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
text-align: center;
}
section.center h1 {
font-size: 64px;
border-bottom: none;
}
section::after {
color: var(--pagenum);
}
細かい工夫としては、箇条書きの ::before で三角形のマーカーを自前描画している点、画像は max-height: 60% で上限を抑えて中央寄せにし下部の余白を必ず確保している点、タイトルスライド用に section.title / section.center というクラスを分けて配置調整している点などがあります。@import 'default' でMarp標準テーマをベースにしつつ、配色・レイアウトだけ上書きする形にしているので、Marp標準の挙動を壊さずに済んでいます。
運用上のこだわり・ルール
パイプライン自体の技術要素以外に、日次バッチ運用を安定させるために以下のようなルールを明文化しています。
- 著作者様を明記する:誰の投稿・記事を元にしたスライドかが必ずわかるようにする
-
出典元のURLを記載する:
x_urlそのものを最終スライドに残し、原文に辿れる状態を保つ - 作成日を記載する:表紙にスライドの作成日を必ず入れる
- 1記事1デッキ、例外なし:まとめて処理する場合も、URLごとに1つのスライドとして独立させる
- マネタイズ導線は除外:広告・アフィリエイト的な内容はスライド化しない
- 未確認情報はweb_searchで裏取り:本文中の事実関係が怪しい場合は検証してから採用する
- 出力ファイル名は拡張子以外すべて統一:PDF・PPTX・HTMLでファイル名がバラバラだと管理が破綻するため
- 出力先は
YYYYMMDD/<スラッグ>/の日付+記事単位のサブフォルダ構成
このうち「著作者様を明記する」「出典元のURLを記載する」「作成日を記載する」の3つは、他のルールとは別格の絶対ルールとして扱っています。効率化や自動化のためにどれだけ工程を省略しても、この3点だけは絶対に省略しない、という位置づけです。元の投稿者・記事への敬意を欠かさず、かつ後から見返した時に「誰が」「どこで」「いつ」書いたものかを必ず追えるようにするためです。
これらのルールは、コマンドの説明とは別に運用ドキュメント(CLAUDE.md本体から分離した専用ファイル)として保持し、作業前に必ず読み込む形にしています。
ハマったポイント
開発・運用中に何度か踏んだ問題として、read_media_file(画像読み込み)がセッション内で不安定になり、画像が [image] というプレースホルダーに置き換わってしまう現象がありました。対策としては、
- 出力画像のdpiを調整する
- 出力ディレクトリを変える
- 新しいスレッド(セッション)でやり直す
といった回避策で対応しています。根本原因の特定には至っていませんが、運用上はこれで問題を回避できています。
まとめ
x_to_pptx は「Playwrightでの本文・画像取得」「Claudeによる構成・要約」「Marp記法への変換」「PPTX/PDF/HTML生成」「PNG化による目視QA」という5つの工程を、1つのコマンド呼び出し感覚で実行できるようにしたパイプラインです。
ポイントは、コンテンツの解釈・構成設計という「判断が必要な部分」はあえてツール化せずClaude自身に任せ、レイアウトの安定性が必要な部分(Marp記法・テーマ指定・ファイル命名など)は厳格なルールとして固定化している点だと思います。今後はQA工程の自動判定強化や、read_media_file 不具合の根本対応などが課題です。