When you drag any Markdown file onto an Obsidian Canvas, Obsidian creates a plain grey file node — it has no way of knowing what color that card was on a previous Canvas. Visual Sync solves this: the plugin intercepts the moment a node is added, reads theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/redsheep913/Canvas-Card-Materializer/llms.txt
Use this file to discover all available pages before exploring further.
canvas_color field from the file’s YAML frontmatter, and immediately applies the correct color to the newly created node. The result is that moving materialized notes between Canvases (or re-opening them on the same Canvas) always restores their original visual context automatically.
How It Works
1. Monkey-Patching canvas.addNode
Obsidian does not expose a native event for when a node is added to a Canvas. To work around this, the plugin patches the addNode method on the Canvas prototype at runtime:
addNode logic is preserved — originalFn.apply(this, arguments) runs first — and then a custom canvas:node:added workspace event is fired with the Canvas instance and the newly added node as arguments.
2. Listening for the Custom Event
The plugin registers a handler forcanvas:node:added during onload:
.md file, then reads its metadata cache to find canvas_color. If the field exists, the color is applied via node.setAttributes({ color: colorStr }) (with a fallback to direct property assignment for older Canvas API versions). If the node exposes a render() method, it is called immediately after to force a visual refresh. Finally, canvas.requestSave() persists the color change to the .canvas file on disk.
3. The 150 ms Delay
ThesetTimeout(..., 150) delay is intentional. When a file node is first added to a Canvas, Obsidian’s metadata cache may not yet have indexed that file’s frontmatter. Waiting 150 ms gives the cache time to populate before the handler tries to read canvas_color.
Frontmatter Requirement
Visual Sync only activates if the Markdown file contains acanvas_color field in its YAML frontmatter. Every file produced by the materialization step includes this field automatically:
canvas_idstores the original Canvas node ID so the file can always be traced back to its source node.canvas_colorstores Obsidian’s internal color identifier (a string from"0"to"6") that maps to the color sub-folder names described in Folder Structure.
canvas_color — are ignored by the Visual Sync handler; their color is left unchanged.
Lazy Patch Application
The monkey-patch is applied lazily rather than immediately at plugin load time, because the Canvas constructor is only accessible through a live Canvas instance:patchCanvasConstructor(), the plugin looks for any open Canvas leaf:
- If a Canvas leaf is found, the patch is applied immediately to that Canvas’s constructor prototype, which covers all Canvas instances in the session.
- If no Canvas leaf is open, the plugin registers a temporary
layout-changelistener and retries as soon as a Canvas leaf appears. Once patched, the listener removes itself.
onunload), the original addNode function is restored to the prototype, leaving no trace of the patch:
Because the patch targets the Canvas constructor’s prototype, it only needs to be applied once per session. All Canvas instances — whether open at startup or opened later — share the same prototype and therefore all benefit from the
canvas:node:added event.