fix: 13 skill review issues in /canvas
Critical: - find precedence bug fixed: added \( -name '*.png' -o -name '*.jpg' \) grouping so -newer applies to BOTH extensions, not just .jpg - Auto-positioning row y-detection: replaced broken right-half heuristic with min(n.y for all inside) — matches canvas-spec.md pseudocode - WIKI.md canvas color table corrected: 1=red,2=orange,3=yellow,4=green,5=cyan,6=purple (was wrong mapping 1=blue etc from the graph CSS scheme, not canvas colors) High: - ID generation: full Unix timestamp (10 digits) instead of last-4-digits + added collision fallback (-2, -3 suffix) - README: added /canvas add text and /canvas add pdf to commands table - Aspect ratio: removed duplicate partial table from SKILL.md — now defers to canvas-spec.md as single source of truth - new op: writes to wiki/overview.md not wiki/index.md (index has fixed schema) - from banana: added explicit note that /banana is an optional external skill Medium: - add note: clarified 'type: file' vs 'type: link' — .md files use file nodes - zone fallback y: changed from -140 (overlaps starter) to 280 (safe below all content) - CLAUDE.md: added /save, /autoresearch, /canvas to Plugin Skills table Low: - allowed-tools: removed Grep (unused by any documented operation) - Frontmatter: flattened description to single-line quoted string (fixes IDE YAML block scalar parsing diagnostic on lines 4-9)
This commit is contained in:
2
.obsidian/graph.json
vendored
2
.obsidian/graph.json
vendored
@@ -67,6 +67,6 @@
|
||||
"repelStrength": 20,
|
||||
"linkStrength": 1,
|
||||
"linkDistance": 80,
|
||||
"scale": 0.6620854838064228,
|
||||
"scale": 0.33684385915601145,
|
||||
"close": false
|
||||
}
|
||||
34
.obsidian/workspace.json
vendored
34
.obsidian/workspace.json
vendored
@@ -11,10 +11,14 @@
|
||||
"id": "a31de1b302cdc5cf",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "graph",
|
||||
"state": {},
|
||||
"icon": "lucide-git-fork",
|
||||
"title": "Graph view"
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "CLAUDE.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
},
|
||||
"icon": "lucide-file",
|
||||
"title": "CLAUDE"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -190,20 +194,20 @@
|
||||
},
|
||||
"active": "a31de1b302cdc5cf",
|
||||
"lastOpenFiles": [
|
||||
"README.md.tmp.224546.1775557396282",
|
||||
"README.md.tmp.224546.1775557389171",
|
||||
"README.md.tmp.224546.1775557379648",
|
||||
"skills/wiki/references/plugins.md.tmp.224546.1775557354797",
|
||||
"skills/wiki/SKILL.md.tmp.224546.1775557343437",
|
||||
"README.md.tmp.224546.1775557814794",
|
||||
"CLAUDE.md.tmp.224546.1775557799570",
|
||||
"WIKI.md.tmp.224546.1775557791066",
|
||||
"skills/canvas/SKILL.md.tmp.224546.1775557782936",
|
||||
"skills/canvas/SKILL.md.tmp.224546.1775557766591",
|
||||
"skills/canvas/SKILL.md.tmp.224546.1775557704281",
|
||||
"skills/canvas/SKILL.md.tmp.224546.1775557697284",
|
||||
"skills/canvas/SKILL.md.tmp.224546.1775557686442",
|
||||
"skills/canvas/SKILL.md.tmp.224546.1775557679632",
|
||||
"skills/canvas/SKILL.md.tmp.224546.1775557667692",
|
||||
"skills/canvas/SKILL.md.tmp.224546.1775557654636",
|
||||
"skills/canvas/references/canvas-spec.md",
|
||||
"skills/canvas/references/canvas-spec.md.tmp.224546.1775557327401",
|
||||
"skills/canvas/SKILL.md",
|
||||
"skills/canvas/SKILL.md.tmp.224546.1775557280886",
|
||||
"commands/canvas.md",
|
||||
"commands/canvas.md.tmp.224546.1775557227716",
|
||||
"wiki/canvases",
|
||||
"skills/canvas/references",
|
||||
"skills/canvas",
|
||||
"wiki/comparisons/Wiki vs RAG.md",
|
||||
"wiki/questions/How does the LLM Wiki pattern work.md",
|
||||
"wiki/meta/workflow-loop.gif",
|
||||
|
||||
@@ -54,6 +54,9 @@ Do NOT read the wiki for general coding questions or things already in this proj
|
||||
| `ingest [source]` | Single or batch source ingestion |
|
||||
| `query: [question]` | Answer from wiki content |
|
||||
| `lint the wiki` | Health check |
|
||||
| `/save` | File the current conversation as a structured wiki note |
|
||||
| `/autoresearch [topic]` | Autonomous research loop: search, fetch, synthesize, file |
|
||||
| `/canvas` | Visual layer: add images, PDFs, notes to Obsidian canvas |
|
||||
|
||||
## MCP (Optional)
|
||||
|
||||
|
||||
@@ -83,7 +83,9 @@ Then scaffold the full wiki structure.
|
||||
| `/autoresearch [topic]` | Run the autonomous research loop: search, fetch, synthesize, file |
|
||||
| `/canvas` | Open or create the visual canvas, list zones and nodes |
|
||||
| `/canvas add image [path]` | Add an image (URL or local path) to the canvas with auto-layout |
|
||||
| `/canvas add note [page]` | Pin a wiki page as a card on the canvas |
|
||||
| `/canvas add text [content]` | Add a markdown text card to the canvas |
|
||||
| `/canvas add pdf [path]` | Add a PDF document as a rendered preview node |
|
||||
| `/canvas add note [page]` | Pin a wiki page as a linked card on the canvas |
|
||||
| `/canvas zone [name]` | Add a new labeled zone to organize visual content |
|
||||
| `/canvas from banana` | Capture recently generated images onto the canvas |
|
||||
| `lint the wiki` | Health check: orphans, dead links, gaps, suggestions |
|
||||
|
||||
3
WIKI.md
3
WIKI.md
@@ -822,7 +822,8 @@ Create `.canvas` files for visual overviews:
|
||||
}
|
||||
```
|
||||
|
||||
Colors map to the CSS scheme: 1=blue, 2=purple, 3=yellow, 4=orange, 5=green, 6=red.
|
||||
Canvas node colors (Obsidian canvas color codes): 1=red, 2=orange, 3=yellow, 4=green, 5=cyan, 6=purple.
|
||||
Note: these differ from the wiki graph CSS color scheme. See `skills/canvas/references/canvas-spec.md` for the full canvas color table.
|
||||
|
||||
Create a domain relationship canvas during scaffold. Update as the wiki grows.
|
||||
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
---
|
||||
name: canvas
|
||||
description: >
|
||||
Visual layer of the wiki. Add images, text cards, PDFs, and wiki pages to Obsidian
|
||||
canvas files. Auto-positions nodes inside zones using bbox math. Integrates with
|
||||
/banana skill for generated image capture. Triggers on: "/canvas", "canvas new",
|
||||
"canvas add image", "canvas add text", "canvas add pdf", "canvas add note",
|
||||
"canvas zone", "canvas list", "canvas from banana", "add to canvas",
|
||||
"put this on the canvas", "open canvas", "create canvas".
|
||||
allowed-tools: ["Read", "Write", "Edit", "Bash", "Glob", "Grep"]
|
||||
description: "Visual 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, canvas zone, canvas list, canvas from banana, add to canvas, put this on the canvas, open canvas, create canvas."
|
||||
allowed-tools: ["Read", "Write", "Edit", "Bash", "Glob"]
|
||||
---
|
||||
|
||||
# canvas — Visual Reference Layer
|
||||
@@ -66,7 +60,7 @@ If it does not exist, create it:
|
||||
|
||||
1. Slugify the name: lowercase, spaces → hyphens, strip special chars.
|
||||
2. Create `wiki/canvases/[slug].canvas` with the starter structure, title updated to `# [Name]`.
|
||||
3. Add entry to `wiki/index.md` under a "## Canvases" section (create the section if it doesn't exist).
|
||||
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).
|
||||
4. Report: "Created wiki/canvases/[slug].canvas"
|
||||
|
||||
---
|
||||
@@ -83,10 +77,7 @@ Create `_attachments/images/canvas/` if it doesn't exist.
|
||||
|
||||
**Detect aspect ratio:**
|
||||
Use `python3 -c "from PIL import Image; img=Image.open('[path]'); print(img.width, img.height)"` or `identify -format '%w %h' [path]`.
|
||||
- 16:9 (width/height ≈ 1.7–2.0): width=420, height=236
|
||||
- 1:1 (ratio ≈ 1.0): width=280, height=280
|
||||
- 9:16 (ratio < 0.65): width=200, height=356
|
||||
- Unknown: width=320, height=240
|
||||
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.
|
||||
|
||||
**Position using auto-layout** (see Auto-Positioning section below).
|
||||
|
||||
@@ -127,6 +118,8 @@ Same as add image. Obsidian renders PDFs natively as file nodes.
|
||||
|
||||
1. Search `wiki/` for a file matching the page name (case-insensitive, partial match ok).
|
||||
2. Use the vault-relative path as the `file` field.
|
||||
- Use `"type": "file"` (not `"type": "link"`) — `.md` files use file nodes, not link nodes.
|
||||
- `"type": "link"` takes a `url: "https://..."` — it is for web URLs only.
|
||||
3. Create a file node: width=300, height=100.
|
||||
4. Position using auto-layout.
|
||||
|
||||
@@ -145,7 +138,7 @@ Same as add image. Obsidian renders PDFs natively as file nodes.
|
||||
### zone (`/canvas zone [name] [color]`)
|
||||
|
||||
1. Read canvas JSON.
|
||||
2. Find max_y: `max(node.y + node.height for all nodes) + 60`. Use -140 if no nodes.
|
||||
2. Find max_y: `max(node.y + node.height for all nodes) + 60`. Use 280 if no nodes (leaves room above the starter title node).
|
||||
3. Create a group node:
|
||||
|
||||
```json
|
||||
@@ -183,9 +176,12 @@ wiki/canvases/design-ideas.canvas — 42 nodes (30 images, 4 text, 8 groups)
|
||||
### from banana (`/canvas from banana`)
|
||||
|
||||
1. Check `wiki/canvases/.recent-images.txt` first (session log of newly written images).
|
||||
2. If not found or empty: `find _attachments/images -name "*.png" -o -name "*.jpg" -newer [10min-ago-file]`
|
||||
Create the reference file: `python3 -c "import time; open('/tmp/ten-min-ago','w').close(); import os; os.utime('/tmp/ten-min-ago', (time.time()-600, time.time()-600))"`
|
||||
Then: `find _attachments/images -newer /tmp/ten-min-ago -name "*.png" -o -name "*.jpg"`
|
||||
2. If not found or empty: use `find` with correct precedence (parentheses required — without them `-newer` only binds to the last `-name` clause):
|
||||
```bash
|
||||
python3 -c "import time,os; open('/tmp/ten-min-ago','w').close(); os.utime('/tmp/ten-min-ago',(time.time()-600,time.time()-600))"
|
||||
find _attachments/images -newer /tmp/ten-min-ago \( -name "*.png" -o -name "*.jpg" \)
|
||||
```
|
||||
Note: `/banana` is an optional external skill not shipped in this plugin. If the user has it installed, the `.recent-images.txt` log will be populated. If not, the `find` command above is the fallback.
|
||||
3. If still none: show the 5 most recently modified images.
|
||||
4. Present list: "Found N recent images: [list]. Add to canvas? Which zone? (zone name / 'new [name]' / 'skip')"
|
||||
5. On confirmation: add each using the add image logic.
|
||||
@@ -228,10 +224,8 @@ def next_position(canvas_nodes, target_zone_label, new_w, new_h):
|
||||
max_row_y = max(n['y'] + n.get('height', 0) for n in inside)
|
||||
return zx + 20, max_row_y + 20
|
||||
|
||||
# Same row — match the top y of existing row
|
||||
current_row_y = min(n['y'] for n in inside if n['x'] > zx + zw / 2) \
|
||||
if any(n['x'] > zx + zw / 2 for n in inside) \
|
||||
else zy + 20
|
||||
# Same row — align to the top of all existing nodes in the zone
|
||||
current_row_y = min(n['y'] for n in inside)
|
||||
return next_x, current_row_y
|
||||
```
|
||||
|
||||
@@ -241,9 +235,13 @@ def next_position(canvas_nodes, target_zone_label, new_w, new_h):
|
||||
|
||||
Read the canvas, collect all existing IDs. Never reuse one.
|
||||
|
||||
Safe ID pattern: `[type]-[content-slug]-[unix-timestamp-last-4-digits]`
|
||||
Safe ID pattern: `[type]-[content-slug]-[full-unix-timestamp]`
|
||||
|
||||
Examples: `img-cover-7823`, `text-note-1045`, `zone-branding-3391`
|
||||
Use the full Unix timestamp (10 digits) to avoid collisions in batch operations.
|
||||
|
||||
Examples: `img-cover-1744032823`, `text-note-1744032845`, `zone-branding-1744032901`
|
||||
|
||||
If a collision is detected (ID already exists in the canvas), append `-2`, `-3`, etc.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user