Search...Search plugins and themes...
⌘K
Sign in
  • Get started
  • Download
  • Pricing
  • Enterprise
  • Account
  • Obsidian
  • Overview
  • Sync
  • Publish
  • Canvas
  • Mobile
  • Web Clipper
  • CLI
  • Learn
  • Help
  • Developers
  • Changelog
  • About
  • Roadmap
  • Blog
  • Resources
  • System status
  • License overview
  • Terms of service
  • Privacy policy
  • Security
  • Community
  • Plugins
  • Themes
  • Discord
  • Forum / 中文论坛
  • Merch store
  • Brand guidelines
Follow us
DiscordTwitterBlueskyThreadsMastodonYouTubeGitHub
© 2026 Obsidian

Crystal Vault

ZhangrunyaoZhangrunyao257 downloads

Turn a folder of Markdown cards into a living crystal vault: see the structure, follow the links, read PDFs side by side, and recall what you wrote.

Add to Obsidian
  • Overview
  • Scorecard
  • Updates78

把一文件夹的 Markdown 卡片变成一座能看的知识晶体库。 QQ 群:831440768

截图预览:

桌面模式:

Crystal Vault overview

故事线模式:

故事线模式

而它真正的战场是文献模式:一边读 PDF / 图片 / Markdown,一边把读到的东西当场立成结构—— 读完一章,那一章的结构也就搭好了。桌面把这些摆成一桌能拖能缩的窗, 结构窗让库的结构跟你正在读的那一页并排待着,不用切走。

卡片就是普通的 Markdown,文件夹就是文件夹。没有任何东西被锁进数据库,也不出你的 vault。

English: README.en.md。


主功能:文献模式 · 桌面

阅读器有两种版式:网格是一屏摊开 N 页(翻页扫读用),桌面是一页一扇窗 ——后者是主力,因为它把「我要同时看几样东西」这件事交回给你自己。

  • 一页一扇窗,摆法自己定。 拖标题栏挪位置、拉右下角改大小, 关掉阅读器再打开,摆法原样还在。

  • 桌上不只有文献页。 卡片、结构、网页都是同一种窗,共用同一套拖、缩、收。 卡片窗顶上会显示这张卡的概念,那行里的公式照常渲染。

  • 收纳栏(顶栏那颗按钮)。左边出来一条竖栏,是这些窗的架子:把窗拖到栏上, 或者按窗上的「收纳」,它就收起来、栏里留一条,点一下再拿出来。 收着的窗,关掉阅读器也还在库里。

  • 外部标签页(收纳栏最上面那颗 +)。填一条网址,网课、文档站就挂在你正读的 那一页旁边,和别的窗一样能拖能收。

    ⚠️ 网页嵌不嵌得进来由那个站说了算,不是这个插件说了算:站点可以用响应头 拒绝被别的页面嵌(Google 系一律拒绝),这是浏览器的规矩,绕不过去。 所以那扇窗里常驻一颗「用系统浏览器打开」——嵌得进去当窗用,嵌不进去也始终有出路, 不会给你一个白框。

  • 右栏也能收。 同一颗「收纳栏」按钮还能把右边「边看边记」那一栏挤回去,读宽一点。

+ 页:Markdown 是按行分页的

顶栏那颗「+ 页」每按一次,就把这份文献的下一段摆到桌面上。 对 Markdown 来说「一段」是行数——接着桌上最后一扇的结束行,往下 40 行。

想改某一扇看的是哪几行,就改它标题栏里那两个框:「起始行」和「结束行」, 改完按回车。旁边那颗「共 N 行」是这份文件今天的总行数,挑区间时拿它当尺子。

同样的规矩也适用于 PDF / 图片那一档:它标题栏里那个框是页码,也是改完按回车。

这是和桌面配着用的那一半。

读文献最烦的是「这块东西在库里到底长什么样」——切过去看一眼,回来就得重新找刚才那行。 结构窗把这层结构开成你桌上的一扇窗,和正在读的那一页并排:

  • 看一眼,不是离开。 切走是「离开」;一扇窗只是瞥一眼。
  • 固定看一颗。 顶栏那颗「晶体:…」换看哪颗,下次打开还是它。
  • 顶栏挡着就收起来。 顶栏最左边那颗 ▲ 是整条栏的开关,颜色就是状态: 蓝 = 按钮都摆着;白 = 全收起来了,屏幕上只剩这一颗。再点一下全回来。 收没收起记着,下次开窗不用重收。

画线:看 / 写

顶栏那颗「画线:看 / 写」管的是拖一根线的后果:

档位 拖一根线,会发生什么
看(默认) 画一根金线。它存在库里,一个字都不碰你的笔记。
写 往起点那张卡的正文里真写一条 [[目标卡]]——笔记跟着变。线是蓝的。

蓝跟金的区别说的就是这件事:金线是一种看法,蓝线是笔记里真有的东西。

你亲手拖过连接点的那一根线,接法会写进这张卡自己的 frontmatter(字段 晶体接法)——所以它跟着笔记文件走:改名、搬到别的文件夹、压缩发给别人, 都还在。没过手的那些不写,它们按位置算就够了。

蓝线接在卡片的哪一边,默认按位置算:上下叠着的两张走「下→上」,左右摆的走 「右→左」。想改成别的走法,在写模式下从你要的那条边拖一次,那一根就按你拖的走 (手动拖过的永远压过默认)。

在写模式下把蓝线框住删掉,删的是卡片正文里那条 [[链接]],不是画在屏幕上的东西。 删错了可以撤销一次(和卡片编辑那条撤销同一套)。

右键:三种落点,三种结果

  • 对着卡片右键 → 隐藏这张卡片所有的入链和出链。 一张卡连进连出十几根线的时候,把它整个收干净、只留别的, 一眼就能看清剩下的结构。再右键一次就放回来; 只要有东西藏着,顶栏就会出现一颗「显示全部」,一下全放回来。
  • 右键落在金线上 → 进连线编辑模式。 顶栏出现「选框:线」和「选框」两颗, 拖鼠标就能框住几根线;框住之后出现「删除实线(N)」。 (右边那颗「选框:线」点一下会变成「框:卡」,那是整批挪卡片用的,见下一节。)
  • 右键空白处(在「写」档下)→ 也出现「选框」,但这一档框的是蓝线。 框住之后是「删除蓝线(N)」——按下去会从卡片正文里把对应的那条 [[链接]] 删掉。

一个细节:「对着卡片右键」这个入口是由「写」档开的——在「看」档下, 右键卡片仍然是老行为(进连接模式)。但已经藏起来的卡,两种档位下右键它都管用, 不然你一切回「看」,藏起来的东西就只剩顶栏那颗按钮能救了。

收纳方框:把一片收干净,但线不算断

画面上那些虚线框是收纳方框。每个子晶体自动一个,名字就是文件夹名; 框可以改名(点名字)也可以收起(点左边那个小三角)。

框有两种颜色,含义不一样:

是什么 是容器吗
金色(点线,暖) 子晶体——文件夹长出来的 是,见下
蓝色(虚线,冷) 你用「+ 框」自己画的 不是,卡片随便进出

金框一层一个、层层套起来(1.3.88 起)。一个文件夹的框里,装着它自己的卡, 外加它每个子文件夹各自的框,所以整棵树的层级一路看得见。框内部横着切:

┌ A ─────────────────────────────────┐
│  [A 自己的卡]  ┃  [B1 的卡]  ┊  [B2 的卡] │
└────────────────┸────────────┸──────┘
        珊瑚橙竖线 ↑      金色竖线 ↑
      (本级 ↔ 子文件夹)  (同级 ↔ 同级)
  • 珊瑚橙 #FF6B6B 分的是这个文件夹自己的卡和它的子文件夹;
  • 金色分的是两个同级子文件夹。

金框是容器。 里面的卡拖不进别的金框,也拖不过那条珊瑚橙线到上一级"自己的卡"里 ——卡片停在边界上。蓝框不能移出它所在的那个金框(拖和拉大小都出不去), 但蓝框本身不是容器,卡片照样进出。拖金框时里面所有东西跟着走,蓝框也跟。

你画的框属于你画它的那一层。 在「Python/数据分析」里建的框,切到 「Python/爬虫」就看不见了——回到那一层它原样还在。以前不是这样:框是全局的, 换一个文件夹看,别的层画的框还在原地摆着。

点「+ 框」建出来的框落在你正看着的地方(视口正中),而不是世界的某个固定角落 ——以前框建在固定的 (60,60),视口推远了就得先推回去找它。新建的卡片同理。

框里任何一块空白都能拖动整框(1.3.83 起),不只是顶上那条标题栏——按住框的边、 框的空处都行,框和里面的卡一起挪。压在卡片上时拖的仍然是卡片(卡片层级更高), 所以想挪卡片就按卡片,想挪整框就按框的空白处。拖动按格点走,见下面 「一格一格地摆」。

收起之后,框里的卡和连着它们的线一起收起来——但「那边还有东西」这件事不会丢:

  • 外面凡是有蓝线连进去的卡,右上角点一个黄色实心圆点;
  • 鼠标悬停那张卡,和它有关联的、正收着的框会绕边闪一圈。

不这么做的话,收起读起来就是「我的双链丢了」,而你明明没删。 框展开着的时候,里面的卡照常可以往外连蓝线——跨级连也没问题。

框:卡 —— 一次挪好几张

结构窗顶栏有两颗挨着的按钮,各管一件事,别混:

按钮 它说的是
选框:线 ⇄ 框:卡 框住的东西是什么
选框 ⇄ 退出选框 现在能不能框

默认是「选框:线」:右键进连线编辑模式之后,拖鼠标框住几根线,再点「删除实线 / 删除蓝线」。 点一下「选框:线」,它变成「框:卡」——这时拖出来的方框框的是卡片:

  1. 框住几张卡,它们会亮起青边;
  2. 按住其中任意一张拖走 = 整批一起动;
  3. 松手时整批一起判归属:拖进收纳方框就归它,拖到框外就移出来;
  4. 想清掉它们:点顶栏那颗红框的「删除卡片(n)」——连笔记文件一起进回收站。

少了这一条,把十几张卡收进一个框就只能一张一张拖;要清掉一批,就只能切回库里 一张一张走「删除卡片」。

  • 按住没被框住的那张,只挪它自己——框选之后顺手拖一张别的, 意思显然是「我要挪这一张」,不是「顺便把刚才那几张也带上」。
  • 「删除卡片」删的是卡片文件本身(不是解绑、不是隐藏):它连那张笔记一起进 回收站,能捡回来;那张卡所在的晶体不动。它只在真有卡被框住时才出现, 张数写在按钮上——这扇窗没有确认弹窗,按钮上的数、悬停那句话、底下那条说明 就是全部的告知。
  • 按 D 在卡档里不删卡:一个裸按键就能把好几个文件扔进回收站太容易误触 (那会儿手正放在方向键上挪卡片)。要删就走那颗按钮。
  • 框选本身不动你的笔记一个字——「删除实线 / 删除蓝线」那颗按钮在卡档里会 自己收起来,因为卡档里没有线可删。
  • 框选完之后想让它们不亮:点一下空白,或者按 Esc。

卡片的位置会跟着笔记走

卡片摆在哪儿,写进卡片自己的 frontmatter 里(字段叫 晶体坐标)。所以换一台电脑、 装同一个插件、打开同一个库,卡片的相对摆放位置和你这台机器上一模一样—— 视图状态是每台机器各存各的,只有写进文件才跟着走。

字段长这样,单位是「格」(最小单位 = 卡片宽的 1/10 = 21px),以左下角为准:

晶体坐标: [3, 5]

字段名带「晶体」前缀是故意的:这个插件装在别人的库里,而 坐标 是个 太通用的名字——谁要是有个自用的同名字段,会被静默顶掉。

  • 金色方框不用单独存:它的位置和大小就是里面卡片的包围盒,卡片跟着文件走, 它自然跟着走。
  • 收纳方框也有自己的文件:每颗晶体一个 .crystal-boxes.json,就放在那颗晶体的 文件夹里。点开头 → Obsidian 的文件列表里看不见,也不会变成一张卡片 (适配层另外只认 .md,两道都挡得住)。里面存的是框的左下角坐标、 名字、大小、收起状态和成员。手改前先关掉 Obsidian。
  • ⚠️ 同步通道必须带点开头的文件。FNS 走文件系统那一层,没问题; 换成会跳过 . 开头的通道(Obsidian 自带的 Sync 就是),这个文件传不过去, 框就只在你这台机器上——那种情况下你不会收到任何提示。
  • 外来卡(「导入卡片」引过来的)也不写:它在你这层的落点和它在自己晶体里的 位置是两回事,写进去就等于改了它老家的位置。
  • 写盘是拖完停一小会儿才做的(你有多端同步,拖几下就写几次会引发同步风暴)。 写完之前关掉库也会催一下,不会白摆。

一格一格地摆:卡片的格点与方向键

卡片在故事线里落在一层格点上,坐标以左下角为准——两张卡并排时,是下边对齐。

按键 一步走多远
← → 42px(最小单位的 2 倍,5 步正好一张卡宽)
↑ ↓ 21px(最小单位)

最小单位 = 卡片宽的 1/10 = 21px。 就是这么算出来的:每张卡大小一样,拿它当尺子, 整张图自然就对得齐。

拖一张卡,停在哪儿就自动落到最近的格点上;框选之后按方向键,一格一格挪。

  • 收纳方框也走格点(1.3.83 起):拖动时框的左下角吸到格点上,框里的卡按 同一段位移整体挪,它们之间的相对位置一点不变。大小仍然随你拉—— 框是你画出来的容器,多大由你定,只有摆在哪儿才需要对齐。
  • 金色方框(文件夹长出来的那个)按整格移动。 它的位置和大小是从里面的卡片 算出来的,自己没有坐标可吸,所以吸的是位移:框和里面的卡一起按整格的 整数倍走,同样是整体平移。
  • 已经摆好的旧位置不会被集体挪动。 格点只在你下一次拖它 / 按方向键时生效 ——不然那是一次没人按过按钮的破坏。代价是一张从没被碰过的老卡可能停在格外, 动它一下就归位。

导入卡片:把别的晶体里的卡借过来

一颗晶体只画得下它自己文件夹里的卡。可你常常想让 A 晶体的卡去连 B 晶体的卡—— 这时候点结构窗顶栏的「导入卡片」,从别的晶体挑一张进来:

  1. 它落在窗的正中间(不是自动排到某个角落——你看得见,才知道它进来了);
  2. 拖它进任意一个收纳方框就归它,跨级连蓝线从此成立;
  3. 不想要了,点它右上角那颗 ✕。

引进来的卡是点线紫框,一眼能和本层的卡分开。它本身一个字都不动: 还在原来那个文件夹里,别人指向它的双链也都在。拿走再引回来,连你给它摆的位置都还在。

  • 引一张本来就在这颗晶体里的卡会被挡下来,并告诉你为什么。
  • 只有结构窗里能引;引进来之后,在晶体库的故事线上看同一颗晶体,它也在那儿。
  • 「删除实线 / 删除蓝线」和它无关——引卡不会删任何东西。
  • 一颗晶体最多引 500 张(这只是一个防坏存档的上限,正常用不到)。
  • 引来的卡进不了子晶体框——那种框的成员是文件夹长出来的。拖进去它会告诉你 一句,要给它分组请用「+ 框」建一个手动框。
  • 选择器里点文件夹名是展开它(不是"就选这个文件夹")。挑卡片的三档 (导入 / 删除卡 / 重命名卡)都是这个手感。

边看边记:读到什么,当场立成卡

阅读器右边那一栏。填卡片名 / 概念 / 来源 / 正文就能建卡,不用离开这一页。

  • 想用真编辑器写:点「✎ 在编辑器里写」,它先把卡建出来,正文改用 Obsidian 自己的 实时渲染编辑器(边写边渲染、自动存盘)。
  • 反悔了:点「返回」,刚建的那张卡撤掉,正文原封不动转进草稿纸。
  • 草稿纸:一块用原生编辑器写的便签,落在你指定的文件夹里,不建成卡片。
  • 卡片盒:搜库里的卡片,点一张就摆到桌面上,并在那张卡里留一行指回这一页的链接。
  • 重命名卡片 / 重命名晶体就在这一栏。走的是 Obsidian 自己的改名通道, 所以全库指向它的 [[双链]] 会一起跟着改。
  • 挑文件夹那块面板抬头有一颗「取消」(1.3.83 起)。「将建在」、新建 / 删除 / 重命名晶体、删除 / 重命名卡片、结构窗挑晶体,打开的都是这块面板,关闭统一走 这一颗——它只收起面板,什么都不改。

晶体库:不读文献的时候

  • 一个文件夹 = 一颗晶体。卡片目录下的每个子文件夹在环上就是一颗晶体,可以一层层钻进去, 面包屑随时告诉你站在哪儿。
  • 双链变成形状。正文里写 [[另一张卡]],两张卡之间就出现一根线。故事线按连线拓扑 把整颗晶体铺开。A→B 与 B→A 合成一条、两头带箭头:一个箭头是单向,两个是互相。
  • 孤岛是信号,不是错误。既没链出去也没人链它的卡会被标出来——那是还没接进任何脉络的卡。
  • 先想再看。回忆模式下卡片内容默认遮住,点一下才显示;复习模式全部摊开。
  • 就地改。点面板右上角那颗笔,原地改概念 / 来源 / 标签 / 正文——不跳转、不开新标签页。
  • 删除走回收站。删晶体、删卡片,都按你在「文件与链接 → 删除的文件」里选的那一档,能捡回来。

为什么不直接用图谱?

图谱回答的是「这张笔记和谁有关系」——它以笔记为起点、连线是主角,而文件夹根本不在图里。 如果你的知识是按科目和章节组织的,图谱会把你所有东西搅成一团。 这正是很多人觉得它「好看但没用」的原因:他们找不到自己组织知识的那条线。

晶体库问的是另一个问题:「这一块知识里有什么、长到什么程度了」。它以文件夹为起点, 结构本身就是主角。

它不是更好的图谱,是不同的起点。

三种打开方式:全屏 / 浮窗 / 嵌入

点侧边栏图标打开晶体库,默认是全屏——铺满整个窗口、盖在笔记上。 另外两档在插件设置的「打开方式」里选,库里顶栏那颗按钮也能随时循环切 (全屏 → 浮窗 → 嵌入,按钮上写的就是下一档叫什么):

长什么样
全屏 铺满整个窗口,盖在笔记上。老行为,也是出厂默认。
浮窗 收成屏幕上一块矩形,浮在笔记上——一边看笔记一边用库。
嵌入 就长在它那颗 Obsidian 标签页里,不盖任何东西。可以和别的标签页左右分屏。

浮窗:拖顶栏挪位置、拖右下角改大小;位置和大小跟着 vault 走, 换台机器打开也在你放的地方。

  • 三档切换都会重开一次视图(阅读器里开着的文献、桌面上的窗会没)。这一档换的是 库的几何,原地改总有一块不跟着变。
  • 文献阅读器、卡片面板这些也都待在当前这一档里——浮窗里点开一张卡, 面板不会盖住你的笔记;嵌入模式下它也只占这颗标签页。
  • 嵌入模式不锁笔记的滚动(另外两档会——它们盖在笔记上,背后不该跟着滚)。
  • dataviewjs 那种用法没有这几档(它本来就嵌在笔记里),所以那颗按钮不会出现。

第四档:浮到 Obsidian 之外(悬浮伴侣)

上面那三档都跳不出 Obsidian 的窗口——它们是这个插件在自己进程里造的浮层。 想让它压在 Edge、微信、Word 上面(在浏览器里查资料,边看边记还挂在旁边), 得有一个系统级的窗口,而这件事插件做不到:Obsidian 的插件沙箱里没有那条路。

所以有了 CrystalFloat——一个单独的小程序:

大小 从哪来
晶体库(就是这个插件) ~2 MB 插件市场,照旧
CrystalFloat(悬浮伴侣) ~107 MB 另一个仓的 Release

装完之后不用填任何路径——插件会自己找到它。命令面板里多两条:

  • 晶体库:独立窗口:边看边记
  • 晶体库:独立窗口:结构窗

窗口顶栏有拖拽区,右边是置顶开关 / 最小化 / 关闭。

没装伴侣的时候,上面所有功能一个不少,只是没有这两条命令。 点它们会给你一句人话加一个下载入口,不会静默失败。

压得住什么,压不住什么

压得住:Edge、Chrome、微信、QQ、Word、资源管理器——常规窗口,最大化的也算。

压不住(这条清单是诚实的):

  • 独占全屏的应用(全屏视频、游戏)
  • 另一个同样置顶的窗口——同档相撞时谁后激活谁赢。装了 Raycast (它默认置顶)、或者某些截图/录屏工具,就会撞上这条
  • UAC 提权弹窗(那在安全桌面上,谁都压不住)

三条已知的折价

  1. 悬浮窗里编辑卡片正文是纯文本框,不是 Obsidian 那个实时预览编辑器 ——那个组件跨不了进程。翻 PDF、拖卡片、写笔记都照常,只有编辑体验这一项降级。
  2. 悬浮文档里的 [[双链]] 和 callout 渲染成纯文本,Dataview 之类的扩展不生效。
  3. 不要同时在两边拖同一张卡——卡片坐标是防抖写、没有基线比对, 同时动手会有一边被静默覆盖。一边改完再动另一边就没问题。

遇到问题 / 想提意见

QQ 群:831440768

装不上、用着哪儿不对劲、想要个什么功能,都可以直接进来说。 (在 GitHub 上开 Issue 也一样, 只是群里问一句通常快得多。)

安装

在 设置 → 第三方插件 → 浏览 里搜 Crystal Vault。

手动装:从 最新 Release 下载 main.js / manifest.json / styles.css,放进 <你的 vault>/.obsidian/plugins/crystal-vault/, 然后在 设置 → 第三方插件 里启用。

上手

  1. 在插件设置里把卡片目录指到你放笔记的那个文件夹。默认是 cards—— 还没有的话,在 vault 里建一个叫这个名字的文件夹就行。 设置页会当场告诉你这个路径在不在、里面有几颗晶体。
  2. 往卡片目录里放一份能读的东西——你在看的那本书、那门课的讲义、那份论文。 PDF 最好(图片也行)。别放一个空文件进去:阅读器只会说一句 「这份文献里没有可显示的内容」。放进去之后它就会出现在阅读器的文献清单里, 第 6 步要用。
  3. 点侧边栏那颗宝石图标(或运行命令 Crystal Vault: Open)。
  4. 在卡片目录里建一个子文件夹——那就是一颗晶体。
  5. 按下面的格式写一张卡,再用 [[双链]] 把它连出去。
  6. 点顶栏的「文献」进阅读器,选刚才放进去的那一份,开始读; 切到「桌面」,再点「结构窗」——这就是它日常的样子。

放什么格式:阅读器认 PDF / 图片(png、jpg、jpeg、gif、webp、bmp、svg、avif)/ Markdown。 PPTX 不在里面,也加不了——先自己导出成 PDF 再放进来。

⚠️ 放进卡片目录的 .md 会同时是一张卡片(子文件夹 = 晶体,.md = 卡片), 也就是说那份 markdown 会一起出现在库里。想图干净就放 PDF。

卡片格式

---
概念: 一句话说清它是什么
来源: 哪本书 / 哪节课 / 哪份文献
tags: [科目, 类型]
---

先用自己的话说清它是什么……

接着看 [[02-下一张]] 连过去的原因就写在后面

==高亮== 的部分会被抽成自测点。
字段 在库里长什么样
(文件名) 卡片的标题,卡片- / 卡片_ 前缀会自动剥掉
概念 面板顶部那一行
来源 悬停浮层里的「来源」
tags 卡面上最多显示前 6 个

四条让库活起来的习惯:至少连一次(不然是孤岛)· 连的时候写下理由 · 用编号前缀控制顺序(01- 02-)· 想自测的地方用 ==高亮==。

更新记录

新的在上。这一份跟着每一版一起改,只记用户看得见的东西。

1.4.14 · 修:「文件改动」点出来的面板会被桌面上的窗盖住。

那棵树和新建/重命名那个方框原来分别是 z-index:6 和 7——够压住「选哪份文献」那一层,但桌面上的窗(页窗 / 卡片窗 / 结构窗)的 z-index 是点一下涨一次的(点一下抬到最前)。所以用上一会儿它们就爬到了面板上面:表现为「点了删除卡片,树被一张卡挡住、点不着」,而屏幕上看不出被谁挡了。

现在那两个面板拉到 100000 / 100001——桌面那边要点一万下才追得上。面板本来就是「临时盖住一切」的东西,桌面窗是「常驻、可以互相叠」的,两者不该比大小。


1.4.13 · 改:三件事——「将建在」搬到顶栏、改概念结构窗立刻跟上、外面动文件晶体库也跟上。

一、「将建在」从「更多」里搬出来,落在「换一份」左边。 卡片名 / 概念 / 来源是"这一张卡才用得上"的,收着是对的;而「将建在」是跨卡片的设置——你改一次,后面每张卡都建到那儿去。埋在两层里等于每次建卡都要先开一次盒子确认。显示的是最后一段,鼠标悬停看全路径。

二、在卡片窗里改「概念」,结构窗立刻跟上。 这条底下其实是两个毛病叠着,缺一个都不生效:

  • 保存走的是宿主原生编辑器那条路,写的是整份文件(YAML 也能在里面改),而核心保存后传的是一张空字段表——只更新正文,模型里的概念一直是旧的。现在改成把 概念/来源/tags 读回来。
  • 而且没人叫结构窗重画:整份代码里能让一扇已挂载的结构窗重画的只有 renderCrystals 那个漏斗,而这条路一次都没碰到它。现在补上了。

(卡片盒那条路走同一段代码,一起好。)

三、在 Obsidian 自己的文件列表里新建/删除文件夹或文件,晶体库立刻跟上。 从前这条压根没修过——不是漏了,是有意留白(代码里写着"create 故意不订;外面新增一张卡是另一个特性")。现在做了:订了 create,文件夹的所有事件也不再被 .md 过滤掉,收到就整份对账一次(重读卡片清单 + 重跑 listFolders,空文件夹照样算一颗晶体)。带 400ms 防抖,同步拖一批下来不会连着炸。


1.4.12 · 修:删掉线之后,卡片里的 晶体接法 还留着那一条。

1.4.11 让"删线"顺手把 晶体接法 里对应那条也摘掉,可摘不掉——因为 patchFrontmatter 根本没有"删字段"这条路:它只会写 键: 值。而清空一个字段时,调用方为了不在卡上留一行空字段,干脆跳过不写。两头一凑,结果是:

删掉一个卡片的最后一条线时,那条 晶体接法 永远留在文件里。

现在 patchFrontmatter 认 null = 把这个字段整个删掉(连那两块 --- 一起收掉,如果整个块都空了的话),linksides 在表空时就走这条路。


1.4.11 · 修:删掉一根蓝线之后,这一对卡再也连不上了。

根因是用户自己找到的:「首次打开晶体库都能正常连接,连完一条线再删除,这时候晶体接法上仍然有刚才的链接」。

链条是这样接起来的:

  1. 拖一根线 → 正文里写下 [[目标卡]],同时在这张卡的 frontmatter 里记一条 晶体接法: ["[[目标卡]] 起点 终点"]。
  2. 删掉这根线 → 正文里那条 [[…]] 被挖掉了,但 晶体接法 那一条没人清。
  3. 再拖同一对 → 判重那一句用的是整份文件(card.content.indexOf(...)),于是命中 frontmatter 里那条残留 → 判定"这两张卡已经连着了" → 不写、不画。而且永远这样。

改了两处:

  • 判重只看正文(splitCard(base).body)。链接住在正文里,parseLinks 和删除那条路都在正文上解析切割,判重没有理由用别的口径。
  • 删线时把对应的 晶体接法 一起摘掉(走 queueCardSides 防抖合流,和坐标那条路一样,免得一次框选删好几根引发同步风暴)。

1.4.10 · 修:拖蓝线文件里有、屏幕上没有,而且怎么重拖都出不来。

两个问题,第二个是把你卡死的那一环。

一、早退那一支不重画。 writeStoryLink 发现源卡正文里已经有那条链接时,会说一句「这两张卡已经连着了。接的位置按你拖的改过来了」,然后直接返回、什么都不重画。

而那句话本身承诺了接的位置改过来了——它确实刚写进去。于是只要盘上早就有那条链接、屏幕上因为任何原因没有线,你每拖一次都掉进这一支,它说一句已经连着了就完事。屏幕上永远补不上,怎么重拖都没用。(你说的「现在又好了」,是重开窗触发了整窗重画。)

二、写完之后那几步刷新,任何一步抛了都会把最后的重画一起带走。 现在它们被单独圈起来:报错留痕,重画照做。


1.4.9 · 修:1.4.8 那个「存完自动摆出来」根本没跑。

写错了作用域:viaHost 是在一个 { } 块里面声明的,而新加的那段在块外面读它——const 是块级作用域,块外读它是 ReferenceError。

更糟的是那一段套着 try/catch,报错被吞掉了:屏幕上没有卡片窗、控制台里一条错都没有。

顺带:那个 catch 现在会 console.error 留痕——以后同样的坏法至少看得见。


1.4.8 · 改:桌面模式下存下一张卡,它就当场摆在你眼前、可以直接接着写。

从前点「存进晶体库」,卡是建出来了,但屏幕上什么都不动——你得自己回库里把它找出来。

现在,桌面模式下存一张卡,它会

  • 自动开成一扇窗,贴右下角(窗的右边离桌面右边 5%,下边离底边 5%);
  • 而且直接进入编辑模式,光标就在正文里,接着写就行。

只在桌面模式下做。网格模式是"一屏摊开 N 页扫读",那时候硬开一扇窗会把人从翻页里拽出来。


1.4.7 · 修:1.4.6 那三个能力位根本没传到阅读器。

mount() 是用具名参数收的,而它内部调阅读器那一行是一张写死的表。 1.4.6 只把 storyHost / cardHost / onCardCreated 加进了阅读器的参数表, 忘了在 mount 这一层列出来——没列出来的字段直接丢掉,而且屏幕上、 控制台里一句错都不报。

症状就是伴侣那边"点了没反应 / 卡片出不去":它拿到的还是老行为。

同一个版本里还补了两条漏写的:

  • 在伴侣的「边看边记」那扇窗里点「结构窗」,从前什么都不发生(能力位说 "交给宿主",可宿主那份结构窗只存在于另一扇窗里)。现在它是开/聚焦那扇窗; 窗已经开着时还能把"换一颗晶体看"推进去。
  • 在伴侣的结构窗里点一个节点,从前是交给 Obsidian 打开那张卡。现在它 给那张卡开一扇自己的窗——那才是用户要的。

⚠️ 要配 CrystalFloat 1.0.15。


1.4.6 · 改:悬浮伴侣换成「组件直接挂」,并且每张卡自己一扇窗。

这一版应用内看不出任何变化——它改的是伴侣那边要用到的三个"能力位":

  • 结构窗那扇不再走桌面层。 以前是把整个桌面层端出来、桌上摆一扇铺满的结构窗; 现在结构窗那个组件直接挂进窗口,桌面层根本不参与。 (1.4.3 试过一次,但那次顺手把「边看边记」那扇的导航也收掉了——这次一条不动。)
  • 每张卡一扇自己的系统窗。 在卡片盒或结构窗里点一张卡,伴侣会为它开一扇 独立窗口:浮在所有页面之上、不随伴侣窗口一起最小化、能拖到伴侣窗口外面去。
  • 「新建卡片」是一扇自己的窗:打开是一张空白卡,写完存下去,它就变成那张卡的窗。

⚠️ 要配 CrystalFloat 1.0.5。伴侣的安装包在 伴侣的 Releases 上。


1.4.5 · 改:阅读器顶栏重排,「边看边记」那一栏撤掉。

顶栏现在长这样(括号里是新加的):

‹ 返回 │ 换一份 桌面 + 页 收纳栏 (文件改动) (新建卡片) 卡片盒 草稿纸 故事线 结构窗 收起
        └ 桌面模式下:上一屏 / 下一屏 / - / 100% / + 收起来
        └ 页阵模式下:+ 页 收起来

去掉了:文献名、页码计数、边看边记 那颗开关。 文献名和计数说的都是你刚自己挑的那份文献——顶栏再念一遍是重复;页码本来就印在每一页上。

新加的两颗:

  • 文件改动 —— 一个下拉,装原来的五颗:新建晶体 / 删除晶体 / 删除卡片 / 重命名卡片 / 重命名晶体。功能一行没改,只是从右边那一栏搬到了顶栏。
  • 新建卡片 —— 点了在它右边摊开:一个写正文的框 →「更多」(卡片名 / 概念 / 来源 / 建在哪个文件夹)→「存进晶体库」。卡片名留空就从正文第一行取, 所以默认用法是「写完直接存」。 没打开文献也能用——它落在你上次挑的那个文件夹里(没挑过就落卡片根目录)。

「边看边记」那一栏整条撤了,里面的东西一样没丢:

原来在那儿 现在在哪儿
五颗文件操作 顶栏「文件改动」下拉
卡片名 / 概念 / 来源 / 正文 / 存进晶体库 顶栏「新建卡片」摊开的框
「将建在」文件夹选择 「更多」里面
草稿纸的起名框 挪进浮层,功能照旧

删掉的只有一样:✎ 在编辑器里写(连同它那套「返回 = 把刚建出来的卡撤掉」)。 它和「新建卡片」是两条并行的建卡路,而它那条会先在库里留下一张半成品卡。

⚠️ 这一版只改应用内。悬浮伴侣那边这次没动——它的两扇窗怎么分,等定下来再说。


1.4.4 · 回退:悬浮窗回到 1.4.2 那套形态。

1.4.3 把「结构窗」那扇改成了组件直接挂(不经过桌面层),理论上更干净, 但用起来不对,退回 1.4.2 的形态:两扇窗,结构窗那扇是「桌面层 + 桌上只有 一扇铺满的结构窗」。

1.4.3 那一条更新记录留着不改——它确实发出去过。现在这一版把它撤了。

⚠️ 要配 CrystalFloat 1.0.4。


1.4.3 · 改:浮出去的是「组件」,不是「整个桌面模式」。

1.4.2 的「结构窗」那扇窗做错了:它开的是整个桌面层,桌上摆一扇铺满的结构窗。 量出来窗里实际有这些东西——

.kb-v13-trigger       976×80    晶体库的入口按钮(跟浮窗毫无关系的库层残渣)
.kb-v13-reader-desk   976×778   整个桌面层容器
  .kb-v13-desk-win   1378×1180  桌面窗,带自己的顶栏「结构:X 收纳 ✕」和拖拽角

那不是结构窗,那是把桌面模式整扇端了出来。现在结构窗那个组件是直接挂的, 桌面层根本不参与:

#float-story-host      906×724
  .kb-v13-embedstory   906×724
    .kb-v13-stage      906×724   节点画布
    .kb-v13-embedbar   304×34    结构窗自己的顶栏

两扇窗都顺带清掉了晶体库那颗入口按钮(在浮窗里点它没有意义,伴侣不承载库那一层)。

「边看边记」那扇也收掉了晶体库自己的导航(桌面 / +页 / 收纳栏 / 卡片盒 / 故事线 / 结构窗)——那些是整个库的东西,不是这个组件的。尤其那颗「桌面」: 按下去会把桌面层拉进这扇窗。阅读器自己的控件(返回 / 换一份 / 翻页 / 缩放 / 边看边记 / 收起顶栏)一个不少。

⚠️ 要配 CrystalFloat 1.0.3。


1.4.2 · 改:两个功能各成一扇窗,并排放。

1.4.0/1.4.1 那两版是一扇窗切来切去,而且「结构窗」那条命令会把整个桌面层端出来 (还自动多摆一扇 PDF 窗)。不是当初要的样子。现在:

命令 开出来的窗
独立窗口:边看边记 文献 + 右边那条笔记栏。顶栏多一颗「只看笔记栏」,按一下收掉文献区、笔记栏铺满整窗(钉在屏幕一侧当便签用)。
独立窗口:结构窗 只有结构窗。桌面层不再露出来、不再自动多摆 PDF 窗,阅读器自己那条顶栏也收起来了。

两条命令互不影响:点第二条不会关掉第一扇,也不再"先杀掉重开"。两扇窗各有各的 位置、各有各的状态(你在边看边记那扇收起了阅读区,不会把结构窗那扇也改了)。

顺带修了一个一直没生效的东西:悬浮窗读偏好和视图状态的那条路是坏的 (契约要求同步读,而桥是异步的,第一版直接漏了个 Promise 出去)——所以 「在 Obsidian 里布置好再飘出来」这件事从来没成功过,现在真的能了。

⚠️ 这一版要配 CrystalFloat 1.0.2。


1.4.1 · 修:开过一次悬浮窗、关掉之后,那两条命令就再也不响应了。

1.4.0 发出去当天就撞上的。伴侣在你点 ✕ 关掉窗之后进程不退——它变成一个没有 窗口的隐形进程,而它一直占着单实例锁。于是之后每一次「独立窗口」命令都在 后台被干净地拒掉(退出码 0、窗一闪都没有),你看到的只是点了没反应, 诊断日志里也只有一句「伴侣退出了」——一个字都不会提到锁。

现在关窗就退。另外自己双击启动伴侣也能用了:它以前没有 --bridge 参数就连不上库,只会干坐着;现在它会去读插件留下的发现文件。

⚠️ 这一版要重新下一个伴侣安装包(CrystalFloat 1.0.1)。旧的那个请先卸载或 关掉——它正是占着锁的那个。装完之后如果你还开着旧的,先在任务管理器里 结束 CrystalFloat.exe 再试。


1.4.0 · 新:「边看边记」和「结构窗」现在能浮到 Obsidian 外面去了。

设置里那三档(全屏 / 浮窗 / 嵌入)都跳不出 Obsidian 的窗口——它们是插件在自己 进程里画的浮层。这一版加了第四档:一扇真的独立窗口,压在 Edge、微信、Word 上面。

它必须是一个单独的程序(CrystalFloat,约 107MB),因为插件沙箱里造不出系统级 窗口——这是平台限制,不是偷懒。装了之后不用填任何路径,插件会自己找到它; 命令面板里多两条「独立窗口:边看边记」和「独立窗口:结构窗」。

没装它的时候,上面所有功能一个不少,只是没有那两条命令。

三条要提前知道的折价(README 上面有完整清单):

  • 悬浮窗里编辑卡片正文是纯文本框——那个组件跨不了进程。翻页、拖卡、写笔记照常。
  • 悬浮文档里的 [[双链]] 和 callout 渲染成纯文本。
  • 不要同时在两边拖同一张卡(卡片坐标是防抖写、没有基线比对,同时动手会有一边被静默覆盖)。

1.3.97 · 修:一篇笔记都没开的时候,桌面卡片点「编辑」会弹一句看不懂的话。

插件要挂 Obsidian 的原生编辑器,而 Obsidian 不公开导出编辑器类 —— 只能从 一个活着的笔记实例上把类「借」过来。原来的判据是「必须有一颗 Markdown 笔记开着」, 可这个前提从来没写出来过,而你的用法很可能就是从来不打开 .md 标签页 (都在晶体库里读)—— 于是每一次点「编辑」都借不到、都掉进降级那条路, 还顺带弹一句给开发看的报错。

现在借类有三条路,依次试,任何一条走通就不再往下:

  1. 活着的 Markdown 实例(原路,判据放宽了)
  2. Obsidian 的视图类型表(viewRegistry.viewByType)—— 不需要任何笔记开着
  3. 上一次借成的那一份,本会话内一直有效

三条都不通时,那句话也换成正常人话了:说清楚为什么、下一步做什么, 并点明下面那个输入框照样能写(它不是错误,是降级)。

1.3.96 · 修:删掉一条蓝线,那条线还在——关掉 Obsidian 重启也在,可文件里已经没有它了, 而且它还会变成幽灵。

根因是算关系的时候读到 frontmatter 里去了。「晶体接法」那个字段长这样:

晶体接法: ["[[花式索引和布尔索引]] b t"]

目标写成 [[双链]] 是故意的——给卡片改名时 Obsidian 会连它一起改,接法不会失联。 可"算出两张卡之间有没有关系"那一步,是在整份文件上找 [[…]] 的, 于是 frontmatter 里这一条也长出一条边:

  • 删蓝线删的是正文里的链接,动不到 frontmatter → 线还在
  • 它在文件里 → 重启照样在
  • 目标卡不在这一层时 → 变成幽灵

现在算关系只看正文。剥的只是文件最开头那一段 frontmatter——正文中间的分隔线 (--- 单独一行)不受影响。

1.3.95 · 结构窗和故事线里,「写」模式下右键空白处不再弹那条说明条。

原来是这么一条:点顶栏「选框」,然后拖出方框 · Esc 退出。它出现在"右键空白处、 进了删蓝线模式、但还什么都没选中"这一档——那时候屏幕上一个选中物都没有,弹这句话是噪音。

其余三档照旧留着,尤其是「看」模式下右键金线那一条:金色线框选唯一的入口就是顶栏 那颗「选框」按钮,少了这句用户只会盯着线发呆。

1.3.94 · 修:关掉 Obsidian 再打开,框的位置变回旧的(1.3.93 没修干净,这次是根因)。

线索是你自己给的那两句:「只要我不关 Obsidian,一切正常,关了再打开,又变成这个 bug 了」。能同时满足这两句的只有一种情况——存下去的是旧的那一份。

根因:两条持久化路线读的不是同一个对象。

进故事线 / 结构窗就是进相机档,那一刻会开一份草稿,你的改动全落在草稿里。 问题在于保存视图状态的那个函数只读 state.view,压根不看草稿——所以开着故事线时, 每一次"保存"写下去的都是那份还没并进草稿的旧状态。而边车(.crystal-boxes.json) 读的是"草稿优先"。

于是:屏幕上一切正常(界面读草稿)、边车是对的、唯独视图状态是旧的。 两条路线必然分叉,而分叉只在重开之后才显形。

现在那个函数改成和"提交草稿"用同一个式子({ ...view, ...draft }), 两条路线读同一份东西,不可能再分叉。

这条也解释了为什么 1.3.93 的时间戳没能救你:那一版保证"谁新听谁的", 而新的那一份本身就没被写进视图状态——它一直躺在草稿里。

1.3.93 · 修:关掉 Obsidian 再打开,蓝色收纳方框会跳回旧位置——而开着的时候 怎么看都是对的。

你报的原话是「只要我不关 Obsidian,一切正常,关了再打开,又变成这个 bug 了」。 这两句合起来就把它锁死了:不是跟随坏了,是那一笔没写进文件。

根因是落盘规则本身:边车(.crystal-boxes.json)一直是**「文件无条件优先」**。 那条规矩有一个它自己写明了的前提——文件永远是较新的那一份。而它不是:

写边车是异步的,而且关库那条路上催写盘的调用没有被等待 (closeFullscreen 整个是同步函数,没地方 await)。 那一笔没走完,文件就停在旧值上;而视图状态是同步写掉的,是新的。

于是开库时旧文件盖掉新状态:框跳回原处、卡片留在新位置, 看上去就是「卡片跑到蓝框外面了」——而且只在重开之后才出现。

现在每一笔都盖上时间戳,开库时逐框比时间、谁新听谁的:

  • 文件不比我旧 → 听文件的(平手也让文件赢,它本来就是为跨机器准备的那一份);
  • 我严格更新 → 留着我的,并把文件补写出去(不然它永远追不上);
  • 两边都没有时间戳(1.3.93 之前写的存档)→ 听本地的。本地那份是这台机器上 你最后看到的样子,而文件恰恰可能是写丢的那一份。

某一次写丢了,从此不会再毁掉你的摆法——不管它是为什么丢的。 你库里那个框(m:6)现在正好是「视图状态说 2667、边车说 2730」的状态, 这一版开库就会自己取新的那个,不用你再拖一遍。

1.3.92 · 跨层拖金框,蓝框现在跟着走了。(这一条是前几版都没接住的那个。)

蓝框是按层存的——你在哪一层画的,它就记在哪一层。而金框从 1.3.88 起 逐层都有。这两件事撞在一起就是一个天天会踩的形状:

你站在浅层(比如「机器学习」),拖某个深文件夹(比如 「…/准确度的陷阱与混沌矩阵」)的金框。这个动作会带动那个文件夹里的卡—— 可你给那个文件夹画的蓝框,存在更深那一层(你是进去画的), 它压根不在这一屏上,于是一个都不跟。

然后你打开结构窗(钉着最深那层)——卡片已经在蓝框外面好一段距离了。

现在按文件夹的包含关系去找:拖一个金框,凡是在里面(它自己那层、 以及它下面任何一层)画的蓝框,只要有成员卡在这一趟里动,就一起跟着走。

那些框在浅层不画(它们属于别的层,画出来就是幽灵),所以你看不到它们动 ——但你打开结构窗时它们已经在正确的位置上了,这才是要紧的。 顺带修了落盘:跨层拖动时,边车写的是框自己那一层,不是"你站在哪一层"。

1.3.91 · 修三条,都跟「拖动金色方框」有关:

① 拖金框时,蓝色收纳方框还是不跟。 判据一直是错的,而且正好错在你这一类上:

原来问的是「我这个蓝框的全部成员是不是都在你里面」。可是一个蓝框跨两个同级 子文件夹的时候,它的共同祖先正是你当时站的那一层——而按你拍板的「本级不画框」, 那一层根本不长金框。于是哪个框都装不下它,判据回 false,代码就退回一条更老的、 「看蓝框画出来的中心落在哪」的位置判据——而你手画的框比贴身的金框大,中心落在 外面,于是静默不跟。框里混一张引进来的外来卡也是同一个下场。

现在换成一句充要的话:这一趟要动的卡,恰好就是那个金框底下的所有卡。 蓝框里只要有任何一张在里面,它就得跟;一张都不在,它就该留在原地。 跟你怎么画、画多大、收没收起,全都无关。

顺带:收起来的蓝框现在也跟着走了(它那条标题栏摆在重心上,位移得从它真正的 位置加起,以前干脆跳过了它)。

② 金框的身份被拼重复了。 同一个文件夹,站在不同层看会拿到不同的 id——而框的 名字和收起状态是按 id 存的两张全局表。所以「我在这一层把它收起来了,换一层它又自己 展开了」,改名同理,而且不报错。根因是递归发框时把完整路径又和父路径拼了一遍。

③ 边框位置的那个文件,会被静默丢掉一笔。 这个是从你库里真实的数据里查出来的:

data.json(视图状态,每次拖动同步写)  m:6  x=3003  bottom=294
.crystal-boxes.json(边车,11:55:52)  m:6  x=2709  bottom=252

两份对不上,而落盘规则是文件优先——所以下次开库那个框会跳回旧位置、卡片却 留在新的地方,看就是「卡片跑到蓝框外面去了」,跟你拖不拖没关系。根因是关库那条 路上催写盘的调用没有被等待(closeFullscreen 整个是同步函数),而排队表又在写 成之前就被清空了。现在改成写成了才出队,并把合并窗口从一个 700ms 的防抖压到 一个 tick(同一次松手里的几笔合并,跨 tick 立刻写)——窗口小到几乎没有。

1.3.90 · 结构窗顶栏能整条收起来了。 最左边那颗 ▲ 现在是一颗按钮两种状态, 颜色就是状态:

  • 蓝 = 顶栏所有按钮都摆着(默认,和以前一样);
  • 白 = 全收起来,屏幕上只剩这一颗 ▲;再点一下全回来。

收没收起记着,下次开窗不用重收。(它顶替了 1.3.84 那对只收晶体名的 ▲/▼—— 那把粒度更细,但现在这一颗一次就把名字和按钮一起收了,所以 ▼ 撤掉了。)

为什么这回敢连"换晶体"那颗入口一起收(上一版的注释里明令禁止过):出口就在 原地——同一颗 ▲ 再点一下全回来。原来那条禁令防的是"入口在需要它的那一刻恰好 不可见,而且没有回头路",这两件事不一样。底线没松:收起态下这颗 ▲ 永远 留在屏幕上,它是唯一能把顶栏叫回来的东西。

1.3.89 · 修两条(都是 1.3.88 带出来的):

① 拖金色方框时,里面的蓝色收纳方框还是不跟着走。 你报的原话是「打开结构窗时候, 卡片已经移出蓝色方框之外好一段距离了,但是这个蓝色方框里面仍然算着这些卡片, 然后移动蓝色方框,就连同这些物理位置上不在这个方框里面的卡片一起移动」。

根因是 1.3.88 那条跟随的判据写错了:它问的是「蓝框的中心落不落在金框矩形里」。 而蓝框是你手画的,通常比那个贴身的金框大——往一边探出去之后中心就跑到金框外面, 于是这一趟一个跟随者都找不到,一声不响。

现在改成看成员:一个蓝框"住在"哪个金框里,看它收的那几张卡是不是全都在那个 金框里。这个判据跟你怎么画无关。顺带两条:

  • 拖外层的金框,住在里层的蓝框也跟着(拖 A 的时候 C 里的卡同样在动);
  • 蓝框"不许移出金框"那条约束用的是同一个判据——它原来有一模一样的毛病, 蓝框画大一点约束就静默失效了。

② 金色方框的标题栏下面,加了一条金色实线。 金框现在一层层套着,抬头和数据之间 没有分界,一眼看不出"这一条是这个框的名字"还是"里面某个子框的东西"。

1.3.88 · 金色方框一层一层地分开了。 以前一个文件夹长出来的金框,会把它整棵 子树的卡全摊平吞进去——A 里面嵌着 B1、B2,B2 里面又嵌着 C 的时候,屏幕上只有 A 一个 框,四层的卡混在一起,层级完全看不出来,而那正是结构窗存在的意义。

现在每一层文件夹都发一个框,框就自然套起来了,一个框内部按你拍板的方式横着切:

┌ A ─────────────────────────────────┐
│  [A 自己的卡]  ┃  [B1 的卡]  ┊  [B2 的卡] │
└────────────────┸────────────┸──────┘
        珊瑚橙竖线 ↑      金色竖线 ↑
      (本级 ↔ 子文件夹)  (同级 ↔ 同级)
  • 珊瑚橙 #FF6B6B 实线分的是跨层:这个文件夹自己的卡 ↔ 它的子文件夹;
  • 金色实线(和框同一个金)分的是同级:两个兄弟子文件夹之间。 再深一层也一样——C 在 B2 里,B2 内部又是「B2 自己的卡 ┃ C」,还是珊瑚橙。

另外三条一起改了(都是同一次报告的):

  • 蓝色收纳方框现在压在金色方框上面。 金框变成嵌套的之后,一个蓝框常常嵌在好几层 金框里面,不给它一个更高的层级就会被内层金框盖住。
  • 金框是容器了:里面的卡拖不进别的金框,也不能拖进上一级"自己的卡"那一块 (就是珊瑚橙线的另一边)。拖动时卡片停在那条边界上,不是滑进去再弹回来。 蓝色收纳方框也不能移出它所在的那个金框——拖和拉大小都出不去。 而蓝框不是容器:卡片照样可以拖进拖出。
  • 拖金框,里面所有元素跟着走。 卡片本来就跟着;这次补上的是蓝色收纳方框 ——它是个自己记着矩形的容器,以前拖金框时它钉在原地不动。

1.3.87 · 连线接法现在跟着卡片走——把一颗晶体压缩发给别人,对方打开时线的 走向和你这边一模一样。(用户 10-01 报:「压缩发给朋友,他那边只有左右连线」。)

根因是接法一直存在本机:它在视图状态里,而且键是"你当时站在哪一层"。所以 换台电脑是空的、把文件夹复制到库里别处键也对不上——压缩包本身没带走它。 现在它写进卡片自己的 frontmatter:

晶体接法: ["[[02-中继]] b t"]

一条 = 「往 02-中继 那根线,从我的下边出去、进它的上边」(t/r/b/l 是上下右左)。 只在你亲手拖过连接点的那些线才写,没动过的一律不写(默认接法是按位置算出来的, 本来就换哪台电脑都一样)。一张卡手动调过 10 根线,也就多约 250 字节。

  • 目标写成 [[双链]] 的形状,所以给那张卡改名时 Obsidian 会连它一起改, 接法不会失联。
  • 老接法会在开库时自动搬进文件(一次最多搬一批,剩下的下次开接着搬)。
  • 顺手把「写进文件却读不回来」那条路堵了:解析器原来被调两道,第二道拿到的 已经是对象,被当成字符串整表丢掉——文件里写着、屏幕上却没生效,一声不响。

1.3.86 · 修:蓝色连线不管卡片怎么摆,永远从左右两边接。上下叠着的两张卡, 线也是从右边出去、绕一圈回到左边。根因是"没有手工指定时"的兜底判据写死了左右 (只看谁在左谁在右)。现在改成按位置挑面对面的一边:上下叠着的走「下→上」, 左右摆的走「右→左」。 这件事跟换电脑还有一层关系:你亲手拖过的接法是存在本机视图状态里的,不跟着 卡片走——所以你把资料搬到别人电脑上一跑,一条接法都不在,整屏退化成清一色左右。 改成按位置算之后,默认接法是从排布推出来的,哪台电脑都一样;你亲手拖过的那根 仍然以你拖的为准(手动 > 自动)。

1.3.85 · 修:点方框的名字改不了名了——1.3.83 带进来的。1.3.83 让整个方框 都能起手拖动,而拖动在按下的那一刻就把指针抓走了。于是「按在名字上、原地松手」 那一下:按下的目标是名字、松开的目标变成了整个方框,而 click 的目标是这两者的 最近公共祖先——落到方框上,那就查不到名字了,改名当场哑掉。 (1.3.83 之前它只在空框上是好的:那会儿空框在守卫上直接早退,压根没抓指针。 我放开那道早退的时候,把「空框能拖」和「点名字改名」共用的一扇门一起拆了。) 改法和 panzoom / holodrag 里早就写着的那条一致:过了 4px 才抓指针。 没真拖的那一下,从头到尾什么都没发生。

1.3.84 · 修:结构窗顶栏的晶体名太长,会把后面的按钮挤出窗外。那条栏是 不换行、也没有宽度上限的,而晶体名是里面唯一会长的东西——名字一长,它一路 往右顶,而窗的外层是 overflow:hidden,被顶出去的按钮就再也点不到了。 现在给名字封了顶(超长用省略号,完整的那颗在悬停提示里),顶栏本身也改成到边 换行——两道一起上,按钮再也不会跑出窗外。名字左边多了一对 ▲ / ▼: ▲ 收起名字,▼ 放出来(收起后那颗按钮缩成「晶体」两个字,换晶体的入口还在)。 收起来的这件事记进偏好,下次开窗不用重收。 (顺带一句:上一版 1.3.83 修好的「空方框拖不动」,要是你还看得到,多半是插件 没重载——在 设置 → 第三方插件 里把它关掉再打开一次。)

1.3.83 · 四条,都在故事线 / 结构窗里(用户 09-30)。

方框整块都能拖了。 以前只有顶上那条 26px 的标题栏能抓,现在框里任何一块空白 都能起手。压在卡片上时拖的仍然是卡片——卡片层级比框高,这一条是层级给的,不用额外判 (所以「拖卡片区域不会拖框」是白拿的)。代价说清楚:在框的空白处按下不再平移画面, 推画面请拖框外面,或者用滚轮。顺带修好一条:一个还没装卡的框以前拖不动, 现在也能摆了。

金色方框里的连线,走线方式和进到那个文件夹里一样了。 「接法」(这根线从卡片的 哪一边出去、怎么拐)是按层记的,站在外面看金色方框时查不到那一份,就退回默认的 「看谁在左谁在右」——同一对卡、同一根线,两个地方长得不一样,而屏幕上没有任何东西 解释这件事。现在各层的接法都算数,当前这一层优先。

方框也走格点了。 手动框吸到格点上(判据和卡片同一把尺子,左下角),框里的卡 按同一段位移整体挪——相对位置一点不变,不会被挤到一起;金色方框没有自己的坐标, 退一步按整格移动。大小仍然随你拉,只有摆在哪才需要对齐。 (格点 1.3.34 撤过一次,这一版按你的要求装回来。)

挑文件夹那块面板的抬头多了一颗「取消」。 将建在、新建 / 删除 / 重命名晶体、 删除 / 重命名卡片、结构窗挑晶体——它们打开的都是这块面板,关法从这一版起统一成 这一颗(以前只能再点一次「将建在」把它收起来,那颗按钮叫「将建在」,不像一个"关")。

1.3.82 · 新增:结构窗里可以一次删掉一批卡片。框选卡片(顶栏「框:卡」+「选框」, 框住几张)之后,顶栏多出一颗红框的「删除卡片(n)」——点一下,这几张 连笔记文件一起进回收站(能捡回来),卡片所在的晶体不动。 删的是文件,所以代价写了三处:按钮上的张数、悬停那句话、底下那条说明条 ——这扇窗没有确认弹窗是既定的规矩(09-20 定的),说明条就是仅有的告知。 按 D 不删卡:一个裸按键就能把好几个文件扔进回收站,太容易误触 (那会儿手正放在方向键上挪卡片)。要删就走那颗按钮。 (库那一屏的卡档仍然只有移动——那边没有这颗按钮。)

1.3.81 · 修:点「编辑」会凭空多出一个空白标签页(全屏 / 浮窗 / 嵌入都中)。 根因是插件向宿主"借一颗现成的标签页"时用的是 getLeaf(false),而那句话的语义 不是"拿一颗现成的"——宿主内部走的是 getUnpinnedLeaf():"拿一颗没被钉住的", 当前活动的那颗要是钉住的,它就当场造一个新的空页。你在阅读器里时,活动的那颗 正是晶体库自己,于是每点一次 ✎ 就多一个。 实证是往宿主 Console 挂了个探针,在标签页被插进 DOM 的那一刻打出了调用栈 (mountEditor → getLeaf → getUnpinnedLeaf → setActiveLeaf → … → insertBefore)。 改法:那个位置根本不需要一颗真标签页,只需要它的"类"——改成从已经查到的 markdown 标签页上取构造器,只是查表,不激活、不新建。

1.3.80 · 修:别的机器改过的卡,这边从 1.3.59 起就没跟上过。多设备同步把 改好的正文、概念、来源、标签、坐标传过来时,一样都不会变,屏幕上什么都不发生—— 看着像通知根本没送到。根因是加「晶体坐标」那一次,调用参数错位了一格, 卡片对象被挤掉;而那个名字在作用域里正好还有一份,于是不报错。 测试只逮到 2 条,实际断掉的是整条同步链路。

1.3.79 · 修:新卡还是落在"默认坐标"。1.3.77 里我拿屏幕坐标当世界坐标用了, 而这两者只在"相机停在原点、缩放 1"时才重合——所以新卡永远落在一个 和你推到哪儿毫无关系的固定地方。现在先换算再落座:你说的"当前视口"就是相机 此刻的位置,新卡因而真的落在你正看着的那一屏右边 5%、上下居中。

1.3.78 · 修:浮窗 / 嵌入档下点「编辑」会把笔记开到一颗空标签页旁边。 根因不在"编辑"本身,在它依赖的那个前提:从"当前活动的那颗叶子"裂一半—— 而这两档多了一颗属于插件自己的标签页,它完全可以就是活动的那颗。 现在 split 的基准自己挑一颗已有的 markdown 叶子。全屏档逐字不变 (那两档下"最近用过的那颗"本来就是你的笔记)。

1.3.77 · 修:建在子文件夹里的新卡还是落在默认坐标——建卡有两条路, 我只在其中一条里摆了位,而你走的恰好是另一条(「✎ 在编辑器里写」)。 两条路都是"建一张卡",位置这件事只能一样。落点也按你定的公式改成 视口右侧 5%(卡片右边缘落在"右边减 5% 宽"上,纵向居中), 不吸附格点——你给的是具体公式,硬吸反而会差半格。

1.3.76 · 修:建在子文件夹里的新卡不会被摆进结构窗的视口(落回默认位置)。 判据原来写的是"卡片所属晶体的链必须和你看着的那一层完全相等",而卡片常常建在 更深的子文件夹里——它明明画在这一屏上(取卡片是递归的),却被这条判据挡掉了。

1.3.75 · 阅读器顶栏可以收起来了:顶栏最右端多一颗图标,点一下把它压成一颗图标, 桌面就多出一条——结构窗和页面窗能摆到原先顶栏占的位置上。图标两档之间转 180° (展开态箭头朝上=按下去内容往上走,收起态朝下=按下去挤回来), 图形始终是同一个,状态的差别由鼠标悬停那句话讲清楚。展开时被压在顶栏下面的窗 会跟着往下让。

1.3.74 · 修 1.3.73 的四处 + 一处你报的:嵌入档那个"跟着标签页大小走"的观察器 因为一个声明顺序错误从来没建起来过(而且被一个 catch 吞掉了,没留任何痕迹); 嵌入档按整块屏幕而不是标签页缩放(卡片会撑出半宽的分屏);连点两下切换按钮会跳档; 顶栏那颗按钮的刷新漏了重排。另外:把卡片存进晶体库之后,结构窗现在会实时显示 ——以前要关一次再打开(刷新的收口从"逐个入口"移到了"库重画就刷窗")。

1.3.73 · 新增第三档「嵌入」:库就长在它那颗 Obsidian 标签页里,不盖任何东西, 可以和别的标签页分屏。顶栏那颗按钮变成三档循环(全屏 → 浮窗 → 嵌入), 按钮上写的就是下一档叫什么。嵌入模式不锁笔记的滚动(另外两档会,它们盖在笔记上)。

1.3.72 · 浮窗模式的六处修正:卫星和悬浮窗跑偏(它们的坐标是屏幕坐标, 而它们住的那一层是"层内坐标",浮窗时差一个窗口原点);右下角抓手关库后还留在笔记上 (而且只增不减);拖拽监听没摘(每开一次漏六个);卡片面板会高于窗口 (vh 量的永远是视口)→ 现在 CSS 改问"这一层多大";顶栏在窄窗口里被裁掉 (连 ✕ 都点不到)→ 改成可换行;窗口比屏幕宽时抓手跑到屏幕外。

1.3.71 · 修 1.3.70 的致命错误:晶体库打不开(报 Cannot access 'j' before initialization)。 原因是我把 viewBox 的声明放在了用到它的那行之后(一个 TDZ 错误),而生产包里变量名被压成 一个字母,从报错上完全看不出是谁。现在声明挪到了使用之前。

1.3.70 · 浮窗模式:库可以不占满屏,收成一块可拖可缩的矩形浮在笔记上方, 一边看笔记一边用库。插件设置里选默认档,库里顶栏那颗按钮随时切。 (版本号从 1.3.60 跳到这里:这是一次架构调整——库第一次有了"占多少屏幕"这个概念, 所有"拿视口当边界"的坐标计算都改成了"拿这一层界面当边界"。)

1.3.60 · 收纳方框落盘:每颗晶体一个 .crystal-boxes.json(点开头,Obsidian 里看不见), 名字、大小、收起状态、成员都在里面。老版本里只存在本机的位置,升级后第一次开库会自动搬进去。

1.3.59 · 卡片坐标写进卡片自己的 frontmatter(晶体坐标: [3, 5],以左下角为准) ——换台电脑打开,相对摆放位置一样。同时:收纳方框取消格点(拖到哪停哪), 新建的卡片和 + 框 落在你正看着的地方(以前建在世界的固定角落,视口推远了得推回去找)。

1.3.58 · 收纳方框按晶体分层。以前它是全局的——换一个文件夹看,别的层画的框还在原地摆着。

1.3.57 · 卡片的格点与方向键:拖动吸附到格点,选中后方向键一格一格挪。 最小单位 = 卡片宽的 1/10,坐标以左下角为准。

1.3.56 · 修「导入卡片」的四件事。其中两件要紧的:在挑卡片的选择器里点文件夹名 会静默改掉你的「将建在」;外来卡拖进子晶体框时一声不响(现在会告诉你去用「+ 框」)。

1.3.55 · 导入卡片:从别的晶体引一张卡到这一屏上来,拖进收纳方框, 跨级连蓝线从此成立。卡片本身一个字都不动。

1.3.54 · 框选卡片、整批拖走。顶栏多一颗「框:卡」——框住几张,按住其中任意一张 整批一起动,松手整批判归属。在这之前,把十几张卡收进一个框只能一张一张拖。

1.3.53 · 修:拖框走的世界距离和卡片不一致(相机会缩放时框走得短);收起态的框一拖就把卡片甩到框外。

1.3.52 · 收纳方框改成「你自己画的框」:可以拖、可以拉大小,不再只是卡片周围一圈算出来的外壳。 收起之后外面有蓝线连进来的卡会点一个黄点,鼠标悬停它,相关的框边框闪一圈。

1.3.51 · 收纳方框的颜色加深。第一版太浅,在库自绘的深底上几乎看不见。

1.3.50 · 修:空框不画 → 「点了 + 框 一点反应都没有」。建完框要能把卡拖进去,而拖进去的前提是屏幕上看得见那个框。

1.3.49 · 拖收纳方框的标题栏 = 整组卡片一起挪。

1.3.48 · 手动收纳方框的入口「+ 框」;卡片拖进拖出;删框(框只是分组,删框不动你的卡)。

1.3.47 · 修:方框没被清场,每重画一次就叠一层。

1.3.46 · 结构窗的收纳方框:每个子晶体自动一个,可改名、可收起;收起后里面的卡和线一起收起来, 但「那边还有东西」这件事不丢。

1.3.45 · 桌面卡片窗顶上补一行「概念」。

1.3.44 · 结构窗那一节补全(看 / 写模式、右键三种落点);+页的 markdown 按行分页、改完按回车; 上手补一步「往卡片目录里放一份能读的东西」。README 在这版重写过一次——把文献模式 · 桌面提到主功能位置。

1.3.43 · 重命名卡片 / 重命名晶体两颗按钮;修「别人在 Obsidian 里改了名,插件不知道」—— 以前会在图上留下一张灰色的、点进去什么都没有的卡。

1.3.42 · 每一扇窗都有一颗「收纳」,不带条件。

1.3.41 · 收纳栏最上面那颗 +:外部标签页,可以内嵌 deepseek、Google 这些站点。

1.3.40 · 阅读器的收纳栏,以及「边看边记」那一栏的开关。

1.3.39 · 故事线也有「看 / 写」两档了:写模式下拖线真写 [[双链]]、选框删蓝线、一层撤销。

1.3.38 · 去掉写模式里那个「为什么连过去?」输入框——连着拖几根线时每根都被它截一下。 理由照样可以手写在 ]] 后面,只是不再由插件代劳。

1.3.37 · 写模式下多一颗「选框」删蓝线:框住几根,从卡片正文里精确挖掉那条 [[链接]] (两个方向一起删、逐字节可还原、一次撤销)。

1.3.36 · 蓝线改成和金线一样的折线(直线 + 圆弧拐角),不再是贝塞尔弧 ——弧线从卡片中段穿过去,两根一交就看不出谁接谁。

1.3.35 · 蓝线能从上 / 下 / 左 / 右接(认你拖的那个连接点); 写模式下右键一张卡就藏掉它所有入链出链,顶栏「显示全部」一键收回;橡皮筋预览和落地同形同色。

1.1.31 / 1.1.3 / 1.1.2 / 1.1.1 / 1.1.0 · 草稿纸、边看边记的「返回」、删除卡片; 草稿纸从一堆文字改成摆到桌面上的一张真卡。几个补丁版本号是因为发过的号不能复用。

1.0.2 / 1.0.1 / 1.0.0 · 默认卡片目录改成中性的 cards;按自动审查改三处;首次提交。

许可

GPL-3.0。

HealthExcellent
ReviewSatisfactory
About
Turn a folder of Markdown cards into a living crystal vault and navigate nested folders as crystals on a ring. Visualize links as lines with directional arrows, read PDFs/images/Markdown side-by-side while taking notes, and test recall by hiding card content until you reveal it.
GraphVisualizationFlashcards
Details
Current version
1.4.15
Last updated
4 days ago
Created
3 weeks ago
Updates
78 releases
Downloads
257
Compatible with
Obsidian 1.5.0+
Platforms
Desktop only
License
GPL-3.0
Report bugRequest featureReport plugin
Author
ZhangrunyaoZhangrunyaorunyao-zhang
GitHubrunyao-zhang
  1. Community
  2. Plugins
  3. Graph
  4. Crystal Vault

Related plugins

Excalidraw

Visual PKM powerhouse. Create and edit Excalidraw drawings.

Advanced Canvas

Supercharge your canvas experience. Create presentations, flowcharts and more.

ExcaliBrain

An interactive, structured mind-map of your Obsidian vault.

Breadcrumbs

Visualise the hierarchy of your vault using a breadcrumb trail or matrix view.

Mermaid Tools

Improved Mermaid.js experience: visual toolbar with common elements and more.

Maps

Adds a map layout to bases so you can display notes as an interactive map view.

Flashcards

Anki integration.

Spaced Repetition

Fight the forgetting curve by reviewing flashcards & entire notes.

Persistent Graph

Save and restore the positions of nodes on your graph.

Strange New Worlds

Reveal networked thought and the strange new worlds created by your vault.