Help us improve
Share bugs, ideas, or general feedback.
From claude-canvas
Add content to existing Obsidian Canvas files. Supports all node types: images (with auto aspect ratio detection), text cards, PDFs, wiki notes, web links, Mermaid diagrams, SVGs, GIFs, AI-generated images via banana. Also adds zones (groups), edges between nodes, and imports recent banana images. Triggers on: canvas add, add to canvas, put on canvas, canvas zone, canvas connect, canvas from banana, add image to canvas, add text to canvas.
npx claudepluginhub agricidaniel/claude-canvasHow this skill is triggered — by the user, by Claude, or both
Slash command
/claude-canvas:canvas-populateThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Read `../canvas/references/canvas-spec.md` for the full JSON format before any edit.
Manages Obsidian canvas JSON files: creates visual boards, adds images/text cards/PDFs/wiki pages with zone auto-positioning. Integrates /banana images. Use /canvas commands.
AI-orchestrated visual production for Obsidian Canvas. Create presentations, flowcharts, mood boards, knowledge graphs, galleries, storyboards, timelines, dashboards, and more with intelligent layout and AI-generated content. Claude acts as Creative Director — dispatching sub-agents for image generation, SVG diagrams, GIF creation, and spatial layout. Supports 12 template archetypes, 6 layout algorithms, and Advanced Canvas presentation mode. Triggers on: /canvas, create canvas, build canvas, make a presentation, visual board, mood board, flowchart canvas, storyboard, canvas from template, lay out canvas, export canvas, canvas layout, canvas generate, add to canvas, put this on the canvas, open canvas, canvas present, canvas template.
Create and edit .canvas JSON files for Obsidian, managing nodes, edges, groups, and connections. Ideal for mind maps, flowcharts, and visual diagrams with ID validation.
Share bugs, ideas, or general feedback.
Read ../canvas/references/canvas-spec.md for the full JSON format before any edit.
Read ../canvas/references/performance-guide.md for node limits and constraints.
For every add operation:
nodes and edges arrays.[type]-[slug]-[unix-timestamp].nodes array (after any groups — z-index ordering).python3 scripts/canvas_validate.py <path> — check for overlaps and node count./canvas add image [path or url])Resolve the image:
http): download with curl -sL [url] -o [media_dir]/[filename].
Derive filename from URL path, or use img-[timestamp].jpg if unclear.cp [path] [media_dir]/Detect aspect ratio:
python3 -c "from PIL import Image; img=Image.open('[path]'); print(img.width, img.height)"
# or fallback
identify -format '%w %h' [path]
Map to the sizing table in ../canvas/references/canvas-spec.md (7 ratios + PDF + fallback).
Create file node with calculated dimensions. Position using auto-layout.
/canvas add text [content]){
"id": "text-[slug]-[timestamp]",
"type": "text",
"text": "[content]",
"x": 0, "y": 0,
"width": 300, "height": 120
}
For multi-line content, estimate height: count newlines, multiply by 24, add 40px padding. Minimum 120px.
/canvas add pdf [path])Copy to [media_dir]/ if outside canvas dir. Fixed size: width=400, height=520.
/canvas add note [wiki-page])"type": "file" with vault-relative path. Not "type": "link" — that's for URLs only./canvas add link [url]){
"id": "link-[slug]-[timestamp]",
"type": "link",
"url": "[url]",
"x": 0, "y": 0,
"width": 400, "height": 120
}
Obsidian fetches Open Graph preview automatically.
/canvas add mermaid [code])Mermaid renders natively in Obsidian text nodes. Wrap in a fenced code block:
{
"id": "text-mermaid-[timestamp]",
"type": "text",
"text": "```mermaid\n[code]\n```",
"x": 0, "y": 0,
"width": 500, "height": 400,
"color": "5"
}
Wider text nodes work better for Mermaid (min 400px wide, 300px tall).
/canvas add svg [description or path])/svg skill to generate, then add the output file.<img> — no interactivity. Must have viewBox attribute./canvas add gif [description or path])/claude-gif-generate skill, then add the output./canvas add banana [prompt]).recent-images.txt in the canvas directory./canvas zone [name] [color])-80 if canvas is empty (consistent with starter canvas layout where title is at y=-300 and default zone at y=-140):
if not canvas_nodes:
max_y = -80
else:
max_y = max(n["y"] + n.get("height", 0) for n in canvas_nodes) + 60
{
"id": "zone-[slug]-[timestamp]",
"type": "group",
"label": "[name]",
"x": -400,
"y": "[max_y]",
"width": 1000,
"height": 400,
"color": "[color or '4']"
}
Valid colors: "1"=red "2"=orange "3"=yellow "4"=green "5"=cyan "6"=purple
/canvas connect [from] [to] [label])from and to nodes by ID, label text, or partial match.{
"id": "e-[from-slug]-[to-slug]-[timestamp]",
"fromNode": "[from-id]",
"toNode": "[to-id]",
"toEnd": "arrow"
}
fromSide/toSide for auto-routing (better results).label if provided./canvas from banana)[canvas_dir]/.recent-images.txt for recently logged image paths.find [media_dir] -name "*.png" -o -name "*.jpg" -newer /tmp/ten-min-ago
_attachments/images/canvas/.canvases/assets/