JSON Canvas
3 min read
Open file format for infinite canvas data, created by Obsidian and released under MIT. Uses .canvas extension with standard JSON encoding.
Top-level Structure
json
{
"nodes": [ ... ],
"edges": [ ... ]
}
Both arrays are optional and default to empty.
Nodes
All nodes share a common base:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Unique within the file |
type | string | yes | text, file, link, or group |
x | number | yes | X position (canvas coordinates) |
y | number | yes | Y position (canvas coordinates) |
width | number | yes | Width in pixels |
height | number | yes | Height in pixels |
color | string | no | Preset name or hex #rrggbb |
Text Node
Markdown content embedded directly.
json
{
"id": "abc1",
"type": "text",
"x": 0, "y": 0, "width": 300, "height": 200,
"text": "## Hello\nSome **markdown** content."
}
File Node
References a file by path (relative to the vault/project root).
json
{
"id": "abc2",
"type": "file",
"x": 400, "y": 0, "width": 400, "height": 300,
"file": "notes/project.md",
"subpath": "#Section"
}
• file — relative path to the file
• subpath — optional anchor (#heading) or block reference (^blockid)
Link Node
Embeds a URL (typically rendered as a web preview).
json
{
"id": "abc3",
"type": "link",
"x": 0, "y": 300, "width": 500, "height": 300,
"url": "https://example.com"
}
Group Node
Visual container for organizing other nodes. Does not affect node ownership — nodes are not logically "inside" a group; the group is purely cosmetic.
json
{
"id": "abc4",
"type": "group",
"x": -50, "y": -50, "width": 800, "height": 600,
"label": "Project Overview",
"background": "images/bg.png",
"backgroundStyle": "cover"
}
• label — displayed title for the group
• background — path or URL to a background image
• backgroundStyle — cover, ratio, or repeat
Edges
Edges connect two nodes with an optional directional arrow.
json
{
"id": "edge1",
"fromNode": "abc1",
"fromSide": "right",
"fromEnd": "none",
"toNode": "abc2",
"toSide": "left",
"toEnd": "arrow",
"color": "1",
"label": "relates to"
}
| Field | Type | Required | Values |
|---|---|---|---|
id | string | yes | Unique within file |
fromNode | string | yes | Source node id |
toNode | string | yes | Target node id |
fromSide | string | no | top, right, bottom, left |
toSide | string | no | top, right, bottom, left |
fromEnd | string | no | none (default) or arrow |
toEnd | string | no | none or arrow (default) |
color | string | no | Preset or hex |
label | string | no | Text label shown on the edge |
Colors
Preset color names map to theme-aware values in supporting apps:
| Value | Meaning |
|---|---|
"1" | Red |
"2" | Orange |
"3" | Yellow |
"4" | Green |
"5" | Cyan |
"6" | Purple |
Custom colors use hex strings: "#ff5722".
Coordinate System
• Origin (0, 0) is arbitrary — the canvas is infinite in all directions.
• x increases rightward, y increases downward.
• Node position refers to the top-left corner.
Compatible Applications
• Obsidian — origin app, full read/write support via native canvas view
• Heptabase — partial support
• Logseq — import support
• Miro — export to JSON Canvas
• Various open-source viewers and converters on GitHub
Tooling
bash
# Validate a .canvas file (Node.js library)
npm install jsoncanvas
The jsoncanvas npm package provides a parser, validator, and typed builder API.
Example — Minimal Canvas
json
{
"nodes": [
{
"id": "n1", "type": "text",
"x": 0, "y": 0, "width": 200, "height": 100,
"text": "Start"
},
{
"id": "n2", "type": "text",
"x": 300, "y": 0, "width": 200, "height": 100,
"text": "End"
}
],
"edges": [
{
"id": "e1",
"fromNode": "n1", "toNode": "n2",
"toEnd": "arrow", "label": "leads to"
}
]
}
Spec: https://jsoncanvas.org/spec/1.0/