news 2026/9/14 15:44:43

claude-obsidian Canvas 规范详解:Obsidian JSON Canvas 的节点、边、坐标系统与实战避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
claude-obsidian Canvas 规范详解:Obsidian JSON Canvas 的节点、边、坐标系统与实战避坑指南

claude-obsidian Canvas 规范详解:Obsidian JSON Canvas 的节点、边、坐标系统与实战避坑指南

【免费下载链接】claude-obsidianSelf-organizing AI second brain for Obsidian + Claude Code. Drop any source and Claude reads, links, and files it into one connected knowledge graph of plain Markdown you own. AI note-taking, personal knowledge management (PKM), and an open-source Notion alternative. Based on Karpathy's LLM Wiki pattern.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-obsidian

本文围绕 claude-obsidian 仓库中的 Canvas JSON 规范参考 展开,系统讲解.canvas文件的双键结构、四类节点与边的字段语义、坐标系统和配色约定,并进一步结合 Canvas 技能定义、事务模块 和 事务测试 说明该规范如何被工程化地执行:从 ID 生成策略、图像尺寸计算到写作用法的路径与写入范围约束。读完后你可以直接手写或程序化生成合法的 canvas 文件,并理解该仓库为什么要求 canvas 变更必须走可恢复的事务通道。

文件格式与 ID 约定

Canvas 文件本质是 UTF-8 编码的 JSON 文件,扩展名为.canvas,只有两个顶层键:

  • nodes:节点数组;
  • edges:边(连接关系)数组。

该结构对齐 JSON Canvas 1.0 开放规范。所有结构体都支持任意附加字段([key: string]: any)以保持前向兼容——Obsidian 在读写 canvas 文件时会原样保留未知字段。这一点对自动化工具很关键:解析和重写 canvas 时不应丢弃自己不认识的字段,否则会破坏用户在 Obsidian 中保存的视图状态等私有数据。

关于 ID 格式,规范中有明确的产品约定,值得单独强调:

  • JSON Canvas 1.0 只要求每个节点和边的 ID 是唯一字符串,不规定长度或字符集;
  • 该技能的新变更(mutation)偏好随机 16 位小写十六进制 ID(例如"a1b2c3d4e5f67890"),并校验其未被占用;
  • 规范文档较长示例里出现的描述性 ID(如title-0001zone-logos)只是可读性标签,不是生成规则

为什么强调随机 ID?因为规范在"常见错误"一节把ID 冲突列为首要风险:生成新 ID 前必须先读取文件中已存在的全部 ID。随机 16 位 hex 的空间足够大,把碰撞概率降到可忽略水平,同时"校验未使用"这一步是强制的。

坐标系

规范用一张 ASCII 图定义了坐标系统:

x increases → ┌───────────────────────────────── │ (-920, -2400) (0, -2400) │ y │ (-920, 0) (0, 0) ← origin ↓ │ │ (-920, 540) (500, 540)

四条核心规则:

  1. 原点 (0, 0) 是画布视口的中心
  2. x 向右增大,负 x 表示位于中心左侧;
  3. y 向下增大,负 y 表示位于中心上方——注意这与多数数学坐标系相反;
  4. 节点的x/y是节点左上角的坐标,不是中心点;
  5. Obsidian 首次打开画布时会自动平移视图以适配全部节点,所以负坐标完全合法,只是"更靠左/更上"而已。

规范在常见错误一节专门提醒:y: -2400y: -1000上方(越负越靠上)。这是布局脚本中最容易写反的一维——如果你按"屏幕坐标系 y 向上"的直觉摆放节点,整版布局会上下颠倒。

四类节点

Text 节点

把 markdown 内容渲染为带样式的卡片:

{ "id": "text-title-4821", "type": "text", "text": "# Heading\n\nParagraph with **bold** and `code`.", "x": -400, "y": -300, "width": 400, "height": 120, "color": "6" }

要点:

  • text是 markdown 字符串,换行必须写成 JSON 转义的\n,而不是字面的反斜杠加 n 两个字符;
  • 可读的最小尺寸:width ≥ 200height ≥ 60
  • color可选,省略即为默认(无颜色)。

Canvas 技能 在操作手册层补充了两条硬约束:每个节点的xywidthheight都必须是整数;文本节点高度过小虽能渲染但可能被裁剪,经验公式是height ≥ 内容行数 × 24

File 节点

内联渲染库(vault)内的图像、PDF、markdown 笔记或其他文件:

{ "id": "img-cover-7823", "type": "file", "file": "_attachments/images/example.png", "x": -900, "y": -100, "width": 420, "height": 236 }

要点:

  • file必须是vault 相对路径——不能是绝对路径,也不能是~/开头的家目录快捷写法;
  • 支持的类型:.png.jpg.webp.gif.pdf.md.canvas
  • .md文件渲染为预览卡片,.pdf文件渲染首页预览;
  • 与普通节点一样可以携带可选的color字段。

Canvas 技能 对路径安全的要求比规范正文更严格:filebackground一律拒绝绝对路径、..目录穿越、家目录快捷路径,以及通过符号链接逃逸 vault 的路径,并且只能引用已经存在于 vault 内的文件。技能文档还给出了一个增强写法:file可配合可选的subpath: "#Heading"字段,让笔记节点定位到文档内某个标题。

Group 节点(Zone)

带标签的矩形区域。需要特别注意:group 不裁剪也不包含节点,它只是一个视觉参考框。所谓"放在 group 里面",只是把节点定位到了它的包围盒范围内——JSON 中不存在父子关系。

{ "id": "zone-branding-3391", "type": "group", "label": "Brand Identity", "x": -920, "y": -880, "width": 1060, "height": 290, "color": "6", "background": "_attachments/images/grid-bg.png", "backgroundStyle": "cover" }

字段说明:

  • label:显示在 group 框顶部;
  • color:同时着色 group 边框和标签;
  • background(可选):group 背景图,vault 相对路径;
  • backgroundStyle(可选):背景渲染方式——
    • "cover":填满 group,必要时裁切(默认行为);
    • "ratio":保持宽高比,完整放入 group 内部;
    • "repeat":平铺背景图;
  • group 不参与自动布局,纯粹是视觉容器。

Link 节点

把 Web URL 渲染为内嵌预览卡片:

{ "id": "link-karpathy-2233", "type": "link", "url": "https://github.com/karpathy", "x": 200, "y": -300, "width": 400, "height": 120 }

要点与安全边界:

  • url必须是合法的https://URL;
  • Obsidian 会抓取目标页的 Open Graph 元数据(标题、描述、缩略图);
  • 写入 link 节点本身不发起任何网络请求;但用户在 Obsidian 中打开或渲染它时,Obsidian 会访问 URL 所在主机。规范因此要求先向用户披露这一"渲染期出站"(render-time egress),如果用户不接受,就改用 text 节点承载 URL 文本。

Canvas 技能 对此的表述是:link 节点不授予抓取该页面的许可——生成 JSON 无请求,但在 Obsidian 中打开可能拉取该 URL 主机的 Open Graph 元数据,必须先确认用户可接受,否则用 text 节点。

Edges(边)

边表示节点之间的连接,在纯排版型的画布(mood board)上通常留空。

{ "id": "e-hub-cidx", "fromNode": "hub", "fromSide": "right", "fromEnd": "none", "toNode": "c-idx", "toSide": "left", "toEnd": "arrow", "label": "concepts", "color": "5" }

字段语义与默认值(这里有一个容易踩坑的不对称默认值):

字段必填说明
id边的唯一 ID
fromNode/toNode源/目标节点的 ID,必须指向已存在或同批草稿中的节点
fromSide/toSide"top""bottom""left""right";省略时 Obsidian 根据节点相对位置自动计算最佳边
fromEnd源端端帽,默认"none",取值"none"|"arrow"
toEnd目标端端帽,默认"arrow",取值"none"|"arrow"
label显示在边上的文本
color与节点相同的调色板("1""6"或十六进制)

由于大多数边表达有向关系,这个不对称的默认组合(fromEnd: "none"toEnd: "arrow")意味着:什么都不写,就是一条从源指向目标的单箭头。这是规范专门点名的设计意图。

配色参考表

编码颜色近似 Hex典型用途
"1"红 / 番茄色#e03e3e警告、归档
"2"#d09035进行中的工作
"3"黄 / 金#d0a023未完成、笔记
"4"绿 / 青#448361内容、来源
"5"蓝 / 青#3ea7d3导航、信息
"6"紫 / 罗兰#9063d2标题、身份标识

完全省略color字段即为默认外观(无边框色、标签透明)。边的color与节点共用同一调色板,额外支持十六进制值。

图像尺寸计算

file 节点的width/height不应拍脑袋,规范给出的流程是:先用工具读出图像实际像素,再按宽高比查表。

python3 -c "from PIL import Image; img=Image.open('path.png'); print(img.width, img.height)" # 或 identify -format '%w %h' path.png

宽高比对照表:

宽高比条件(ratio)Canvas 宽Canvas 高
16:9(宽屏)1.6–2.0420236
2:1(超宽)> 2.0440220
4:31.2–1.6380285
1:1(正方形)0.9–1.1280280
3:40.6–0.9240320
9:16(竖版)< 0.6200356
PDF任意400520
未知兜底320240

自动定位伪代码

规范提供了一段确定性的放置算法,用于向画布追加节点时的自动布局。它的核心逻辑分三种情况:

function place_node(canvas, zone_label, new_w, new_h): zone = find group node where label == zone_label padding = 20 if zone not found: max_y = max(n.y + n.height for n in canvas.nodes) + 60 return (-400, max_y) # Nodes visually inside zone inside = [n for n in canvas.nodes if n.type != 'group' and zone.x <= n.x < zone.x + zone.width and zone.y <= n.y < zone.y + zone.height] if inside is empty: return (zone.x + padding, zone.y + padding) # Rightmost point in zone rightmost = max(n.x + n.width for n in inside) next_x = rightmost + 40 if next_x + new_w > zone.x + zone.width - padding: # Overflow → new row bottom_of_row = max(n.y + n.height for n in inside) return (zone.x + padding, bottom_of_row + padding) # Same row row_y = min(n.y for n in inside) # align to top of existing row return (next_x, row_y)

逐条解读:

  1. 找不到目标 group时,新节点落在整画布最底部之下 60 px、x = -400 处;
  2. 目标 group 为空时,落在 group 内左上角,留 20 px 内边距;
  3. 同排有空位时,新节点接在"区域内最右点 + 40 px 间隙"处,y 对齐当前行的顶边(取行内最小 y),实现行首对齐;
  4. 横向放不下next_x + new_w越过 group 右边界减去 padding)时,换行:回到 group 左内边距,y 取"当前行底部 + 20 px"。

注意算法用"视觉包含"(坐标落在包围盒内)判断节点属于哪个 zone,而不是任何父子字段——再次印证 group 只是视觉容器。Canvas 技能 在操作手册中把这套参数固化为硬性要求:20 px 内边距、40 px 间隙、必要时换行,group 扩容前需先给出预览。

完整示例:双 Zone 画布

一个最小完整的双分区画布,覆盖 text、group、file 三类节点与空 edges 数组:

{ "nodes": [ { "id": "title-0001", "type": "text", "text": "# Brand Reference\n\n**AI Marketing Hub** visual assets", "x": -920, "y": -2440, "width": 560, "height": 180, "color": "6" }, { "id": "zone-logos", "type": "group", "label": "Logos & Icons", "x": -920, "y": -2200, "width": 1800, "height": 320, "color": "6" }, { "id": "img-logo-pro", "type": "file", "file": "_attachments/images/example.png", "x": -900, "y": -2180, "width": 420, "height": 236 }, { "id": "img-icon-free", "type": "file", "file": "_attachments/images/example-icon.png", "x": -440, "y": -2180, "width": 280, "height": 280 }, { "id": "zone-covers", "type": "group", "label": "Skill Covers", "x": -920, "y": -1820, "width": 1800, "height": 340, "color": "3" }, { "id": "img-seo", "type": "file", "file": "_attachments/images/example-cover.png", "x": -900, "y": -1800, "width": 420, "height": 236 } ], "edges": [] }

从这个示例可以读出几处隐含的布局约定:zone 之间的垂直间距(第一个 zone 底部 y=-1880 到第二个 zone 顶部 y=-1820 留了 60 px)、图像节点相对 group 左内边距 20 px(-920 → -900)、标题区与第一个 zone 之间的 40 px 间隔(-2440+180=-2260 → -2200)。节点数组在技能手册中被明确说明是自底向上的 z-order:重写 canvas 时必须保持现有数组顺序,新节点追加即可。

常见错误清单

规范最后集中列出五类高频错误,前四条与前面各节呼应,最后一条是文本节点的尺寸经验:

  1. 路径格式错误:应使用 vault 相对路径如_attachments/images/file.png,不能是宿主机绝对路径;
  2. ID 冲突:生成新 ID 前必须读取全部现有 ID 并校验唯一性;
  3. 负 y 方向混淆y: -2400y: -1000上方,越负越靠上;
  4. Group 不裁剪:JSON 中没有父子关系,"放进 group" 只是坐标落在包围盒内;
  5. 文本节点高度不足:Obsidian 能渲染但可能裁剪,建议height ≥ 内容行数 × 24

仓库实现侧:规范如何被强制执行

规范文档给出"应该怎么写",而 claude-obsidian 仓库的源码定义了"写坏了会发生什么"。canvas 是 事务模块 中一个独立的操作类型canvas(见OPERATION_TYPES集合),其写入范围在代码中被硬编码约束:

if operation_type == "canvas" and not ( (relative.startswith("wiki/canvases/") and relative.endswith(".canvas")) or relative == "wiki/canvases/index.md" ): raise TransactionValidationError( "WRITE_SCOPE_VIOLATION", "canvas operations may write only wiki/canvases/*.canvas " f"and wiki/canvases/index.md: {relative}", )

(transaction.py)

即 canvas 事务只能wiki/canvases/下的.canvas文件和目录索引wiki/canvases/index.md,任何其它目标都会抛出WRITE_SCOPE_VIOLATION。事务测试 中有对应的最小权限用例:把.raw/.manifest.json(受管元数据)写进 canvas 包会得到MANAGED_METADATA_COLLISION,把wiki/sources/NotACanvas.md写进 canvas 包会得到WRITE_SCOPE_VIOLATION

从源码结构看,这套约束是刻意设计的"操作类型即权限边界":canvasbasefoldcapture等操作类型各自声明了内容域,generic类型也被限定为 wiki-only,即使它名义上最宽泛。

规范与技能手册之间的分工也体现在工程流程上。Canvas 技能 规定完整的变更流程:

  1. 只读操作(状态查询、列表)直接解析.canvas文件,报告节点数、group 标签、悬空边端点和缺失的 vault 相对文件目标;默认画布不存在时只报告并提供创建预览,不在状态请求中创建文件;
  2. 草稿阶段:读取整个 canvas 和目录索引,记录每个目标的期望 SHA-256(必须不存在的文件记null);保留未知字段和数组顺序;新节点要求唯一 ID、整数坐标与尺寸、边端点必须存在;
  3. 校验与预览:JSON 可解析且只用支持的节点类型、ID 唯一、边端点存在、尺寸为正整数、file/background路径安全且存在、新节点不与现有节点意外重叠或溢出目标 group;
  4. 应用阶段:打包为一个claude-obsidian.transaction.v1bundle(操作类型canvas),目录索引若变化则与画布同包提交,然后:
python3 "$CORE" transaction inspect BUNDLE --vault VAULT # Set APPROVAL_SHA256 to the inspect result's approval_sha256 after review. python3 "$CORE" transaction apply BUNDLE --vault VAULT \ --approved-plan-sha256 "$APPROVAL_SHA256"

approval_sha256来自 inspect 结果,它把展开后的计划绑定到规范化的 vault 根,不能复用于另一个 vault——这一机制在 操作事务参考 中有完整契约说明(预期哈希、原子替换、持久化日志、可恢复回滚)。

对于删除、替换、改名等破坏性变更,技能要求先展示预览并获得明确同意,然后报告操作 ID、变更路径、板名、节点 ID 和最终坐标,且不做 Git 提交——若需要版本历史,走独立的显式 checkpoint 命令。

另外值得一提的旁路保护:仓库的 URL 凭据检测模块 会拦截 userinfo 凭据和敏感查询参数(token、api_key、X-Amz-Signature 等)。虽然它服务于 URL 校验场景而非 canvas JSON 本身,但与规范中 link 节点"披露渲染期出站"的要求共同构成该仓库对外部资源的一贯审慎态度:canvas 里放一个 URL 是纯本地 JSON 写入,而网络行为只发生在用户在 Obsidian 里打开它的那一刻。

小结

把 canvas-spec.md 当作生成.canvas文件的事实标准:双键结构 + 未知字段保留、左上角锚定的 y 向下坐标系、text/file/group/link 四类节点各自的必填与可选字段、边的不对称默认箭头、"1""6"调色板、按宽高比查表的图像尺寸、20/40 px 的自动定位参数,加上五条常见错误清单,就是一份可直接落地的生成规则。而 Canvas 技能 与 事务实现 则在其外围加了两层护栏——vault 相对路径安全校验和wiki/canvases/的写入域约束——确保程序化生成的画布既符合规范格式,又不会越权改动 vault 的其他部分。

【免费下载链接】claude-obsidianSelf-organizing AI second brain for Obsidian + Claude Code. Drop any source and Claude reads, links, and files it into one connected knowledge graph of plain Markdown you own. AI note-taking, personal knowledge management (PKM), and an open-source Notion alternative. Based on Karpathy's LLM Wiki pattern.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-obsidian

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 15:43:29

Autoware 完整指南:从克隆仓库到跑通自动驾驶软件栈

Autoware 完整指南&#xff1a;从克隆仓库到跑通自动驾驶软件栈 【免费下载链接】autoware Autoware - the worlds leading open-source software project for autonomous driving 项目地址: https://gitcode.com/GitHub_Trending/au/autoware 想把一套完整的自动驾驶系…

作者头像 李华
网站建设 2026/9/14 15:40:52

web-print-pdf:从浏览器打印到专业PDF生成的分页与字体方案

在接触web-print-pdf之前&#xff0c;我花了大半年时间跟浏览器打印死磕&#xff1a;页面上布局好好的票据&#xff0c;一进打印预览就表头断页、边框缺线&#xff1b;font-family里明明写了中文字体&#xff0c;生成PDF后中文全部变成豆腐块&#xff1b;页码想放到页面底部居中…

作者头像 李华
网站建设 2026/9/14 15:38:54

C盘爆满怎么办?从系统清理到应用迁移的安全实操指南

"C 盘又红了"&#xff0c;这四个字几乎是家用电脑和办公电脑的共同痛点。平时装软件、收文件、写文档&#xff0c;C盘空间就像钱包里的余额一样&#xff0c;不知不觉就见底。系统开始卡顿、更新失败、软件报错&#xff0c;这时候很多人第一反应就是“赶紧清理”&…

作者头像 李华
网站建设 2026/9/14 15:37:50

手把手实现中文Transformer对话系统:从词表构建到推理部署

简介&#xff1a;这是一份基于Transformer架构实现的单轮中文对话聊天机器人完整项目资源&#xff0c;面向计算机、人工智能、自动化等专业的在校学生、教师及初学者&#xff0c;适用于课程设计、毕业设计、项目演示或自然语言处理入门实践。资源包共13个文件&#xff0c;含6个…

作者头像 李华