anim-slides は何をしますか?
既存のスライドまたはドキュメントから、スライドデッキ用のアニメーションSVGイラストを生成します。
出力は常にフラグメントです。1つのHTMLファイルに<style>と1つの<svg>を含み、スクリプトや外部ファイルはなく、CSS変数でテーマ設定され、任意のデッキにそのまま挿入できます。
references/fragment-contract.mdが契約書です。何かを構築する前に読んでください。
使用するタイミング
- スライドがテキストカードの並び、箇条書き、またはスクリーンショットであり、その内容がプロセス、フロー、依存関係構造、タイムライン、比較、アーキテクチャ、時系列である場合。
- ドキュメント(Markdown、Confluenceエクスポート、README、Mermaidブロック)がプロセスや依存関係を説明しており、ユーザーがそれをスライドやページ上でアニメーションとして表示したい場合。
- ホストがHTMLデッキ(frontend-slides、reveal.js、impress.js、Slidev、手書き)またはプレーンなWebページである場合。
.pptxまたはMarkdownソースは、まずデッキスキルによってデザインされたHTMLデッキに変換されます(ステップ0)。このスキルはその後、イラストを追加します。
ワークフロー
以下の<skill-dir>は、このSKILL.mdを含むフォルダです(Claude Codeでは$CLAUDE_SKILL_DIRとして公開されます。他の環境では、このファイルをロードしたパスを使用してください)。スクリプトにはPython 3.9+と、レンダリング用のChromeまたはChromiumバイナリが必要です。anim/<name>/は、ユーザーのデッキの隣にあるフォルダです。
0. 取り込み
最初にHTMLデッキを用意してください。 anim-slidesはHTMLデッキに図を追加するものであり、デッキをデザインするものではありません。
- ソースがすでにHTMLデッキ(reveal.js、impress.js、
<section>または.slideデッキ)である場合:進めてください。 - ソースが
.pptx、Markdown、remark、ドキュメント、またはHTMLデッキ以外のものである場合:デッキスキルが最初にHTMLデッキを構築します。anim-slidesは構築しません。優先順位は以下の通りです:(a) ユーザー自身または組織のデッキスキルがインストールされている場合、それを使用;(b)frontend-slidesがインストールされている場合、それを使用(pptxとMarkdownをデザインされたHTMLデッキに変換します。美的プレビューを提供する場合は、ユーザーが新しい外観を希望しない限り、ソースデッキのブランドに最も近いものを選択);(c) デッキスキルがインストールされていない場合のみ、フォールバックとしてscripts/md_to_deck.pyを使用(以下のフォールバックの箇条書きを参照)。その場合、出力はプレーンなホストであり、デザインされたものではないことを一文でユーザーに伝え、デッキスキルまたはデザイナーがスタイルを適用するまでドキュメントのように読めることを伝えます。ケース(a)と(b)では、元の.pptxはextract_slides.pyとrender_deck.pyのトリアージ(チャート、図、ノート)のソースとして残りますが、統合はスキルが生成したデッキをターゲットとし、マッチルックはhost_theme.pyを介してそのデッキのパレットから取得されます。デッキスキルに(またはその直後に)各候補スライドの本文を、固定サイズのスロット<div id="sN-slot">で<!-- sN-body -->と<!-- /sN-body -->の間にラップするように依頼してください(IDとマーカー名はmd_to_deck.pyが使用するものです。ただし、そこではスロットは本文の空の兄弟要素です):measure_slot.py --selector '#sN-slot'は正確になり、integrate_fragment.py --anchor/--replace-untilはマーカーをターゲットにします。デッキスキル独自のフォントリンク(Google Fonts、Fontshare)はデッキの読み込みであり、anim-slidesが追加したものではありません。それを保持し、bundle_deck.py --fetchで引き渡し時にインライン化します。
次に、該当するエントリポイントを決定します:
- 既存のデッキ:
python3 <skill-dir>/scripts/extract_slides.py deck.pptx|deck.html|doc.md -o anim/outline.jsonとpython3 <skill-dir>/scripts/render_deck.py deck -o anim/renderを実行し、sheet-NN.pngのコンタクトシート(12枚の番号付きスライド)をページごとではなく確認します(スライドのoutline.json内の画像数がレンダリング内の画像数と異なる場合は、スライドレイアウトの画像を確認します:レイアウト上のカバー写真は見逃しやすいです)。次にreferences/input-stage.mdでトリアージし、テーブルをanim/triage.mdに書き込みます:すべてのスライドについて、決定と理由を記載し、黙ってスキップしないでください(30スライドあたり3~8のイラストが標準です。短いデッキでは、すべてのプロセス、構造、タイムライン、比較、データスライドに1つずつイラストが付きます)。その後、デッキ全体に対してルックを一度決定します:マッチ(フラグメントはホストのパレットとフォントを採用、ブランドまたはコーポレートデッキのデフォルト)またはリーン(フラグメントはリーンパレットをダークグラウンドで保持、トークやピッチ向け)。python3 <skill-dir>/scripts/host_theme.py deck.html --mode match -o anim/host-theme.cssは、デッキのCSSからマッチグルーを導出します(--mode leanはリーングルーを書き込みます)。導出されたブロックをデッキ自身の変数(ミュートされたテキスト色、セカンダリ背景)と一度比較し、導出が計算されたミックスを選択した場合は手動で修正します。両方の方法で最初のフラグメントをレンダリングし(render-phases.sh --theme anim/host-theme.css ...)、残りを構築する前に2つの静止画を表示します。ただし、ユーザーが既にルックを指定している場合はその限りではありません。2つの間で色とフォントのみが変更されます。references/style.mdの形状ルールは両方で保持されます。 コントロールは、ユーザーがクリックスルーを要求しない限り、デッキ全体でonceです:各スライドの図は、スライドが表示されたときに1回静かに通過し、その後静止します。自分からstepを推奨しないでください。outline.jsonがbuildsを0より多く報告する場合(ソースが既にクリックでビルドされる:reveal.jsフラグメント、PowerPointクリックアニメーション、impress.jsサブステップ、デッキ自身のビルドステップ)にのみ、一文で言及します:「あなたのデッキはクリックでビルドされます。図も同様に動作させることができます(step)。希望する場合はそのように言ってください。」stepでは、エントランスが描画され、各クリックで次のフェーズが着地します。フェーズはブリーフのナレーションフェーズ(スライドあたり3~5)であり、フラグメントファイルは同じで、クリックはデッキ自身のナビゲーションを利用します。Stepはキーのみをリッスンするため、ステップデッキはキーボードまたはクリッカーで提示されます(frontend-slidesのようにホイールやスワイプでもナビゲートするデッキは、スクロール時にフェーズをスキップします)。ルックとコントロールをanim/triage.mdのヘッダーに記述します。 - フォールバック、デッキスキルがインストールされていない場合(Markdown、remark、またはMarkdownに抽出されたpptx):
python3 <skill-dir>/scripts/md_to_deck.py deck.md -o deck.htmlで、統合用のプレーンで自己完結型のホストを作成します(スライドごとに1つの<section>、.visibleゲーティング、印刷レイアウト、各スライドの本文を囲む<!-- sN-body -->マーカー)。これはデザインされたデッキではありません:それを一文でユーザーに伝えます。Markdownが参照する画像(相対パス)を最初に同じフォルダにフェッチしてください。そうしないとデッキにプレースホルダが表示されます。その後、元のソース(存在する場合は.pptx)またはMarkdownから抽出します。 - ドキュメント:ソースを読み、
references/archetypes.mdのテーブルでアーキタイプを選択し、仕様を抽出します(ステップ1)。 - 単一スライドのリクエスト:そのスライドについて直接ステップ1に進みます。 ソースの順序、方向、グループ化が不明確な場合のみユーザーに問い合わせてください。それ以外の場合は、ブリーフ内でその前提を述べて続行します。
1. 仕様
references/spec-format.mdに従ってanim/<name>/spec.yamlを記述します:名前、アーキタイプ、ノード、エッジ、グループ、秒単位のマーク付きフェーズ、サイクル(パスの長さ)、コントロール(取り込みからのデッキの選択:once、スライドがカレントになったときに4~10秒の静かなパスを1回、静止フレームで終了;step、同じパスをフェーズマークで区切り、各クリックで次のフェーズが着地;loop、ユーザーが連続ループを要求した場合のみ)。フラグメントファイルはonceとstepで同じです。フェーズマークはdata-anim-phasesになります。ソース自身の言葉をラベルとして再利用します。仕様は約12ノード以下に保ちます。それ以上は分割します。
1b. プールを確認
<skill-dir>/pool/index.yamlを読み、次に$ANIM_POOL/index.yaml(または$ANIM_POOL/*/をリスト)が設定されている場合、同じアーキタイプと類似のストーリーまたはタグを持つエントリを探します。
- 近い一致:フォルダを
anim/<name>/にコピーし、フラグメントとすべてのプレフィックスを<name>にリネームし、ステップ3でラベル、データ、タイミング、viewBoxをスキャフォールディングではなく適応させます。そのspec.yamlがあれば、あなたの仕様の開始点になります。 - 同じアーキタイプのみ:通常通りスキャフォールディングし、プールフラグメントを密度、モーション、静止フレームの品質基準として開きます。
- 適合するものなし:仕様から構築します。最も近いプールエントリは依然として一見の価値があります。 プールフラグメントを変更せずにデッキにコピーしないでください。そのストーリーは例であり、ユーザーのものではありません。
2. スロットとブリーフ
スライド上の空きボックスを計測します:python3 <skill-dir>/scripts/measure_slot.py deck.html --slide N [--selector SEL] [--ignore .body]は、ステージピクセル単位のボックス、一致するviewBox、およびチェッカーフラグを出力します(references/layouts.mdに手動での方法が説明されています)。絶対配置のレイアウトでは、--selectorなしでの計測は無効な値を返します。スロットdiv(--selector '#sN-slot'、ステップ0)を計測します。同じアスペクト比のviewBoxを選択し、references/brief-template.mdからanim/<name>/brief.mdを埋めます。ブリーフはviewBoxとレンダリングサイズ、構成、フェーズ、静止フレーム、テーマトークン、最小テキストサイズを固定し、フラグメントがスライド上の何を置き換えるかを指定します(ピル、ボックス図、箇条書き列)。フラグメントの品質はブリーフの品質に依存します。
3. ビルド
python3 <skill-dir>/scripts/scaffold_from_spec.py anim/<name>/spec.yaml -o anim/<name>/<name>.html --rendered-width <px>は仕様を検証し、契約に準拠したスケルトン(レイアウト、フェーズ、パケット、ノート、静止フレーム;フォントサイズはレンダリング幅でフロアに切り上げられます)を書き込み、チェッカーを実行します。出力の先頭のコメントには、手動で洗練するものをリストします。ブリーフが説明するイラストに洗練するには、references/archetypes.md(構成とモーション)、references/motion-rules.md(タイミングとイージング)、references/style.md(ルック:リーン:リングと細い線、ボックスなし、1つの光るアクセント、モノサブラベル、プレーンなキャプション)を使用します。複数のイラストの場合は、共有ブリーフから一度に1つのフラグメントを構築するか、ハーネスが対応している場合はフラグメントごとに1つの並列サブエージェントを使用します。統合は常にメインスレッドで行われます。
4. 見て確認
python3 <skill-dir>/scripts/check_fragment.py anim/<name>/<name>.html --name <name> --rendered-width <px> --stage-width <デッキステージ幅>が合格する必要があります(プレフィックス、トークン、ゲーティング、テキストサイズ、禁止コンテンツ)。--stage-widthはテキストフロアを設定します(1920で18px、1280で12px)。outline.jsonがステージを報告します。<skill-dir>/scripts/render-phases.sh anim/<name> <W> <H> 1.5 4 7 10 restでフェーズPNGとコンタクトシートを、ポーズとネガティブディレイ方式で一時フォルダにレンダリングします(--out DIRでフォルダを指定可能)。統合後、render-phases.sh --page deck.html 1920 1080 restでホストページの静止フレームを確認します。複数スライドページの場合は--slide N(または#hash、CSSセレクタ)を追加します。--no-scriptは、ページ自身のスクリプトがゲートクラスを切り替える場合のタイムドマークまたはフェーズフレームに使用します。restには決して使用しないでください。frontend-slidesデッキでは、.visibleはゲートとスライドを表示するクラスの両方であり、restレンダリングはそれを除去します。スライドはデッキのスクリプトが.activeも設定するためにのみ表示されます。スクリプトなしでは静止フレームは空白になります。すべてのPNGを画像ビューワで開きます。クリッピング、重なり、読めないテキスト、空のパネルを修正します。少なくとも1回は反復します。- 静止フレームは完全な静止画として読める必要があります(PDFエクスポートはそれのみを表示します)。
python3 <skill-dir>/scripts/verify_facts.py anim/<name>/<name>.html --source anim/outline.json --slide <N>(または--source doc.md)が合格する必要があります:フラグメント内のすべての数値はソースに由来するか、例示としてマークされている必要があります。各WARNを読み、トレース不可能な表現をソース自身の言葉に置き換えるか削除します。ルールはreferences/accuracy.mdにあります。このテストに合格するまで図は完了しません。--virtual-time-budgetを信頼せず、PNGの代わりにソースを読み取ることも信頼しないでください。
5. 統合
python3 <skill-dir>/scripts/integrate_fragment.py deck.html anim/<name>/<name>.html --name <name> --anchor '<スライド内の一意の文字列>' [--replace-until '<文字列>'] [--gate 'section.present'] [--control once|step] --backup
スタイルをheadに移動し、<!-- anim:<name>:start -->と<!-- anim:<name>:end -->マーカーの間にフラグメントを挿入し(スタイルはanim-styleマーカーの間)、ホストデッキのゲートを書き換え、すり抜けたクラスにプレフィックスを付けます。プレーンページの場合は、<skill-dir>/scripts/snippets/observer.htmlをページにコピーします。
--controlはラッパーにデッキのコントロールを設定します。--control stepはまた、scripts/snippets/step-host.html(小さなプレーンスクリプト、ライブラリなし)をheadに一度配置し、--gateからゲートを設定します。コントロールは統合時のデッキ全体のスイッチです。別の値で再実行すると変更され、フラグメントはそのまま残ります。
アンカーとuntil文字列は保持されます。それらの間にあるものが置き換えられます。ゲートはホストの「現在のスライド」マーカーです:reveal.jsの場合はsection.present、プレーンページ(scripts/snippets/observer.html)およびmd_to_deck.pyからのデッキの場合は.visible。md_to_deck.pyデッキ、およびステップ0のスロットマーカーを持つデッキスキルデッキでは、フラグメントは本文を置き換えます:--anchor '<!-- sN-body -->' --replace-until '<!-- /sN-body -->'。
スライドの見出しと本文テキストがデッキスクリプトなしで、また印刷時に表示されることを確認します。デッキスキルのエントランスアニメーションは、多くの場合、現在のスライドクラス(frontend-slidesは.slide.visibleの下でのみ.reveal要素を表示)でのみリビールをキーとするため、restレンダリングとPDFは空のスライドを表示します。これらのリビールをデッキのアクティブクラス(.slide.active)でもキーにし、それらを表示する印刷ルールを追加します。(クラス名.revealは、host_theme.pyのスライドセレクタにおけるreveal.js検出とも一致します。今のところ無害ですが、どのスライドが見つかったかを確認してください。)
また、PDFエクスポート(revealの?print-pdfはすべてのスライドを存在としてマーク)が静止フレームを表示するように、印刷ガードを追加します。
作業用デッキはリーンに保ちます:フラグメントは小さなSVGテキストであり、マーカーによって挿入されますが、作業中にフォント、画像、ライブラリ、スタイルシートをインライン化せず、デッキ全体をコンテキストに読み込まないでください。アンカーの周りのスライスを読み取り(grep -n、sed -n)、スクリプトに編集させてください。
次に、実際のブラウザでデッキを開き、待機します。