json-canvas について
Obsidianなどで使われるJSON Canvas(.canvas)ファイルを、互換エージェントが作成・編集するためのスキルです。ノードの種類や接続、色、レイアウトの仕様を扱います。
主な機能
- 01.canvasファイルの作成と編集
- 02テキスト、ファイル、リンク、グループノード
- 03エッジや矢印によるノード接続
- 04色、座標、サイズの設定
- 05JSON Canvas Spec 1.0への準拠
活用シーン
- 01テキストとファイルを結ぶキャンバスの作成
- 02プロジェクトボードのグループ整理
- 03フローチャートの作成
- 04ファイルやリンクを含む調査用キャンバス
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ freestylefly/ canghe-skills --skill json-canvasインストール後、Claude Code で/json-canvasを入力して読み込まれたか確認します。
詳細
JSON Canvas スキル
このスキルを使用すると、スキル互換のエージェントが、Obsidian やその他のアプリケーションで使用される有効な JSON Canvas ファイル(.canvas)を作成および編集できます。
概要
JSON Canvas は、無限キャンバスのデータを扱うオープンなファイル形式です。Canvas ファイルには .canvas 拡張子が付き、JSON Canvas Spec 1.0 に準拠した有効な JSON が含まれます。
ファイル構造
Canvas ファイルには、最上位に次の 2 つの配列があります。
{
"nodes": [],
"edges": []
}
nodes(省略可):ノードオブジェクトの配列edges(省略可):ノード同士を接続するエッジオブジェクトの配列
ノード
ノードは、キャンバス上に配置されるオブジェクトです。ノードには次の 4 種類があります。
text- Markdown を含むテキストコンテンツfile- ファイルや添付ファイルへの参照link- 外部 URLgroup- 他のノードをまとめる視覚的なコンテナー
Z インデックスの順序
配列内では、ノードは Z インデックス順に並びます。
- 最初のノード = 最下層(他のノードの下に表示)
- 最後のノード = 最上層(他のノードの上に表示)
共通のノード属性
すべてのノードに共通する属性は次のとおりです。
| 属性 | 必須 | 型 | 説明 |
|---|---|---|---|
id | はい | string | ノードの一意な識別子 |
type | はい | string | ノードの種類:text、file、link、または group |
x | はい | integer | ピクセル単位の X 座標 |
y | はい | integer | ピクセル単位の Y 座標 |
width | はい | integer | ピクセル単位の幅 |
height | はい | integer | ピクセル単位の高さ |
color | いいえ | canvasColor | ノードの色(「色」セクションを参照) |
テキストノード
テキストノードには Markdown コンテンツが含まれます。
{
"id": "6f0ad84f44ce9c17",
"type": "text",
"x": 0,
"y": 0,
"width": 400,
"height": 200,
"text": "# Hello World\n\nThis is **Markdown** content."
}
| 属性 | 必須 | 型 | 説明 |
|---|---|---|---|
text | はい | string | Markdown 構文を含むプレーンテキスト |
ファイルノード
ファイルノードは、ファイルや添付ファイル(画像、動画、PDF、ノートなど)を参照します。
{
"id": "a1b2c3d4e5f67890",
"type": "file",
"x": 500,
"y": 0,
"width": 400,
"height": 300,
"file": "Attachments/diagram.png"
}
{
"id": "b2c3d4e5f6789012",
"type": "file",
"x": 500,
"y": 400,
"width": 400,
"height": 300,
"file": "Notes/Project Overview.md",
"subpath": "#Implementation"
}
| 属性 | 必須 | 型 | 説明 |
|---|---|---|---|
file | はい | string | システム内のファイルパス |
subpath | いいえ | string | 見出しまたはブロックへのリンク(# で始まる) |
リンクノード
リンクノードには外部 URL が表示されます。
{
"id": "c3d4e5f678901234",
"type": "link",
"x": 1000,
"y": 0,
"width": 400,
"height": 200,
"url": "https://obsidian.md"
}
| 属性 | 必須 | 型 | 説明 |
|---|---|---|---|
url | はい | string | 外部 URL |
グループノード
グループノードは、他のノードを整理するための視覚的なコンテナーです。
{
"id": "d4e5f6789012345a",
"type": "group",
"x": -50,
"y": -50,
"width": 1000,
"height": 600,
"label": "Project Overview",
"color": "4"
}
{
"id": "e5f67890123456ab",
"type": "group",
"x": 0,
"y": 700,
"width": 800,
"height": 500,
"label": "Resources",
"background": "Attachments/background.png",
"backgroundStyle": "cover"
}
| 属性 | 必須 | 型 | 説明 |
|---|---|---|---|
label | いいえ | string | グループのテキストラベル |
background | いいえ | string | 背景画像のパス |
backgroundStyle | いいえ | string | 背景の描画スタイル |
背景スタイル
| 値 | 説明 |
|---|---|
cover | ノードの幅と高さ全体を塗りつぶします |
ratio | 背景画像のアスペクト比を維持します |
repeat | 画像を縦横両方向にパターンとして繰り返します |
エッジ
エッジは、ノード同士を接続する線です。
{
"id": "f67890123456789a",
"fromNode": "6f0ad84f44ce9c17",
"toNode": "a1b2c3d4e5f67890"
}
{
"id": "0123456789abcdef",
"fromNode": "6f0ad84f44ce9c17",
"fromSide": "right",
"fromEnd": "none",
"toNode": "b2c3d4e5f6789012",
"toSide": "left",
"toEnd": "arrow",
"color": "1",
"label": "leads to"
}
| 属性 | 必須 | 型 | デフォルト | 説明 |
|---|---|---|---|---|
id | はい | string | - | エッジの一意な識別子 |
fromNode | はい | string | - | 接続の始点となるノード ID |
fromSide | いいえ | string | - | エッジの始点となる側面 |
fromEnd | いいえ | string | none | エッジの始点の形状 |
toNode | はい | string | - | 接続の終点となるノード ID |
toSide | いいえ | string | - | エッジの終点となる側面 |
toEnd | いいえ | string | arrow | エッジの終点の形状 |
color | いいえ | canvasColor | - | 線の色 |
label | いいえ | string | - | エッジのテキストラベル |
側面の値
| 値 | 説明 |
|---|---|
top | ノードの上辺 |
right | ノードの右辺 |
bottom | ノードの下辺 |
left | ノードの左辺 |
端点の形状
| 値 | 説明 |
|---|---|
none | 端点の形状なし |
arrow | 矢印の端点 |
色
canvasColor 型は、次の 2 通りの方法で指定できます。
16 進数カラー
{
"color": "#FF0000"
}
プリセットカラー
{
"color": "1"
}
| プリセット | 色 |
|---|---|
"1" | 赤 |
"2" | オレンジ |
"3" | 黄 |
"4" | 緑 |
"5" | シアン |
"6" | 紫 |
注: プリセットの具体的な色値は意図的に定義されていません。これにより、アプリケーションは独自のブランドカラーを使用できます。
完全な例
テキストと接続を含むシンプルなキャンバス
{
"nodes": [
{
"id": "8a9b0c1d2e3f4a5b",
"type": "text",
"x": 0,
"y": 0,
"width": 300,
"height": 150,
"text": "# Main Idea\n\nThis is the central concept."
},
{
"id": "1a2b3c4d5e6f7a8b",
"type": "text",
"x": 400,
"y": -100,
"width": 250,
"height": 100,
"text": "## Supporting Point A\n\nDetails here."
},
{
"id": "2b3c4d5e6f7a8b9c",
"type": "text",
"x": 400,
"y": 100,
"width": 250,
"height": 100,
"text": "## Supporting Point B\n\nMore details."
}
],
"edges": [
{
"id": "3c4d5e6f7a8b9c0d",
"fromNode": "8a9b0c1d2e3f4a5b",
"fromSide": "right",
"toNode": "1a2b3c4d5e6f7a8b",
"toSide": "left"
},
{
"id": "4d5e6f7a8b9c0d1e",
"fromNode": "8a9b0c1d2e3f4a5b",
"fromSide": "right",
"toNode": "2b3c4d5e6f7a8b9c",
"toSide": "left"
}
]
}
グループを含むプロジェクトボード
{
"nodes": [
{
"id": "5e6f7a8b9c0d1e2f",
"type": "group",
"x": 0,
"y": 0,
"width": 300,
"height": 500,
"label": "To Do",
"color": "1"
},
{
"id": "6f7a8b9c0d1e2f3a",
"type": "group",
"x": 350,
"y": 0,
"width": 300,
"height": 500,
"label": "In Progress",
"color": "3"
},
{
"id": "7a8b9c0d1e2f3a4b",
"type": "group",
"x": 700,
"y": 0,
"width": 300,
"height": 500,
"label": "Done",
"color": "4"
},
{
"id": "8b9c0d1e2f3a4b5c",
"type": "text",
"x": 20,
"y": 50,
"width": 260,
"height": 80,
"text": "## Task 1\n\nImplement feature X"
},
{
"id": "9c0d1e2f3a4b5c6d",
"type": "text",
"x": 370,
"y": 50,
"width": 260,
"height": 80,
"text": "## Task 2\n\nReview PR #123",
"color": "2"
},
{
"id": "0d1e2f3a4b5c6d7e",
"type": "text",
"x": 720,
"y": 50,
"width": 260,
"height": 80,
"text": "## Task 3\n\n~~Setup CI/CD~~"
}
],
"edges": []
}
ファイルとリンクを含むリサーチキャンバス
{
"nodes": [
{
"id": "1e2f3a4b5c6d7e8f",
"type": "text",
"x": 300,
"y": 200,
"width": 400,
"height": 200,
"text": "# Research Topic\n\n## Key Questions\n\n- How does X affect Y?\n- What are the implications?",
"color": "5"
},
{
"id": "2f3a4b5c6d7e8f9a",
"type": "file",
"x": 0,
"y": 0,
"width": 250,
"height": 150,
"file": "Literature/Paper A.pdf"
},
{
"id": "3a4b5c6d7e8f9a0b",
"type": "file",
"x": 0,
"y": 200,
"width": 250,
"height": 150,
"file": "Notes/Meeting Notes.md",
"subpath": "#Key Insights"
},
{
"id": "4b5c6d7e8f9a0b1c",
"type": "link",
"x": 0,
"y": 400,
"width": 250,
"height": 100,
"url": "https://example.com/research"
},
{
"id": "5c6d7e8f9a0b1c2d",
"type": "file",
"x": 750,
"y": 150,
"width": 300,
"height": 250,
"file": "Attachments/diagram.png"
}
],
"edges": [
{
"id": "6d7e8f9a0b1c2d3e",
"fromNode": "2f3a4b5c6d7e8f9a",
"fromSide": "right",
"toNode": "1e2f3a4b5c6d7e8f",
"toSide": "left",
"label": "supports"
},
{
"id": "7e8f9a0b1c2d3e4f",
"fromNode": "3a4b5c6d7e8f9a0b",
"fromSide": "right",
"toNode": "1e2f3a4b5c6d7e8f",
"toSide": "left",
"label": "informs"
},
{
"id": "8f9a0b1c2d3e4f5a",
"fromNode": "4b5c6d7e8f9a0b1c",
"fromSide": "right",
"toNode": "1e2f3a4b5c6d7e8f",
"toSide": "left",
"toEnd": "arrow",
"color": "6"
},
{
"id": "9a0b1c2d3e4f5a6b",
"fromNode": "1e2f3a4b5c6d7e8f",
"fromSide": "right",
"toNode": "5c6d7e8f9a0b1c2d",
"toSide": "left",
"label": "visualized by"
}
]
}
フローチャート
{
"nodes": [
{
"id": "a0b1c2d3e4f5a6b7",
"type": "text",
"x": 200,
"y": 0,
"width": 150,
"height": 60,
"text": "**Start**",
"color": "4"
},
{
"id": "b1c2d3e4f5a6b7c8",
"type": "text",
"x": 200,
"y": 100,
"width": 150,
"height": 60,
"text": "Step 1:\nGather data"
},
{
"id": "c2d3e4f5a6b7c8d9",
"type": "text",
"x": 200,
"y": 200,
"width": 150,
"height": 80,
"text": "**Decision**\n\nIs data valid?",
"color": "3"
},
{
"id": "d3e4f5a6b7c8d9e0",
"type": "text",
"x": 400,
"y": 200,
"width": 150,
"height": 60,
"text": "Process data"
},
{
"id": "e4f5a6b7c8d9e0f1",
"type": "text",
"x": 0,
"y": 200,
"width": 150,
"height": 60,
"text": "Request new data",
"color": "1"
},
{
"id": "f5a6b7c8d9e0f1a2",
"type": "text",
"x": 400,
"y": 320,
"width": 150,
"height": 60,
"text": "**End**",
"color": "4"
}
],
"edges": [
{
"id": "a6b7c8d9e0f1a2b3",
"fromNode": "a0b1c2d3e4f5a6b7",
"fromSide": "bottom",
"toNode": "b1c2d3e4f5a6b7c8",
"toSide": "top"
},
{
"id": "b7c8d9e0f1a2b3c4",
"fromNode": "b1c2d3e4f5a6b7c8",
"fromSide": "bottom",
"toNode": "c2d3e4f5a6b7c8d9",
"toSide": "top"
},
{
"id": "c8d9e0f1a2b3c4d5",
"fromNode": "c2d3e4f5a6b7c8d9",
"fromSide": "right",
"toNode": "d3e4f5a6b7c8d9e0",
"toSide": "left",
"label": "Yes",
"color": "4"
},
{
"id": "d9e0f1a2b3c4d5e6",
"fromNode": "c2d3e4f5a6b7c8d9",
"fromSide": "left",
"toNode": "e4f5a6b7c8d9e0f1",
"toSide": "right",
"label": "No",
"color": "1"
},
{
"id": "e0f1a2b3c4d5e6f7",
"fromNode": "e4f5a6b7c8d9e0f1",
"fromSide": "top",
"fromEnd": "none",
"toNode": "b1c2d3e4f5a6b7c8",
"toSide": "left",
"toEnd": "arrow"
},
{
"id": "f1a2b3c4d5e6f7a8",
"fromNode": "d3e4f5a6b7c8d9e0",
"fromSide": "bottom",
"toNode": "f5a6b7c8d9e0f1a2",
"toSide": "top"
}
]
}
ID の生成
ノードとエッジの ID は一意の文字列である必要があります。Obsidian は 16 文字の 16 進数 ID を生成します:
"id": "6f0ad84f44ce9c17"
"id": "a3b2c1d0e9f8g7h6"
"id": "1234567890abcdef"
この形式は、16 文字の小文字の 16 進数文字列(64 ビットの乱数値)です。
レイアウトのガイドライン
配置
- 座標は負の値にすることができます(キャンバスは無限に広がります)
xは右方向に増加しますyは下方向に増加します- 位置はノードの左上隅を基準とします
推奨サイズ
| ノードの種類 | 推奨幅 | 推奨高さ |
|---|---|---|
| 小さいテキスト | 200-300 | 80-150 |
| 中程度のテキスト | 300-450 | 150-300 |
| 大きいテキスト | 400-600 | 300-500 |
| ファイルプレビュー | 300-500 | 200-400 |
| リンクプレビュー | 250-400 | 100-200 |
| グループ | 可変 | 可変 |
間隔
- グループの内側には 20-50px の余白を確保してください
- 読みやすさのため、ノード同士は 50-100px 離して配置してください
- よりすっきりしたレイアウトにするため、ノードはグリッド(10 または 20 の倍数)に揃えてください
検証ルール
- すべての
idの値は、ノードとエッジの間で一意である必要があります fromNodeとtoNodeは、既存のノード ID を参照する必要があります- 各ノードの種類に必要なフィールドが存在する必要があります
typeは次のいずれかである必要があります:text、file、link、groupbackgroundStyleは次のいずれかである必要があります:cover、ratio、repeatfromSide、toSideは次のいずれかである必要があります:top、right、bottom、leftfromEnd、toEndは次のいずれかである必要があります:none、arrow- カラープリセットは
"1"から"6"のいずれか、または有効な 16 進数カラーである必要があります