git clone https://github.com/ComeOnOliver/skillshub
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/kepano/obsidian-skills/json-canvas" ~/.claude/skills/comeonoliver-skillshub-json-canvas-8ca3a2 && rm -rf "$T"
skills/kepano/obsidian-skills/json-canvas/SKILL.mdJSON Canvas Skill
File Structure
A canvas file (
.canvas) contains two top-level arrays following the JSON Canvas Spec 1.0:
{ "nodes": [], "edges": [] }
(optional): Array of node objectsnodes
(optional): Array of edge objects connecting nodesedges
Common Workflows
1. Create a New Canvas
- Create a
file with the base structure.canvas{"nodes": [], "edges": []} - Generate unique 16-character hex IDs for each node (e.g.,
)"6f0ad84f44ce9c17" - Add nodes with required fields:
,id
,type
,x
,y
,widthheight - Add edges referencing valid node IDs via
andfromNodetoNode - Validate: Parse the JSON to confirm it is valid. Verify all
/fromNode
values exist in the nodes arraytoNode
2. Add a Node to an Existing Canvas
- Read and parse the existing
file.canvas - Generate a unique ID that does not collide with existing node or edge IDs
- Choose position (
,x
) that avoids overlapping existing nodes (leave 50-100px spacing)y - Append the new node object to the
arraynodes - 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
andfromNode
to the source and target IDstoNode - Optionally set
/fromSide
(top, right, bottom, left) for anchor pointstoSide - Optionally set
for descriptive text on the edgelabel - Append the edge to the
arrayedges - Validate: Confirm both
andfromNode
reference existing node IDstoNode
4. Edit an Existing Canvas
- Read and parse the
file as JSON.canvas - Locate the target node or edge by
id - 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 |
{ "id": "6f0ad84f44ce9c17", "type": "text", "x": 0, "y": 0, "width": 400, "height": 200, "text": "# Hello World\n\nThis is **Markdown** content." }
Newline pitfall: Use
\n for line breaks in JSON strings. Do not use the literal \\n -- Obsidian renders that as the characters \ and n.
File Nodes
| Attribute | Required | Type | Description |
|---|---|---|---|
| Yes | string | Path to file within the system |
| No | string | Link to heading or block (starts with ) |
{ "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 |
{ "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 |
{ "id": "d4e5f6789012345a", "type": "group", "x": -50, "y": -50, "width": 1000, "height": 600, "label": "Project Overview", "color": "4" }
Edges
Edges connect nodes via
fromNode and toNode 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 |
{ "id": "0123456789abcdef", "fromNode": "6f0ad84f44ce9c17", "fromSide": "right", "toNode": "a1b2c3d4e5f67890", "toSide": "left", "toEnd": "arrow", "label": "leads to" }
Colors
The
canvasColor 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,x
increases down; position is the top-left cornery- 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 edgesid - Every
andfromNode
references an existing node IDtoNode - Required fields are present for each node type (
for text nodes,text
for file nodes,file
for link nodes)url
is one of:type
,text
,file
,linkgroup
/fromSide
values are one of:toSide
,top
,right
,bottomleft
/fromEnd
values are one of:toEnd
,nonearrow- Color presets are
through"1"
or valid hex (e.g.,"6"
)"#FF0000" - 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.