$npx -y skills add AgriciDaniel/claude-obsidian --skill canvasVisual layer of the wiki. Add images, text cards, PDFs, and wiki pages to Obsidian canvas files with auto-positioning inside zones. Integrates with /banana for image capture. Triggers on: /canvas, canvas new, canvas add image, canvas add text, canvas add pdf, canvas add note, can
| 1 | # canvas: Visual Reference Layer |
| 2 | |
| 3 | The three knowledge capture layers: |
| 4 | - `/save` → text synthesis (wiki/questions/, wiki/concepts/) |
| 5 | - `/autoresearch` → structured knowledge (wiki/sources/, wiki/concepts/) |
| 6 | - `/canvas` → visual references (wiki/canvases/) |
| 7 | |
| 8 | A canvas is a JSON file Obsidian renders as an infinite visual board. This skill reads and writes canvas JSON directly. Read `references/canvas-spec.md` for the full format reference before making any edits. This spec aligns with the [JSON Canvas open standard](https://jsoncanvas.org/). |
| 9 | |
| 10 | **Substrate preference (v1.7+)**: This skill is a self-contained fallback. **Prefer `kepano/obsidian-skills`** as the authoritative substrate — its `json-canvas` skill is the canonical spec reference. If you see a `json-canvas` skill available without the `claude-obsidian:` namespace, that is kepano's version: use it for spec questions. Continue to use this `canvas` skill for the wiki-scoped *workflows* (positioning into wiki/canvases/, /banana integration, zone layout) — those are unique to claude-obsidian and live above kepano's primitive. Install kepano: `claude plugin marketplace add kepano/obsidian-skills`. |
| 11 | |
| 12 | --- |
| 13 | |
| 14 | ## Default Canvas |
| 15 | |
| 16 | `wiki/canvases/main.canvas` |
| 17 | |
| 18 | If it does not exist, create it: |
| 19 | |
| 20 | ```json |
| 21 | { |
| 22 | "nodes": [ |
| 23 | { |
| 24 | "id": "title", |
| 25 | "type": "text", |
| 26 | "text": "# Visual Reference\n\nDrop images, PDFs, and notes here.", |
| 27 | "x": -400, "y": -300, "width": 400, "height": 120, "color": "6" |
| 28 | }, |
| 29 | { |
| 30 | "id": "zone-default", |
| 31 | "type": "group", |
| 32 | "label": "General", |
| 33 | "x": -400, "y": -140, "width": 800, "height": 400, "color": "4" |
| 34 | } |
| 35 | ], |
| 36 | "edges": [] |
| 37 | } |
| 38 | ``` |
| 39 | |
| 40 | --- |
| 41 | |
| 42 | ## Operations |
| 43 | |
| 44 | ### open / status (`/canvas` with no args) |
| 45 | |
| 46 | 1. Check if `wiki/canvases/main.canvas` exists. |
| 47 | 2. If yes: read it, count nodes by type, list all group node labels (zone names). |
| 48 | Report: "Canvas has N nodes: X images, Y text cards, Z wiki pages. Zones: [list]" |
| 49 | 3. If no: create it with the starter structure above. |
| 50 | Report: "Created main.canvas with a General zone." |
| 51 | 4. Tell user: "Open `wiki/canvases/main.canvas` in Obsidian to view." |
| 52 | |
| 53 | --- |
| 54 | |
| 55 | ### new (`/canvas new [name]`) |
| 56 | |
| 57 | 1. Slugify the name: lowercase, spaces → hyphens, strip special chars. |
| 58 | 2. Create `wiki/canvases/[slug].canvas` with the starter structure, title updated to `# [Name]`. |
| 59 | 3. Add entry to `wiki/overview.md` under a "## Canvases" subsection (append after the Current State section). Do not modify `wiki/index.md`. It uses a fixed section schema (Domains, Entities, Concepts, Sources, Questions, Comparisons). |
| 60 | 4. Report: "Created wiki/canvases/[slug].canvas" |
| 61 | |
| 62 | --- |
| 63 | |
| 64 | ### add image (`/canvas add image [path or url]`) |
| 65 | |
| 66 | **Resolve the image:** |
| 67 | - If URL (starts with `http`): download with `curl -sL [url] -o _attachments/images/canvas/[filename]` |
| 68 | Derive filename from URL path, or use `img-[timestamp].jpg` if unclear. |
| 69 | - If local path outside vault: `cp [path] _attachments/images/canvas/` |
| 70 | - If already vault-relative: use as-is. |
| 71 | |
| 72 | Create `_attachments/images/canvas/` if it doesn't exist. |
| 73 | |
| 74 | **Detect aspect ratio:** |
| 75 | Use `python3 -c "from PIL import Image; img=Image.open('[path]'); print(img.width, img.height)"` or `identify -format '%w %h' [path]`. |
| 76 | See `references/canvas-spec.md` for the full aspect ratio → canvas size table (7 ratios including 4:3, 3:4, ultra-wide). Do not use an inline table here. The spec is the single source of truth for sizing. |
| 77 | |
| 78 | **Position using auto-layout** (see Auto-Positioning section below). |
| 79 | |
| 80 | **Append node to canvas JSON and write.** |
| 81 | |
| 82 | Report: "Added [filename] to [zone] zone at position ([x], [y])." |
| 83 | |
| 84 | --- |
| 85 | |
| 86 | ### add text (`/canvas add text [content]`) |
| 87 | |
| 88 | Create a text node: |
| 89 | ```json |
| 90 | { |
| 91 | "id": "text-[timestamp]", |
| 92 | "type": "text", |
| 93 | "text": "[content]", |
| 94 | "x": [auto], "y": [auto], |
| 95 | "width": 300, "height": 120, |
| 96 | "color": "4" |
| 97 | } |
| 98 | ``` |
| 99 | |
| 100 | Position using auto-layout. Write and report. |
| 101 | |
| 102 | --- |
| 103 | |
| 104 | ### add pdf (`/canvas add pdf [path]`) |
| 105 | |
| 106 | Same as add image. Obsidian renders PDFs natively as file nodes. |
| 107 | - Copy to `_attachments/pdfs/canvas/` if outside vault. |
| 108 | - Fixed size: width=400, height=520. |
| 109 | - Report page count if you can determine it. |
| 110 | |
| 111 | --- |
| 112 | |
| 113 | ### add note (`/canvas add note [wiki-page]`) |
| 114 | |
| 115 | 1. Search `wiki/` for a file matching the page name (case-insensitive, partial match ok). |
| 116 | 2. Use the vault-relative path as the `file` field. |
| 117 | - Use `"type": "file"` (not `"type": "link"`): `.md` files use file nodes, not link nodes. |
| 118 | - `"type": "link"` takes a `url: "https://..."`: it is for web URLs only. |
| 119 | 3. Create a file node: width=300, height=100. |
| 120 | 4. Position us |