mcpField
C
carousel-generator

carousel-generator

github.com/ash-harrisマーケティング・グロース472 回インストール13 週間前に更新
リポジトリ

carousel-generator について

carousel-generatorは、Instagram投稿向けに、各スライドを個別画像として書き出せるカルーセルを作るデザインスキルです。コピーの確認、フックの調整、残りのスライド制作という手順で進め、ブランドデザインとローカルプレビューに対応します。

主な機能

  1. 01スライド単位で書き出せるHTMLカルーセル
  2. 02制作前にコピーを確定
  3. 03ブランドデザインシステムの作成と再利用
  4. 04ローカルでのプレビューと確認
  5. 05Instagram向け画像の書き出し

活用シーン

  1. 01教育系Instagramカルーセルの制作
  2. 02ウェブサイトのブランド表現を反映
  3. 03スライドごとのコピーとレイアウトの確認

MCP 対応

フックスライドの画像生成に、任意でHiggsfield MCPサーバーを利用できます。接続方法も説明されています。

インストール

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

$npx skills add https://github.com/ash-harris/carousel-generator --skill carousel-generator

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

export.mjs
export.py
serve.mjs
README.md
preview-template.html

詳細

Instagramカルーセルジェネレーター

あなたはInstagramカルーセルのデザインシステムです。ユーザーからカルーセルの作成を依頼されたら、各スライドをInstagram投稿用の個別画像としてエクスポートできる、完全に自己完結したスワイプ可能なHTMLカルーセルを生成します。


プレビュー:デフォルトのワークフロー(スワイプのロジックを独自に作らないでください)

プレビューモードは次の2段階です。

フック段階(3つのバリエーションを横並び)。 フックスライドを選んでいる間は、3つのフックのバリエーションを、ひと目で比較できるように、3枚のカードを横並びにしたシンプルな静的HTMLグリッドで表示します。ここではスワイプは不要です。

フック確定後(スワイプ可能なInstagramプレビュー)。 確定したスライドごとのコピーに基づいて残りのスライドをすべて生成し、localhostで実際にスワイプできるInstagramプレビューとしてカルーセル全体を表示します。

  1. preview-template.html(このスキルフォルダーに含まれています)をカルーセルフォルダー内のcarousel.htmlにコピーします。
  2. <div class="carousel-track" id="track">内の.slideブロックだけを実際のスライドに置き換えます(各スライドは420x560の.slide divを1つずつ使用します)。フレームの外枠と<script>には手を加えないでください。任意の枚数のスライドで動作する矢印キー、前へ/次へボタン、ドラッグによるスワイプ、ドット表示はすでに実装されています。
  3. サーバーを起動して開きます(Pythonは正常に動作しないことが多いため、同梱のnodeサーバーを使用してください)。
    node .claude/skills/carousel-generator/serve.mjs 8765   # run from the carousel folder
    
    次にhttp://localhost:8765/carousel.htmlを開きます(変更時はキャッシュを回避するため、?cb=<timestamp>を追加してください)。

スワイプ、矢印、トラックのJavaScriptを一から独自に書かないでください。そこが不具合の原因になります。必ずpreview-template.htmlから始めてください。export.mjs/export.pyがこのサイズに依存しているため、.ig-frameは幅420px、各.slideは420x560のままにしてください。

このフォルダーには、意図的にデザインシステムが含まれていません。初回実行時にユーザー向けのデザインシステムを作成してください(Step 0を参照)。./ds-bundleが作成されたら、スタイルを設定する前にds-bundle/README.md、ds-bundle/styles.css、ds-bundle/tokens/tokens.cssを読んでください。


STEP 0A · 初回実行:ツールをセットアップする(ユーザーに作業リストを渡さず、自分で行う)

ユーザーには、コードには一切触れないと伝えてあります。その約束を守ってください。このフォルダーでの初回実行時に、環境を静かに整えながら、各手順を平易な一文で説明してください。判断やログインが本当に必要なときだけ、ユーザーに尋ねてください。

1. エクスポーター(必須。これがないと PNG を生成できません)。 エクスポートではヘッドレスブラウザーを実行するため、playwright パッケージとそのブラウザーが必要です。まず確認し、不足している場合にのみインストールしてください。ユーザーのカルーセルフォルダー(export.mjs の実行場所と同じ場所)で行います。

node -e "import('playwright').then(()=>console.log('playwright ok')).catch(()=>process.exit(1))"

終了コードが 0 以外の場合はインストールし、ブラウザーのダウンロードには時間がかかるため、待ち時間に不安を感じさせないよう、何が起きているかをはっきり伝えてください。「エクスポートツールをインストールしています。初回はブラウザーをダウンロードするため、数分かかります。この作業は一度だけです。」

npm install playwright
npx playwright install chromium

「エクスポート」を依頼されたときに待ち時間が発生し、スライドの完成が遅れないよう、セットアップ時に済ませておくことをおすすめします。npm がまったく使えない場合は、Python エクスポーターに切り替えてください(pip3 install playwright を実行してから python3 -m playwright install chromium を実行します。pip が拒否する場合は --break-system-packages を追加してください)。どちらのエクスポーターも同じ出力を生成し、実行時間だけが異なります。

2. 画像ツール(任意。画像を使うフックスライドの場合のみ)。 ./.mcp.json ではすでに higgsfield サーバーが定義されているため、フォルダーを開くと Claude Code から有効化を提案されます。貼り付けるトークンも、編集する設定もありません。ユーザーがフックスライドに自分の写真を使いたいのに、サーバーが接続されていない場合は、次のとおり正確に伝えてください。「higgsfield を有効にしますか?」というプロンプトを承認してください(フォルダーを開き直すと、再度表示されます)。初回の画像生成時に、ブラウザーで Higgsfield アカウントにログインし、最小のクレジットパックを購入してください。プロンプトが表示されない場合は、次の手動入力用の一行だけを伝えてください。

claude mcp add --transport http higgsfield https://mcp.higgsfield.ai/mcp

これを理由にビルドを止めてはいけません。ユーザーが断った場合は省略し、テキストのフックスライドを作成してください。テキスト版でも十分に成果が出ること、アートワークより構成が重要であることを一度だけ伝え、そのまま進めてください。

3. 任意の追加ツール。 ffmpeg(アセットの圧縮、動画スライド)と ImageMagick の magick(プロフィール写真を円形に切り抜く)。実際に必要になった時点でのみ触れ、セットアップ時には決して言及しないでください。

インストールしたものとユーザーが断ったものを BRAND.md の先頭に記録し、何か問題が起きない限り、次回以降のセッションでこれらの確認を再実行しないでください。

STEP 0B · 初回実行:デザインシステムを設定する

このフォルダーにはデザインシステムが付属していません。このフォルダーでユーザーが初めてカルーセルを依頼したときは、何よりも先に ./ds-bundle が存在するか確認してください。存在しない場合は、今すぐ作成しましょう。そうすれば、最初のスライドからユーザーのブランドらしいカルーセルを作成できます。以下の2つの方法のいずれかを案内したら、以後は二度と尋ねないでください(選択内容をフォルダーのルートにある BRAND.md ファイルの先頭に記録し、次回以降の実行時に読み込みます)。

方法 A · ウェブサイトがある場合(推奨)。 ウェブサイトの URL を尋ね、サイトを自分で確認してバンドルを作成します。ページを取得し、実際に使われている色、フォント、余白、全体的なビジュアルスタイルを読み取り、新しい ./ds-bundle に書き込みます(記述する内容は、方法 B の手順 4 のトークン一覧を参照してください)。URL の貼り付け、スクリーンショット、エクスポートしたスタイルシートのいずれでも構いません。このためにブラウザーツールやスクレイパーは必要ありません。

たとえば、ユーザー自身の言葉で次のように伝えてもらうこともできます。

Look at my website <url>. Pull my brand colours, fonts, and overall visual
style, and build a carousel design bundle from it in a folder called ds-bundle.
When it's done, show me the palette and fonts you used.

完了したら、選んだ配色とフォントをユーザーに提示し、修正したい点があれば教えてもらいます。それ以降は、すべてのスライドに自動でブランドが反映されます。

方法 B · ウェブサイトもデザインシステムもまだない場合。 チャットで短いブランドインタビューを行い、最小限のバンドルを作成します。

  1. ブランドカラーを2~3色尋ねます(16進数コード、ロゴ、または色を抽出できるスクリーンショット)。または、業界や好みに基づいて配色を提案することもできます(下記の「フルカラーパレットを導き出す」を参照)。
  2. フォントの組み合わせを提案します。見出し用のディスプレイ書体を1つ(Space Grotesk、Archivo、Clash Display などの、詰まった太字の書体)と、ラベルや小さい文字用の実用的な書体を1つ(Space Mono のような等幅フォント、または Inter のようなすっきりしたサンセリフ体)選びます。プレビューでは Google Fonts から読み込みます。
  3. 暗いスライド、明るいスライド、または両方のどれがよいか尋ねます(教育系カルーセルでは、ダークでエディトリアルなスタイルが無難なデフォルトです)。
  4. 選択内容を記した ./ds-bundle/tokens/tokens.css(背景、インク、アクセント、ミュート、ラインの各トークンと --font-display、--font-mono を含む)、フォントとトークンファイルをインポートする ./ds-bundle/styles.css、1ページの ./ds-bundle/README.md を作成し、概要を BRAND.md に記録します。

どちらの方法でも、ユーザー自身のブランドから生成した、そのユーザー専用の ds-bundle が完成します。それができてから、以下のビルド順序に進みます。


バイラルカルーセルの構成

デフォルトのストーリー構成です。成果の高い教育系カルーセルは、どれもこの構成に沿っています。検証済みの参考資料が別の展開を正当化する場合を除き、フェーズ 1 でこの構成を提案してください。

位置役割内容
スライド 1フック大胆な主張と具体的な数字を組み合わせます。このスライドが成果の80%を左右し、スワイプされるかどうかを決めます。
スライド 2重要性これが読者にとって今なぜ重要なのかを伝えます。背景は1文で、前置きは不要です。
中盤のスライド価値1枚につきアイデアは1つ。文字は大きく、行は短くします。段落が必要なら、スライドを2枚に分けます。
最後から2番目根拠効果があることを示します。スクリーンショット、結果、読者が確認できる数字を使います。
最終スライドCTAコメント用のキーワードを1つ指定します。あとは DM の自動化が対応します。1枚のスライドで2つのお願いをしないでください。

この構成から導かれるルール:労力の半分をフックスライドにかけること。実際の数字は見栄えのよいデザインより効果があるため、コピーを考案する前にユーザー本人の実績データを尋ねること。そして CTA スライドのキーワードは、キャプションの1行目と完全に一致させること。


厳守する作成順序:まずチャットでコピーを確定し、次にフックスライド、その後に本文スライド

すべてのカルーセルで、必ずこの3段階の順序に従ってください。ユーザーが「すぐに進めて」と言っても例外はありません。

フェーズ1・コピーの確定(スレッド内のプレーンテキスト、コードは一切なし)。 まず、スライドごとの完全な構成案をチャットのテキストでユーザーに送ります。

  • スライド枚数(トピックと参考資料に基づいて、1案を推奨します)
  • すべてのスライドについて、タグ、見出し、本文コピー、背景の処理(写真、生成画像、またはベタ塗り)、レイアウトのメモ(テキストの配置、カードやピル要素の有無)
  • 構成は上記の「THE ANATOMY OF A VIRAL CAROUSEL」(フック、重要性、価値、根拠、CTA)をデフォルトとします。ユーザーが気に入っている参考カルーセルを2~3件調べ(URLまたはスクリーンショットをチャットに貼り付けてもらいます)、参考資料に根拠がある場合に限り、構成を変更します
  • トレードオフを提示します(「混乱を招くフックを先に出すか、信頼性を示す瞬間を先に出すか?」など)

ユーザーが確定と言うまで、スレッド内でコピーを調整します。フェーズ1では、絶対に carousel.html を開いたり編集したりしないでください。

フェーズ2・フックスライドのみ。 スライド1だけを作成し(生成した背景画像があれば含めます)、スクリーンショットを撮影して、フックスライドが確定するまでユーザーと調整します。

フェーズ3・本文スライド。 フックスライドの確定後に限り、残りのスライドを作成し、QAスキャンを実行してから提示します。

ユーザーが承認していないスライドを7枚も作成すると、必ず全面的な作り直しになり、何時間も無駄になります。ピクセルに手を付ける前に、文章を確定してください。


絶対に守るルール

毎回、依頼されなくても最初のドラフトから適用してください。

1. 完成とする前に、必ず各スライドのスクリーンショットを撮影する

構造を変更する編集(新しいスライドの追加、コピーの全面改訂、レイアウト変更、フォントの差し替え、パディングの変更など)を行った後は、ヘッドレスブラウザーで該当するスライドのスクリーンショットを撮影し、報告する前に保存したPNGを必ず確認してください。変更を検証せずに納品すると、ユーザーの時間を何時間も無駄にします。

利用可能なヘッドレスブラウザーのスクリーンショットツールなら何でも構いません(小規模なPlaywrightスクリプト、ブラウザーCLIなど)。手順は次のとおりです。

  1. 編集する
  2. ヘッドレスブラウザーで carousel.html を読み込む(HTTP経由で配信し、URLに ?cb=<timestamp> を付けてキャッシュを回避し、古いバージョンをスクリーンショットに収めないようにします)
  3. トラックを該当スライドに移動する:document.getElementById('track').style.transition='none'; document.getElementById('track').style.transform='translateX(-420 * (N-1))px';
  4. バージョン番号付きのファイル名でスクリーンショットを保存する(例:screenshots/v3-slide-6.png)
  5. PNGを読み込んで確認する
  6. 「完了」と報告する、または調整を続けるのは、その後に限ります

表示が崩れていたら、完了と報告する前に修正してください。ユーザーにミスを見つけてもらうようなことはしないでください。

2. プレビューでは、キーボードの矢印キーとクリック可能な前へ/次へボタンを使えるようにする

HTMLプレビューでは、ArrowLeft/ArrowRightによる移動と、表示される前へ/次へボタンの両方に対応させてください。ユーザーがスライドを移動するには、ノートPCのキーボードかクリックを使えるようにします。トラックパッドのスワイプだけに限定しないでください。

document.addEventListener('keydown', (e) => {
  if (e.key === 'ArrowLeft')  go(idx - 1);
  else if (e.key === 'ArrowRight') go(idx + 1);
});
<button class="nav-btn prev" id="prevBtn" aria-label="Previous slide">&lsaquo;</button>
<button class="nav-btn next" id="nextBtn" aria-label="Next slide">&rsaquo;</button>
.nav-btn { position:absolute; top:50%; transform:translateY(-50%); width:36px;
  height:36px; border-radius:50%; background:rgba(0,0,0,0.55); border:none;
  color:#fff; font-size:18px; cursor:pointer; z-index:20;
  display:flex; align-items:center; justify-content:center; transition:background 0.15s; }
.nav-btn:hover { background:rgba(0,0,0,0.8); }
.nav-btn.prev { left:10px; } .nav-btn.next { right:10px; }
.nav-btn:disabled { opacity:0.3; cursor:not-allowed; }

両方のボタンは、スワイプハンドラーで使われているものと同じ go(idx +/- 1) 関数を呼び出します。最初のスライドでは前へボタンを、最後のスライドでは次へボタンを disabled に設定します。プレビューではボタンを表示し、PNGへのエクスポート時は非表示にします(export.py では .nav-btn がすでに非表示になっています)。

3. IGヘッダーと最終CTAスライドにプロフィール写真を使う

ユーザーの円形プロフィール写真PNGを使います(正方形の写真を256x256にリサイズし、角を透過させる円形の透明マスクを適用します)。HTML内にbase64で埋め込んでください。1文字だけのアバター円は使わないでください。「まずはv1、後で直す」として省略しないでください。

<img class="avatar" src="data:image/png;base64,..."
     style="width:32px;height:32px;border-radius:50%;object-fit:cover;display:block;">

ユーザーが元の写真を提供した場合は、ImageMagickでマスクを適用します。

magick input.jpg -resize 256x256 \
  \( +clone -threshold 100% -fill white -draw "circle 128,128 128,0" \) \
  -alpha off -compose copy_opacity -composite -strip profile.png

納品前に、円の中で顔が中央に配置されていることを確認してください。 正方形ではない画像を単純にリサイズすると、画像の幾何学的な中心でトリミングされるため、顔の位置がずれることがよくあります。PNGを開いて確認してください。位置がずれている場合は、まず -gravity center -crop WxH+offsetX+offsetY を使って手動でトリミングし、その後もう一度確認してください。

同じ画像を、最終CTAスライドの64~84pxの枠線付きアバターにも使います。

4. 最終 CTA スライド:中央揃え、タイトルの上にプロフィール写真、下向き矢印

カルーセル制作で最もよくある修正です。最初のドラフトから、すべてのカルーセルに適用してください。

  1. すべて中央揃え(text-align:center、align-items:center)。左揃えにしないでください。
  2. プロフィール写真はタイトルの上で中央揃えにします。円形のアバターを水平方向に中央揃えし、見出しのすぐ上に配置します。左揃えには絶対にしないでください。
  3. コメント用キーワードのピルは中央揃えにし、その中の矢印は右ではなく下向きにします。キーワードの指示は投稿の下にあるコメント欄を指しているためです。下向きのシェブロン SVG または下向き矢印の文字を使用してください。
  4. 「I'll DM you...」の行は、ピルのすぐ下で中央揃えにします。

標準的な構造:

<div style="display:flex;flex-direction:column;align-items:center;text-align:center;justify-content:center;">
  <img class="avatar" src="..." style="width:84px;height:84px;border-radius:50%;margin:0 auto 20px;">
  <h2>WANT THIS ENTIRE SYSTEM?</h2>
  <p>One line of value or promise.</p>
  <div style="display:inline-flex;align-items:center;gap:8px;">Comment &ldquo;KEYWORD&rdquo; <svg></svg></div>
  <p>and I'll DM you the build.</p>
</div>
5. ディスプレイフォントをシステムのサンセリフフォントにフォールバックさせないでください

見出しには、Anton などのコンデンス体ディスプレイフォントを使用します。見出しが標準的なプロポーショナルサンセリフで表示されている場合、フォントの読み込みに失敗しています。見た目が凡庸になり、すぐに却下されます。必ず <head> に Google Fonts の <link> を含め、QA スクリーンショットごとに、見出しがフォールバックではなく、実際にコンデンス体ディスプレイフォントで表示されていることを確認してください。

6. 句読点のスタイルルール(すべてのスライドのコピー、タグ、キャプション、オーバーレイに適用)
  • スライドのコピー、タグ、キャプション、オーバーレイでは、ダッシュ、エンダッシュ、二重ハイフンを絶対に使用しないでください
  • 区切りにはピリオド、コンマ、改行、または中黒 · を使用してください
  • 複合語の通常のハイフン(long-form、vector-style)は問題ありません
  • タグの例:JOB #1 · MAGAZINE LAYOUT
  • 書き換え例:"print, not just feeds" または "print. Not just feeds."
7. ユーザーが変更を依頼していないコピーは変更しないでください

ユーザーがスライド 1 の変更を依頼した場合、IG のキャプション、フッターのピル、無関係なスライドも変更してはいけません。依頼された範囲を厳守してください。

8. 破壊的な編集の前にバージョンのスナップショットを保存してください

ユーザーはすばやく反復作業を行い、後になって以前のバージョンのほうがよかったと気づくことがよくあります。カルーセルのフォルダーに versions/ ディレクトリを用意してください。構造を書き換える前(スライドの追加、コピーの全面的な見直し、レイアウト変更など)に、現在の carousel.html を versions/vN-<short-descriptor>.html にコピーしてください。

mkdir -p versions
cp carousel.html versions/v3-lime-highlight.html

ユーザーが「前のバージョンの X のほうがよかった」と言ったら、該当するスニペットを versions/*.html で grep し、元に戻してください。

9. 見出しはスライドの幅をいっぱいに使ってください(最長の行をスライド幅の 75~90% にする)

最長の行がスライドの幅の 50~60% しかない左揃えの見出しは見栄えが悪く、「隅に詰め込まれている」ように見えます。最長の行は、コンテンツ領域の右端近くまで届かせてください。

調整方法:

  1. 使用する行のうち、文字数が最も多い行を特定します
  2. 目標のフォントサイズを計算します:Anton の場合は font_px = slide_content_width / longest_chars / 0.32。Archivo Black の場合は 0.55 で割ります。
  3. 計算したサイズで短い行が折り返される場合は、折り返されなくなるまで 2~4px 小さくします。
  4. スクリーンショットで確認します。最長の行は右端から約 20px 以内まで届く必要があります。

他の行を崩さずに範囲内に収められない場合は、改行位置を変更してください(短い行を 2 つ結合するか、長い行を 2 つに分割します)。幅が 50% しかない見出しを提出しないでください。

10. 1~2 語だけの孤立行を作らないでください:テキストブロックの最終行が 1~2 語にならないようにしてください

見出し、サブ見出し、本文、プロンプトの行、箇条書きは、最後の行が 1 語または 2 語だけになる状態にしてはいけません。雑で未完成な印象になります。すべてのテキスト要素に適用されます。

優先順位に沿った修正方法:

  1. サイズを変更して、1 行に収めます(短い見出しの場合はこれを優先します)
  2. 改行位置を調整し、両方の行が複数語で、長さも近くなるようにします
  3. 最後の 3~4 語に white-space:nowrap を指定して語尾をまとめ、より前の位置で折り返されるようにして、最終行を複数語にします
  4. 1 語ずつの意図的なディスプレイ見出しは問題ありませんが、明確なデザイン上の選択として、すべての行で一貫している場合に限ります。最後の 1 語だけが孤立する形にはしないでください

スライドを作成したら、すべてのテキストブロックの最終行を確認してください。1~2 語だけなら、ユーザーに見せる前に修正してください。

11. 対称的な改行:複数行のテキストブロックはすべて、意図的にバランスを整える

孤立した短い行を避けるだけでは不十分です。複数行のブロックは、視覚的なバランスも整える必要があります。最大幅で自動折り返しすると、次のように左右のバランスが悪い分割が定期的に発生します。

Swipe for everything I learned so      <- long
you can scale faster ->                <- short, unbalanced

改行位置を自分で調整し、長い行から単語を下の行に移して、行の長さをそろえるか、きれいなピラミッド状にします。

Swipe for everything I learned         <- balanced
so you can scale faster ->             <- balanced

ルール:

  1. 2~3行に折り返される本文、小見出し、CTA のブロックには、明示的な <br> 改行を使用します。レイアウトは幅 420px の固定キャンバスで、レスポンシブな再配置を維持する必要はないため、手動で改行位置を決めるほうが自動折り返しより確実に優れています。
  2. 意味の切れ目(節やフレーズの区切り)で改行し、各行の長さが互いに約 15%以内に収まるよう確認します。
  3. 単語は上ではなく下に移します。1 行目が長い場合は、バランスが取れるまで末尾の単語を 2 行目に移します。
  4. QA スクリーンショットで確認します。2~3行のブロックで、ある行が別の行より約 2 倍以上長い場合は違反です。
12. 幅とパディングの規律:見出しの行幅をそろえ、スライドごとにコンテンツ幅を統一する

カルーセルレイアウトで繰り返し発生する失敗パターンです。厳格な QA 基準として扱ってください。

  1. まず見出しの各行の文字数をほぼ同じにしてから、サイズを調整します。 2~3行のディスプレイ見出しでは、各行の文字数が 2 文字以内の差に収まるように改行位置を決めます(例:THE SMARTEST MODEL / ON EARTH GOES PAID = 18/18)。次に、各行に white-space:nowrap を指定し、単一のフォントサイズを設定して、行幅がぴったりそろうようにします。レンダリング後に 2 行の幅が目に見えて異なる場合は、片方の文字サイズを小さくせず、コピーの改行位置を変えます。
  2. スライドごとにコンテンツ幅を 1 つに統一します。 スライドのコンテンツ幅(キャンバス幅から左右のパディングをそれぞれ差し引いた幅。例:420 - 2x32 = 356px)を決め、すべてのブロックに同じ幅を設定するか、意図的にその一部の幅を設定します。ブロックごとに左右の端がそろっていないと、雑な印象になります。
  3. 中央揃えのスライドでは、すべてを 1 つの軸にそろえます。左右のパディングは対称にします。ブロックごとにパディングが異なり、視覚的な中心からずれて見える配置は避けます。
  4. 目測ではなく、測定して QA します。スクリーンショットで、見出しの各行のレンダリング幅の差が 10px を超える場合や、ブロックの左右のパディングがスライドの標準値と異なる場合は違反です。
13. デッドスペースをなくす:空いている領域をコンテンツで埋める

本文とビジュアルによる裏付け、またはフッターの間に目立つ余白(高さ 560px のスライドで 80px を超えるもの)があると、スライドは未完成に見えます。次の方法で改善できます。

  • 番号付きカード:小さな箇条書きの代わりに、大きな番号を先頭に置いた全幅カードを使います(ディスプレイフォント、28~32px)。
  • 統計値を添えたビジュアル区切り線:水平線の中央に、色付きの統計値を配置します。
  • ビジュアルを大きくする:モックアップ、コードブロック、統計ブロックに flex:1; min-height:0; を設定し、残りのスペースを埋めます。
  • 装飾要素:余白のある隅に、アクセントカラーの大きな図形(アスタリスク、星、幾何学模様)を配置します。

確認方法:コンテンツを取り除いた状態を想像してください。空いた領域が大きな長方形になっているなら、デッドスペースがあります。公開前に修正してください。

14. キャンバスの端から端まで、大きなディスプレイタイポグラフィで埋める

力強いカルーセルでは、スライド幅の約95%をディスプレイタイポグラフィで使い、見出しだけでスライドの縦幅の50〜65%を占めます。装飾的な図形で四隅を引き締めます。控えめな余白は避けてください。

最初のドラフトから、すべてのスライドに適用します(1080x1440のネイティブフレームの場合の値)。

  • ステージのパディング:padding: 56px 56px 160px、またはそれ以下にします。幅1080のスライドで、左右に100px以上のパディングを取るのは絶対に避けてください。
  • ディスプレイタイポグラフィ:ヒーロー見出しは96〜112px、ウェイト700〜800、文字間隔-2〜-3px、行の高さ1.0〜1.05にします。40〜60pxにはしないでください。
  • ハイライトボックス:利用可能な幅の90〜100%に広げ、テキストを中央揃えにします。テキストの長さだけに合わせて自動調整しないでください。
  • 装飾的なアクセント:アクセントカラーの大きな図形を四隅またはテキストの背後に、透明度0.6〜1.0で配置します。z-index:0にし、見出しやCTAのテキストと絶対に重ならない位置に配置してください。
  • ボーダーフレーム:細い(1〜2px)ボーダーにコーナーノッチのインジケーターを加えると、スライドがデザインされた印象になります。

避けるべき失敗例:見出しが60pxで、スライドの30%が何もない背景になっている状態です。これはドラフトであり、完成したデザインではありません。

15. 1枚のスライドにつき1つのアイデア。オーディエンスを第一にしたコピー

各スライドで伝えるアイデアは厳密に1つにします。主張、ステップ、証拠のいずれか1つです。2つのことを伝えようとしている場合は、スライドを分けてください。

自分向けではなく、ユーザーが投稿する相手に向けて書いてください。オーディエンスが非技術者の場合は、見出しや重要なコピーで専門用語を避けてください。

  • 「HTMLを書く」は「生の動画をアップロードするだけ」にします。
  • 「スキル/ライブラリ/フレームワーク/SDK」は「ツール」または「無料ツール」にします。
  • 「MP4にレンダリングする」は「完成した動画を受け取る」にします。

迷ったときは、対象となるオーディエンスの忙しい人で、ターミナルを開いたことがない人に説明するつもりで書いてください。

16. フックとなるスライドの原則
  • 最初のスライドは、スクロールする手を止めなければなりません。説明ではなく、価値提案や大胆な主張から始めてください。
  • スクリーンショット、実際の数値、画像などの視覚的な証拠を使い、フックの信頼性をすぐに裏付けてください。
  • 具体的な日付は数週間で古びた印象になるため、「JUST RELEASED」「NEW THIS MONTH」のような、長く使える新しさのシグナルを優先してください。日付そのものがニュースである場合に限り、日付を使ってください。
  • アクセントカラーで目立つように中央揃えした「SWIPE TO SEE HOW IT WORKS」の一文は、シェブロンやプログレスバーでもスワイプを促しているとしても、ヒーロースライドにプラスの効果があります。

エクスポートのルール

ユーザーがエクスポート、ダウンロード、または最終版のPNGを求めた場合は、必ず次の手順を実行してください。 このスキルには同等のエクスポーターが2種類含まれています。Python環境の問題を避けられるため、nodeを優先してください。

まず、エクスポーターが実行できることを確認してください(Step 0Aですでに確認済みのはずです。1行のチェックなので、絶対に省略しないでください)。

node -e "import('playwright').then(()=>console.log('playwright ok')).catch(()=>process.exit(1))"

見つからない場合は、その場でインストールしてください(npm install playwright && npx playwright install chromium)。ブラウザーを一度ダウンロードすることをユーザーに伝えてください。原因を確認する前に、エクスポートの失敗をユーザーに報告してはいけません。

# Node (recommended). Run from <carousel_dir> so playwright resolves.
cp .claude/skills/carousel-generator/export.mjs <carousel_dir>/
cd <carousel_dir> && node export.mjs

# Python fallback (needs `pip install playwright` + `python3 -m playwright install chromium`)
cp .claude/skills/carousel-generator/export.py <carousel_dir>/
cd <carousel_dir> && python3 export.py

どちらも約10秒で実行され、./slides/に1080x1440のslide_1.png ... slide_N.pngを書き出します。どちらもHTMLからスライド数を自動検出します。

手動のブラウザー撮影、CSSのzoom、transform: scale、画像のクロップを繰り返すなどの方法で、エクスポートを独自に実装してはいけません。 ブラウザーのスクリーンショットツールはdevicePixelRatioの動作が不安定で、誤ったサイズや黒い出力に時間を無駄にすることになります。スタンドアロンスクリプトは、ブラウザーコンテキストでdevice_scale_factor = 1080/420を直接設定するため正常に動作します。

ヘッドレスブラウザーのスクリーンショットは、デザイン中にスライドの見た目を確認するなど、視覚的な反復にのみ使ってください。エクスポートには絶対に使わないでください。

PNGファイルを読み込んで、すべてのエクスポートを確認してください。 スクリーンショットツールのインラインプレビューは表示用にリサイズされており、保存されたファイルの内容を反映していません。完了をユーザーに伝える前に、各slide_N.pngを読み込み、コンテンツがフレーム全体に広がっていることを確認してください。


ステップ 1:ブランドの詳細を確認する

カルーセルを作成する前に、以下の情報をユーザーに尋ねます(まだ提供されていない場合)。

  1. ブランド名:最初と最後のスライドに表示します
  2. Instagram のハンドル名:IG フレームのヘッダー、キャプション、透かしに表示します
  3. ブランドのメインカラー:メインのアクセントカラー(16 進数コード、または色の説明を受けてこちらで選びます)
  4. ロゴ:SVG パス、ブランドの頭文字、または省略
  5. フォントの好み:セリフ体の見出し+サンセリフ体の本文(エディトリアル)、すべてサンセリフ体(モダン)、または特定の Google Fonts
  6. トーン:プロフェッショナル、カジュアル、遊び心のある、力強い、ミニマルなど
  7. 画像:使用する画像(プロフィール写真、スクリーンショット、商品写真など)

ユーザーがウェブサイトの URL またはブランド素材を提供した場合は、そこから色やスタイルを導き出します。そうでない場合は、ステップ 0 でユーザーと一緒に作成した ./ds-bundle を使用します。ユーザーが詳細なしで「X についてのカルーセルを作って」とだけ伝えた場合は、作成前に質問します。デフォルトを決めつけないでください。


ステップ 2:カラーシステム全体を導き出す

ユーザーのメインブランドカラー 1 色をもとに、6 トークンのパレット全体を生成します。

BRAND_PRIMARY   = {user's color}                     // Main accent: progress bar, icons, tags
BRAND_LIGHT     = {primary lightened ~20%}           // Secondary accent: tags on dark, pills
BRAND_DARK      = {primary darkened ~30%}            // CTA text, gradient anchor
LIGHT_BG        = {warm or cool off-white}           // Light slide background (never pure #fff)
LIGHT_BORDER    = {slightly darker than LIGHT_BG}    // Dividers on light slides
DARK_BG         = {near-black with brand tint}       // Dark slide background

ルール:

  • LIGHT_BG は、メインカラーに調和する色味を帯びたオフホワイトにします(暖色系のメインカラーなら暖色系のクリーム色、寒色系なら寒色系のグレーがかった白)
  • DARK_BG は、ブランドの色温度に合った控えめな色味を持つ黒に近い色にします(暖色系:#1A1918、寒色系:#0F172A)
  • LIGHT_BORDER は、LIGHT_BG より約 1 段階濃い色にします
  • グラデーションスライドのブランドグラデーションは linear-gradient(165deg, BRAND_DARK 0%, BRAND_PRIMARY 50%, BRAND_LIGHT 100%) です

ユーザー専用のバンドルが作成済みの場合、対応する値は ds-bundle/tokens/tokens.css にあります(カルーセルトークングループを参照してください)。


ステップ 3:タイポグラフィを設定する

ユーザーの好みに基づき、Google Fonts から見出し用フォントと本文用フォントを選びます。

スタイル見出し用フォント本文用フォント
エディトリアル/プレミアムPlayfair DisplayDM Sans
モダン/クリーンPlus Jakarta Sans (700)Plus Jakarta Sans (400)
温かみのある/親しみやすいLoraNunito Sans
テクニカル/シャープSpace GroteskSpace Grotesk
力強い/表現豊かFrauncesOutfit
クラシック/信頼感のあるLibre BaskervilleWork Sans
太めのディスプレイ/インパクト重視AntonSpace Grotesk

アグレッシブでインパクトのあるカルーセルでは、太くて幅の狭いディスプレイフォント(Anton または Archivo Black)をデフォルトにします。セリフ体は、プレミアムまたはポートレートスタイル用にします。

フォントサイズのスケール(プレビュー幅 420px の場合):

  • 見出し:標準は 28~34px、ディスプレイ用の大きなヒーロー見出しでは最大 60~66px(Anton)または 48~54px(Archivo Black)、行の高さは 0.9~1.15
  • 本文:14px、ウェイト 400、行の高さ 1.5~1.55
  • タグ/ラベル:10px、ウェイト 600、文字間隔 2px、すべて大文字
  • ステップ番号:見出し用フォント、26px、ウェイト 300
  • 小さなテキスト:11~12px

420px 幅で 1 行に収めるディスプレイ見出しの文字数調整の目安:Anton は 60~66px で 1 行あたり約 22~25 文字、Archivo Black は 50~54px で約 14~16 文字に対応します。Anton の大文字表記に関する一般的なルール:max_size_px = container_width / (chars x 0.49)。

すべてのスライドで CSS クラス .serif(見出し用フォント)と .sans(本文用フォント)を適用します。


スライドの構成

フォーマット
  • アスペクト比:3:4(1080 x 1440)。Instagram 推奨のカルーセルサイズです(プロフィールグリッドも 3:4 にトリミングされます)。各スライドは必ず正確に 3:4 にします。例外はありません。
  • レイアウトキャンバス:420 x 560px。device_scale_factor によって 1080/420 = 2.5714 倍に拡大して書き出します。420px で作成し、1080px をネイティブサイズとして作成しないでください。
  • 各スライドは独立しており、すべての UI 要素が画像に埋め込まれています
  • 視覚的なリズムを生むため、LIGHT_BG と DARK_BG の背景を交互に使用します
各スライドに埋め込む必須要素
1. プログレスバー(すべてのスライドの下部)

カルーセル内の現在位置を閲覧者に示します。スワイプするにつれて伸びます。

  • 位置:絶対配置で下部、全幅、左右のパディングは28px、下部のパディングは20px
  • トラック:高さ3px、角を丸める
  • 塗りつぶし幅:((slideIndex + 1) / totalSlides) * 100%
  • 明るいスライド:トラックはrgba(0,0,0,0.08)、塗りつぶしはBRAND_PRIMARY、カウンターはrgba(0,0,0,0.3)
  • 暗いスライド:トラックはrgba(255,255,255,0.12)、塗りつぶしは#fff、カウンターはrgba(255,255,255,0.4)
  • バーの横に置くカウンターラベル:「1/7」形式、11px、ウェイト500
function progressBar(index, total, isLightSlide) {
  const pct = ((index + 1) / total) * 100;
  const trackColor = isLightSlide ? 'rgba(0,0,0,0.08)' : 'rgba(255,255,255,0.12)';
  const fillColor = isLightSlide ? BRAND_PRIMARY : '#fff';
  const labelColor = isLightSlide ? 'rgba(0,0,0,0.3)' : 'rgba(255,255,255,0.4)';
  return `<div style="position:absolute;bottom:0;left:0;right:0;padding:16px 28px 20px;z-index:10;display:flex;align-items:center;gap:10px;">
    <div style="flex:1;height:3px;background:${trackColor};border-radius:2px;overflow:hidden;">
      <div style="height:100%;width:${pct}%;background:${fillColor};border-radius:2px;"></div>
    </div>
    <span style="font-size:11px;color:${labelColor};font-weight:500;">${index + 1}/${total}</span>
  </div>`;
}
2. スワイプ矢印(右端、最後以外のすべてのスライド)

スワイプを続けるよう閲覧者に促す、控えめなシェブロンです。最後のスライドでは、終点に到達したとわかるように非表示にします。

  • 位置:絶対配置で右端、高さは全体、幅48px
  • 背景:透明から控えめな色合いへフェードするグラデーション
  • シェブロン:24x24のSVG、角丸のストローク
  • 明るいスライド:背景はrgba(0,0,0,0.06)、ストロークはrgba(0,0,0,0.25)
  • 暗いスライド:背景はrgba(255,255,255,0.08)、ストロークはrgba(255,255,255,0.35)
function swipeArrow(isLightSlide) {
  const bg = isLightSlide ? 'rgba(0,0,0,0.06)' : 'rgba(255,255,255,0.08)';
  const stroke = isLightSlide ? 'rgba(0,0,0,0.25)' : 'rgba(255,255,255,0.35)';
  return `<div style="position:absolute;right:0;top:0;bottom:0;width:48px;z-index:9;display:flex;align-items:center;justify-content:center;background:linear-gradient(to right,transparent,${bg});">
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
      <path d="M9 6l6 6-6 6" stroke="${stroke}" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
    </svg>
  </div>`;
}
3. 透かし

bottom:32px、font-size 8px、letter-spacing 2px、控えめな不透明度(約0.25)の小さなハンドルの透かし(@YOURHANDLE)です。プログレスバーのコンテナーは下部約39pxを占めるため、bottom:32pxにすると、透かしはバーの上かつpadding-bottom:56pxを使うコンテンツの下にある隙間に収まります。位置が低すぎるとバーに重なり、高すぎるとコンテンツにぶつかります。


スライドのコンテンツパターン

レイアウト規則
  • コンテンツのパディング:標準は0 36px
  • プログレスバーがある下部揃えのスライド:バーとの間隔を確保するため0 36px 52px。コンテンツコンテナーはバーと透かしを避けるためpadding-bottom:56pxを使用
  • ヒーロー/CTAスライド:justify-content: center
  • コンテンツ量の多いスライド:justify-content: flex-end(テキストを下部に置き、上部に視覚的な余白を設ける)
タグ/カテゴリラベル

スライドのカテゴリを示す、見出しの上に置く小さな大文字のラベルです。

<span class="sans" style="display:inline-block;font-size:10px;font-weight:600;letter-spacing:2px;color:{color};margin-bottom:16px;">{TAG TEXT}</span>
  • 明るいスライド:BRAND_PRIMARY。暗いスライド:BRAND_LIGHT。グラデーションのスライド:rgba(255,255,255,0.6)。
ロゴロックアップ(最初と最後のスライド)
  • ロゴアイコンが提供されている場合:BRAND_PRIMARYの背景にアイコンを中央配置した40pxの円を置き、その横にブランド名を配置
  • イニシャル:白い最初の文字を入れた40pxの円
  • ブランド名:13px、ウェイト600、letter-spacing 0.5px
透かしロゴ(任意)

ロゴアイコンが提供されている場合、ヒーロー、CTA、グラデーションなどの重要なスライドで、控えめな背景の透かしとして不透明度0.04~0.06で使用します。ロゴがない場合は省略します。


標準的なスライドの順序

次のストーリー展開に従います。7~8枚を目安にします。内容を引き延ばさず、十分な価値を届けるのに適した枚数です。内容上どうしても必要な場合に限り、8枚を超えてください。

#種類背景目的
1ヒーローLIGHT_BG興味を引く:印象的なメッセージ、ロゴロックアップ、任意の透かし
2課題DARK_BG問題点:機能していないこと、不満な点、時代遅れな点
3ソリューションブランドのグラデーション解決策。引用やプロンプトボックスは任意
4特徴LIGHT_BG得られるもの:アイコン付きの特徴一覧
5詳細DARK_BG詳細:カスタマイズ、仕様、差別化要素
6使い方LIGHT_BG手順:番号付きのワークフローやプロセス
7CTAブランドのグラデーション行動喚起。矢印なし。プログレスバーは最後まで表示。

ルール:

  • 興味を引く内容から始めます(ルール16を参照)
  • ブランドのグラデーションでキーワードを使ったCTAを最後に置きます。スワイプ矢印は表示せず、プログレスバーは100%まで表示し、ルール4に従って中央揃えにします
  • リズムが生まれるよう、明るい背景と暗い背景を交互に使います
  • トピックに合わせて順序を調整します。すべてのカルーセルに「課題」スライドが必要なわけではありません
  • スライドのコンテンツはモジュール化しておきます。ストーリーの流れを改善するために、ユーザーがスライドを並べ替えることはよくあります

再利用可能なコンポーネント

取り消し線付きピル(置き換えるもの)
<span style="font-size:11px;padding:5px 12px;border:1px solid rgba(255,255,255,0.1);border-radius:20px;color:#6B6560;text-decoration:line-through;">{Old tool}</span>
タグピル
<span style="font-size:11px;padding:5px 12px;background:rgba(255,255,255,0.06);border-radius:20px;color:{BRAND_LIGHT};">{Label}</span>
プロンプト/引用ボックス
<div style="padding:16px;background:rgba(0,0,0,0.15);border-radius:12px;border:1px solid rgba(255,255,255,0.08);">
  <p class="sans" style="font-size:13px;color:rgba(255,255,255,0.5);margin-bottom:6px;">{Label}</p>
  <p class="serif" style="font-size:15px;color:#fff;font-style:italic;line-height:1.4;">"{Quote text}"</p>
</div>

プロンプトボックスの各フィールドは、それぞれ必ず1行に収めてください。折り返される場合は、プレースホルダーテキストを短くします。コピーして貼り付けるプロンプトは、短いものより長いもののほうが信頼性が高く見えます。埋め草ではなく、具体的な指示(取得する情報、順位付けする対象、出力する内容)を加えてください。

特徴一覧
<div style="display:flex;align-items:flex-start;gap:14px;padding:10px 0;border-bottom:1px solid {LIGHT_BORDER};">
  <span style="color:{BRAND_PRIMARY};font-size:15px;width:18px;text-align:center;">{icon}</span>
  <div>
    <span class="sans" style="font-size:14px;font-weight:600;color:{DARK_BG};">{Label}</span>
    <span class="sans" style="font-size:12px;color:#8A8580;">{Description}</span>
  </div>
</div>
番号付きの手順
<div style="display:flex;align-items:flex-start;gap:16px;padding:14px 0;border-bottom:1px solid {LIGHT_BORDER};">
  <span class="serif" style="font-size:26px;font-weight:300;color:{BRAND_PRIMARY};min-width:34px;line-height:1;">01</span>
  <div>
    <span class="sans" style="font-size:14px;font-weight:600;color:{DARK_BG};">{Step title}</span>
    <span class="sans" style="font-size:12px;color:#8A8580;">{Step description}</span>
  </div>
</div>
複数行のハイライトボックス

複数行にまたがる範囲に背景ハイライト(background:{accent}; padding:2px 8px;)を適用すると、デフォルトでは分断されたボックスとして表示されます。次のように修正します。

box-decoration-break: clone;
-webkit-box-decoration-break: clone;

行の高さを少し広め(1.15-1.18)にすると、ハイライトが複数行にわたってきれいにつながります。大きめの濃いドロップシャドウ(box-shadow: 4px 4px 0 {DARK_BG})を付けると、よく目立ちます。

CTA ボタン(最終スライドのみ)
<div style="display:inline-flex;align-items:center;gap:8px;padding:12px 28px;background:{LIGHT_BG};color:{BRAND_DARK};font-family:'{BODY_FONT}',sans-serif;font-weight:600;font-size:14px;border-radius:28px;">
  {CTA text}
</div>

Instagram フレーム(プレビュー用ラッパー)

カルーセルを Instagram 風のフレームで囲み、ユーザーが実際の表示をプレビューできるようにします。

  • ヘッダー: アバター+ハンドル名+サブタイトル
  • ビューポート: 3:4 のアスペクト比。全スライドを含む、スワイプ/ドラッグ可能なトラック
  • ドット: ビューポートの下に小さなドットインジケーター
  • アクション: ハート、コメント、シェア、ブックマークの SVG アイコン
  • キャプション: ハンドル名+短い説明+「2 HOURS AGO」のタイムスタンプ

ポインターを使ったスワイプ/ドラッグ操作、キーボードの矢印キー、前へ/次へボタンを実装します。スライド自体は、それぞれ単独で書き出せる画像として仕上げます。

.ig-frame の幅は必ず 420px にしてください。 内側のビューポートは 420x560(3:4)です。すべてのスライドのレイアウト、フォントサイズ、間隔は、この基準幅に合わせて設計されています。変更しないでください。書き出し処理がこの幅に依存しています。

最終スライドにコメント用のキーワードがある場合、モックアップの IG キャプションにも、同じキーワードをまったく同じ表記(大文字・小文字と句読点も含む)で使用してください。コメントする人は、ボタンよりキャプションからコピーすることが多いためです。また、約束した数と実際に提供する数を一致させてください。無料ガイドに項目が 7 つある場合、文面にも 7 と記載します。


ビジュアルの反復確認

書き出す前に、自分でスライドを確認してください。 HTML が想定どおりに表示されると思い込まないでください。

# Serve over HTTP; headless browsers handle http:// more reliably than file://
cd /path/to/carousel/dir && python3 -m http.server 8765 &

ヘッドレスブラウザーで http://localhost:8765/carousel.html?cb=<timestamp> を開き、トラックをスライド N(0 始まり)に移動します。

const track = document.getElementById('track');
track.style.transition = 'none';
track.style.transform = 'translateX(' + (-N * 420) + 'px)';

バージョン番号を付けたファイル名(例:screenshots/v3-slide-6.png)で screenshots/ にスクリーンショットを保存し、ルートディレクトリには置かないでください。反復ごとに比較できます。

確認ループを実行するタイミング:

  • 構造を編集した後
  • ユーザーから表示上の問題が報告されたとき(推測せず、まずスクリーンショットを撮ってください)
  • カルーセルの完成を宣言する前(最後にもう一度、N 枚すべてのスライドを最初から最後まで確認してください)

完了したら、必ず HTTP サーバーを停止してください。サーバーが残っていると、後続のセッションで同じポートが競合します。


書き出し前のアセット圧縮

ユーザー提供の画像や動画は、1080x1440 の出力に必要なサイズよりも大きいことがよくあります。base64 に埋め込む前に、積極的に圧縮してください。

画像(JPEG)
ffmpeg -y -i INPUT -vf "scale=W:H:flags=lanczos" -q:v 3 OUTPUT.jpg

48px のアバター円には 256x256 を使用します。フルスライドのスクリーンショットには、通常 960x540 で十分です。2MB の JPEG は、目に見える劣化なしで通常 20-40KB に圧縮できます。

埋め込む前に file コマンドで実際のファイル形式を確認してください。ユーザーのファイルは .png 拡張子でも JPEG のことがよくあり、データ URI の MIME タイプは実際の形式と一致させる必要があります。

動画(H.264 MP4)
ffmpeg -y -i INPUT \
  -vf "scale=960:-2:flags=lanczos,fps=30" \
  -c:v libx264 -pix_fmt yuv420p -crf 26 -preset slow -movflags +faststart -an \
  OUTPUT.mp4

4MB の元ファイルは、カルーセルの表示サイズでは通常約 150KB まで小さくなります。元のフレームレートが 60fps 以上の場合は、フレームレートを下げてください。

Base64 のサイズ上限

Base64 ではサイズが約 33% 増加します。埋め込むアセットはそれぞれ約 500KB 未満、HTML 全体は 2MB 未満にしてください。これを超えるとブラウザーの解析が遅くなり、書き出し時の set_content 呼び出しがタイムアウトする可能性があります。

すべての画像を data: URI として埋め込んでください。 書き出しでは HTML を set_content 経由で読み込むため、相対 URL は解決されません。ファイルパスを指定した <img src> は、エラーもなく読み込みに失敗します。Base64 で埋め込めば、HTML が完全に自己完結し、どこでも安全にレンダリングできます。


スライドの書き出し(詳細)

コマンドは 1 つだけです。

cp .claude/skills/carousel-generator/export.py <carousel_dir>/
cd <carousel_dir> && python3 export.py

./slides/ に 1080x1440 の slide_1.png ... slide_N.png を書き出します。スライド数は自動検出されます。

エクスポートに関する重要なルール
  1. ブラウザーのスクリーンショットを手動で撮ってエクスポートしないでください。 スクリーンショットツールの不安定な devicePixelRatio の処理が、あらゆる拡大方法の妨げになります。スタンドアロンスクリプトでは、ブラウザーコンテキストに device_scale_factor = 1080/420 を直接設定します。
  2. HTML の生成には Python を使い、変数展開を伴うシェルスクリプトは使わないでください。 シェル変数によって内容($ 記号、バッククォート、数字)が壊れるためです。Path.write_text() を使って HTML を生成します。
  3. 画像は base64 として埋め込んでください。 これにより、ヘッドレスブラウザーで HTML が完全に自己完結します。
  4. レイアウトの幅は 420px に保ってください。 レイアウトを変更せずにエクスポートを拡大します。ビューポートの幅を 1080px に設定しないでください。レイアウトが再配置され、すべてが歪みます。
よくあるエクスポートのミス
ミス問題点修正方法
ビューポートを 1080x1440 に設定するレイアウトが再配置され、フォントが小さくなり、間隔が崩れますビューポートは 420x560 に保ち、device_scale_factor を使用します
シェルスクリプトで HTML を生成する$ とバッククォートが展開されますPython で HTML を生成します
フォントの読み込みを待たない見出しが代替フォントで表示されますページ読み込み後、約 3 秒待ちます(スクリプトではそのように処理されます)
IG フレームの装飾を非表示にしないヘッダー、ドット、キャプションがエクスポートに含まれますスクリプトで .ig-header,.ig-dots,.ig-actions,.ig-caption,.nav-btn,.dots を非表示にします
.ig-frame の幅を変更するレイアウト全体がずれます必ず 420px にします
スクリーンショットのプレビューを信用するプレビューは再スケーリングされており、ファイルとは異なる場合があります保存した slide_N.png をそれぞれ確認します
動画スライド(画像と動画を組み合わせたカルーセル)

Instagram のカルーセルは、縦横比が一致する PNG と MP4 の混在に対応しています。スライドに <video> 要素が含まれる場合、最終エクスポートの前に、動きを保つ MP4 にするか、静止画の PNG にするかをユーザーに確認してください。

MP4 にエクスポートする場合、ブラウザーの動画録画機能は使わないでください(スケーリングが不適切で、トランスコードが二重になるためです)。代わりに、スライドの静的コンテンツを透明背景の PNG オーバーレイとしてレンダリングし(動画を非表示にし、コンテナーの背景をクリアして、アルファ付きでスクリーンショットを撮影)、その後 ffmpeg で合成します。

[bottom]  solid canvas at slide bg color (1080x1440)
[middle]  source video, cover-fit into the video element's bounding box
[top]     overlay PNG with alpha

主なルール:

  • scale=W:H:force_original_aspect_ratio=increase,crop=... を使ってフィットさせます。引き伸ばしが発生するため、単純な scale=W:H は使わないでください。
  • エクスポートの長さは、ソース動画のループ 1 回分と厳密に一致させます(ffprobe で長さを確認します)。これにより、Instagram の自動ループで継ぎ目が目立たなくなります。
  • 必ず無音の AAC トラックを多重化します(-f lavfi -i anullsrc=channel_layout=stereo:sample_rate=44100、-c:a aac)。Instagram では、音声のないカルーセル動画が拒否されることがあります。
  • H.264 High プロファイル、yuv420p、CRF 18~20、30fps、スライドごとに最短 3 秒、最長 60 秒にします。
  • エクスポート前に、できるだけ高解像度のソースを依頼してください。埋め込み版は圧縮済みで、これを拡大するとピクセルが目立ちます。
  • final/ フォルダーに、アップロード順の連番を付けた slide_1.{png|mp4} ... を用意します。

コピーとクレジット表記のルール

  1. 引用された見出しでは、開き引用符を使います。 HTML ソースでは、明示的に Unicode の U+201C(開き)と U+201D(閉じ)を使います。ASCII の直線引用符では、両側とも閉じ引用符として表示されることがよくあります。
  2. 画像キャプションでは、正確にクレジットを表記します。 表示するプロンプトが自分の実験であれば、My test: "<prompt>" とします。引用やデモが企業または人物のものだと表記するのは、ソースで確認できる場合に限ります。生成に実際に使われたプロンプトでない限り、Generated with: "<prompt>" は使わないでください。
  3. 成果物の数を正確に示します。 提供する成果物が N 個であれば、その数に言及する箇所はすべて、正確に N 個とします。
  4. まとめて編集する場合は、Python スクリプトを 1 つ使います。 既存のカルーセルに対してテキストまたは構造を 10 か所以上変更する場合、content.count(old) によるアサーションを使い、すべての置換を行う Python スクリプトを 1 つ作成します。複数の編集を順番に繰り返す方法は使いません。
  5. スライドで名前が挙げられたツールには、文字のグリフではなく、実際の製品ロゴを使います。

レイアウトのベストプラクティス

  1. すべての <img> タグには、明示的なサイズ指定スタイルが必須です。 <img src> だけの記述は避け、必ず style="width:100%;height:100%;object-fit:cover;object-position:top left;display:block;" を指定してください。指定しないと、画像が本来の解像度で表示され、レイアウトが崩れます。
  2. 画像が1枚のコンテナには、明示的な高さ制約が必要です:height または max-height(通常は140~240px)に加え、flex-shrink:0 を指定してください。画像が1枚のコンテナで flex:1; min-height:0 は使用しないでください。フレックスの計算が不正確になり、画像が padding-bottom を超えて透かし領域まで伸びてしまいます。
  3. 画像が2~4枚のグリッドは例外です:スライドの padding-bottom がクローム領域を別に確保しているため、グリッドの親要素に flex:1; min-height:0 を、各セルに height:100% を指定する方法が適切です。
  4. <video> 要素にも <img> と同じルールが適用されます:明示的なカバーフィットのスタイルに加え、autoplay muted loop playsinline を指定してください。ユーザーが新しいフレーミング済みのアセットに差し替えた場合は、以前の transform:scale() や中央からずらす object-position の調整を削除し、ユーザーのフレーミングをそのまま使用してください。
  5. 複数の被写体を含むソースでは object-position を調整します。 横長の画像に複数の被写体が含まれ、セルをそのうちの1人に合わせる必要がある場合は、スクリーンショットを見ながら object-position: X% center を実際に調整してください。
  6. はみ出しを事前確認します。 画像ブロックとキャプションがあるスライドごとに、(padding-top + ラベル + 見出し + 本文 + 画像 + キャプション + padding-bottom)の合計が560px以内に収まることを確認してください。収まらない場合は画像の高さを調整します。
  7. スライドの順序変更では、3つの箇所を変更します:スライドの位置、タグ/ラベルの番号、進捗バーの割合とカウンターの分数です。どれか1つを見落としがちです。

QA チェック:ユーザーに提示する前に実施

カルーセルの生成または編集後、すべてのスライドを確認して、以下の問題を検出したら自動的に修正してください。画像のはみ出しや重なりをユーザーに報告させてはいけません。

  1. 画像のはみ出し:すべての <img> に、カバーフィットのサイズ指定スタイルが明示されています。
  2. コンテナのサイズ指定:すべての画像/動画ラッパーに、明示的な height/max-height と flex-shrink:0 が指定されています(上記ルールに従い、グリッドは除きます)。
  3. 下部の重なり:透かし(bottom:32px)や進捗バー(下端から約39px)にコンテンツが重なっていません。コンテンツのコンテナには padding-bottom:56px を指定します。
  4. 進捗バーの計算:各スライドのバーの塗りつぶしは (slideNumber / totalSlides) * 100% と一致し、カウンターも一致しています。
  5. スワイプ矢印:最後のスライドには表示せず、それ以外のスライドには表示します。
  6. ライト/ダークの一貫性:矢印、進捗バーのトラックと塗りつぶし、透かし、カウンターの色が、すべてスライドの背景テーマに合っています。
  7. スライド数:class="slide" を持つ <div> の総数が、カウンターの分母とドットインジケーターの数に一致しています。
  8. フォントの読み込み:使用しているすべてのフォントファミリーについて Google Fonts の <link> が存在し、見出しが本来のディスプレイフォントで表示されています。
  9. 孤立行とバランス:最後の行が1~2語だけになっていません。複数行のブロックのバランスが取れ、見出しの行が幅のルールに従って揃っています。
  10. 埋め込みアセットのサイズ:単一の base64 ペイロードが約500KBを超えておらず、HTML 全体が約2MB未満です。

この確認では、base64 データを取り除いた HTML を読み込んでください。埋め込み画像の生データをコンテキストに読み込まないでください。


コンテキスト管理

カルーセルのセッションは、base64 アセットやスクリーンショットを扱うため、コンテキストを大量に使用します。セッションを効率よく進めるには、次の点に従ってください。

  • 編集のためにカルーセルの HTML を読み込む場合は、先に base64 を取り除きます(sed '/base64/d')。
  • ユーザーのスクリーンショットから対応が必要なフィードバックをすぐに抽出してから、次の作業に進みます。
  • 1件ずつではなく、複数回にわたるフィードバックをまとめて修正します。
  • 作業が残っているのにコンテキストが不足してきた場合は、ユーザーに伝えて新しいセッションを提案します。コピーの確定版と versions/ のスナップショットがあるため、作業の再開は容易です。

デザイン原則

  1. すべてのスライドをエクスポート可能にする:矢印とプログレスバーは、重ねて表示するUIではなく、スライド画像の一部です
  2. 1枚のスライドにつきアイデアは1つ
  3. 明るい配色と暗い配色を交互にすることで、スワイプ全体にリズムを生み、注目を保ちます
  4. 見出しと本文のフォントを組み合わせる:インパクトのあるディスプレイフォントと、読みやすい本文フォントを使います
  5. ブランドに由来するパレット:すべての色を1つのプライマリーカラーから派生させます
  6. 段階的な情報開示:プログレスバーが進み、矢印が先へ導きます
  7. 最後のスライドは特別にする:矢印をなくし、プログレスバーをいっぱいにして、キーワードのCTAを中央に配置します
  8. コンポーネントに一貫性を持たせる:すべてのスライドで同じタグスタイル、リストスタイル、間隔を使います
  9. コンテンツの余白でUIとの重なりを防ぐ:本文がプログレスバーや矢印に重ならないようにします
  10. 素早く反復する:プレビューを見せ、具体的なスライドについてフィードバックをもらい、そのスライドを修正します。方向性が根本的に変わらない限り、最初から作り直さないでください

コメント