excalidraw-use について
既存画像を整理した別ファイルのシーンに配置し、対応するスライドデッキの画像化やシーンの検査も行うExcalidraw向けスキルです。説明文から図を生成するのではなく、現在のボードを保護することに重点を置きます。
主な機能
- 01画像を間隔のあるグリッドに配置
- 02ボード上の既存画像を除外
- 03スライドを画像として撮影
- 04シーン要素と画像データを検査
- 05貼り付け用に大きなシーンを分割
活用シーン
- 01Excalidrawボード用の画像トレイ作成
- 02Vite/Reactスライドデッキのスクリーンショット化
- 03画像の整合性と占有範囲の確認
- 04クリップボード貼り付け用に大きなシーンを準備
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ daymade/ claude-code-skills --skill excalidraw-useインストール後、Claude Code で/excalidraw-useを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/deck_screenshot_pitfalls.mdpaste_workflow.mdscene_file_format.mdscripts/build_scene.pyinspect_scene.pyshoot_deck.mjssplit_scene.py詳細
Excalidraw:ボードに画像を追加する
Excalidrawは、その場で描き込めるホワイトボードです。このスキルでは、手作業だと面倒な作業、つまり既存の画像を大量にボードに追加し、あとから画像をドラッグして離す必要がないように配置する作業を扱います。
文章から図を生成するものではありません。「アーキテクチャを描いて」「フローチャートを作って」という依頼は、図の生成に関する作業です。複数のツールやスキルが対応しており、ユーザーがインストールしていれば、gstackスイートのdiagramスキルも利用できます。
どの作業ですか?
| ユーザーの依頼 | 参照先 |
|---|---|
| 「これらの画像をボードに置いて」「古いスクリーンショットをキャンバスに追加して」 | Job 1 — 画像のピックトレイを作成する |
| 「デッキを画像にして」「すべてのスライドをスクリーンショットにして」 | Job 2 — デッキを画像に変換する、その後Job 1 |
| 「このファイルには何が入っている?」「このボードのサイズは?」「何か壊れている?」 | Job 3 — 調査する |
| 「この説明からフローチャートを描いて」 | このスキルではありません |
Job 1 — 画像のピックトレイを作成する
python3 scripts/build_scene.py \
--out tray.excalidraw \
--cols 6 \
--template-from ~/path/to/their-board.excalidraw \
--exclude already-placed.png \
images/*.png
期待される出力 — verified:行が表示されない場合、そのファイルは使用できません。
verified: 30 image element(s), hashes match, no overlap
placed 30 image(s), 6 x 5 grid, min gap 600
wrote tray.excalidraw (3.5 MB)
ファイルと、それをユーザーのボードに追加する方法を伝えてください。 問題が起きるのは後半です。excalidraw.comでは、Openもドラッグ&ドロップも現在のシーン全体を置き換えます。ライブのボードがある人に「このファイルを開いて」と伝えるのは、ボードを失うように伝えるのと同じです。追加するにはクリップボードを使います。手順と理由の詳細は references/paste_workflow.mdにあります。引き継ぎメッセージを書く前に読んでください。
意識して判断すべき点は3つです。
- 既存のボードがある場合は必ず
--template-fromを指定します。 Excalidrawが公開しているJSONスキーマには、トップレベルの構造とfilesマップは記載されていますが、画像要素自体のフィールド(fileId、status、scale、crop)は記載されていません。そのため、ユーザーのボードからライブ要素をコピーするのが、実際に使っているビルドにフィールド一式が合うと確かめる唯一の方法です。指定しない場合は妥当なデフォルトが使われます。これまで問題なく機能していますが、これは確認されたフィールド一式の1つであり、仕様ではありません。 references/scene_file_format.mdにはフィールドごとの詳細がまとめられています。公式ドキュメントに記載されている内容と、実際のファイルから読み取った内容が区別されています。スクリプトにシーンを書き込ませず、手作業で作成または修復する場合は、こちらを開いてください。 - ボードにすでにあるものはすべて
--excludeで除外します。 判定はファイル名ではなく画像の内容で行うため、名前を変更したコピーも検出されます。除外を省くと、同じ画像が2つ並び、1つを手作業で削除することになります。 - 間隔。
--cellは各画像の長辺を合わせるサイズ、--pitchはセルの中心間の距離です。間隔はpitch - cellで、デフォルト(800 / 1400 → 600)は余裕を持たせています。ユーザーが一度でも「間隔をまた直させないで」と言ったことがあるなら、--pitchを下げるのではなく上げてください。
シーンが約15 MBを超える場合は分割してください。大きなシーンではクリップボードで処理が止まります。
python3 scripts/split_scene.py --scene tray.excalidraw --out-dir parts/ --chunks 4
ジョブ 2 — スライドデッキを整った画像に変換する
src/slides/index.ts に、{ id: 'intro', component: S01, fragmentCount: 3 } の形式のエントリでスライドが登録されている Vite/React デッキ向けです。
# 1. Build the deck FROM SOURCE and serve that build (not a dev server).
cd <deck>; npx vite build --outDir /tmp/deck-dist --emptyOutDir
cd /tmp/deck-dist && python3 -m http.server 8080 &
# 2. Shoot it.
node scripts/shoot_deck.mjs \
--index <deck>/src/slides/index.ts \
--url http://127.0.0.1:8080/index.html \
--out shots/ \
--advance pdf # or: keys
期待される出力:
30 slides (7 with fragments), advance=pdf
30/30 captured, 32 inline chrome element(s) hidden -> shots/
all .fragment elements rendered visible (opacity check)
最後の行が重要です。代わりに WARNING: N slide(s) have fragments that never revealed と表示される場合、スクリーンショットにはコンテンツが欠けています。ジョブ 1 には渡さないでください。 references/deck_screenshot_pitfalls.md を確認してください。よくある原因は、配信されているビルドがソースより古いことです。
puppeteer は、スクリプトを実行する場所から解決できる必要があります。 通常、独自に PDF を生成するデッキにはすでに含まれています。そのプロジェクトからスクリプトを実行するか、node_modules をスクリプトの隣にシンボリックリンクしてください。npx puppeteer では、ESM インポートで解決可能なモジュールはインストールされません。
--advance の選び方: デッキの Deck コンポーネントで pdf を検索してください。?pdf=1 クエリを読み取る場合は pdf を、それ以外の場合は keys を使います。両方を使ってはいけません。?pdf=1 ではフラグメントインデックスがすでに最大値になっているため、キーを追加で押すと 次の スライドに進み、気付かないまま誤った内容をキャプチャしてしまいます。
パイプライン内で実行する際に、未表示のフラグメントをゼロ以外の終了コードにしたい場合は --strict を追加してください。.fragment を意図的に非表示にするデッキが実行全体を失敗させないよう、デフォルトでは警告のままです。
ジョブ 3 — シーンを調べる
python3 scripts/inspect_scene.py board.excalidraw --images
種類ごとの要素数、埋め込みペイロードのサイズ、すべての画像要素がキーと一致する内容のファイルを参照しているかどうか、および占有範囲を報告します。読み取り専用です。
実用上役立つ数値は 占有範囲 です。貼り付けたコンテンツはビューポートがある場所に配置されるため、既存の作業がどこにあるかを把握していれば、貼り付ける前にどこまでスクロールすべきかをユーザーに伝えられます。
使用中のボードファイルには絶対に書き込まないでください
別のシーンファイルを作成し、ユーザーにそこから貼り付けてもらいます。実際に確認された独立した理由が 2 つあります。
- ブラウザーのタブで開いているボードは、ディスク上のファイルを変更しても再読み込みされず、次にアプリ内で保存すると、書き込んだ内容が上書きされます。
- ディスク上のファイルは通常、ブラウザーの状態より古いものです。誰かが数日前にエクスポートして以来、タブ上で作業を続けている場合があります。そのエクスポートに結合すると、それ以降の作業がすべて気付かないまま失われます。
結合済みファイルが本当に必要な場合は、新しいパスに書き込み、どれを開くかはユーザーに選んでもらいます。元のファイルを上書きしてはいけません。
トラブルシューティング
| 症状 | 原因 | 解決方法 |
|---|---|---|
| シーンは開くが、画像が空白になる | files エントリがないか、そのキーがペイロードと一致していません | inspect_scene.py が両方を報告します。再構築してください |
| ボード上で画像が接触または重なっている | --pitch が --cell より大きくありません | スクリプトはこの組み合わせを拒否します。--pitch を大きくしてください |
| 貼り付けが機能しない/非常に時間がかかる | シーンがクリップボードに対して大きすぎます | split_scene.py を実行し、分割した各部分を貼り付けてください |
| 貼り付けによってボード全体が置き換わった | コピー&ペーストではなく、開く/ドラッグ&ドロップを使用しました | references/paste_workflow.md を参照し、アプリ内の元に戻す操作で復元してください |
| スライドの後半のコンテンツが欠けている | フラグメントが表示されていません | ソースからデッキを再構築し、再配信して、再撮影してください |
| スライドのスクリーンショットにキー押下のバッジが表示される | バッジが消えるまでの待機時間が短すぎます | スクリプトは最後のキー押下からすでに約 2.9 秒待機します。デッキの表示がさらに長く残る場合は、待機時間を延ばしてください |
Cannot find package 'puppeteer' | スクリプトの場所から解決できません | puppeteer があるプロジェクトから実行してください |
| 画像が誤った形状で描画される | 要素のアスペクト比がソースと一致しません | build_scene.py はこの場合、書き込みを行わずに失敗します |
次のステップ
トレイの作成後に自然に続くのは貼り付けですが、これはユーザー自身にしか行えません。ファイルパス、空きスペースまでスクロールするよう注意を促すメッセージ、そして 3 キーの手順を伝えたら、そこで止めてください。ファイルを「確認」するために excalidraw.com を開いてはいけません。そこでシーンを読み込むと、そのブラウザーの現在のセッションにある内容が置き換わり、保護しようとしていたボードが失われる可能性があります。