JSON Canvas Skill
File Structure
A canvas file (
) contains two top-level arrays following the
JSON Canvas Spec 1.0:
json
{
"nodes": [],
"edges": []
}
- (optional): Array of node objects
- (optional): Array of edge objects connecting nodes
Common Workflows
1. Create a New Canvas
- Create a file with the base structure
{"nodes": [], "edges": []}
- Generate unique 16-character hex IDs for each node (e.g., )
- Add nodes with required fields: , , , , ,
- Add edges referencing valid node IDs via and
- Validate: Parse the JSON to confirm it is valid. Verify all / values exist in the nodes array
2. Add a Node to an Existing Canvas
- Read and parse the existing file
- Generate a unique ID that does not collide with existing node or edge IDs
- Choose position (, ) that avoids overlapping existing nodes (leave 50-100px spacing)
- Append the new node object to the array
- Optionally add edges connecting the new node to existing nodes
- Validate: Confirm all IDs are unique and all edge references resolve to existing nodes
3. Connect Two Nodes
- Identify the source and target node IDs
- Generate a unique edge ID
- Set and to the source and target IDs
- Optionally set / (top, right, bottom, left) for anchor points
- Optionally set for descriptive text on the edge
- Append the edge to the array
- Validate: Confirm both and reference existing node IDs
4. Edit an Existing Canvas
- Read and parse the file as JSON
- Locate the target node or edge by
- Modify the desired attributes (text, position, color, etc.)
- Write the updated JSON back to the file
- Validate: Re-check all ID uniqueness and edge reference integrity after editing
Nodes
Nodes are objects placed on the canvas. Array order determines z-index: first node = bottom layer, last node = top layer.
Generic Node Attributes
| Attribute | Required | Type | Description |
|---|
| Yes | string | Unique 16-char hex identifier |
| Yes | string | , , , or |
| Yes | integer | X position in pixels |
| Yes | integer | Y position in pixels |
| Yes | integer | Width in pixels |
| Yes | integer | Height in pixels |
| No | canvasColor | Preset - or hex (e.g., ) |
Text Nodes
| Attribute | Required | Type | Description |
|---|
| Yes | string | Plain text with Markdown syntax |
json
{
"id": "6f0ad84f44ce9c17",
"type": "text",
"x": 0,
"y": 0,
"width": 400,
"height": 200,
"text": "# Hello World\n\nThis is **Markdown** content."
}
Newline pitfall: Use
for line breaks in JSON strings. Do
not use the literal
-- Obsidian renders that as the characters
and
.
File Nodes
| Attribute | Required | Type | Description |
|---|
| Yes | string | Path to file within the system |
| No | string | Link to heading or block (starts with ) |
json
{
"id": "a1b2c3d4e5f67890",
"type": "file",
"x": 500,
"y": 0,
"width": 400,
"height": 300,
"file": "Attachments/diagram.png"
}
Link Nodes
| Attribute | Required | Type | Description |
|---|
| Yes | string | External URL |
json
{
"id": "c3d4e5f678901234",
"type": "link",
"x": 1000,
"y": 0,
"width": 400,
"height": 200,
"url": "https://obsidian.md"
}
Group Nodes
Groups are visual containers for organizing other nodes. Position child nodes inside the group's bounds.
| Attribute | Required | Type | Description |
|---|
| No | string | Text label for the group |
| No | string | Path to background image |
| No | string | , , or |
json
{
"id": "d4e5f6789012345a",
"type": "group",
"x": -50,
"y": -50,
"width": 1000,
"height": 600,
"label": "Project Overview",
"color": "4"
}
Edges
Edges connect nodes via
and
IDs.
| Attribute | Required | Type | Default | Description |
|---|
| Yes | string | - | Unique identifier |
| Yes | string | - | Source node ID |
| No | string | - | , , , or |
| No | string | | or |
| Yes | string | - | Target node ID |
| No | string | - | , , , or |
| No | string | | or |
| No | canvasColor | - | Line color |
| No | string | - | Text label |
json
{
"id": "0123456789abcdef",
"fromNode": "6f0ad84f44ce9c17",
"fromSide": "right",
"toNode": "a1b2c3d4e5f67890",
"toSide": "left",
"toEnd": "arrow",
"label": "leads to"
}
Colors
The
type accepts either a hex string or a preset number:
| Preset | Color |
|---|
| Red |
| Orange |
| Yellow |
| Green |
| Cyan |
| Purple |
Preset color values are intentionally undefined -- applications use their own brand colors.
ID Generation
Generate 16-character lowercase hexadecimal strings (64-bit random value):
"6f0ad84f44ce9c17"
"a3b2c1d0e9f8a7b6"
Layout Guidelines
- Coordinates can be negative (canvas extends infinitely)
- increases right, increases down; position is the top-left corner
- Space nodes 50-100px apart; leave 20-50px padding inside groups
- Align to grid (multiples of 10 or 20) for cleaner layouts
| 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 |
Validation Checklist
After creating or editing a canvas file, verify:
- All values are unique across both nodes and edges
- Every and references an existing node ID
- Required fields are present for each node type ( for text nodes, for file nodes, for link nodes)
- is one of: , , ,
- / values are one of: , , ,
- / values are one of: ,
- Color presets are through or valid hex (e.g., )
- JSON is valid and parseable
If validation fails, check for duplicate IDs, dangling edge references, or malformed JSON strings (especially unescaped newlines in text content).
Complete Examples
See references/EXAMPLES.md for full canvas examples including mind maps, project boards, research canvases, and flowcharts.
References