edit | blame | history | raw

---
words:

2026-08-25: 919

00index.canvas 自动生成原理说明

一句话概括

00index.canvas 不是 Obsidian 插件生成的,而是由你自建的守护脚本 /Users/ar/bin/tagfeed.py 持续重写的一个 Obsidian Canvas(JSON)文件;Obsidian 里的 Cammvas 社区插件 读取其中的 mindmap: true,把它渲染成「向右展开的目录脑图」。

启动链路(谁把它跑起来)

  1. macOS 登录 / 开机自启~/Library/LaunchAgents/com.ar.tagfeedwatch-login.plist(Label com.ar.tagfeedwatch-loginRunAtLoad=true)执行 /usr/bin/open -g /Users/ar/Applications/TagfeedWatch.app
  2. TagfeedWatch.app/Users/ar/Applications/):只是一个 ~60KB 的 Mach-O 外壳,内部用 /usr/bin/python3 调用真正的脚本。
  3. 真正的生成器/Users/ar/bin/tagfeed.py,以 tagfeed.py --watch 常驻运行,默认 每 3 秒轮询一次 vault(检测到变化后还会等 1.5 秒防抖再处理)。

生成逻辑(每次触发都重画)

核心函数:generate_canvas_index(vault, rel_dir="00index", canvas_name="00index.canvas")(tagfeed.py 约 1124–1291 行)。

  1. 触发条件:每轮用 canvas_signature() 计算 00index 目录的「结构指纹」——所有 .md 文件与子目录的相对路径集合。文件**改名**不改 mtime(普通内容指纹看不见),所以这个独立指纹专门捕捉「增 / 删 / 改名」。指纹变了才重画,否则跳过本轮。
  2. 建树 build():递归遍历 00index,同层文件夹在前、.md 文件在后;跳过 SKIP_DIRS(如 X.Attachment.obsidian)和 CANVAS_SKIP_DIRS={"0inbox"}(实时聚合草稿目录,不进脑图)。
  3. 布局:自底向上算子树高度、每层取最大宽度决定列间距,整体向右展开。
  4. 放置 place():根节点 → 文件夹节点(📁)→ 文件节点。文件节点用**文字节点 + wikilink**([[路径|文件名]])而非 file 节点,避免渲染满屏「笔记属性」预览;点击可直接打开对应笔记。节点 id 由路径经 md5 确定性生成。
  5. 颜色策略:生成器**不再自动上任何颜色**(旧逻辑用 CANVAS_COLORS 给每个分支染红/绿/蓝,会覆盖你手动设的色,已停用)。改为「读取旧画布里已有的 color,按节点 id 匹配后保留」——所以你手动上的色在每次重画后都还在;新出现的节点默认无色,由你上色。
  6. 写盘门控:整张画布序列化为 JSON 后与磁盘现有内容比对,完全相同就**不写盘**,避免无谓改动触发 Obsidian 重载。

渲染(怎么变成脑图)

  • 文件本身是标准 Obsidian Canvas JSON({nodes, edges})。
  • 你装的 Cammvas 插件(社区插件)读取画布里的 mindmap: true,渲染成「向右展开的脑图」样式。
  • 注意:Obsidian 直接打开 .canvas 默认是自由画布视图,要看到脑图需启用 Cammvas 的 mindmap 模式。

涉及的文件 / 插件清单

角色 名称 位置
启动项 LaunchAgent plist ~/Library/LaunchAgents/com.ar.tagfeedwatch-login.plist
外壳 App TagfeedWatch.app /Users/ar/Applications/TagfeedWatch.app
生成脚本 tagfeed.py /Users/ar/bin/tagfeed.py
生成函数 generate_canvas_index() / canvas_signature() tagfeed.py 内(约 1124–1291 行)
渲染插件 Cammvas(社区插件,mindmap 模式) Obsidian 设置 → 社区插件
产物 00index.canvas /Users/ar/Downloads/Syn/Ob/Ob.temp/00index/00index.canvas

关于你刚挪动的 0inbox

你把 00index/标签聚合/0inbox 移到了 00index/0inbox
- 画布CANVAS_SKIP_DIRS={"0inbox"} 按目录名全局跳过,位置变化不影响排除 → 画布依旧不含 0inbox。
- sync_0inbox.py:其 INBOX_DIR="0inbox" 本就拼成 00index/0inbox,与你的新位置一致 → 无需改动脚本。
- 当前画布实测:**73 节点 / 72 连线 / 0 个 0inbox / 72 个带颜色**(即你手动上的色都被成功保留)✅