Back to Workflow & Productivity

json-canvas

json canvasobsidiancanvasmind mapflowchartvisual notesknowledge graphproductivity
35.8k📄 MIT🕒 2026-06-08Source ↗

Install this skill

npx skills add kepano/obsidian-skills

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

The JSON Canvas skill allows agents to programmatically generate and manipulate data structures formatted for the open JSON Canvas specification. This format functions as an infinite, coordinate-based layout system. By managing nodes—including text snippets, local file references, external web links, and grouping containers—and defining directional edges between them, the agent can structure visual knowledge graphs. The system relies on Cartesian coordinates and unique identifiers to ensure that nodes and connectors render correctly within Obsidian or compatible viewers. Because the format is strictly JSON, agents can create complex, multi-layered visual workflows by calculating spatial arrangements, establishing color-coded associations, and linking documentation directly through file paths or specific subpath anchors.

When to Use This Skill

  • Generating automated project architecture maps from existing markdown documentation
  • Creating visual mind maps that link multiple technical project files
  • Building dynamic documentation dashboards that aggregate external links and local snippets
  • Constructing organizational flowcharts for complex system requirements

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • Create a new canvas file to organize my project notes
  • Generate a visual map connecting these three markdown files
  • Add a group node to the canvas for organizing these documentation links
  • Draw an arrow edge between the project overview node and the implementation details node
  • Update the canvas file to position the text nodes in a horizontal flow

Pro Tips

  • 💡Leverage the `group` node type to logically organize related information, significantly improving the readability and maintainability of complex canvases.
  • 💡When creating new nodes, specify the `id` attribute carefully to ensure uniqueness across the canvas, as it's crucial for establishing valid edge connections.
  • 💡Always validate the generated JSON against the official JSON Canvas Spec 1.0 to prevent parsing errors and ensure compatibility with target applications like Obsidian.

What this skill does

  • Programmatically generate infinite canvas files following JSON Canvas 1.0 specifications
  • Define and position heterogeneous nodes including markdown text, file links, and web URLs
  • Create visual hierarchies using group nodes with custom background rendering styles
  • Establish structured relationships between nodes using directional edge connections
  • Assign z-index layering to control visual overlap of nodes on the canvas

When not to use it

  • Handling high-frequency, real-time data visualization that requires constant state updates
  • Managing large-scale vector graphics or high-resolution image editing tasks

Example workflow

  1. Identify target nodes and files to be mapped
  2. Calculate spatial coordinates and dimensions for each node
  3. Construct the JSON node array with unique IDs for all items
  4. Define edge connections by referencing the source and target node IDs
  5. Compile the final structure into a .canvas file within the vault
  6. Verify file syntax against the 1.0 specification

Prerequisites

  • Obsidian or a compatible JSON Canvas-enabled viewer
  • Understanding of the target file paths within the workspace

Pitfalls & limitations

  • !Incorrectly referencing IDs leads to broken connections between nodes
  • !Manually overlapping nodes without considering z-index can hide important information
  • !Missing file paths or invalid subpath references render file nodes non-functional

FAQ

Can I link directly to a specific header in a file?
Yes, use the 'subpath' attribute in your file node to define a specific heading or block reference using standard hash syntax.
How do I ensure a node appears in front of another?
The order of nodes in the array dictates the z-index; nodes later in the array render on top of those placed earlier.
Is this format compatible with software other than Obsidian?
The specification is open and adopted by various tools that support the JSON Canvas 1.0 standard.
How do group nodes affect the nodes inside them?
Group nodes act as visual containers; while they do not programmatically encapsulate the children in the JSON structure, they visually organize them within the specified coordinates.

How it compares

Unlike manual dragging in a UI or generic JSON generation, this skill ensures strict adherence to the coordinate and ID-linking requirements defined by the JSON Canvas 1.0 schema, preventing structural corruption in the canvas.

Source & trust

36k stars📄 MIT🕒 Updated 2026-06-08
📄 Full skill instructions — original source: kepano/obsidian-skills
# JSON Canvas Skill

This skill enables skills-compatible agents to create and edit valid JSON Canvas files (.canvas) used in Obsidian and other applications.

## Overview

JSON Canvas is an open file format for infinite canvas data. Canvas files use the .canvas extension and contain valid JSON following the [JSON Canvas Spec 1.0](https://jsoncanvas.org/spec/1.0/).

## File Structure

A canvas file contains two top-level arrays:

{
"nodes": [],
"edges": []
}


- nodes (optional): Array of node objects
- edges (optional): Array of edge objects connecting nodes

## Nodes

Nodes are objects placed on the canvas. There are four node types:
- text - Text content with Markdown
- file - Reference to files/attachments
- link - External URL
- group - Visual container for other nodes

### Z-Index Ordering

Nodes are ordered by z-index in the array:
- First node = bottom layer (displayed below others)
- Last node = top layer (displayed above others)

### Generic Node Attributes

All nodes share these attributes:

| Attribute | Required | Type | Description |
|-----------|----------|------|-------------|
| id | Yes | string | Unique identifier for the node |
| type | Yes | string | Node type: text, file, link, or group |
| x | Yes | integer | X position in pixels |
| y | Yes | integer | Y position in pixels |
| width | Yes | integer | Width in pixels |
| height | Yes | integer | Height in pixels |
| color | No | canvasColor | Node color (see Color section) |

### Text Nodes

Text nodes contain Markdown content.

{
"id": "6f0ad84f44ce9c17",
"type": "text",
"x": 0,
"y": 0,
"width": 400,
"height": 200,
"text": "# Hello World\n\nThis is **Markdown** content."
}


| Attribute | Required | Type | Description |
|-----------|----------|------|-------------|
| text | Yes | string | Plain text with Markdown syntax |

### File Nodes

File nodes reference files or attachments (images, videos, PDFs, notes, etc.).

{
"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"
}


| Attribute | Required | Type | Description |
|-----------|----------|------|-------------|
| file | Yes | string | Path to file within the system |
| subpath | No | string | Link to heading or block (starts with #) |

### Link Nodes

Link nodes display external URLs.

{
"id": "c3d4e5f678901234",
"type": "link",
"x": 1000,
"y": 0,
"width": 400,
"height": 200,
"url": "https://obsidian.md"
}


| Attribute | Required | Type | Description |
|-----------|----------|------|-------------|
| url | Yes | string | External URL |

### Group Nodes

Group nodes are visual containers for organizing other nodes.

{
"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"
}


| Attribute | Required | Type | Description |
|-----------|----------|------|-------------|
| label | No | string | Text label for the group |
| background | No | string | Path to background image |
| backgroundStyle | No | string | Background rendering style |

#### Background Styles

| Value | Description |
|-------|-------------|
| cover | Fills entire width and height of node |
| ratio | Maintains aspect ratio of background image |
| repeat | Repeats image as pattern in both directions |

## Edges

Edges are lines connecting nodes.

{
"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"
}


| Attribute | Required | Type | Default | Description |
|-----------|----------|------|---------|-------------|
| id | Yes | string | - | Unique identifier for the edge |
| fromNode | Yes | string | - | Node ID where connection starts |
| fromSide | No | string | - | Side where edge starts |
| fromEnd | No | string | none | Shape at edge start |
| toNode | Yes | string | - | Node ID where connection ends |
| toSide | No | string | - | Side where edge ends |
| toEnd | No | string | arrow | Shape at edge end |
| color | No | canvasColor | - | Line color |
| label | No | string | - | Text label for the edge |

### Side Values

| Value | Description |
|-------|-------------|
| top | Top edge of node |
| right | Right edge of node |
| bottom | Bottom edge of node |
| left | Left edge of node |

### End Shapes

| Value | Description |
|-------|-------------|
| none | No endpoint shape |
| arrow | Arrow endpoint |

## Colors

The canvasColor type can be specified in two ways:

### Hex Colors

{
"color": "#FF0000"
}


### Preset Colors

{
"color": "1"
}


| Preset | Color |
|--------|-------|
| "1" | Red |
| "2" | Orange |
| "3" | Yellow |
| "4" | Green |
| "5" | Cyan |
| "6" | Purple |

Note: Specific color values for presets are intentionally undefined, allowing applications to use their own brand colors.

## Complete Examples

### Simple Canvas with Text and Connections

{
"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"
}
]
}


### Project Board with Groups

{
"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": []
}


### Research Canvas with Files and Links

{
"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"
}
]
}


### Flowchart

{
"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 Generation

Node and edge IDs must be unique strings. Obsidian generates 16-character hexadecimal IDs:

"id": "6f0ad84f44ce9c17"
"id": "a3b2c1d0e9f8g7h6"
"id": "1234567890abcdef"


This format is a 16-character lowercase hex string (64-bit random value).

## Layout Guidelines

### Positioning

- Coordinates can be negative (canvas extends infinitely)
- x increases to the right
- y increases downward
- Position refers to top-left corner of node

### Recommended Sizes

| Node Type | Suggested Width | Suggested Height |
|-----------|-----------------|------------------|
| Small text | 200-300 | 80-150 |
| Medium text | 300-450 | 150-300 |
| Large text | 400-600 | 300-500 |
| File preview | 300-500 | 200-400 |
| Link preview | 250-400 | 100-200 |
| Group | Varies | Varies |

### Spacing

- Leave 20-50px padding inside groups
- Space nodes 50-100px apart for readability
- Align nodes to grid (multiples of 10 or 20) for cleaner layouts

## Validation Rules

1. All id values must be unique across nodes and edges
2. fromNode and toNode must reference existing node IDs
3. Required fields must be present for each node type
4. type must be one of: text, file, link, group
5. backgroundStyle must be one of: cover, ratio, repeat
6. fromSide, toSide must be one of: top, right, bottom, left
7. fromEnd, toEnd must be one of: none, arrow
8. Color presets must be "1" through "6" or valid hex color

## References

- [JSON Canvas Spec 1.0](https://jsoncanvas.org/spec/1.0/)
- [JSON Canvas GitHub](https://github.com/obsidianmd/jsoncanvas)

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/json-canvas/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/kepano/obsidian-skills/json-canvas/SKILL.md
  • Cursor: ~/.cursor/skills/kepano/obsidian-skills/json-canvas/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/kepano/obsidian-skills/json-canvas/SKILL.md

🚀 Install with CLI:
npx skills add kepano/obsidian-skills

Read the Master Guide: Mastering Agent Skills

Recommended Rules

View more rules

Recommended Workflows

View more workflows

Recommended MCP Servers

View more MCP servers

Take It Further

Maximize your productivity with these powerful resources

📋

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
📖

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid workflow & productivity issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under Workflow & Productivity and is published by Kepano, maintained in kepano/obsidian-skills.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.