Overview
Basic Memory can create visual representations of your knowledge graph using Obsidian canvas files. These visualizations help you:
See relationships between concepts
Understand knowledge structure
Present ideas visually
Plan projects and workflows
Document architectures
Basic Memory uses the JSON Canvas 1.0 specification , an open format created by Obsidian. Canvas files (.canvas) are JSON files that define:
Nodes - Visual elements representing content
Edges - Connections between nodes
Layout - Positioning and styling
Creating a Canvas
Use the canvas tool to create visualizations:
canvas(
nodes = [ ... ],
edges = [ ... ],
title = "My Canvas" ,
directory = "diagrams"
)
Node Types
Canvas supports four node types:
File Nodes
Text Nodes
Link Nodes
Group Nodes
Reference existing notes: {
"id" : "node1" ,
"type" : "file" ,
"file" : "notes/authentication.md" ,
"x" : 0 ,
"y" : 0 ,
"width" : 400 ,
"height" : 300
}
Key points:
file must reference an existing file path
Path is relative to project root
Obsidian will show file preview
Add standalone text: {
"id" : "node2" ,
"type" : "text" ,
"text" : "This is a text node with **markdown**" ,
"x" : 450 ,
"y" : 0 ,
"width" : 250 ,
"height" : 150
}
Key points:
Supports Markdown formatting
Good for labels and annotations
Doesn’t require an existing file
Embed web content: {
"id" : "node3" ,
"type" : "link" ,
"url" : "https://example.com" ,
"x" : 750 ,
"y" : 0 ,
"width" : 400 ,
"height" : 300
}
Key points:
Embeds web pages in canvas
Useful for external references
Requires valid URL
Organize related nodes: {
"id" : "group1" ,
"type" : "group" ,
"label" : "Core Components" ,
"x" : - 50 ,
"y" : - 50 ,
"width" : 1200 ,
"height" : 400
}
Key points:
Visual container for nodes
Add label for clarity
Position behind other nodes
Edges
Edges connect nodes to show relationships:
{
"id" : "edge1" ,
"fromNode" : "node1" ,
"toNode" : "node2" ,
"label" : "implements"
}
Edge Properties
Unique identifier for the edge
Optional label to describe the relationship
Color as hex code (e.g., "#FF0000") or preset ("1" through "6")
Styling
Node Colors
Style nodes with colors:
{
"id" : "node1" ,
"type" : "text" ,
"text" : "Important" ,
"color" : "1" , # Red
"x" : 0 ,
"y" : 0 ,
"width" : 200 ,
"height" : 100
}
Color presets:
"1" - Red
"2" - Orange
"3" - Yellow
"4" - Green
"5" - Cyan
"6" - Purple
Or use hex colors: "#FF5733"
Edge Colors
Style connections:
{
"id" : "edge1" ,
"fromNode" : "node1" ,
"toNode" : "node2" ,
"color" : "3" , # Yellow
"label" : "depends on"
}
Layout Strategies
Hierarchical Layout
Top-down or left-right hierarchy:
nodes = [
# Top level
{ "id" : "root" , "x" : 400 , "y" : 0 , ... },
# Second level
{ "id" : "child1" , "x" : 100 , "y" : 200 , ... },
{ "id" : "child2" , "x" : 400 , "y" : 200 , ... },
{ "id" : "child3" , "x" : 700 , "y" : 200 , ... },
# Third level
{ "id" : "leaf1" , "x" : 100 , "y" : 400 , ... },
{ "id" : "leaf2" , "x" : 400 , "y" : 400 , ... },
]
Network Layout
Central hub with connections:
import math
# Center node
nodes = [{ "id" : "center" , "x" : 500 , "y" : 500 , ... }]
# Surrounding nodes in circle
for i in range ( 6 ):
angle = ( 2 * math.pi * i) / 6
nodes.append({
"id" : f "node { i } " ,
"x" : 500 + 300 * math.cos(angle),
"y" : 500 + 300 * math.sin(angle),
...
})
Grid Layout
Organized in rows and columns:
row_height = 250
col_width = 350
nodes = []
for row in range ( 3 ):
for col in range ( 4 ):
nodes.append({
"id" : f "node_ { row } _ { col } " ,
"x" : col * col_width,
"y" : row * row_height,
"width" : 300 ,
"height" : 200 ,
...
})
Example Canvases
System Architecture
canvas(
nodes = [
# Frontend
{
"id" : "frontend" ,
"type" : "file" ,
"file" : "docs/frontend-architecture.md" ,
"x" : 0 ,
"y" : 0 ,
"width" : 400 ,
"height" : 300 ,
"color" : "4"
},
# API
{
"id" : "api" ,
"type" : "file" ,
"file" : "docs/api-design.md" ,
"x" : 450 ,
"y" : 0 ,
"width" : 400 ,
"height" : 300 ,
"color" : "5"
},
# Database
{
"id" : "database" ,
"type" : "file" ,
"file" : "docs/database-schema.md" ,
"x" : 900 ,
"y" : 0 ,
"width" : 400 ,
"height" : 300 ,
"color" : "6"
},
],
edges = [
{
"id" : "e1" ,
"fromNode" : "frontend" ,
"toNode" : "api" ,
"label" : "calls"
},
{
"id" : "e2" ,
"fromNode" : "api" ,
"toNode" : "database" ,
"label" : "queries"
},
],
title = "System Architecture" ,
directory = "diagrams"
)
Project Roadmap
canvas(
nodes = [
# Phases
{
"id" : "phase1" ,
"type" : "text" ,
"text" : "## Phase 1: Foundation \n - Setup \n - Basic features" ,
"x" : 0 ,
"y" : 0 ,
"width" : 300 ,
"height" : 200 ,
"color" : "4"
},
{
"id" : "phase2" ,
"type" : "text" ,
"text" : "## Phase 2: Enhancement \n - Advanced features \n - Optimization" ,
"x" : 350 ,
"y" : 0 ,
"width" : 300 ,
"height" : 200 ,
"color" : "3"
},
{
"id" : "phase3" ,
"type" : "text" ,
"text" : "## Phase 3: Launch \n - Testing \n - Deployment" ,
"x" : 700 ,
"y" : 0 ,
"width" : 300 ,
"height" : 200 ,
"color" : "1"
},
],
edges = [
{ "id" : "e1" , "fromNode" : "phase1" , "toNode" : "phase2" },
{ "id" : "e2" , "fromNode" : "phase2" , "toNode" : "phase3" },
],
title = "Project Roadmap" ,
directory = "planning"
)
Concept Map
canvas(
nodes = [
# Central concept
{
"id" : "main" ,
"type" : "file" ,
"file" : "concepts/machine-learning.md" ,
"x" : 400 ,
"y" : 300 ,
"width" : 400 ,
"height" : 300 ,
"color" : "6"
},
# Related concepts
{
"id" : "supervised" ,
"type" : "file" ,
"file" : "concepts/supervised-learning.md" ,
"x" : 0 ,
"y" : 0 ,
"width" : 350 ,
"height" : 250
},
{
"id" : "unsupervised" ,
"type" : "file" ,
"file" : "concepts/unsupervised-learning.md" ,
"x" : 850 ,
"y" : 0 ,
"width" : 350 ,
"height" : 250
},
{
"id" : "reinforcement" ,
"type" : "file" ,
"file" : "concepts/reinforcement-learning.md" ,
"x" : 425 ,
"y" : 650 ,
"width" : 350 ,
"height" : 250
},
],
edges = [
{
"id" : "e1" ,
"fromNode" : "main" ,
"toNode" : "supervised" ,
"label" : "includes"
},
{
"id" : "e2" ,
"fromNode" : "main" ,
"toNode" : "unsupervised" ,
"label" : "includes"
},
{
"id" : "e3" ,
"fromNode" : "main" ,
"toNode" : "reinforcement" ,
"label" : "includes"
},
],
title = "Machine Learning Concepts" ,
directory = "concepts"
)
Working with Claude
Ask Claude to create canvases naturally:
Architecture Visualization
You: Create a canvas showing our authentication system architecture.
Include the frontend, API gateway, auth service, and database.
Show the relationships between components.
Claude: [Creates canvas with file nodes for each component and edges
showing data flow]
Project Planning
You: Make a visual roadmap for Q1 with three phases: foundation,
enhancement, and launch. Show what depends on what.
Claude: [Creates canvas with text nodes for phases and edges showing
dependencies]
Concept Exploration
You: Create a concept map for semantic search showing how it relates
to embeddings, vector databases, and similarity search.
Claude: [Creates canvas linking related concept notes]
Viewing Canvases
Canvas files are stored in your project directory and can be opened in:
Obsidian
Open in Obsidian
Canvas files appear in the file explorer with a canvas icon
Interactive Editing
Drag nodes to reposition
Click edges to edit labels
Add new nodes and connections
Change colors and styling
Pan and Zoom
Scroll to zoom
Click and drag background to pan
Fit to screen with toolbar button
As JSON
Canvas files are plain JSON:
# View canvas file
cat diagrams/architecture.canvas | jq
# Edit with any text editor
code diagrams/architecture.canvas
Advanced Techniques
Dynamic Node IDs
Generate IDs programmatically:
import uuid
nodes = [
{
"id" : str (uuid.uuid4()),
"type" : "text" ,
"text" : f "Node { i } " ,
...
}
for i in range ( 10 )
]
Compute Layout Automatically
Calculate positions based on relationships:
def layout_tree ( root , depth = 0 , offset_x = 0 ):
"""Layout nodes in a tree structure"""
nodes = [{
"id" : root[ "id" ],
"x" : offset_x,
"y" : depth * 250 ,
...
}]
child_width = 400
for i, child in enumerate (root.get( "children" , [])):
child_offset = offset_x + i * child_width
nodes.extend(layout_tree(child, depth + 1 , child_offset))
return nodes
Generate from Knowledge Graph
Create canvas from existing notes:
# Get related notes
context = build_context( "memory://main-topic" )
# Convert to canvas nodes
nodes = []
for i, result in enumerate (context[ "results" ]):
nodes.append({
"id" : result[ "permalink" ],
"type" : "file" ,
"file" : f " { result[ 'permalink' ] } .md" ,
"x" : (i % 3 ) * 400 ,
"y" : (i // 3 ) * 300 ,
"width" : 350 ,
"height" : 250
})
# Create edges from relations
edges = []
for result in context[ "results" ]:
for relation in result.get( "relations" , []):
edges.append({
"id" : f " { result[ 'permalink' ] } - { relation[ 'to' ] } " ,
"fromNode" : result[ "permalink" ],
"toNode" : relation[ "to" ],
"label" : relation[ "type" ]
})
Best Practices
Sketch your layout before asking Claude: "Create a canvas with:
- Main concept at center
- 4 related concepts around it
- Use file nodes for existing notes
- Color code by category"
Maintain readable layouts: # Good spacing
horizontal_gap = 50
vertical_gap = 50
node_width = 400
node_height = 300
x = col * (node_width + horizontal_gap)
y = row * (node_height + vertical_gap)
Use descriptive relationship labels: # Good
{ "label" : "implements" }
{ "label" : "depends on" }
{ "label" : "extends" }
# Avoid
{ "label" : "related" }
{ "label" : "connected" }
Assign colors to indicate categories: # Define color scheme
COLORS = {
"frontend" : "4" , # Green
"backend" : "5" , # Cyan
"database" : "6" , # Purple
"external" : "2" , # Orange
}
Troubleshooting
Canvas won't open in Obsidian
Verify file has .canvas extension
Check JSON is valid: cat file.canvas | jq
Ensure file is in Obsidian vault directory
File nodes show as broken
Verify file path is correct and relative to project root
Check file exists: ls notes/file.md
Use exact path shown in Obsidian file explorer
Increase spacing between nodes
Check x,y coordinates are unique
Consider different layout strategy
Verify fromNode and toNode IDs exist
Check IDs match exactly (case-sensitive)
Ensure nodes have valid positions
Next Steps
Writing Notes Create notes to reference in canvases
Building Context Navigate your knowledge graph
JSON Canvas Spec Full canvas specification
Canvas API Complete API documentation