{“content”:”---\nname: obsidian-canvas-analysis\ndescription: Analyze and modify Obsidian Canvas (.canvas) files — JSON structure, overlap detection, color assignment\n---\n\n# Obsidian Canvas Analysis & Modification\n\n## File Format Discovery\n\nObsidian Canvas files (.canvas) are NOT valid single-line JSON. They are line-delimited JSON — each line is a separate, complete JSON object.\n\n\nFile: 幸福-canvas.canvas (~190KB, 4 lines)\nLine 0: 62613 chars → nodes=329, edges=328\nLine 1: 63600 chars → nodes=334, edges=333 ← most complete\nLine 2: 50 chars → nodes=1, edges=0 (partial)\nLine 3: 63600 chars → nodes=334, edges=333\n\n\nTo parse, split by newline first, then parse each line as JSON:\npython\nwith open('vault.canvas') as f:\n lines = f.read().strip().split('\\n')\nfor i, line in enumerate(lines):\n data = json.loads(line)\n # data has 'nodes' and 'edges' keys\n\n\n## Canvas JSON Structure\n\n### Node\njson\n{\n \"id\": \"n1\",\n \"text\": \"幸福\",\n \"type\": \"text\",\n \"x\": 480,\n \"y\": 20,\n \"width\": 120,\n \"height\": 60,\n \"color\": \"\" // empty = no color, or hex like \"#ff0000\"\n}\n\n\n### Edge\njson\n{\n \"id\": \"e1\",\n \"fromNode\": \"n1\",\n \"fromSide\": \"left\",\n \"toNode\": \"n2\",\n \"toSide\": \"top\"\n}\n\n\n## Overlap Detection\npython\nfor i, n1 in enumerate(nodes):\n for j, n2 in enumerate(nodes):\n if i >= j: continue\n x1,y1,w1,h1 = n1['x'],n1['y'],n1.get('width',100),n1.get('height',40)\n x2,y2,w2,h2 = n2['x'],n2['y'],n2.get('width',100),n2.get('height',40)\n if x1 < x2+w2 and x1+w1 > x2 and y1 < y2+h2 and y1+h1 > y2:\n # overlapping\n\n\n## Color Assignment — CRITICAL LIMITATION\n\npython\n# Assign color to node (per Canvas JSON schema)\nnode['color'] = '#ff6b6b'\n\n\nObsidian Canvas does NOT render the color field. Despite the JSON schema supporting a color hex field on nodes, Obsidian’s canvas rendering ignores it entirely. All nodes appear in monochrome regardless of their color value. This was confirmed empirically on 2026-04-21 — 333 nodes were colored in JSON but rendered as black/white in both PC and mobile Obsidian.\n\nWorkarounds:\n\n1. CSS Snippet — Target canvas nodes via Obsidian theme CSS. Likely selectors: .canvas-node, .canvas-node-content. Unknown if Obsidian exposes node ID or text as CSS-accessible attributes. Not verified to work as of 2026-04-21.\n\n2. Excalidraw — Native background color support; export canvas to .excalidraw format. Excalidraw has working color per-element. See excalidraw skill.\n\n3. Manual — Right-click node in Obsidian Canvas → no color option in the UI.\n\nRecommendation: For colored mind maps, use Excalidraw (.excalidraw) rather than Obsidian Canvas.\n\n## Copying Canvas via SCP (from Termux to PC)\nbash\nscp [email protected]:\"H:/My Drive/Jakephone/Obsidian Vault/幸福-canvas.canvas\" ~/.hermes/tmp_canvas.canvas\n\n\n## Copying Modified Canvas back to PC\nbash\nscp modified.canvas [email protected]:\"H:/My Drive/Jakephone/Obsidian Vault/幸福-canvas.canvas\"\n\n\n## Layout Algorithm Notes\n\nTree/radial layout stretched Y to 19900px — not practical for Obsidian canvas viewing.\n\nCompact layout with overlap-fixing works better:\n- Root at top center, 3 pillars spread horizontally below (x=0, 400, 800)\n- Children fan out right, iterative Y-shifting to resolve overlaps\n- Result: Y range ~6400px, 0 overlaps for 334 nodes\n\n## Color Theme (Sozo’s 幸福 mind map)\n- 身体 (n2): #27ae60 (green)\n- 财富 (n3): #f39c12 (gold)\n- 心理 (n4): #8e44ad (purple)\n\n## Redesign Workflow (fix overlaps + add colors)\n1. SCP canvas from PC → scp [email protected]:\"H:/My Drive/.../幸福-canvas.canvas\" ~/.hermes/tmp.canvas\n2. Parse line-delimited JSON, find line with most nodes\n3. Build tree from edges, identify 3 pillars\n4. Compute compact positions, assign colors\n5. Apply to nodes, save new canvas\n6. SCP back, rename original → BACKUP, rename new → canvas name\n7. Trigger Syncthing scan: curl -X POST \"http://localhost:8384/rest/db/scan?folder=pcf98-nk5lq\" -H \"X-API-Key: ...\"\n\n## Typical Canvas Stats (Sozo’s 幸福 canvas)\n- Nodes: 334\n- Edges: 333\n- Y-levels: 17 (y=20 to y=910)\n- Overlapping pairs: 1621 (due to dense packing)\n- Colored nodes: 333 (in JSON, but NOT rendered by Obsidian)\n- After layout fix: 0 overlaps, Y range ~6400px\n\n## Common Issues\n- Line-delimited JSON causes json.decoder.JSONDecodeError: Extra data if you try to load the whole file at once\n- Canvas uses 0-based Y levels starting at y=20 for root\n- Width of nodes is typically 120-150px, height 36-60px\n”}