mcpField
J
json-canvas

json-canvas

github.com/davila7生産性33.0k397 回インストール1 日前に更新
リポジトリ

json-canvas について

Obsidian などで使う有効な JSON Canvas ファイルを作成・編集する Claude Code 向けスキルです。ノード、エッジ、レイアウト、形式の検証ルールを扱います。

主な機能

  1. 01.canvas ファイルの作成と編集
  2. 02テキスト、ファイル、リンク、グループノード
  3. 03エッジとノード間の接続定義
  4. 04レイアウト、色、背景の設定
  5. 05JSON Canvas の検証ルール確認

活用シーン

  1. 01Obsidian のプロジェクトボード作成
  2. 02キャンバス上で研究ファイルやリンクを整理
  3. 03接続関係のある図やフローチャートの作成

インストール

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

$npx skills add https://github.com/davila7/claude-code-templates --skill json-canvas

インストール後、Claude Code で/json-canvasを入力して読み込まれたか確認します。

詳細

JSON Canvas スキル

このスキルにより、Claude Code は 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ノードの色(Color セクションを参照)
テキストノード

テキストノードには 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 進数カラーである必要があります

参考資料

コメント