excalidraw について
excalidrawは、Excalidrawの`.excalidraw`シーンファイルを作成、編集、分析するスキルです。小規模な変更はJSONを直接編集し、大きな図はスクリプトで構築、検査、レンダリングできます。
主な機能
- 01`.excalidraw`シーンファイルの作成と編集
- 02JSONによる手動でのシーン作成
- 03JavaScriptツールチェーンによる図の構築
- 04Mermaid図からExcalidrawシーンへの変換
- 05ジオメトリ検査とSVGプレビューの描画
活用シーン
- 01アーキテクチャ図やフロー図の作成
- 02既存シーンの編集や拡張
- 03シーンの要素を基にした図の要約
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ djalmajr/ skills --skill excalidrawインストール後、Claude Code で/excalidrawを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
examples/architecture.example.mjsreferences/element-reference.mdminimal-scene.excalidrawscripts/.gitignoredom-shim.mjsexcalidraw-lib.mjslint-scene.mjspackage.jsonREADME.mdrender.mjssetup.shscripts/vendor/entry.mjs詳細
excalidraw
.excalidrawファイルを作成・編集します。無限キャンバス上に要素(長方形、
テキスト、矢印)を配置した平面的なシーンです。規模に応じて、次の2つの方法があります。
- 手作業(JSON) — ボックスが少数の場合や、既存のシーンの編集(色の変更、 名前の変更、接続の変更、要素の追加)に適しています。以下の要素形式とバインド/グループ化のルールが 必要です。また、プログラムで作成する場合も同じ形式で出力されるため、どちらの方法でも目を通してください。
- プログラムで作成 — 大規模なものや、継続的にメンテナンスするものに適しています。
scripts/の ツールチェーンは、Excalidraw独自のconvertToExcalidrawElements(相互バインド、コンテナーラベル、テキストサイズ、重ね合わせ順序などの注意点を処理します)を使ってシーンを構築し、exportToSvgで忠実なSVGプレビューをレンダリングし、ジオメトリをリントします。詳しくは、以下のプログラムによる作成を参照してください。
.excalidrawは、Excalidraw独自のディスク上のJSON形式です。Mermaidは別のものですが、 便利な入力形式です。標準的な図形(フローチャート、シーケンス図、クラス図、ER図)には、 Mermaidを記述して、ネイティブなExcalidrawシーンに変換します。エディター組み込みの 「Mermaid to Excalidraw」を使うか、scripts/のfromMermaid()を使います。どちらの方法でも、 その後編集するファイルはExcalidraw JSONです。このスキルでは、その形式を扱います。
使用する場面
.excalidrawファイルを一から作成する(アーキテクチャ図、フロー、ボックスと矢印の図など)。- 既存のシーンを編集する:セクションの追加、一部の置き換え、ボックスの色や名前の変更、 矢印の接続変更。
- シーンを読み取って要約したり、内容を推論したりする(要素から概要を作成する)。
実際のExcalidrawエディターが利用可能で、ユーザーが単に描画したい場合は、エディターを優先してください。 このスキルはファイルを直接生成・編集するためのものです。小規模な作業や編集には手作業の方法を、 複雑な図にはプログラムによる方法(次項)を選んでください。
プログラムによる作成(プレビューとリントの反復)
複雑な図や継続的にメンテナンスする図では、何十個もの要素を手作業で配置せず、scripts/の
JSツールチェーンを使ってください。公式のExcalidraw関数をラップしているため、出力が形式から逸脱することはありません。
convertToExcalidrawElements(skeleton)— Excalidraw独自のコンパイラーです。高レベルの図形と、矢印がどのボックスにつながるかを渡すと、 相互バインド、コンテナーラベル、計測済みテキスト、ID、重ね合わせ順序を含む有効な要素を返します。正確性を大きく向上させる機能です。以下の注意点は、 自分で対処するのではなく、この関数に任せられます。exportToSvg(scene)— ラフな線やフォントなど、実際の見た目をレンダリングするため、近似レンダラーのようにプレビューが実際と異なることはありません。
初回のみのセットアップ(ヘッドレスツールチェーンをインストールし、@excalidraw/*をバンドルします。nodeと
npmに加え、ヘッドレスのテキスト計測用にcanvas/jsdomが必要です):
sh scripts/setup.sh
次に、構築 → リント → レンダリング → 確認 → 反復の順に進めます。
node examples/architecture.example.mjs # build with the Diagram builder
node scripts/lint-scene.mjs /tmp/arch.excalidraw # arrow crossings / label overflow / overlap
node scripts/render.mjs /tmp/arch.excalidraw # -> /tmp/arch.svg (faithful)
rsvg-convert -w 1200 /tmp/arch.svg -o /tmp/arch.png # rasterize, then actually LOOK
レンダリング結果の確認が最も重要です。 JSONが有効でも、読みにくい図になることがあります。たとえば、矢印が無関係なボックスを通ったり、ラベルがカードからはみ出したりします。リンターで機械的な問題を検出し、矢印の経路は目視で確認します。JSONではなく、ビルダーのコードを修正して繰り返してください。
Diagramビルダー(scripts/excalidraw-lib.mjs)では、card()、zone()、note()と、
arrow(a, b, label, {waypoints, dashed, color})を使えます。arrow()は両端をバインドし、絶対座標の経由点を通るように経路を設定します(直交線をきれいにするには、経由点を軸に沿って配置してください)。
fromMermaid()は、標準的な図の種類に対応するMermaidを変換します(依存関係は任意です)。
以下の要素形式リファレンスも引き続き重要です。ビルダーの出力形式であり、小規模なシーンを手作業で編集するときにも、既存ファイルを理解するときにも必要です。
ファイルのエンベロープ
すべての .excalidraw ファイルは、次のトップレベルオブジェクトです。
{
"type": "excalidraw",
"version": 2,
"source": "your-tool-name",
"elements": [ /* the scene, in draw order */ ],
"appState": { "viewBackgroundColor": "#ffffff", "gridSize": null },
"files": {}
}
type/versionは固定値です(現在のスキーマでは"excalidraw"/2)。sourceは、書き込み元が設定する任意の文字列です(例:"my-tool")。elementsはシーン全体です。配列の順序が描画順になります(後の要素ほど手前に描画されます)。その上にテキストや矢印を配置する長方形は、それらより先に置いてください。appStateは最小限に抑えてください。ほとんどのファイルで必要なのはviewBackgroundColorだけです。filesは、ファイル ID をキーとする埋め込み画像のバイナリデータです。図では空の{}にします。
要素モデル
要素は type による判別共用体です。すべての要素に次の共通ブロックが含まれます(以下の値は安全なデフォルト値です)。
| フィールド | 型 | デフォルト値/備考 |
|---|---|---|
id | string | シーン内で一意にします。任意の文字列を使用できます("el-1"、nanoid など)。 |
type | string | "rectangle" | "text" | "arrow"(ほかにもありますが、ほとんどの図ではこの 3 つで対応できます)。 |
x,y | number | キャンバス上の左上の位置です。Y は下方向、X は右方向に増加し、単位は px です。 |
width,height | number | 外接サイズです。矢印の場合は points の範囲です。 |
angle | number | ラジアン単位の回転角です。0 は垂直です。 |
strokeColor | string | 輪郭/テキストの色です。デフォルトは #1e1e1e です。 |
backgroundColor | string | 塗りつぶしの色です。図形を塗りつぶさない場合は "transparent" を指定します。 |
fillStyle | string | "solid" | "hachure" | "cross-hatch"。"solid" を使用してください。 |
strokeWidth | number | 1 は細線、2 は太線(デフォルト)、4 は極太線です。 |
strokeStyle | string | "solid" | "dashed" | "dotted"。 |
roughness | number | 手描き風の度合いです。0 は建築家風(滑らか)、1 はアーティスト風(デフォルト)、2 は漫画家風です。 |
opacity | number | 0~100。 |
groupIds | string[] | グループへの所属を示します。グループを参照してください。[] はグループ化されていない状態です。 |
frameId | string | null | 所属するフレームの ID、または null です。 |
roundness | object | null | 角/曲線のスタイルです。タイプごとの説明を参照してください。 |
seed | number | 任意の整数(Excalidraw の手描き用乱数シード)です。任意の整数を指定できます。 |
versionNonce | number | 任意の整数です。編集のたびに変わります。 |
version | number | 編集カウンターです。1 から始め、変更のたびに増やします。 |
isDeleted | boolean | false。論理削除された要素は、true のままファイルに残ります。 |
boundElements | array | バインドされた矢印/ラベルへの逆参照です。バインディングを参照してください。 |
updated | number | エポックミリ秒のタイムスタンプ(または、決定的な出力に使う単調増加する任意の整数)です。 |
link | string | null | 任意のハイパーリンクです。 |
locked | boolean | false。 |
index(Z オーダー): Excalidraw エディターは、積み重ね順を管理するため、要素ごとに小数インデックス文字列("a0"、"a1"、…)を追加します。手動で作成する場合は省略してください。エディターは配列の順序から、読み込み時にインデックスを割り当てます。一部の要素にだけ設定し、ほかには設定しないでください。インデックスが不完全だと、Z オーダーが破損します。
rectangle
{ "type": "rectangle", "roundness": { "type": 3 }, /* + common fields */ }
roundness: { "type": 3 }→ 角丸になります。roundness: null→ 角が直角になります。- ラベル付きのボックスは、長方形と別個のテキスト要素で構成されます(ラベルを参照してください)。
text
{
"type": "text",
"text": "Login service",
"originalText": "Login service",
"fontSize": 16,
"fontFamily": 2,
"textAlign": "left",
"verticalAlign": "top",
"containerId": null,
"lineHeight": 1.25,
"baseline": 13,
"autoResize": true,
"roundness": null
/* + common fields */
}
textが描画される内容です。originalTextはその内容を反映します(Excalidraw は両方を保持します。理由がわからない限り、両者を同じ値にしてください)。fontFamily:1は手描き風(Virgil)、2は標準(Helvetica、デフォルト)、3はコード向け(Cascadia/等幅フォント)です。width/heightは、描画されるテキストに合わせる必要があります。合っていないと、再計算されるまでエディターの表示が崩れます。フォントメトリクスを利用できない場合は、次の式で概算してください。width ≈ longestLineChars × fontSize × 0.58、height ≈ lineCount × fontSize × 1.25。baseline ≈ round(fontSize × 0.8)。autoResize: trueを設定すると、エディターが読み込み時にサイズを修正します。textAlign:"left" | "center" | "right"。verticalAlign:"top" | "middle" | "bottom"。
arrow
{
"type": "arrow",
"points": [[0, 0], [0, 80]],
"lastCommittedPoint": null,
"startBinding": { "elementId": "el-1", "focus": 0, "gap": 4 },
"endBinding": { "elementId": "el-2", "focus": 0, "gap": 4 },
"startArrowhead": null,
"endArrowhead": "arrow",
"roundness": { "type": 2 }
/* + common fields */
}
pointsは矢印自身のx/yを基準とします。 最初の点は[0, 0]です。矢印のx/yは、キャンバス上の絶対座標における最初の点です。width/heightは、すべての点を囲む範囲です。よくある間違いは、絶対座標の点を保存することです。そうしないでください。- 複数セグメント(直交/エルボー)矢印は、点を増やすだけです。
[[0,0],[0,40],[120,40]]は、下方向に進んでから右方向に進む線を描画します。きれいに経路を描くには、セグメントを軸に沿った(純粋に水平または垂直な)線にしてください。 roundness: { "type": 2 }は曲がり角を丸めます。nullにすると、角が鋭いエルボーになります。endArrowhead/startArrowhead:"arrow"(終点のデフォルト)、null(なし)、または"triangle"、"dot"、"bar"。strokeColorで矢印の色を指定します(控えめな#495057はデフォルト色として見やすいです)。
バインディング — 矢印を図形に追従させる
バインディングは双方向で相互的です。2つの図形の間に矢印をバインドするには、3か所を設定する必要があります。そうしないと、図形を移動したときに矢印が追従しません。
arrow.startBinding = { elementId: from.id, focus: 0, gap: 4 }arrow.endBinding = { elementId: to.id, focus: 0, gap: 4 }- それぞれの図形の
boundElementsに逆参照を追加します。from.boundElements.push({ id: arrow.id, type: "arrow" })を設定し、toにも同様に追加します。
focus(-1〜1)は、バインドされた辺のどの位置に矢印を接続するかを指定します。0は中央です。gapは、矢印の先端と図形の間に保たれるピクセル単位の間隔です(2〜6 が適切です)。- 矢印のバインディングだけを設定し、図形の
boundElementsを設定しない場合、矢印は描画されますが、図形をドラッグした瞬間に切り離されます。必ず両方向を設定してください。 - ビルダーを使ってください。
diagram.arrow(a, b)は、公式コンパイラーを通じて3か所すべてを設定します。手書きのバインディングは、生の JSON を編集するときに限って使用してください。いずれの場合も、lint-scene.mjsは、バインドされていない、一方向のみ、または宙に浮いた矢印があると終了コード1で失敗するようになりました。そのため、シーンを完成とする前に実行してください。移動時に追従しない矢印は、スタイル上の些細な問題ではなくエラーです。
ラベル — ボックス内のテキスト(2つの方法)
A. コンテナーにバインドされたラベル(Excalidraw ネイティブ)。 テキストは子要素になり、エディターがボックス内で自動的に中央揃えし、折り返します。
- テキスト:
containerId = rect.idとし、rect の内側に配置します。 - rect:
boundElementsに{ "type": "text", "id": text.id }を含めます。 ボックスのサイズを変更すると、エディターがラベルを再配置します。人が編集を続ける場合に最適です。
B. 独立したラベル(決定的)。 テキストは、ボックス内の絶対座標 x/y に配置する独立した要素です。containerId: null とし、ボックスの boundElements から参照しません。生成しやすく、動作も完全に予測できますが、自動的な再配置は行われません。生成された静的な図に適しています。よく使われるパターンは「カード」です。角丸の rect、左上付近のタイトルテキスト、その下の任意の小さな本文テキストを組み合わせ、すべてに同じ groupIds を設定します。
グループ
グループとは、各メンバーの groupIds に共通の ID を設定することです。個別のグループオブジェクトはありません。要素をグループ化するには、すべての要素の groupIds に同じグループ ID 文字列を設定します。グループを入れ子にする場合は、ID を重ねて指定します(外側のグループが最後)。視覚的にラベル付きの「コンテナー」を描くには、メンバーの背面に破線の四角形を追加します(strokeStyle: "dashed"、控えめな線色、backgroundColor: "transparent")。これは通常の四角形で、同じグループに含めることもできます。
プログラムによる方法: diagram.group(ids, { title }) は、配置済みのカードから実際のグループを作成します。各カードのすべてのパーツ(rect + タイトル + 本文)に共通の groupId を設定し、任意で破線の枠とラベルを背面に描画します。ブロックをひとまとまりとして移動したい場合は、これを使ってください。card() に渡したものと同じ ID を渡します(groupIds は convertToExcalidrawElements の後も保持されるため、ビルダーはスケルトンに設定するだけです。)
座標とレイアウトの規則
- キャンバスは無限です。任意の原点を選びます(例:
0,0の付近から始めます)。Y 軸は下向きです。 - 列は
xの値を増やしながら左から右へ配置し、行はyの値を増やしながら上から下へ積み重ねます。 - ボックスの間には余白を設けます(例:列間は 80~90px、縦に積み重ねるボックス間は約 28px)。これにより、矢印を配置するスペースができ、関係のない図形と交差しなくなります。
- 矢印を見やすくしたい場合、ボックスを重ねないでください。重なりや、関係のないボックスを通る矢印は、図が乱雑になる主な原因です。
- 見やすく、Excalidraw に適した配色:デフォルトの線の色は
#1e1e1e、落ち着いたグレーは#495057/#868e96/#adb5bd、アクセントカラーは青#1971c2、オレンジ#e8590c、紫#7048e8、緑#2f9e44です。装飾ではなく、意味を示すために色を使います(例:エッジの種類ごとに色相を変える)。
既存のシーンを読み取る
JSON を解析して elements を順に確認します。コンパクトなアウトラインを作成するには(生の JSON よりもモデルが推論しやすくなります):
- 長方形 → ラベルは、
containerIdが長方形の id と一致するテキスト、または長方形の範囲内に配置された独立したテキストです。 - 矢印 →
startBinding.elementId/endBinding.elementIdを、それぞれの図形のラベルに対応付け、「Arrow: "A" → "B"」の形式で出力します。 isDeleted: trueの要素は除外します。非常に大きなシーンには上限を設けます(例:最初の約 200 要素)。
アウトラインの行の形の例:Rectangle "Login"、Arrow: "Login" → "Session" (label: "auth")。
シーンの一部を更新する
既存のファイルに対して実際に行う操作は、次の 3 つです。
1. 既存の内容の下にブロックを追加する
座標を推測せず、測定してずらします。
- 既存の要素の外接ボックスを計算します(
minX/minYとmaxX = max(x+width)、maxY = max(y+height))。 - 追加する要素の外接ボックスを計算します。
dy = existing.maxY + gap − incoming.minY(gapは約 60px が見やすい値です)。dx = 0とします。- 追加する要素すべてを
(dx, dy)だけ移動します。各x/yに値を加えるだけです。矢印のpointsは矢印自身のx/yを基準とするため、x/yを動かせば矢印全体が移動し、点を書き換える必要はありません。バインディングは id を参照するため、変更せずにそのまま維持されます。 - 結合します:
existing.concat(shiftedIncoming)。
2. 領域を置き換える
- 削除する要素を特定します(id、または共通の
groupIdsエントリーで指定します)。 elementsから要素を削除する(完全削除)、または履歴を残すためにisDeleted: trueを設定します。- 参照先がなくなった矢印を再接続します。
startBinding/endBindingが削除した図形を指している矢印については、矢印も削除するか、バインディングのelementIdを置き換え後の図形に付け替えて、その図形のboundElementsを更新します。また、残った図形のboundElementsから、削除した矢印を参照する古いエントリーも削除します。 - 置き換え後の要素を挿入し、新しい矢印を Binding に従ってバインドします。
3. 要素をその場で編集する
フィールドを直接変更し、エディターが適切に変更を反映できるよう通知します。
versionを増やし(version + 1)、versionNonceに新しい整数を設定し、updatedを現在時刻にします。- テキストを変更する場合は、
textとoriginalTextの両方を更新し、width/heightを再計算します(またはautoResize: trueを使用します)。 - 移動・サイズ変更では、
x/y/width/heightを更新します。バインドされた矢印はバインディングによって自動的に追従するため、矢印を編集する必要はありません。 - 色を変更するには、
strokeColor/backgroundColorを変更します。
注意点(実際にシーンを壊す要因)
プログラムによる方法(convertToExcalidrawElements)では、最初の4項目が自動的に処理されます。相互バインディング、相対座標、テキストのサイズ、重ね順が設定されます。これらが問題になるのは、主に手動で作成する場合です。
- 一方向のバインディング → ドラッグすると矢印が外れます。矢印の
*Bindingと図形のboundElementsを必ず設定してください。 - 矢印の絶対座標 → 矢印が誤った位置に描画されます。座標は相対値です。最初の座標は
[0,0]にしてください。 - テキストの
width/heightの欠落 → 再読み込みするまでラベルのサイズが不正になります。おおよその値を設定するか、autoResize: trueを設定してください。 - 一部の
indexフィールドのみ設定 → 重ね順が壊れます。手動で作成する場合は、indexをすべて省略してください。 - ボックスの重なり/無関係な図形を通る矢印 → 図が読みづらくなります。余白を確保し、直交するように経路を設定してください。
- ソフト削除の残骸 →
isDeleted: trueの図形が、ほかの場所にその図形を参照するboundElementsのエントリーを残すことがあります。バインドされた矢印も削除したい場合は、それらを整理してください。 textとoriginalTextの不一致 → 意図的に異なる値にする場合を除き、同じ値にしてください。
リファレンスと実例
references/element-reference.md— フィールドごとの詳細な表、値の一覧(fontFamily、arrowhead、roundness、appState のキー)、バインディング/グループ化の仕様。references/minimal-scene.excalidraw— コピーして調整できる、2つのボックスと1つの矢印を含む完全な読み込み可能シーン。scripts/— プログラムによるツールチェーン:excalidraw-lib.mjs(DiagramビルダーとwriteScene/writeSvg/fromMermaid)、render.mjs(忠実な SVG エクスポート)、lint-scene.mjs(ジオメトリーリンター)、setup.sh(初回インストールとバンドル)。scripts/README.mdを参照してください。examples/architecture.example.mjs— ビルダーを使って作成した、実行可能なエンドツーエンドの図。
信頼できる情報源
上記の要素形式は、Excalidraw 0.18.1 のシーンで検証された、実際に Excalidraw が読み込む最小限のサブセットです。エディターは、往復処理の際に追加フィールド(例:index、要素ごとのカスタムデータ)を追加または保持する場合があります。ここで説明するフィールドがあれば、エディターで問題なく開けるファイルを作成できます。このスキルで扱っていないフィールドについて迷った場合は、Excalidraw エディターで一度図形を描画して保存し、生成された JSON を確認してください。往復処理後のファイルが正しい情報源です。