mcpField
J
json-canvas

json-canvas

github.com/mavcui生産性19361 回インストール33 週間前に更新
リポジトリ

json-canvas について

json-canvas は、skills 対応エージェントが Obsidian などで使う JSON Canvas ファイルを作成・編集するためのスキルです。ノード、エッジ、レイアウト、色、検証ルールを扱います。

主な機能

  1. 01.canvas ファイルの作成と編集
  2. 02テキスト、ファイル、リンク、グループのノード
  3. 03エッジと端点の設定
  4. 04色と背景スタイルの指定
  5. 05JSON Canvas Spec 1.0 への準拠

活用シーン

  1. 01テキストと接続を含むキャンバスの作成
  2. 02グループを使ったプロジェクトボードの整理
  3. 03調査用キャンバスやフローチャートの作成

インストール

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

$npx skills add https://github.com/mavcui/agent-skills-hunter --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 - 外部 URL
  • group - 他のノードをまとめる視覚的なコンテナー
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はいstringMarkdown 構文を含むプレーンテキスト
ファイルノード

ファイルノードは、ファイルや添付ファイル(画像、動画、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いいえstringnoneエッジの始点の形状
toNodeはいstring-接続の終点となるノード ID
toSideいいえstring-エッジの終点となる側面
toEndいいえstringarrowエッジの終点の形状
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-30080-150
中程度のテキスト300-450150-300
大きいテキスト400-600300-500
ファイルプレビュー300-500200-400
リンクプレビュー250-400100-200
グループ可変可変
間隔
  • グループの内側には 20-50px の余白を確保してください
  • 読みやすさのため、ノード同士は 50-100px 離して配置してください
  • よりすっきりしたレイアウトにするため、ノードはグリッド(10 または 20 の倍数)に揃えてください

検証ルール

  1. すべての id の値は、ノードとエッジの間で一意である必要があります
  2. fromNode と toNode は、既存のノード ID を参照する必要があります
  3. 各ノードの種類に必要なフィールドが存在する必要があります
  4. type は次のいずれかである必要があります: text、file、link、group
  5. backgroundStyle は次のいずれかである必要があります: cover、ratio、repeat
  6. fromSide、toSide は次のいずれかである必要があります: top、right、bottom、left
  7. fromEnd、toEnd は次のいずれかである必要があります: none、arrow
  8. カラープリセットは "1" から "6" のいずれか、または有効な 16 進数カラーである必要があります

参考資料

コメント