/canvas-populate
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
$ npx -y skills add AgriciDaniel/claude-canvas --skill canvas-populate --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/canvas-populate
Context preview
The summary Claude sees to decide when to auto-load this skill.
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
SKILL.md
canvas-populate.SKILL.mdname: canvas-populate
description: >
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.
user-invocable: false
canvas-populate: Add Content to Canvases
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.
---
General Workflow
For every add operation:
1. **Read** the target canvas JSON. Parse `nodes` and `edges` arrays. 2. **Collect existing IDs** to prevent collisions. 3. **Generate a new ID**: `[type]-[slug]-[unix-timestamp]`. 4. **Calculate position** using the auto-positioning algorithm (see canvas orchestrator). 5. **Spacing check**: Verify the calculated position has at least 80px horizontal and 60px vertical gap from ALL existing content nodes. If not, shift the position until spacing is clear. 6. **Append** the new node to the `nodes` array (after any groups — z-index ordering). 7. **Validate**: Run `python3 scripts/canvas_validate.py <path>` — check for overlaps and node count. 8. **Write** the updated canvas JSON. 9. **Report**: "Added [description] to [zone] zone at position ([x], [y])."
---
Node Operations
add image (`/canvas add image [path or url]`)
**Resolve the image:**
- If URL (starts with `http`): download with `curl -sL [url] -o [media_dir]/[filename]`.
Derive filename from URL path, or use `img-[timestamp].jpg` if unclear.
- If local path outside canvas dir: `cp [path] [media_dir]/`
- If already canvas-relative: use as-is.
**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.
add text (`/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.
add pdf (`/canvas add pdf [path]`)
Copy to `[media_dir]/` if outside canvas dir. Fixed size: width=400, height=520.
add note (`/canvas add note [wiki-page]`)
1. Search for a file matching the page name (case-insensitive, partial match). 2. Use `"type": "file"` with vault-relative path. Not `"type": "link"` — that's for URLs only. 3. Default size: width=300, height=100.
add link (`/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.
add mermaid (`/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).
add svg (`/canvas add svg [description or path]`)
- If path: copy SVG to media dir, add as file node. Width=400, height based on viewBox aspect ratio.
- If description: delegate to `/svg` skill to generate, then add the output file.
- SVGs render as `<img>` — no interactivity. Must have `viewBox` attribute.
add gif (`/canvas add gif [description or path]`)
- If path: copy GIF to media dir, add as file node.
- If description: delegate to `/claude-gif-generate` skill, then add the output.
- Performance limit: max 3 GIFs per canvas, max 480px width. Warn if exceeded.
add banana (`/canvas add banana [prompt]`)
1. Check if banana skill is available. If not: "Install the banana skill for AI image generation." 2. Delegate to banana skill with the prompt. 3. Wait for image generation. 4. Add the generated image as a file node (detect aspect ratio, auto-size). 5. Log the path to `.recent-images.txt` in the canvas directory.
---
Zone Operations
zone (`/canvas zone [name] [color]`)
1. Read canvas JSON. 2. Find max_y of all existing nodes. Use `-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) + 603. Create group node:
{
"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
4. Insert the group node BEFORE content nodes in the array (z-index: groups render behind). 5. Write and report.
---
Edge Operations
connect (`/canvas connect [from] [to] [label]`)
1. Read canvas JSON. 2. Find `from` and `to` nodes by ID, label text, or partial match. 3. If ambiguous, list matches and ask the user to clarify. 4. Create edge:
{
"id": "e-[from-slug]-[to-slug]-[timestamp]",
"fromNode": "[from-id]",
"toNode": "[to-id]",
"toEnd": "arrow"
}5. Omit `fromSide`/`toSide` for auto-routing (better results). 6. Add optional `label` if provided. 7. Write and report.
---
Banana Import
from banana (`/canvas from banana`)
1. Check `[canvas_dir]/.recent-images.txt` for recently logged image paths. 2. If not found or empty: search for images modified in the last 10 minu
Read more
name: canvas-populate description: > 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. user-invocable: false
canvas-populate: Add Content to Canvases
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.
---
General Workflow
For every add operation:
1. **Read** the target canvas JSON. Parse `nodes` and `edges` arrays. 2. **Collect existing IDs** to prevent collisions. 3. **Generate a new ID**: `[type]-[slug]-[unix-timestamp]`. 4. **Calculate position** using the auto-positioning algorithm (see canvas orchestrator). 5. **Spacing check**: Verify the calculated position has at least 80px horizontal and 60px vertical gap from ALL existing content nodes. If not, shift the position until spacing is clear. 6. **Append** the new node to the `nodes` array (after any groups — z-index ordering). 7. **Validate**: Run `python3 scripts/canvas_validate.py <path>` — check for overlaps and node count. 8. **Write** the updated canvas JSON. 9. **Report**: "Added [description] to [zone] zone at position ([x], [y])."
---
Node Operations
add image (`/canvas add image [path or url]`)
**Resolve the image:**
- If URL (starts with `http`): download with `curl -sL [url] -o [media_dir]/[filename]`.
Derive filename from URL path, or use `img-[timestamp].jpg` if unclear.
- If local path outside canvas dir: `cp [path] [media_dir]/`
- If already canvas-relative: use as-is.
**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.
add text (`/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.
add pdf (`/canvas add pdf [path]`)
Copy to `[media_dir]/` if outside canvas dir. Fixed size: width=400, height=520.
add note (`/canvas add note [wiki-page]`)
1. Search for a file matching the page name (case-insensitive, partial match). 2. Use `"type": "file"` with vault-relative path. Not `"type": "link"` — that's for URLs only. 3. Default size: width=300, height=100.
add link (`/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.
add mermaid (`/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).
add svg (`/canvas add svg [description or path]`)
- If path: copy SVG to media dir, add as file node. Width=400, height based on viewBox aspect ratio.
- If description: delegate to `/svg` skill to generate, then add the output file.
- SVGs render as `<img>` — no interactivity. Must have `viewBox` attribute.
add gif (`/canvas add gif [description or path]`)
- If path: copy GIF to media dir, add as file node.
- If description: delegate to `/claude-gif-generate` skill, then add the output.
- Performance limit: max 3 GIFs per canvas, max 480px width. Warn if exceeded.
add banana (`/canvas add banana [prompt]`)
1. Check if banana skill is available. If not: "Install the banana skill for AI image generation." 2. Delegate to banana skill with the prompt. 3. Wait for image generation. 4. Add the generated image as a file node (detect aspect ratio, auto-size). 5. Log the path to `.recent-images.txt` in the canvas directory.
---
Zone Operations
zone (`/canvas zone [name] [color]`)
1. Read canvas JSON. 2. Find max_y of all existing nodes. Use `-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) + 603. Create group node:
{
"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
4. Insert the group node BEFORE content nodes in the array (z-index: groups render behind). 5. Write and report.
---
Edge Operations
connect (`/canvas connect [from] [to] [label]`)
1. Read canvas JSON. 2. Find `from` and `to` nodes by ID, label text, or partial match. 3. If ambiguous, list matches and ask the user to clarify. 4. Create edge:
{
"id": "e-[from-slug]-[to-slug]-[timestamp]",
"fromNode": "[from-id]",
"toNode": "[to-id]",
"toEnd": "arrow"
}5. Omit `fromSide`/`toSide` for auto-routing (better results). 6. Add optional `label` if provided. 7. Write and report.
---
Banana Import
from banana (`/canvas from banana`)
1. Check `[canvas_dir]/.recent-images.txt` for recently logged image paths. 2. If not found or empty: search for images modified in the last 10 minu
AI-orchestrated visual production for Obsidian Canvas. Create presentations, flowcharts, mood boards, knowledge graphs, and galleries with intelligent layout and AI-generated content.
Other skills on claude-canvas.
- /canvas-create
Create new Obsidian Canvas files — blank with a starter structure, or from one of 12 template archetypes (presentation, flowchart, mind-map, gallery, dashboard, storyboard, knowledge-graph, mood-board, timeline, comparison, kanban, project-brief). Handles directory creation,
Open skill - /canvas-export
Export Obsidian Canvas files to PNG, SVG, or PDF formats. Uses the Advanced Canvas plugin's built-in export when Obsidian is running, or falls back to Playwright browser-based screenshot capture. Supports single canvas export, presentation slide-per-page PDF export, and batch
Open skill - /canvas-generate
AI-orchestrated full canvas generation. Given a description, detects the best archetype, generates content and visuals, instantiates a template, applies layout, and produces a complete canvas. The flagship command. Dispatches canvas-media and canvas-composer agents for parallel
Open skill - /canvas-layout
Re-layout existing Obsidian Canvas nodes using 6 spatial algorithms: grid (galleries, mood boards), dagre (flowcharts, org charts), radial (mind maps), force-directed (knowledge graphs), linear (timelines), and auto-detect. Preserves group membership, snaps to 20px grid, refits
Open skill - /canvas-present
Build presentation-mode canvases for the Advanced Canvas plugin. Creates slide-deck canvases with 1200x675 group nodes connected by edges for arrow-key navigation. Supports title slides, content slides with images, full-text slides, and optional script annotation columns for
Open skill - /canvas-template
Browse and instantiate 12 canvas template archetypes: presentation, flowchart, mind-map, gallery, dashboard, storyboard, knowledge-graph, mood-board, timeline, comparison, kanban, project-brief. Each template generates a ready-to-use canvas with proper layout, zones, and
Open skill

