Skip to content

Releases: YaYII/obsidian-zoomable-reader

1.3.12

Choose a tag to compare

@github-actions github-actions released this 21 Sep 10:13

Changelog

1.3.12

  • 图里的文字固定 ≤16px,不再被「拉伸」放大。 用户原话:「你的插件和主题在生成 mermaid 里面的
    文字打小应该是固定的,不能超过 16px 的大小」。根因是 1.3.9 那条「图表撑满版心」的规则:
    它把 svg 连字带线一起放大 —— 一张 478px 的图铺进 900px 版心是 1.9 倍(白板 1280px 时 2.7 倍),
    图里 16px 的字渲染成 30~43px。现在图表只保证「不溢出」(max-width):窄图保持原尺寸,
    宽图按比例缩进版心;主题侧把图内字号改成固定令牌(节点 14px、边标签与时序消息 12.5px),
    不再跟着「设置 → 外观 → 字体大小」和分辨率增益浮动。
  • 长标签自动折行,不再「一行顶一个宽度」。 用户原话:「图形里面的文字内容太多了,你应该可以
    换行呀,而不是一行顶一个宽度呀」。查证(Mermaid 10.9 实测):普通标签 A[长文本] 从不折行 ——
    把 flowchart.wrappingWidth 从 460 改成 120,渲染结果一模一样(同一个 478×42 的框、同一行字)。
    也就是说,过去插件里那个「标签最大宽度」滑块对普通标签其实是个空旋钮,这正是抱怨的根源。现在:
    • 插件把长标签改写成 markdown 字符串(A["长文本"])—— 只有这种标签 Mermaid 才按折行宽度排版;
      同时打开 markdownAutoWrap,默认折行宽度 460 → 260(一行约 16 个汉字,长标签折成 2~3 行);
    • 白板 / 版面视图在渲染前改写(wrapMermaidFences);阅读视图由 Markdown 后处理器接管:
      用 context.getSectionInfo 取回该块源码 → 改写 → 自己重渲染换上去。任何一步失败都保持宿主
      原本那张图不换 —— 这块代码最坏的结局必须是「没折行」,而不是「图没了」;
    • 真实渲染实测(真 Mermaid + 真主题 CSS):同一个 43 字标签,改写前 1 行、框 678px;
      改写后 3 行、框 278px,字号不变(14.96px),文字不溢出框。

Verification: 单元测试 100 条(新增 tests/mermaid-labels.test.ts 十条:只改长标签、短标签一字不动、
markdown 字符串不重复包装、边标签、幂等、围栏提取);npm run verify:layout 新增 6 条真实渲染断言
(改写前后的行数 / 框宽 / 字号 / 溢出);npm run verify:reading 37 条(「流程图按版心宽度显示」
那条按用户的新要求翻过来,改成断言保持自然宽度 478px)。

1.3.11

  • 查看器里给的是「原图」,不是正文里那张缩略图。 用户原话:「查看图片的时候,放大后,点击图片的时候,
    你需要确定放大的图片是原图高清的」。正文里的 <img> 可能带 srcset(浏览器按正文的显示尺寸 × DPR
    挑一张),也可能被懒加载插件塞了 1px 占位图、真图在 data-src 里。查看器现在自己挑:
    srcset 里取分辨率最高的一张,src 是占位图就用 data-src。顺带修掉一个真 bug ——
    srcset 不能按逗号 split:data: URL 里全是逗号,切完每个候选都成了半截地址
    (在验证台里的表现是「查看器的图自然尺寸 0」)。
  • 右上角多了一个关闭按钮。 用户要求:「放大后的图片,右上角应该有一个关闭的按钮,方便关闭放大的图」。
    它钉在图片区域的右上角(跟着安全区走),与图片的缩放平移无关 —— 图拖到哪儿它都在同一个位置;
    桌面 34px、手机 44px(Apple HIG 的最小可点尺寸),鼠标 / 触摸 / Esc 三条路都能关。
    工具条里那个 12px 的小叉已去掉:两个关闭按钮只会让人犹豫。
  • 点一下图片 = 落到原图 100%(已经在原图了就收回「适配」)。这是「点击图片 → 确认是原图高清」最直接的
    落点:点完读数会写明 1600 x 900 px → 1600 x 900 px · 原图 / native。
    三条防误触:位移 ≤ 8px、时长 ≤ 500ms、全程单指;拖动平移松手那一下不会触发
    (手势层一旦判定为拖动就会 setPointerCapture,pointerup 根本回不到内容元素上)。
    双击仍然是放大到 200%,两条路不打架。

Verification: 单元测试 88 条(新增 parseSrcset / pickHiResSource:data URL 里的逗号、
1x/2x 描述符、懒加载占位图、相对地址拼接);npm run verify:gestures 93 条断言,
其中 8 条新断言先在旧代码上跑出红色:懒加载只拿到 1x1、关闭按钮不存在(桌面与手机各两条)、
点图片没反应(0.533 → 0.533)、手机触摸图片同样没反应(0.642),红的时候 85/93。
诚实边界:无头 Chromium 自己给 srcset 挑的就是最大的那张,所以浏览器侧那条「拿到 1600px 原图」
证明的是最终结果;「比浏览器更会挑」这条逻辑由 tests/lightbox.test.ts 的单测钉住。

1.3.10

  • 手机上终于看得见那个放大的 icon 了 —— 这一条是用户直接点名的。 触屏设备上按钮以前是
    @media (hover: none) { display: none } 被整个藏起来的,理由是「轻点图片就能放大,按钮不必占地方」。
    用户的回答:「你应该展示放大的 icon,这样我就可以点击了,而不是依靠点击图片,因为图片点击的时候
    可能点击到了背景上去了,所以体验不是很好」。现在触屏上按钮常驻可见(不再靠悬停提亮:触屏没有
    悬停,0.42 的不透明度等于看不见),视觉 34px,触区用 ::after 外扩到约 46px —— 手指按不准也点得到。
    轻点图片这条入口保留,但按钮才是明确的那一个。
  • 连点两下按钮不再进编辑。 按钮就贴在图片角上,而「双击」的第二次 tap 正是 Obsidian
    「双击进入编辑」的触发点:现在第二次 tap 会被吃掉(第一次照旧打开查看器,且只打开一次)。
  • 查看器里的图现在是高清的,不是被压缩后再拉大的。 两个独立原因,都修了:
    • 100% 的基准错了:以前「1 个源像素 = 1 个 CSS 像素」,所以在 DPR=3 的手机上,一张 1600px 的
      截图被铺到 4800 个物理像素上 —— 横向拉伸 3 倍,这就是用户说的「放大查看都模糊了」。现在按
      naturalWidth / devicePixelRatio 排版:100% 就是原图分辨率(1 源像素 = 1 设备像素),读数也
      对得上(1600 x 900 px → 1600 x 900 px)。再往上放大才是放大镜。
    • 画布上带着 will-change: transform:它把画面钉死在提层时的比例上,之后放大只是把旧位图拉大
      (照片发软、图表里的 CSS 文字直接糊)。已去掉。
    • 另外,打开小图不再「适配」放大(适配比例封顶 100%),并解除主题/宿主塞给 img 的
      max-width: 100%(它会把刚摆好的 1:1 又压回去,窄屏上高清立刻失效)。
  • 细节:插件的手机手势拦截器现在会避开自己的放大按钮 —— 按钮里的图标是 <svg>,不排除就会被
    「这是不是图表」的判定当成一张 18px 的图表打开。

Verification: 单元测试 82 条(新增 tests/lightbox.test.ts 钉住 1:1 的换算,含 devicePixelRatio
不老实的情况);npm run verify:gestures 82 条断言,npm run verify:reading 36 条断言。
新断言先在旧代码上跑过一遍确认它们能失败:1.3.9 上触屏的按钮是 display=none opacity=0.42 0x0、
小图打开是 426%、will-change 计算值是 transform。

1.3.9

  • Fixed: flow charts (and every other diagram) ignored the line width. 1.3.7's width rules only
    targeted img and video, but a Mermaid flow chart is an <svg> — and themes set
    flowchart.useMaxWidth: false (that is what makes boxes follow the text), so Mermaid renders at
    its natural width and the diagram stayed at 478 px inside a 900 px column, or overflowed on a
    phone. The rules now cover .mermaid svg, .block-language-mermaid svg,
    .excalidraw-svg svg and .block-language-chart svg/canvas as well, and the plugin's own
    view got the same treatment in styles.css.
  • Scaling is by ratio (SVG is vector, so the text scales with it): measured in a real browser, a
    478 × 98 diagram becomes 900 × 184 with the 478:98 ratio intact, and on a 390 px phone viewport
    both the diagram and a photo land at 342 px — one screen wide, as asked. Double-tap still opens the
    zoomable viewer, which is where detail reading now happens.
  • The setting is now called 阅读视图图片/图表宽度 (it always governed both, the label just lied).

Verification: npm run verify:reading is now 32 assertions — the new ones measure the diagram in
the DOM: fill → 900 px with the aspect ratio preserved, contain → stays 478 px, and on a phone
viewport the diagram and the photo are both clamped to the same screen width.

1.3.8

  • Fixed: double tapping still opened the editor. 1.3.7 only intercepted double taps on images,
    but Obsidian's double-tap-to-edit is a gesture of the whole reading view — tapping text
    triggers it too, so in practice nothing changed. The interception now covers every double tap
    inside the reading view (text, images, diagrams); double tapping an image or diagram opens the
    zoomable viewer instead. Two separate switches: 手机:双击不进编辑 and 手机:双击图片 = 放大查看.
  • Three more real bugs, all found by the browser harness rather than by reading the code:
    • The same event was handled twice (the module listens on both window and document in
      the capture phase), so one tap looked like two and a single tap opened the viewer. Events are now
      deduplicated.
    • A two-finger pinch was counted as a tap, poisoning the next double tap. Multi-touch now
      cancels tap tracking, and only touchend counts as a tap (pointerup/click are used for
      swallowing only).
    • Within one gesture, touchstart targets the image but touchend and the synthetic
      dblclick target the container
      , so the hit test concluded "text" and the image never zoomed.
      The hit is now resolved from the touch-start element and the coordinates as a fallback.
  • A touch double tap also produces a synthetic dblclick (in an unstable order) and both used to
    open the viewer; they now share a short window so one double tap opens exactly once.
  • 手机:双击自检 (off by default) shows a notice for every intercepted double tap — if a gesture
    still misbehaves on a real phone, the notice tells whether the plugin saw it at all.

Verification: npm run verify:reading — 28 assertions. Besides the earlier reading-view
checks: a single tap does nothing, a double tap on text does not enter editing and opens nothing,
a double tap on an image opens the viewer exactly once and the simulated editor handler records
zero events, gestures outside the reading view are ignored, and mobile: false (desktop) does
not intercept at all.

1.3.7

  • Images follow the line width, scaled by ratio. In the reading view every image is now scaled to
    exactly the line width you chose (900 px by default) with `height: auto`, so nothing is cropped
    or stretched and a 600 × 200 screenshot becomes 900 × 300. Explicit widths (`![[image.png|300]]`)
    are normalised too — one page, one image width, as asked. Two other policies stay available
    (fit within the line width, natural size), and the rules only ever touch
    `.markdown-reading-view`, never the editor.
  • Mobile: double-tapping an image zooms it instead of entering editing. In Obsidian's reading
    view a double tap on an image means "edit", which is exactly wrong while reading on a phone. The
    plugin now intercepts that gesture inside the reading view and opens the zoomable viewer instead;
    the edit path is suppressed (use the menu button when you really want to edit). A single tap does
    nothing new, gestures outside the reading view are ignored, and desktop is untouched — as
    asked, this is a mobile behaviour.
  • Two ordering bugs found by the browser harness, both fixed rather than papered over. A touch
    double tap also produces a synthetic `dblclick`, and which one arrives first is not stable — the
    first version opened the viewer twice. Both paths now share a short mutual-exclusion window: one
    double tap opens the viewer exactly once. The harness also had to be honest: its simulated
    "Obsidian edit" listener originally counted every tap, which proved nothing; it now does real
    double-tap detection, so "0 edits" means the double tap was genuinely consumed.

Verification: npm run verify:reading is now 26 assertions — the image policies are measured
in the DOM (fill: 600 px image → 900 px, ratio still 3:1; contain: stays 600 px; natural: no rules
injected), the desktop path is asserted not to open the viewer, and on a phone viewport a real CDP
double tap opens the viewer exactly once while the simulated edit handler records zero events.

1.3.6

  • The reading view itself now has a width and a zoom. Obsidian's own reading view is not taken
    over — the plugin changes two CSS properties of it: the line width (default 900 px, the value
    that was asked for, with 760–1200 px and 跟随主题 / follow-the-theme options) and a zoom level
    (60 %–200 %, default 100 %). Your theme files are untouched, and follow the theme + 100 % injects
    nothing beyond one `touch-action` line.
  • Zoom reflows instead of stretching. It is applied as CSS `zoom` with the sizer's `max-width`
    divided by the same factor, so the text gets bigger while the measure on screen stays exactly the
    line width you picked. A screenshot-level stretch would have changed the line length; this does
    not.
  • **You operate it: pinch, ...
Read more

1.3.11

Choose a tag to compare

@github-actions github-actions released this 21 Sep 02:00

Changelog

1.3.11

  • 查看器里给的是「原图」,不是正文里那张缩略图。 用户原话:「查看图片的时候,放大后,点击图片的时候,
    你需要确定放大的图片是原图高清的」。正文里的 <img> 可能带 srcset(浏览器按正文的显示尺寸 × DPR
    挑一张),也可能被懒加载插件塞了 1px 占位图、真图在 data-src 里。查看器现在自己挑:
    srcset 里取分辨率最高的一张,src 是占位图就用 data-src。顺带修掉一个真 bug ——
    srcset 不能按逗号 split:data: URL 里全是逗号,切完每个候选都成了半截地址
    (在验证台里的表现是「查看器的图自然尺寸 0」)。
  • 右上角多了一个关闭按钮。 用户要求:「放大后的图片,右上角应该有一个关闭的按钮,方便关闭放大的图」。
    它钉在图片区域的右上角(跟着安全区走),与图片的缩放平移无关 —— 图拖到哪儿它都在同一个位置;
    桌面 34px、手机 44px(Apple HIG 的最小可点尺寸),鼠标 / 触摸 / Esc 三条路都能关。
    工具条里那个 12px 的小叉已去掉:两个关闭按钮只会让人犹豫。
  • 点一下图片 = 落到原图 100%(已经在原图了就收回「适配」)。这是「点击图片 → 确认是原图高清」最直接的
    落点:点完读数会写明 1600 x 900 px → 1600 x 900 px · 原图 / native。
    三条防误触:位移 ≤ 8px、时长 ≤ 500ms、全程单指;拖动平移松手那一下不会触发
    (手势层一旦判定为拖动就会 setPointerCapture,pointerup 根本回不到内容元素上)。
    双击仍然是放大到 200%,两条路不打架。

Verification: 单元测试 88 条(新增 parseSrcset / pickHiResSource:data URL 里的逗号、
1x/2x 描述符、懒加载占位图、相对地址拼接);npm run verify:gestures 93 条断言,
其中 8 条新断言先在旧代码上跑出红色:懒加载只拿到 1x1、关闭按钮不存在(桌面与手机各两条)、
点图片没反应(0.533 → 0.533)、手机触摸图片同样没反应(0.642),红的时候 85/93。
诚实边界:无头 Chromium 自己给 srcset 挑的就是最大的那张,所以浏览器侧那条「拿到 1600px 原图」
证明的是最终结果;「比浏览器更会挑」这条逻辑由 tests/lightbox.test.ts 的单测钉住。

1.3.10

  • 手机上终于看得见那个放大的 icon 了 —— 这一条是用户直接点名的。 触屏设备上按钮以前是
    @media (hover: none) { display: none } 被整个藏起来的,理由是「轻点图片就能放大,按钮不必占地方」。
    用户的回答:「你应该展示放大的 icon,这样我就可以点击了,而不是依靠点击图片,因为图片点击的时候
    可能点击到了背景上去了,所以体验不是很好」。现在触屏上按钮常驻可见(不再靠悬停提亮:触屏没有
    悬停,0.42 的不透明度等于看不见),视觉 34px,触区用 ::after 外扩到约 46px —— 手指按不准也点得到。
    轻点图片这条入口保留,但按钮才是明确的那一个。
  • 连点两下按钮不再进编辑。 按钮就贴在图片角上,而「双击」的第二次 tap 正是 Obsidian
    「双击进入编辑」的触发点:现在第二次 tap 会被吃掉(第一次照旧打开查看器,且只打开一次)。
  • 查看器里的图现在是高清的,不是被压缩后再拉大的。 两个独立原因,都修了:
    • 100% 的基准错了:以前「1 个源像素 = 1 个 CSS 像素」,所以在 DPR=3 的手机上,一张 1600px 的
      截图被铺到 4800 个物理像素上 —— 横向拉伸 3 倍,这就是用户说的「放大查看都模糊了」。现在按
      naturalWidth / devicePixelRatio 排版:100% 就是原图分辨率(1 源像素 = 1 设备像素),读数也
      对得上(1600 x 900 px → 1600 x 900 px)。再往上放大才是放大镜。
    • 画布上带着 will-change: transform:它把画面钉死在提层时的比例上,之后放大只是把旧位图拉大
      (照片发软、图表里的 CSS 文字直接糊)。已去掉。
    • 另外,打开小图不再「适配」放大(适配比例封顶 100%),并解除主题/宿主塞给 img 的
      max-width: 100%(它会把刚摆好的 1:1 又压回去,窄屏上高清立刻失效)。
  • 细节:插件的手机手势拦截器现在会避开自己的放大按钮 —— 按钮里的图标是 <svg>,不排除就会被
    「这是不是图表」的判定当成一张 18px 的图表打开。

Verification: 单元测试 82 条(新增 tests/lightbox.test.ts 钉住 1:1 的换算,含 devicePixelRatio
不老实的情况);npm run verify:gestures 82 条断言,npm run verify:reading 36 条断言。
新断言先在旧代码上跑过一遍确认它们能失败:1.3.9 上触屏的按钮是 display=none opacity=0.42 0x0、
小图打开是 426%、will-change 计算值是 transform。

1.3.9

  • Fixed: flow charts (and every other diagram) ignored the line width. 1.3.7's width rules only
    targeted img and video, but a Mermaid flow chart is an <svg> — and themes set
    flowchart.useMaxWidth: false (that is what makes boxes follow the text), so Mermaid renders at
    its natural width and the diagram stayed at 478 px inside a 900 px column, or overflowed on a
    phone. The rules now cover .mermaid svg, .block-language-mermaid svg,
    .excalidraw-svg svg and .block-language-chart svg/canvas as well, and the plugin's own
    view got the same treatment in styles.css.
  • Scaling is by ratio (SVG is vector, so the text scales with it): measured in a real browser, a
    478 × 98 diagram becomes 900 × 184 with the 478:98 ratio intact, and on a 390 px phone viewport
    both the diagram and a photo land at 342 px — one screen wide, as asked. Double-tap still opens the
    zoomable viewer, which is where detail reading now happens.
  • The setting is now called 阅读视图图片/图表宽度 (it always governed both, the label just lied).

Verification: npm run verify:reading is now 32 assertions — the new ones measure the diagram in
the DOM: fill → 900 px with the aspect ratio preserved, contain → stays 478 px, and on a phone
viewport the diagram and the photo are both clamped to the same screen width.

1.3.8

  • Fixed: double tapping still opened the editor. 1.3.7 only intercepted double taps on images,
    but Obsidian's double-tap-to-edit is a gesture of the whole reading view — tapping text
    triggers it too, so in practice nothing changed. The interception now covers every double tap
    inside the reading view (text, images, diagrams); double tapping an image or diagram opens the
    zoomable viewer instead. Two separate switches: 手机:双击不进编辑 and 手机:双击图片 = 放大查看.
  • Three more real bugs, all found by the browser harness rather than by reading the code:
    • The same event was handled twice (the module listens on both window and document in
      the capture phase), so one tap looked like two and a single tap opened the viewer. Events are now
      deduplicated.
    • A two-finger pinch was counted as a tap, poisoning the next double tap. Multi-touch now
      cancels tap tracking, and only touchend counts as a tap (pointerup/click are used for
      swallowing only).
    • Within one gesture, touchstart targets the image but touchend and the synthetic
      dblclick target the container
      , so the hit test concluded "text" and the image never zoomed.
      The hit is now resolved from the touch-start element and the coordinates as a fallback.
  • A touch double tap also produces a synthetic dblclick (in an unstable order) and both used to
    open the viewer; they now share a short window so one double tap opens exactly once.
  • 手机:双击自检 (off by default) shows a notice for every intercepted double tap — if a gesture
    still misbehaves on a real phone, the notice tells whether the plugin saw it at all.

Verification: npm run verify:reading — 28 assertions. Besides the earlier reading-view
checks: a single tap does nothing, a double tap on text does not enter editing and opens nothing,
a double tap on an image opens the viewer exactly once and the simulated editor handler records
zero events, gestures outside the reading view are ignored, and mobile: false (desktop) does
not intercept at all.

1.3.7

  • Images follow the line width, scaled by ratio. In the reading view every image is now scaled to
    exactly the line width you chose (900 px by default) with `height: auto`, so nothing is cropped
    or stretched and a 600 × 200 screenshot becomes 900 × 300. Explicit widths (`![[image.png|300]]`)
    are normalised too — one page, one image width, as asked. Two other policies stay available
    (fit within the line width, natural size), and the rules only ever touch
    `.markdown-reading-view`, never the editor.
  • Mobile: double-tapping an image zooms it instead of entering editing. In Obsidian's reading
    view a double tap on an image means "edit", which is exactly wrong while reading on a phone. The
    plugin now intercepts that gesture inside the reading view and opens the zoomable viewer instead;
    the edit path is suppressed (use the menu button when you really want to edit). A single tap does
    nothing new, gestures outside the reading view are ignored, and desktop is untouched — as
    asked, this is a mobile behaviour.
  • Two ordering bugs found by the browser harness, both fixed rather than papered over. A touch
    double tap also produces a synthetic `dblclick`, and which one arrives first is not stable — the
    first version opened the viewer twice. Both paths now share a short mutual-exclusion window: one
    double tap opens the viewer exactly once. The harness also had to be honest: its simulated
    "Obsidian edit" listener originally counted every tap, which proved nothing; it now does real
    double-tap detection, so "0 edits" means the double tap was genuinely consumed.

Verification: npm run verify:reading is now 26 assertions — the image policies are measured
in the DOM (fill: 600 px image → 900 px, ratio still 3:1; contain: stays 600 px; natural: no rules
injected), the desktop path is asserted not to open the viewer, and on a phone viewport a real CDP
double tap opens the viewer exactly once while the simulated edit handler records zero events.

1.3.6

  • The reading view itself now has a width and a zoom. Obsidian's own reading view is not taken
    over — the plugin changes two CSS properties of it: the line width (default 900 px, the value
    that was asked for, with 760–1200 px and 跟随主题 / follow-the-theme options) and a zoom level
    (60 %–200 %, default 100 %). Your theme files are untouched, and follow the theme + 100 % injects
    nothing beyond one `touch-action` line.
  • Zoom reflows instead of stretching. It is applied as CSS `zoom` with the sizer's `max-width`
    divided by the same factor, so the text gets bigger while the measure on screen stays exactly the
    line width you picked. A screenshot-level stretch would have changed the line length; this does
    not.
  • You operate it: pinch, Ctrl+wheel, or commands. Pinch inside the reading view on mobile,
    Ctrl / ⌘ + wheel on desktop, or the three new commands (阅读视图放大 / 缩小 / 复位到 100 %,
    each showing the new level). Only two-finger pinches and Ctrl+wheel are intercepted — one-finger
    scrolling, taps and the plain wheel remain Obsidian's.
  • A real bug found by the browser harness. The first implementation listened for pointer events
    and the browser claimed the two-finger gesture for itself: of ten gesture frames only two arrived
    (pointercancel). The fix is to listen for `touchstart`/`touchmove` and to declare
    `touch-action: pan-y` on the reading view — vertical one-finger scrolling still belongs to
    Obsidian, while the two-finger pinch now belongs to the plugin (measured: zoom 1 → 1.86 in one
    pinch).
  • New settings group 阅读视图(Obsidian 自带的页面)/ Reading view, with the three settings above.

Verification: npm run verify:reading — 17 assertions in a real Chromium against a page that
mimics the reading view (a theme width of 720 px, a long document): follow-the-theme really is
720 px with no width rules injected, 900 px really measures 900 px, zoom 150 % keeps the on-screen
measure at 900 px while paragraphs get 1.5x taller, the clamp holds at 60–200...

Read more

1.3.10

Choose a tag to compare

@github-actions github-actions released this 18 Sep 12:20

Changelog

1.3.10

  • 手机上终于看得见那个放大的 icon 了 —— 这一条是用户直接点名的。 触屏设备上按钮以前是
    @media (hover: none) { display: none } 被整个藏起来的,理由是「轻点图片就能放大,按钮不必占地方」。
    用户的回答:「你应该展示放大的 icon,这样我就可以点击了,而不是依靠点击图片,因为图片点击的时候
    可能点击到了背景上去了,所以体验不是很好」。现在触屏上按钮常驻可见(不再靠悬停提亮:触屏没有
    悬停,0.42 的不透明度等于看不见),视觉 34px,触区用 ::after 外扩到约 46px —— 手指按不准也点得到。
    轻点图片这条入口保留,但按钮才是明确的那一个。
  • 连点两下按钮不再进编辑。 按钮就贴在图片角上,而「双击」的第二次 tap 正是 Obsidian
    「双击进入编辑」的触发点:现在第二次 tap 会被吃掉(第一次照旧打开查看器,且只打开一次)。
  • 查看器里的图现在是高清的,不是被压缩后再拉大的。 两个独立原因,都修了:
    • 100% 的基准错了:以前「1 个源像素 = 1 个 CSS 像素」,所以在 DPR=3 的手机上,一张 1600px 的
      截图被铺到 4800 个物理像素上 —— 横向拉伸 3 倍,这就是用户说的「放大查看都模糊了」。现在按
      naturalWidth / devicePixelRatio 排版:100% 就是原图分辨率(1 源像素 = 1 设备像素),读数也
      对得上(1600 x 900 px → 1600 x 900 px)。再往上放大才是放大镜。
    • 画布上带着 will-change: transform:它把画面钉死在提层时的比例上,之后放大只是把旧位图拉大
      (照片发软、图表里的 CSS 文字直接糊)。已去掉。
    • 另外,打开小图不再「适配」放大(适配比例封顶 100%),并解除主题/宿主塞给 img 的
      max-width: 100%(它会把刚摆好的 1:1 又压回去,窄屏上高清立刻失效)。
  • 细节:插件的手机手势拦截器现在会避开自己的放大按钮 —— 按钮里的图标是 <svg>,不排除就会被
    「这是不是图表」的判定当成一张 18px 的图表打开。

Verification: 单元测试 82 条(新增 tests/lightbox.test.ts 钉住 1:1 的换算,含 devicePixelRatio
不老实的情况);npm run verify:gestures 82 条断言,npm run verify:reading 36 条断言。
新断言先在旧代码上跑过一遍确认它们能失败:1.3.9 上触屏的按钮是 display=none opacity=0.42 0x0、
小图打开是 426%、will-change 计算值是 transform。

1.3.9

  • Fixed: flow charts (and every other diagram) ignored the line width. 1.3.7's width rules only
    targeted img and video, but a Mermaid flow chart is an <svg> — and themes set
    flowchart.useMaxWidth: false (that is what makes boxes follow the text), so Mermaid renders at
    its natural width and the diagram stayed at 478 px inside a 900 px column, or overflowed on a
    phone. The rules now cover .mermaid svg, .block-language-mermaid svg,
    .excalidraw-svg svg and .block-language-chart svg/canvas as well, and the plugin's own
    view got the same treatment in styles.css.
  • Scaling is by ratio (SVG is vector, so the text scales with it): measured in a real browser, a
    478 × 98 diagram becomes 900 × 184 with the 478:98 ratio intact, and on a 390 px phone viewport
    both the diagram and a photo land at 342 px — one screen wide, as asked. Double-tap still opens the
    zoomable viewer, which is where detail reading now happens.
  • The setting is now called 阅读视图图片/图表宽度 (it always governed both, the label just lied).

Verification: npm run verify:reading is now 32 assertions — the new ones measure the diagram in
the DOM: fill → 900 px with the aspect ratio preserved, contain → stays 478 px, and on a phone
viewport the diagram and the photo are both clamped to the same screen width.

1.3.8

  • Fixed: double tapping still opened the editor. 1.3.7 only intercepted double taps on images,
    but Obsidian's double-tap-to-edit is a gesture of the whole reading view — tapping text
    triggers it too, so in practice nothing changed. The interception now covers every double tap
    inside the reading view (text, images, diagrams); double tapping an image or diagram opens the
    zoomable viewer instead. Two separate switches: 手机:双击不进编辑 and 手机:双击图片 = 放大查看.
  • Three more real bugs, all found by the browser harness rather than by reading the code:
    • The same event was handled twice (the module listens on both window and document in
      the capture phase), so one tap looked like two and a single tap opened the viewer. Events are now
      deduplicated.
    • A two-finger pinch was counted as a tap, poisoning the next double tap. Multi-touch now
      cancels tap tracking, and only touchend counts as a tap (pointerup/click are used for
      swallowing only).
    • Within one gesture, touchstart targets the image but touchend and the synthetic
      dblclick target the container
      , so the hit test concluded "text" and the image never zoomed.
      The hit is now resolved from the touch-start element and the coordinates as a fallback.
  • A touch double tap also produces a synthetic dblclick (in an unstable order) and both used to
    open the viewer; they now share a short window so one double tap opens exactly once.
  • 手机:双击自检 (off by default) shows a notice for every intercepted double tap — if a gesture
    still misbehaves on a real phone, the notice tells whether the plugin saw it at all.

Verification: npm run verify:reading — 28 assertions. Besides the earlier reading-view
checks: a single tap does nothing, a double tap on text does not enter editing and opens nothing,
a double tap on an image opens the viewer exactly once and the simulated editor handler records
zero events, gestures outside the reading view are ignored, and mobile: false (desktop) does
not intercept at all.

1.3.7

  • Images follow the line width, scaled by ratio. In the reading view every image is now scaled to
    exactly the line width you chose (900 px by default) with `height: auto`, so nothing is cropped
    or stretched and a 600 × 200 screenshot becomes 900 × 300. Explicit widths (`![[image.png|300]]`)
    are normalised too — one page, one image width, as asked. Two other policies stay available
    (fit within the line width, natural size), and the rules only ever touch
    `.markdown-reading-view`, never the editor.
  • Mobile: double-tapping an image zooms it instead of entering editing. In Obsidian's reading
    view a double tap on an image means "edit", which is exactly wrong while reading on a phone. The
    plugin now intercepts that gesture inside the reading view and opens the zoomable viewer instead;
    the edit path is suppressed (use the menu button when you really want to edit). A single tap does
    nothing new, gestures outside the reading view are ignored, and desktop is untouched — as
    asked, this is a mobile behaviour.
  • Two ordering bugs found by the browser harness, both fixed rather than papered over. A touch
    double tap also produces a synthetic `dblclick`, and which one arrives first is not stable — the
    first version opened the viewer twice. Both paths now share a short mutual-exclusion window: one
    double tap opens the viewer exactly once. The harness also had to be honest: its simulated
    "Obsidian edit" listener originally counted every tap, which proved nothing; it now does real
    double-tap detection, so "0 edits" means the double tap was genuinely consumed.

Verification: npm run verify:reading is now 26 assertions — the image policies are measured
in the DOM (fill: 600 px image → 900 px, ratio still 3:1; contain: stays 600 px; natural: no rules
injected), the desktop path is asserted not to open the viewer, and on a phone viewport a real CDP
double tap opens the viewer exactly once while the simulated edit handler records zero events.

1.3.6

  • The reading view itself now has a width and a zoom. Obsidian's own reading view is not taken
    over — the plugin changes two CSS properties of it: the line width (default 900 px, the value
    that was asked for, with 760–1200 px and 跟随主题 / follow-the-theme options) and a zoom level
    (60 %–200 %, default 100 %). Your theme files are untouched, and follow the theme + 100 % injects
    nothing beyond one `touch-action` line.
  • Zoom reflows instead of stretching. It is applied as CSS `zoom` with the sizer's `max-width`
    divided by the same factor, so the text gets bigger while the measure on screen stays exactly the
    line width you picked. A screenshot-level stretch would have changed the line length; this does
    not.
  • You operate it: pinch, Ctrl+wheel, or commands. Pinch inside the reading view on mobile,
    Ctrl / ⌘ + wheel on desktop, or the three new commands (阅读视图放大 / 缩小 / 复位到 100 %,
    each showing the new level). Only two-finger pinches and Ctrl+wheel are intercepted — one-finger
    scrolling, taps and the plain wheel remain Obsidian's.
  • A real bug found by the browser harness. The first implementation listened for pointer events
    and the browser claimed the two-finger gesture for itself: of ten gesture frames only two arrived
    (pointercancel). The fix is to listen for `touchstart`/`touchmove` and to declare
    `touch-action: pan-y` on the reading view — vertical one-finger scrolling still belongs to
    Obsidian, while the two-finger pinch now belongs to the plugin (measured: zoom 1 → 1.86 in one
    pinch).
  • New settings group 阅读视图(Obsidian 自带的页面)/ Reading view, with the three settings above.

Verification: npm run verify:reading — 17 assertions in a real Chromium against a page that
mimics the reading view (a theme width of 720 px, a long document): follow-the-theme really is
720 px with no width rules injected, 900 px really measures 900 px, zoom 150 % keeps the on-screen
measure at 900 px while paragraphs get 1.5x taller, the clamp holds at 60–200 %, Ctrl+wheel zooms
inside the reading view and is ignored outside it (and after the listener is removed), and on a phone
viewport a real CDP two-finger pinch raises the zoom while the throttling keeps the reflow count
below the frame count.

1.3.5

  • The card concept is gone. Whiteboard mode used to compile the note into a board of cards:
    one card per heading, connectors, folding, a card limit, and a column or flow layout. It is now
    what it should have been: one page, 1280 px wide, on a surface you pan, zoom and scroll. The
    width setting belongs to the page, not to a card.
  • Removed along with it: src/board-model.ts (the heading→card compiler), src/board-layout.ts
    (tidy tree / single-column geometry), src/board-render.ts (card DOM, connectors, focus
    buttons), the five card settings (排版 / 展开层级 / 间距 / 连线 / 数量上限), every card style in
    styles.css, and the 43 unit tests that covered them. The verification suite now asserts the
    absence
    : no card class names or card settings in the built bundle, no card modules in the tree,
    and zero card artifacts in the live DOM.
  • What is left is the part that ma...
Read more

1.3.9

Choose a tag to compare

@github-actions github-actions released this 18 Sep 11:52

Changelog

1.3.9

  • Fixed: flow charts (and every other diagram) ignored the line width. 1.3.7's width rules only
    targeted img and video, but a Mermaid flow chart is an <svg> — and themes set
    flowchart.useMaxWidth: false (that is what makes boxes follow the text), so Mermaid renders at
    its natural width and the diagram stayed at 478 px inside a 900 px column, or overflowed on a
    phone. The rules now cover .mermaid svg, .block-language-mermaid svg,
    .excalidraw-svg svg and .block-language-chart svg/canvas as well, and the plugin's own
    view got the same treatment in styles.css.
  • Scaling is by ratio (SVG is vector, so the text scales with it): measured in a real browser, a
    478 × 98 diagram becomes 900 × 184 with the 478:98 ratio intact, and on a 390 px phone viewport
    both the diagram and a photo land at 342 px — one screen wide, as asked. Double-tap still opens the
    zoomable viewer, which is where detail reading now happens.
  • The setting is now called 阅读视图图片/图表宽度 (it always governed both, the label just lied).

Verification: npm run verify:reading is now 32 assertions — the new ones measure the diagram in
the DOM: fill → 900 px with the aspect ratio preserved, contain → stays 478 px, and on a phone
viewport the diagram and the photo are both clamped to the same screen width.

1.3.8

  • Fixed: double tapping still opened the editor. 1.3.7 only intercepted double taps on images,
    but Obsidian's double-tap-to-edit is a gesture of the whole reading view — tapping text
    triggers it too, so in practice nothing changed. The interception now covers every double tap
    inside the reading view (text, images, diagrams); double tapping an image or diagram opens the
    zoomable viewer instead. Two separate switches: 手机:双击不进编辑 and 手机:双击图片 = 放大查看.
  • Three more real bugs, all found by the browser harness rather than by reading the code:
    • The same event was handled twice (the module listens on both window and document in
      the capture phase), so one tap looked like two and a single tap opened the viewer. Events are now
      deduplicated.
    • A two-finger pinch was counted as a tap, poisoning the next double tap. Multi-touch now
      cancels tap tracking, and only touchend counts as a tap (pointerup/click are used for
      swallowing only).
    • Within one gesture, touchstart targets the image but touchend and the synthetic
      dblclick target the container
      , so the hit test concluded "text" and the image never zoomed.
      The hit is now resolved from the touch-start element and the coordinates as a fallback.
  • A touch double tap also produces a synthetic dblclick (in an unstable order) and both used to
    open the viewer; they now share a short window so one double tap opens exactly once.
  • 手机:双击自检 (off by default) shows a notice for every intercepted double tap — if a gesture
    still misbehaves on a real phone, the notice tells whether the plugin saw it at all.

Verification: npm run verify:reading — 28 assertions. Besides the earlier reading-view
checks: a single tap does nothing, a double tap on text does not enter editing and opens nothing,
a double tap on an image opens the viewer exactly once and the simulated editor handler records
zero events, gestures outside the reading view are ignored, and mobile: false (desktop) does
not intercept at all.

1.3.7

  • Images follow the line width, scaled by ratio. In the reading view every image is now scaled to
    exactly the line width you chose (900 px by default) with `height: auto`, so nothing is cropped
    or stretched and a 600 × 200 screenshot becomes 900 × 300. Explicit widths (`![[image.png|300]]`)
    are normalised too — one page, one image width, as asked. Two other policies stay available
    (fit within the line width, natural size), and the rules only ever touch
    `.markdown-reading-view`, never the editor.
  • Mobile: double-tapping an image zooms it instead of entering editing. In Obsidian's reading
    view a double tap on an image means "edit", which is exactly wrong while reading on a phone. The
    plugin now intercepts that gesture inside the reading view and opens the zoomable viewer instead;
    the edit path is suppressed (use the menu button when you really want to edit). A single tap does
    nothing new, gestures outside the reading view are ignored, and desktop is untouched — as
    asked, this is a mobile behaviour.
  • Two ordering bugs found by the browser harness, both fixed rather than papered over. A touch
    double tap also produces a synthetic `dblclick`, and which one arrives first is not stable — the
    first version opened the viewer twice. Both paths now share a short mutual-exclusion window: one
    double tap opens the viewer exactly once. The harness also had to be honest: its simulated
    "Obsidian edit" listener originally counted every tap, which proved nothing; it now does real
    double-tap detection, so "0 edits" means the double tap was genuinely consumed.

Verification: npm run verify:reading is now 26 assertions — the image policies are measured
in the DOM (fill: 600 px image → 900 px, ratio still 3:1; contain: stays 600 px; natural: no rules
injected), the desktop path is asserted not to open the viewer, and on a phone viewport a real CDP
double tap opens the viewer exactly once while the simulated edit handler records zero events.

1.3.6

  • The reading view itself now has a width and a zoom. Obsidian's own reading view is not taken
    over — the plugin changes two CSS properties of it: the line width (default 900 px, the value
    that was asked for, with 760–1200 px and 跟随主题 / follow-the-theme options) and a zoom level
    (60 %–200 %, default 100 %). Your theme files are untouched, and follow the theme + 100 % injects
    nothing beyond one `touch-action` line.
  • Zoom reflows instead of stretching. It is applied as CSS `zoom` with the sizer's `max-width`
    divided by the same factor, so the text gets bigger while the measure on screen stays exactly the
    line width you picked. A screenshot-level stretch would have changed the line length; this does
    not.
  • You operate it: pinch, Ctrl+wheel, or commands. Pinch inside the reading view on mobile,
    Ctrl / ⌘ + wheel on desktop, or the three new commands (阅读视图放大 / 缩小 / 复位到 100 %,
    each showing the new level). Only two-finger pinches and Ctrl+wheel are intercepted — one-finger
    scrolling, taps and the plain wheel remain Obsidian's.
  • A real bug found by the browser harness. The first implementation listened for pointer events
    and the browser claimed the two-finger gesture for itself: of ten gesture frames only two arrived
    (pointercancel). The fix is to listen for `touchstart`/`touchmove` and to declare
    `touch-action: pan-y` on the reading view — vertical one-finger scrolling still belongs to
    Obsidian, while the two-finger pinch now belongs to the plugin (measured: zoom 1 → 1.86 in one
    pinch).
  • New settings group 阅读视图(Obsidian 自带的页面)/ Reading view, with the three settings above.

Verification: npm run verify:reading — 17 assertions in a real Chromium against a page that
mimics the reading view (a theme width of 720 px, a long document): follow-the-theme really is
720 px with no width rules injected, 900 px really measures 900 px, zoom 150 % keeps the on-screen
measure at 900 px while paragraphs get 1.5x taller, the clamp holds at 60–200 %, Ctrl+wheel zooms
inside the reading view and is ignored outside it (and after the listener is removed), and on a phone
viewport a real CDP two-finger pinch raises the zoom while the throttling keeps the reflow count
below the frame count.

1.3.5

  • The card concept is gone. Whiteboard mode used to compile the note into a board of cards:
    one card per heading, connectors, folding, a card limit, and a column or flow layout. It is now
    what it should have been: one page, 1280 px wide, on a surface you pan, zoom and scroll. The
    width setting belongs to the page, not to a card.
  • Removed along with it: src/board-model.ts (the heading→card compiler), src/board-layout.ts
    (tidy tree / single-column geometry), src/board-render.ts (card DOM, connectors, focus
    buttons), the five card settings (排版 / 展开层级 / 间距 / 连线 / 数量上限), every card style in
    styles.css, and the 43 unit tests that covered them. The verification suite now asserts the
    absence
    : no card class names or card settings in the built bundle, no card modules in the tree,
    and zero card artifacts in the live DOM.
  • What is left is the part that made the plugin worth having: one page whose width is a setting
    (1280 px default, A5/A4 presets one slider step away), recompiled every time you enter the mode and
    following the note as you edit, with the same gesture layer as before — drag to pan, pinch to zoom,
    适配宽度 to pull the whole page into the viewport and then simply scroll down.
  • Settings are now: 打开笔记时的默认模式 / default mode and 白板版面宽度 / whiteboard page width.

Verification: npm run verify:board (34 assertions) now checks the whiteboard itself — the page
is 1280 px by default (from the shipped settings data), the page mode follows the theme line width
(760 px), changing the width setting really changes the page, one page element exists, the bundle and
the DOM contain no card artifacts, wheels scroll to the last paragraph, fit-width puts the whole
page inside the viewport, and the mobile touch gestures keep their anchor invariant.

1.3.4

  • The column is 1280 px by default — a desktop web content width. A5 (560 px) turned out to be
    the wrong default for reading on a screen: long Chinese lines wrapped early and the column felt
    narrow. 1280 px is the width a web page uses, so lines are long, tables have room, and the column
    fills a normal screen — which is what makes reading a purely vertical gesture. The slide...
Read more

1.3.8

Choose a tag to compare

@github-actions github-actions released this 18 Sep 11:40

Changelog

1.3.8

  • Fixed: double tapping still opened the editor. 1.3.7 only intercepted double taps on images,
    but Obsidian's double-tap-to-edit is a gesture of the whole reading view — tapping text
    triggers it too, so in practice nothing changed. The interception now covers every double tap
    inside the reading view (text, images, diagrams); double tapping an image or diagram opens the
    zoomable viewer instead. Two separate switches: 手机:双击不进编辑 and 手机:双击图片 = 放大查看.
  • Three more real bugs, all found by the browser harness rather than by reading the code:
    • The same event was handled twice (the module listens on both window and document in
      the capture phase), so one tap looked like two and a single tap opened the viewer. Events are now
      deduplicated.
    • A two-finger pinch was counted as a tap, poisoning the next double tap. Multi-touch now
      cancels tap tracking, and only touchend counts as a tap (pointerup/click are used for
      swallowing only).
    • Within one gesture, touchstart targets the image but touchend and the synthetic
      dblclick target the container
      , so the hit test concluded "text" and the image never zoomed.
      The hit is now resolved from the touch-start element and the coordinates as a fallback.
  • A touch double tap also produces a synthetic dblclick (in an unstable order) and both used to
    open the viewer; they now share a short window so one double tap opens exactly once.
  • 手机:双击自检 (off by default) shows a notice for every intercepted double tap — if a gesture
    still misbehaves on a real phone, the notice tells whether the plugin saw it at all.

Verification: npm run verify:reading — 28 assertions. Besides the earlier reading-view
checks: a single tap does nothing, a double tap on text does not enter editing and opens nothing,
a double tap on an image opens the viewer exactly once and the simulated editor handler records
zero events, gestures outside the reading view are ignored, and mobile: false (desktop) does
not intercept at all.

1.3.7

  • Images follow the line width, scaled by ratio. In the reading view every image is now scaled to
    exactly the line width you chose (900 px by default) with `height: auto`, so nothing is cropped
    or stretched and a 600 × 200 screenshot becomes 900 × 300. Explicit widths (`![[image.png|300]]`)
    are normalised too — one page, one image width, as asked. Two other policies stay available
    (fit within the line width, natural size), and the rules only ever touch
    `.markdown-reading-view`, never the editor.
  • Mobile: double-tapping an image zooms it instead of entering editing. In Obsidian's reading
    view a double tap on an image means "edit", which is exactly wrong while reading on a phone. The
    plugin now intercepts that gesture inside the reading view and opens the zoomable viewer instead;
    the edit path is suppressed (use the menu button when you really want to edit). A single tap does
    nothing new, gestures outside the reading view are ignored, and desktop is untouched — as
    asked, this is a mobile behaviour.
  • Two ordering bugs found by the browser harness, both fixed rather than papered over. A touch
    double tap also produces a synthetic `dblclick`, and which one arrives first is not stable — the
    first version opened the viewer twice. Both paths now share a short mutual-exclusion window: one
    double tap opens the viewer exactly once. The harness also had to be honest: its simulated
    "Obsidian edit" listener originally counted every tap, which proved nothing; it now does real
    double-tap detection, so "0 edits" means the double tap was genuinely consumed.

Verification: npm run verify:reading is now 26 assertions — the image policies are measured
in the DOM (fill: 600 px image → 900 px, ratio still 3:1; contain: stays 600 px; natural: no rules
injected), the desktop path is asserted not to open the viewer, and on a phone viewport a real CDP
double tap opens the viewer exactly once while the simulated edit handler records zero events.

1.3.6

  • The reading view itself now has a width and a zoom. Obsidian's own reading view is not taken
    over — the plugin changes two CSS properties of it: the line width (default 900 px, the value
    that was asked for, with 760–1200 px and 跟随主题 / follow-the-theme options) and a zoom level
    (60 %–200 %, default 100 %). Your theme files are untouched, and follow the theme + 100 % injects
    nothing beyond one `touch-action` line.
  • Zoom reflows instead of stretching. It is applied as CSS `zoom` with the sizer's `max-width`
    divided by the same factor, so the text gets bigger while the measure on screen stays exactly the
    line width you picked. A screenshot-level stretch would have changed the line length; this does
    not.
  • You operate it: pinch, Ctrl+wheel, or commands. Pinch inside the reading view on mobile,
    Ctrl / ⌘ + wheel on desktop, or the three new commands (阅读视图放大 / 缩小 / 复位到 100 %,
    each showing the new level). Only two-finger pinches and Ctrl+wheel are intercepted — one-finger
    scrolling, taps and the plain wheel remain Obsidian's.
  • A real bug found by the browser harness. The first implementation listened for pointer events
    and the browser claimed the two-finger gesture for itself: of ten gesture frames only two arrived
    (pointercancel). The fix is to listen for `touchstart`/`touchmove` and to declare
    `touch-action: pan-y` on the reading view — vertical one-finger scrolling still belongs to
    Obsidian, while the two-finger pinch now belongs to the plugin (measured: zoom 1 → 1.86 in one
    pinch).
  • New settings group 阅读视图(Obsidian 自带的页面)/ Reading view, with the three settings above.

Verification: npm run verify:reading — 17 assertions in a real Chromium against a page that
mimics the reading view (a theme width of 720 px, a long document): follow-the-theme really is
720 px with no width rules injected, 900 px really measures 900 px, zoom 150 % keeps the on-screen
measure at 900 px while paragraphs get 1.5x taller, the clamp holds at 60–200 %, Ctrl+wheel zooms
inside the reading view and is ignored outside it (and after the listener is removed), and on a phone
viewport a real CDP two-finger pinch raises the zoom while the throttling keeps the reflow count
below the frame count.

1.3.5

  • The card concept is gone. Whiteboard mode used to compile the note into a board of cards:
    one card per heading, connectors, folding, a card limit, and a column or flow layout. It is now
    what it should have been: one page, 1280 px wide, on a surface you pan, zoom and scroll. The
    width setting belongs to the page, not to a card.
  • Removed along with it: src/board-model.ts (the heading→card compiler), src/board-layout.ts
    (tidy tree / single-column geometry), src/board-render.ts (card DOM, connectors, focus
    buttons), the five card settings (排版 / 展开层级 / 间距 / 连线 / 数量上限), every card style in
    styles.css, and the 43 unit tests that covered them. The verification suite now asserts the
    absence
    : no card class names or card settings in the built bundle, no card modules in the tree,
    and zero card artifacts in the live DOM.
  • What is left is the part that made the plugin worth having: one page whose width is a setting
    (1280 px default, A5/A4 presets one slider step away), recompiled every time you enter the mode and
    following the note as you edit, with the same gesture layer as before — drag to pan, pinch to zoom,
    适配宽度 to pull the whole page into the viewport and then simply scroll down.
  • Settings are now: 打开笔记时的默认模式 / default mode and 白板版面宽度 / whiteboard page width.

Verification: npm run verify:board (34 assertions) now checks the whiteboard itself — the page
is 1280 px by default (from the shipped settings data), the page mode follows the theme line width
(760 px), changing the width setting really changes the page, one page element exists, the bundle and
the DOM contain no card artifacts, wheels scroll to the last paragraph, fit-width puts the whole
page inside the viewport, and the mobile touch gestures keep their anchor invariant.

1.3.4

  • The column is 1280 px by default — a desktop web content width. A5 (560 px) turned out to be
    the wrong default for reading on a screen: long Chinese lines wrapped early and the column felt
    narrow. 1280 px is the width a web page uses, so lines are long, tables have room, and the column
    fills a normal screen — which is what makes reading a purely vertical gesture. The slider still
    names the paper presets (A5 = 148 mm ≈ 560 px, A4 ≈ 794 px) and the readout says
    1280 px · 网页宽 Web or 560 px · A5 · 148mm so the choice is obvious either way.
  • 适配栏宽 / fit column width — a new toolbar button that fills the viewport with the column
    width, so on a phone (or a small window) you can see a whole line and then just scroll down. The
    board still opens at 100% (readable), and you decide when to trade size for the whole column.
  • Indentation scales with the column: 18 px per level was invisible in a 1280 px column, so it is
    now about 3% of the width (≈ 38 px), still capped at three levels.

Verification: npm run verify:board is now 49 assertions — the default is asserted to be
1280 px with the readout naming it (网页宽 Web), A5 is still asserted to be 148 mm ≈ 560 px as a
preset, and the new fit column width assertion measures the real DOM: after one tap the widest card
edge lands inside the viewport and the scale is below 1.

1.3.3

  • Two layouts for the whiteboard, and the default is the one you read. The board used to be a
    branch tree only: headings in columns with connectors. On a phone that means hunting for content
    sideways. The default is now 单栏纵向流 / single column — one A5-wide sheet per section,
    stacked in document order, so **scrolling down is reading dow...
Read more

1.3.7

Choose a tag to compare

@github-actions github-actions released this 18 Sep 11:17

Changelog

1.3.7

  • Images follow the line width, scaled by ratio. In the reading view every image is now scaled to
    exactly the line width you chose (900 px by default) with `height: auto`, so nothing is cropped
    or stretched and a 600 × 200 screenshot becomes 900 × 300. Explicit widths (`![[image.png|300]]`)
    are normalised too — one page, one image width, as asked. Two other policies stay available
    (fit within the line width, natural size), and the rules only ever touch
    `.markdown-reading-view`, never the editor.
  • Mobile: double-tapping an image zooms it instead of entering editing. In Obsidian's reading
    view a double tap on an image means "edit", which is exactly wrong while reading on a phone. The
    plugin now intercepts that gesture inside the reading view and opens the zoomable viewer instead;
    the edit path is suppressed (use the menu button when you really want to edit). A single tap does
    nothing new, gestures outside the reading view are ignored, and desktop is untouched — as
    asked, this is a mobile behaviour.
  • Two ordering bugs found by the browser harness, both fixed rather than papered over. A touch
    double tap also produces a synthetic `dblclick`, and which one arrives first is not stable — the
    first version opened the viewer twice. Both paths now share a short mutual-exclusion window: one
    double tap opens the viewer exactly once. The harness also had to be honest: its simulated
    "Obsidian edit" listener originally counted every tap, which proved nothing; it now does real
    double-tap detection, so "0 edits" means the double tap was genuinely consumed.

Verification: npm run verify:reading is now 26 assertions — the image policies are measured
in the DOM (fill: 600 px image → 900 px, ratio still 3:1; contain: stays 600 px; natural: no rules
injected), the desktop path is asserted not to open the viewer, and on a phone viewport a real CDP
double tap opens the viewer exactly once while the simulated edit handler records zero events.

1.3.6

  • The reading view itself now has a width and a zoom. Obsidian's own reading view is not taken
    over — the plugin changes two CSS properties of it: the line width (default 900 px, the value
    that was asked for, with 760–1200 px and 跟随主题 / follow-the-theme options) and a zoom level
    (60 %–200 %, default 100 %). Your theme files are untouched, and follow the theme + 100 % injects
    nothing beyond one `touch-action` line.
  • Zoom reflows instead of stretching. It is applied as CSS `zoom` with the sizer's `max-width`
    divided by the same factor, so the text gets bigger while the measure on screen stays exactly the
    line width you picked. A screenshot-level stretch would have changed the line length; this does
    not.
  • You operate it: pinch, Ctrl+wheel, or commands. Pinch inside the reading view on mobile,
    Ctrl / ⌘ + wheel on desktop, or the three new commands (阅读视图放大 / 缩小 / 复位到 100 %,
    each showing the new level). Only two-finger pinches and Ctrl+wheel are intercepted — one-finger
    scrolling, taps and the plain wheel remain Obsidian's.
  • A real bug found by the browser harness. The first implementation listened for pointer events
    and the browser claimed the two-finger gesture for itself: of ten gesture frames only two arrived
    (pointercancel). The fix is to listen for `touchstart`/`touchmove` and to declare
    `touch-action: pan-y` on the reading view — vertical one-finger scrolling still belongs to
    Obsidian, while the two-finger pinch now belongs to the plugin (measured: zoom 1 → 1.86 in one
    pinch).
  • New settings group 阅读视图(Obsidian 自带的页面)/ Reading view, with the three settings above.

Verification: npm run verify:reading — 17 assertions in a real Chromium against a page that
mimics the reading view (a theme width of 720 px, a long document): follow-the-theme really is
720 px with no width rules injected, 900 px really measures 900 px, zoom 150 % keeps the on-screen
measure at 900 px while paragraphs get 1.5x taller, the clamp holds at 60–200 %, Ctrl+wheel zooms
inside the reading view and is ignored outside it (and after the listener is removed), and on a phone
viewport a real CDP two-finger pinch raises the zoom while the throttling keeps the reflow count
below the frame count.

1.3.5

  • The card concept is gone. Whiteboard mode used to compile the note into a board of cards:
    one card per heading, connectors, folding, a card limit, and a column or flow layout. It is now
    what it should have been: one page, 1280 px wide, on a surface you pan, zoom and scroll. The
    width setting belongs to the page, not to a card.
  • Removed along with it: src/board-model.ts (the heading→card compiler), src/board-layout.ts
    (tidy tree / single-column geometry), src/board-render.ts (card DOM, connectors, focus
    buttons), the five card settings (排版 / 展开层级 / 间距 / 连线 / 数量上限), every card style in
    styles.css, and the 43 unit tests that covered them. The verification suite now asserts the
    absence
    : no card class names or card settings in the built bundle, no card modules in the tree,
    and zero card artifacts in the live DOM.
  • What is left is the part that made the plugin worth having: one page whose width is a setting
    (1280 px default, A5/A4 presets one slider step away), recompiled every time you enter the mode and
    following the note as you edit, with the same gesture layer as before — drag to pan, pinch to zoom,
    适配宽度 to pull the whole page into the viewport and then simply scroll down.
  • Settings are now: 打开笔记时的默认模式 / default mode and 白板版面宽度 / whiteboard page width.

Verification: npm run verify:board (34 assertions) now checks the whiteboard itself — the page
is 1280 px by default (from the shipped settings data), the page mode follows the theme line width
(760 px), changing the width setting really changes the page, one page element exists, the bundle and
the DOM contain no card artifacts, wheels scroll to the last paragraph, fit-width puts the whole
page inside the viewport, and the mobile touch gestures keep their anchor invariant.

1.3.4

  • The column is 1280 px by default — a desktop web content width. A5 (560 px) turned out to be
    the wrong default for reading on a screen: long Chinese lines wrapped early and the column felt
    narrow. 1280 px is the width a web page uses, so lines are long, tables have room, and the column
    fills a normal screen — which is what makes reading a purely vertical gesture. The slider still
    names the paper presets (A5 = 148 mm ≈ 560 px, A4 ≈ 794 px) and the readout says
    1280 px · 网页宽 Web or 560 px · A5 · 148mm so the choice is obvious either way.
  • 适配栏宽 / fit column width — a new toolbar button that fills the viewport with the column
    width, so on a phone (or a small window) you can see a whole line and then just scroll down. The
    board still opens at 100% (readable), and you decide when to trade size for the whole column.
  • Indentation scales with the column: 18 px per level was invisible in a 1280 px column, so it is
    now about 3% of the width (≈ 38 px), still capped at three levels.

Verification: npm run verify:board is now 49 assertions — the default is asserted to be
1280 px with the readout naming it (网页宽 Web), A5 is still asserted to be 148 mm ≈ 560 px as a
preset, and the new fit column width assertion measures the real DOM: after one tap the widest card
edge lands inside the viewport and the scale is below 1.

1.3.3

  • Two layouts for the whiteboard, and the default is the one you read. The board used to be a
    branch tree only: headings in columns with connectors. On a phone that means hunting for content
    sideways. The default is now 单栏纵向流 / single column — one A5-wide sheet per section,
    stacked in document order, so scrolling down is reading down, with indentation (up to three
    levels) and the left accent bar carrying the hierarchy instead of connectors.
  • 分支树 / branch tree is still there for the other job: seeing the whole outline at a glance.
    Pick it in the settings (设置 → 白板模式 → 白板排版) or flip it from the view toolbar; connectors
    belong to that layout, and the single column draws none (a line inside a one-wide column only
    overlaps the cards).
  • Why cards at all, if it reads like a document? Because the board is zoomable when Obsidian's
    reading view is not: each section stays a sheet you can pinch into, tap to bring to the front, and
    the sections still fold by heading depth and by card limit. It is a page you can zoom, not a
    scroll that cannot.

Verification: npm run verify:board is now 48 assertions. The new ones assert the shipped
default layout is flow (read from the real settings data, not a number copied into the test),
that every card shares the paper width with y strictly increasing in document order, that a
single column draws zero connectors, and — the behavioural one — that scrolling down alone
reaches the last section
(the final card enters the viewport). Switching to branch tree flips the
connector assertions back on (count = parent/child relations, endpoints on the card edges), and
switching back drops them again.

1.3.2

  • Cards are paper now: A5 by default (148 mm ≈ 560 px). The default card width was 320 px, so a
    card held only about twenty Chinese characters per line and the board read like a narrow strip
    rather than a page — reported as "the whiteboard looks tiny". A5 is the width a Chinese book line
    actually uses (30–40 characters), so it is now the default; A6 and A4 are one slider step away and
    the readout shows millimetres and the paper name (560 px ≈ A5 · 148mm).
  • The board opens at natural size (100%), not fitted. Previously it focused the title card —
    which holds a title and a card count and nothing else — so the screen showed one small box in the
    middle. Now it opens at 100% with the root card in the top-left corner: one A...
Read more

1.3.6

Choose a tag to compare

@github-actions github-actions released this 18 Sep 11:01

Changelog

1.3.6

  • The reading view itself now has a width and a zoom. Obsidian's own reading view is not taken
    over — the plugin changes two CSS properties of it: the line width (default 900 px, the value
    that was asked for, with 760–1200 px and 跟随主题 / follow-the-theme options) and a zoom level
    (60 %–200 %, default 100 %). Your theme files are untouched, and follow the theme + 100 % injects
    nothing beyond one `touch-action` line.
  • Zoom reflows instead of stretching. It is applied as CSS `zoom` with the sizer's `max-width`
    divided by the same factor, so the text gets bigger while the measure on screen stays exactly the
    line width you picked. A screenshot-level stretch would have changed the line length; this does
    not.
  • You operate it: pinch, Ctrl+wheel, or commands. Pinch inside the reading view on mobile,
    Ctrl / ⌘ + wheel on desktop, or the three new commands (阅读视图放大 / 缩小 / 复位到 100 %,
    each showing the new level). Only two-finger pinches and Ctrl+wheel are intercepted — one-finger
    scrolling, taps and the plain wheel remain Obsidian's.
  • A real bug found by the browser harness. The first implementation listened for pointer events
    and the browser claimed the two-finger gesture for itself: of ten gesture frames only two arrived
    (pointercancel). The fix is to listen for `touchstart`/`touchmove` and to declare
    `touch-action: pan-y` on the reading view — vertical one-finger scrolling still belongs to
    Obsidian, while the two-finger pinch now belongs to the plugin (measured: zoom 1 → 1.86 in one
    pinch).
  • New settings group 阅读视图(Obsidian 自带的页面)/ Reading view, with the three settings above.

Verification: npm run verify:reading — 17 assertions in a real Chromium against a page that
mimics the reading view (a theme width of 720 px, a long document): follow-the-theme really is
720 px with no width rules injected, 900 px really measures 900 px, zoom 150 % keeps the on-screen
measure at 900 px while paragraphs get 1.5x taller, the clamp holds at 60–200 %, Ctrl+wheel zooms
inside the reading view and is ignored outside it (and after the listener is removed), and on a phone
viewport a real CDP two-finger pinch raises the zoom while the throttling keeps the reflow count
below the frame count.

1.3.5

  • The card concept is gone. Whiteboard mode used to compile the note into a board of cards:
    one card per heading, connectors, folding, a card limit, and a column or flow layout. It is now
    what it should have been: one page, 1280 px wide, on a surface you pan, zoom and scroll. The
    width setting belongs to the page, not to a card.
  • Removed along with it: src/board-model.ts (the heading→card compiler), src/board-layout.ts
    (tidy tree / single-column geometry), src/board-render.ts (card DOM, connectors, focus
    buttons), the five card settings (排版 / 展开层级 / 间距 / 连线 / 数量上限), every card style in
    styles.css, and the 43 unit tests that covered them. The verification suite now asserts the
    absence
    : no card class names or card settings in the built bundle, no card modules in the tree,
    and zero card artifacts in the live DOM.
  • What is left is the part that made the plugin worth having: one page whose width is a setting
    (1280 px default, A5/A4 presets one slider step away), recompiled every time you enter the mode and
    following the note as you edit, with the same gesture layer as before — drag to pan, pinch to zoom,
    适配宽度 to pull the whole page into the viewport and then simply scroll down.
  • Settings are now: 打开笔记时的默认模式 / default mode and 白板版面宽度 / whiteboard page width.

Verification: npm run verify:board (34 assertions) now checks the whiteboard itself — the page
is 1280 px by default (from the shipped settings data), the page mode follows the theme line width
(760 px), changing the width setting really changes the page, one page element exists, the bundle and
the DOM contain no card artifacts, wheels scroll to the last paragraph, fit-width puts the whole
page inside the viewport, and the mobile touch gestures keep their anchor invariant.

1.3.4

  • The column is 1280 px by default — a desktop web content width. A5 (560 px) turned out to be
    the wrong default for reading on a screen: long Chinese lines wrapped early and the column felt
    narrow. 1280 px is the width a web page uses, so lines are long, tables have room, and the column
    fills a normal screen — which is what makes reading a purely vertical gesture. The slider still
    names the paper presets (A5 = 148 mm ≈ 560 px, A4 ≈ 794 px) and the readout says
    1280 px · 网页宽 Web or 560 px · A5 · 148mm so the choice is obvious either way.
  • 适配栏宽 / fit column width — a new toolbar button that fills the viewport with the column
    width, so on a phone (or a small window) you can see a whole line and then just scroll down. The
    board still opens at 100% (readable), and you decide when to trade size for the whole column.
  • Indentation scales with the column: 18 px per level was invisible in a 1280 px column, so it is
    now about 3% of the width (≈ 38 px), still capped at three levels.

Verification: npm run verify:board is now 49 assertions — the default is asserted to be
1280 px with the readout naming it (网页宽 Web), A5 is still asserted to be 148 mm ≈ 560 px as a
preset, and the new fit column width assertion measures the real DOM: after one tap the widest card
edge lands inside the viewport and the scale is below 1.

1.3.3

  • Two layouts for the whiteboard, and the default is the one you read. The board used to be a
    branch tree only: headings in columns with connectors. On a phone that means hunting for content
    sideways. The default is now 单栏纵向流 / single column — one A5-wide sheet per section,
    stacked in document order, so scrolling down is reading down, with indentation (up to three
    levels) and the left accent bar carrying the hierarchy instead of connectors.
  • 分支树 / branch tree is still there for the other job: seeing the whole outline at a glance.
    Pick it in the settings (设置 → 白板模式 → 白板排版) or flip it from the view toolbar; connectors
    belong to that layout, and the single column draws none (a line inside a one-wide column only
    overlaps the cards).
  • Why cards at all, if it reads like a document? Because the board is zoomable when Obsidian's
    reading view is not: each section stays a sheet you can pinch into, tap to bring to the front, and
    the sections still fold by heading depth and by card limit. It is a page you can zoom, not a
    scroll that cannot.

Verification: npm run verify:board is now 48 assertions. The new ones assert the shipped
default layout is flow (read from the real settings data, not a number copied into the test),
that every card shares the paper width with y strictly increasing in document order, that a
single column draws zero connectors, and — the behavioural one — that scrolling down alone
reaches the last section
(the final card enters the viewport). Switching to branch tree flips the
connector assertions back on (count = parent/child relations, endpoints on the card edges), and
switching back drops them again.

1.3.2

  • Cards are paper now: A5 by default (148 mm ≈ 560 px). The default card width was 320 px, so a
    card held only about twenty Chinese characters per line and the board read like a narrow strip
    rather than a page — reported as "the whiteboard looks tiny". A5 is the width a Chinese book line
    actually uses (30–40 characters), so it is now the default; A6 and A4 are one slider step away and
    the readout shows millimetres and the paper name (560 px ≈ A5 · 148mm).
  • The board opens at natural size (100%), not fitted. Previously it focused the title card —
    which holds a title and a card count and nothing else — so the screen showed one small box in the
    middle. Now it opens at 100% with the root card in the top-left corner: one A5 page at reading
    size. The board still zooms and pans, and 回到全图 / 回到标题卡 are still in the toolbar.
  • Parents are top-aligned with their children, not centred against them. A tidy tree centres a
    parent against its children band; on a document board that pushes a short title card into the
    middle of the screen and leaves the top half empty — the other half of "it looks tiny". Top
    aligned, the top-left corner is content and you read downward, like paper.
  • The whiteboard is a view: it recompiles every time. Entering whiteboard mode compiles the
    Markdown again from scratch, reading the live editor text when the note is open in a pane (so
    unsaved edits show up), and it recompiles again when the note changes — a save, or typing in
    another pane, throttled to 400 ms. Nothing is written back, and there is a new
    重新编译 / recompile button in the toolbar for a forced refresh.
  • Board positions are now keyed by card width: change the paper size and the saved zoom/pan is
    dropped rather than restored onto a board whose geometry no longer matches.

Verification: npm run verify:board is now 42 assertions — the new ones assert the shipped
default is A5 (560 px ≈ A5 · 148mm, from the real settings data, not a number copied into the
test), that opening lands at scale 1 with content within one margin of the top-left corner, and that
every card's real DOM width equals the configured paper width.

1.3.1

  • Fixed: opening a note as a whiteboard showed an empty view. Obsidian's view lifecycle is
    onOpen() and then setState(). onOpen() reads the configured default mode (page) and
    paints the mode classes on the root element; setState() then switches the mode to whiteboard
    because the command asked for it — but nothing repainted the classes. The board was rendered into
    .zr-board-host, which .zr-mode-page .zr-board-host { display: none } hides, and the visible
    layer was the empty page. Symptom: run 编译成白板 / open as a whiteboard and see nothing at all
    (setting the d...
Read more

1.3.5

Choose a tag to compare

@github-actions github-actions released this 18 Sep 10:49

Changelog

1.3.5

  • The card concept is gone. Whiteboard mode used to compile the note into a board of cards:
    one card per heading, connectors, folding, a card limit, and a column or flow layout. It is now
    what it should have been: one page, 1280 px wide, on a surface you pan, zoom and scroll. The
    width setting belongs to the page, not to a card.
  • Removed along with it: src/board-model.ts (the heading→card compiler), src/board-layout.ts
    (tidy tree / single-column geometry), src/board-render.ts (card DOM, connectors, focus
    buttons), the five card settings (排版 / 展开层级 / 间距 / 连线 / 数量上限), every card style in
    styles.css, and the 43 unit tests that covered them. The verification suite now asserts the
    absence
    : no card class names or card settings in the built bundle, no card modules in the tree,
    and zero card artifacts in the live DOM.
  • What is left is the part that made the plugin worth having: one page whose width is a setting
    (1280 px default, A5/A4 presets one slider step away), recompiled every time you enter the mode and
    following the note as you edit, with the same gesture layer as before — drag to pan, pinch to zoom,
    适配宽度 to pull the whole page into the viewport and then simply scroll down.
  • Settings are now: 打开笔记时的默认模式 / default mode and 白板版面宽度 / whiteboard page width.

Verification: npm run verify:board (34 assertions) now checks the whiteboard itself — the page
is 1280 px by default (from the shipped settings data), the page mode follows the theme line width
(760 px), changing the width setting really changes the page, one page element exists, the bundle and
the DOM contain no card artifacts, wheels scroll to the last paragraph, fit-width puts the whole
page inside the viewport, and the mobile touch gestures keep their anchor invariant.

1.3.4

  • The column is 1280 px by default — a desktop web content width. A5 (560 px) turned out to be
    the wrong default for reading on a screen: long Chinese lines wrapped early and the column felt
    narrow. 1280 px is the width a web page uses, so lines are long, tables have room, and the column
    fills a normal screen — which is what makes reading a purely vertical gesture. The slider still
    names the paper presets (A5 = 148 mm ≈ 560 px, A4 ≈ 794 px) and the readout says
    1280 px · 网页宽 Web or 560 px · A5 · 148mm so the choice is obvious either way.
  • 适配栏宽 / fit column width — a new toolbar button that fills the viewport with the column
    width, so on a phone (or a small window) you can see a whole line and then just scroll down. The
    board still opens at 100% (readable), and you decide when to trade size for the whole column.
  • Indentation scales with the column: 18 px per level was invisible in a 1280 px column, so it is
    now about 3% of the width (≈ 38 px), still capped at three levels.

Verification: npm run verify:board is now 49 assertions — the default is asserted to be
1280 px with the readout naming it (网页宽 Web), A5 is still asserted to be 148 mm ≈ 560 px as a
preset, and the new fit column width assertion measures the real DOM: after one tap the widest card
edge lands inside the viewport and the scale is below 1.

1.3.3

  • Two layouts for the whiteboard, and the default is the one you read. The board used to be a
    branch tree only: headings in columns with connectors. On a phone that means hunting for content
    sideways. The default is now 单栏纵向流 / single column — one A5-wide sheet per section,
    stacked in document order, so scrolling down is reading down, with indentation (up to three
    levels) and the left accent bar carrying the hierarchy instead of connectors.
  • 分支树 / branch tree is still there for the other job: seeing the whole outline at a glance.
    Pick it in the settings (设置 → 白板模式 → 白板排版) or flip it from the view toolbar; connectors
    belong to that layout, and the single column draws none (a line inside a one-wide column only
    overlaps the cards).
  • Why cards at all, if it reads like a document? Because the board is zoomable when Obsidian's
    reading view is not: each section stays a sheet you can pinch into, tap to bring to the front, and
    the sections still fold by heading depth and by card limit. It is a page you can zoom, not a
    scroll that cannot.

Verification: npm run verify:board is now 48 assertions. The new ones assert the shipped
default layout is flow (read from the real settings data, not a number copied into the test),
that every card shares the paper width with y strictly increasing in document order, that a
single column draws zero connectors, and — the behavioural one — that scrolling down alone
reaches the last section
(the final card enters the viewport). Switching to branch tree flips the
connector assertions back on (count = parent/child relations, endpoints on the card edges), and
switching back drops them again.

1.3.2

  • Cards are paper now: A5 by default (148 mm ≈ 560 px). The default card width was 320 px, so a
    card held only about twenty Chinese characters per line and the board read like a narrow strip
    rather than a page — reported as "the whiteboard looks tiny". A5 is the width a Chinese book line
    actually uses (30–40 characters), so it is now the default; A6 and A4 are one slider step away and
    the readout shows millimetres and the paper name (560 px ≈ A5 · 148mm).
  • The board opens at natural size (100%), not fitted. Previously it focused the title card —
    which holds a title and a card count and nothing else — so the screen showed one small box in the
    middle. Now it opens at 100% with the root card in the top-left corner: one A5 page at reading
    size. The board still zooms and pans, and 回到全图 / 回到标题卡 are still in the toolbar.
  • Parents are top-aligned with their children, not centred against them. A tidy tree centres a
    parent against its children band; on a document board that pushes a short title card into the
    middle of the screen and leaves the top half empty — the other half of "it looks tiny". Top
    aligned, the top-left corner is content and you read downward, like paper.
  • The whiteboard is a view: it recompiles every time. Entering whiteboard mode compiles the
    Markdown again from scratch, reading the live editor text when the note is open in a pane (so
    unsaved edits show up), and it recompiles again when the note changes — a save, or typing in
    another pane, throttled to 400 ms. Nothing is written back, and there is a new
    重新编译 / recompile button in the toolbar for a forced refresh.
  • Board positions are now keyed by card width: change the paper size and the saved zoom/pan is
    dropped rather than restored onto a board whose geometry no longer matches.

Verification: npm run verify:board is now 42 assertions — the new ones assert the shipped
default is A5 (560 px ≈ A5 · 148mm, from the real settings data, not a number copied into the
test), that opening lands at scale 1 with content within one margin of the top-left corner, and that
every card's real DOM width equals the configured paper width.

1.3.1

  • Fixed: opening a note as a whiteboard showed an empty view. Obsidian's view lifecycle is
    onOpen() and then setState(). onOpen() reads the configured default mode (page) and
    paints the mode classes on the root element; setState() then switches the mode to whiteboard
    because the command asked for it — but nothing repainted the classes. The board was rendered into
    .zr-board-host, which .zr-mode-page .zr-board-host { display: none } hides, and the visible
    layer was the empty page. Symptom: run 编译成白板 / open as a whiteboard and see nothing at all
    (setting the default mode to whiteboard worked, because then onOpen() painted the right classes).
  • The mode classes are now applied inside the render path (renderFile()), not merely while
    building the UI: whichever layer is about to be filled is made visible first. The rule is written
    down next to the code, because "visibility is not a one-time setup" is exactly the sort of
    invariant that silently rots.
  • npm run verify:board now reproduces the bug before asserting the fix (35 assertions): it
    paints the page classes, renders the board without re-aligning them, and asserts that exactly
    0 cards are visible — then re-renders through the real path and asserts all of them are. A test
    that cannot fail is not a test.
  • Board rendering failures are no longer silent: a caught error raises a Notice (and a console
    error) instead of leaving a blank view — on a phone there is no console to open.
  • Keyboard shortcuts (+ - 0) are registered once per view instead of once per UI rebuild,
    so toggling the mode no longer handles the same key twice.

1.3.0

  • Whiteboard mode: the note is compiled into a board, instead of being put on one. The previous
    version rendered the whole note as one tall page inside a zoomable surface. This version adds the
    other reading model: the Markdown itself becomes the board. Every heading turns into a card
    holding that section's content, frontmatter is dropped (it is metadata, not the note), and code
    fences, tables, callouts, quotes, math, images and Mermaid blocks become typed blocks inside their
    card — a # inside a code fence is deliberately not a heading. Cards are laid out as a tidy
    tree (children in the next column, vertically centred against their parent) with bezier
    connectors from the parent's right edge to the child's left edge, so the outline is visible at a
    glance on a phone and readable after a pinch.
  • Heights come from the real DOM, twice. Estimating Chinese text height is guesswork, so the
    board is laid out once from an estimate (the board appears immediately) and again from measured
    offsetHeight values. Tables, images and long paragraphs then take exactly the room they need,
    and no card can overlap another.
  • **Deep headings fold into their ancestor...
Read more

1.3.4

Choose a tag to compare

@github-actions github-actions released this 18 Sep 10:32

Changelog

1.3.4

  • The column is 1280 px by default — a desktop web content width. A5 (560 px) turned out to be
    the wrong default for reading on a screen: long Chinese lines wrapped early and the column felt
    narrow. 1280 px is the width a web page uses, so lines are long, tables have room, and the column
    fills a normal screen — which is what makes reading a purely vertical gesture. The slider still
    names the paper presets (A5 = 148 mm ≈ 560 px, A4 ≈ 794 px) and the readout says
    1280 px · 网页宽 Web or 560 px · A5 · 148mm so the choice is obvious either way.
  • 适配栏宽 / fit column width — a new toolbar button that fills the viewport with the column
    width, so on a phone (or a small window) you can see a whole line and then just scroll down. The
    board still opens at 100% (readable), and you decide when to trade size for the whole column.
  • Indentation scales with the column: 18 px per level was invisible in a 1280 px column, so it is
    now about 3% of the width (≈ 38 px), still capped at three levels.

Verification: npm run verify:board is now 49 assertions — the default is asserted to be
1280 px with the readout naming it (网页宽 Web), A5 is still asserted to be 148 mm ≈ 560 px as a
preset, and the new fit column width assertion measures the real DOM: after one tap the widest card
edge lands inside the viewport and the scale is below 1.

1.3.3

  • Two layouts for the whiteboard, and the default is the one you read. The board used to be a
    branch tree only: headings in columns with connectors. On a phone that means hunting for content
    sideways. The default is now 单栏纵向流 / single column — one A5-wide sheet per section,
    stacked in document order, so scrolling down is reading down, with indentation (up to three
    levels) and the left accent bar carrying the hierarchy instead of connectors.
  • 分支树 / branch tree is still there for the other job: seeing the whole outline at a glance.
    Pick it in the settings (设置 → 白板模式 → 白板排版) or flip it from the view toolbar; connectors
    belong to that layout, and the single column draws none (a line inside a one-wide column only
    overlaps the cards).
  • Why cards at all, if it reads like a document? Because the board is zoomable when Obsidian's
    reading view is not: each section stays a sheet you can pinch into, tap to bring to the front, and
    the sections still fold by heading depth and by card limit. It is a page you can zoom, not a
    scroll that cannot.

Verification: npm run verify:board is now 48 assertions. The new ones assert the shipped
default layout is flow (read from the real settings data, not a number copied into the test),
that every card shares the paper width with y strictly increasing in document order, that a
single column draws zero connectors, and — the behavioural one — that scrolling down alone
reaches the last section
(the final card enters the viewport). Switching to branch tree flips the
connector assertions back on (count = parent/child relations, endpoints on the card edges), and
switching back drops them again.

1.3.2

  • Cards are paper now: A5 by default (148 mm ≈ 560 px). The default card width was 320 px, so a
    card held only about twenty Chinese characters per line and the board read like a narrow strip
    rather than a page — reported as "the whiteboard looks tiny". A5 is the width a Chinese book line
    actually uses (30–40 characters), so it is now the default; A6 and A4 are one slider step away and
    the readout shows millimetres and the paper name (560 px ≈ A5 · 148mm).
  • The board opens at natural size (100%), not fitted. Previously it focused the title card —
    which holds a title and a card count and nothing else — so the screen showed one small box in the
    middle. Now it opens at 100% with the root card in the top-left corner: one A5 page at reading
    size. The board still zooms and pans, and 回到全图 / 回到标题卡 are still in the toolbar.
  • Parents are top-aligned with their children, not centred against them. A tidy tree centres a
    parent against its children band; on a document board that pushes a short title card into the
    middle of the screen and leaves the top half empty — the other half of "it looks tiny". Top
    aligned, the top-left corner is content and you read downward, like paper.
  • The whiteboard is a view: it recompiles every time. Entering whiteboard mode compiles the
    Markdown again from scratch, reading the live editor text when the note is open in a pane (so
    unsaved edits show up), and it recompiles again when the note changes — a save, or typing in
    another pane, throttled to 400 ms. Nothing is written back, and there is a new
    重新编译 / recompile button in the toolbar for a forced refresh.
  • Board positions are now keyed by card width: change the paper size and the saved zoom/pan is
    dropped rather than restored onto a board whose geometry no longer matches.

Verification: npm run verify:board is now 42 assertions — the new ones assert the shipped
default is A5 (560 px ≈ A5 · 148mm, from the real settings data, not a number copied into the
test), that opening lands at scale 1 with content within one margin of the top-left corner, and that
every card's real DOM width equals the configured paper width.

1.3.1

  • Fixed: opening a note as a whiteboard showed an empty view. Obsidian's view lifecycle is
    onOpen() and then setState(). onOpen() reads the configured default mode (page) and
    paints the mode classes on the root element; setState() then switches the mode to whiteboard
    because the command asked for it — but nothing repainted the classes. The board was rendered into
    .zr-board-host, which .zr-mode-page .zr-board-host { display: none } hides, and the visible
    layer was the empty page. Symptom: run 编译成白板 / open as a whiteboard and see nothing at all
    (setting the default mode to whiteboard worked, because then onOpen() painted the right classes).
  • The mode classes are now applied inside the render path (renderFile()), not merely while
    building the UI: whichever layer is about to be filled is made visible first. The rule is written
    down next to the code, because "visibility is not a one-time setup" is exactly the sort of
    invariant that silently rots.
  • npm run verify:board now reproduces the bug before asserting the fix (35 assertions): it
    paints the page classes, renders the board without re-aligning them, and asserts that exactly
    0 cards are visible — then re-renders through the real path and asserts all of them are. A test
    that cannot fail is not a test.
  • Board rendering failures are no longer silent: a caught error raises a Notice (and a console
    error) instead of leaving a blank view — on a phone there is no console to open.
  • Keyboard shortcuts (+ - 0) are registered once per view instead of once per UI rebuild,
    so toggling the mode no longer handles the same key twice.

1.3.0

  • Whiteboard mode: the note is compiled into a board, instead of being put on one. The previous
    version rendered the whole note as one tall page inside a zoomable surface. This version adds the
    other reading model: the Markdown itself becomes the board. Every heading turns into a card
    holding that section's content, frontmatter is dropped (it is metadata, not the note), and code
    fences, tables, callouts, quotes, math, images and Mermaid blocks become typed blocks inside their
    card — a # inside a code fence is deliberately not a heading. Cards are laid out as a tidy
    tree (children in the next column, vertically centred against their parent) with bezier
    connectors from the parent's right edge to the child's left edge, so the outline is visible at a
    glance on a phone and readable after a pinch.
  • Heights come from the real DOM, twice. Estimating Chinese text height is guesswork, so the
    board is laid out once from an estimate (the board appears immediately) and again from measured
    offsetHeight values. Tables, images and long paragraphs then take exactly the room they need,
    and no card can overlap another.
  • Deep headings fold into their ancestor card. Chinese notes often run four or five heading
    levels deep, and one column per level turns the board into a thin ribbon: sections deeper than the
    configured depth are folded in as subsections. A card limit folds deeper automatically, so a note
    with hundreds of headings cannot stall a phone, and the root card says how many cards there are.
  • Tap a card title to bring that card to the front, 回到全图 fits the whole board, 回到标题卡
    returns to the root. Links inside a card keep their normal meaning: only the card head and its
    focus button zoom. The board transition is 240 ms, and it is cancelled the moment a pointer goes
    down so dragging never feels laggy.
  • The settings page is bilingual and searchable. Every setting now reads 中文 / English — name,
    description and the options of every dropdown — and on Obsidian 1.13+ the page is declared through
    getSettingDefinitions(), so settings appear in the settings search: typing 双指 or pinch
    jumps straight to the two-finger switch (双指捏合缩放 / Two-finger pinch zoom), which is exactly
    what could not be found before. The content lives in one data module (src/settings-spec.ts) and is
    rendered twice — declaratively on 1.13+, imperatively on 1.5.7–1.12 — so older versions get the
    same page. A new 手势速查 / gesture cheat sheet lists every gesture in both languages.
  • Two-finger pinch is now a setting, with a sensitivity slider. Turning it off leaves two fingers
    panning with their midpoint (handy when an IME or stylus emits a phantom second pointer); the
    slider scales the pinch ratio between 0.5x and 2x.
  • The zoom button on images and diagrams moved to the top-left corner by default. The top-right
    corner is where Obsidian puts its own 编辑源文件 / edit source and more-options controls, and the
    button used to cover...
Read more

1.3.3

Choose a tag to compare

@github-actions github-actions released this 18 Sep 10:33

Changelog

1.3.3

  • Two layouts for the whiteboard, and the default is the one you read. The board used to be a
    branch tree only: headings in columns with connectors. On a phone that means hunting for content
    sideways. The default is now 单栏纵向流 / single column — one A5-wide sheet per section,
    stacked in document order, so scrolling down is reading down, with indentation (up to three
    levels) and the left accent bar carrying the hierarchy instead of connectors.
  • 分支树 / branch tree is still there for the other job: seeing the whole outline at a glance.
    Pick it in the settings (设置 → 白板模式 → 白板排版) or flip it from the view toolbar; connectors
    belong to that layout, and the single column draws none (a line inside a one-wide column only
    overlaps the cards).
  • Why cards at all, if it reads like a document? Because the board is zoomable when Obsidian's
    reading view is not: each section stays a sheet you can pinch into, tap to bring to the front, and
    the sections still fold by heading depth and by card limit. It is a page you can zoom, not a
    scroll that cannot.

Verification: npm run verify:board is now 48 assertions. The new ones assert the shipped
default layout is flow (read from the real settings data, not a number copied into the test),
that every card shares the paper width with y strictly increasing in document order, that a
single column draws zero connectors, and — the behavioural one — that scrolling down alone
reaches the last section
(the final card enters the viewport). Switching to branch tree flips the
connector assertions back on (count = parent/child relations, endpoints on the card edges), and
switching back drops them again.

1.3.2

  • Cards are paper now: A5 by default (148 mm ≈ 560 px). The default card width was 320 px, so a
    card held only about twenty Chinese characters per line and the board read like a narrow strip
    rather than a page — reported as "the whiteboard looks tiny". A5 is the width a Chinese book line
    actually uses (30–40 characters), so it is now the default; A6 and A4 are one slider step away and
    the readout shows millimetres and the paper name (560 px ≈ A5 · 148mm).
  • The board opens at natural size (100%), not fitted. Previously it focused the title card —
    which holds a title and a card count and nothing else — so the screen showed one small box in the
    middle. Now it opens at 100% with the root card in the top-left corner: one A5 page at reading
    size. The board still zooms and pans, and 回到全图 / 回到标题卡 are still in the toolbar.
  • Parents are top-aligned with their children, not centred against them. A tidy tree centres a
    parent against its children band; on a document board that pushes a short title card into the
    middle of the screen and leaves the top half empty — the other half of "it looks tiny". Top
    aligned, the top-left corner is content and you read downward, like paper.
  • The whiteboard is a view: it recompiles every time. Entering whiteboard mode compiles the
    Markdown again from scratch, reading the live editor text when the note is open in a pane (so
    unsaved edits show up), and it recompiles again when the note changes — a save, or typing in
    another pane, throttled to 400 ms. Nothing is written back, and there is a new
    重新编译 / recompile button in the toolbar for a forced refresh.
  • Board positions are now keyed by card width: change the paper size and the saved zoom/pan is
    dropped rather than restored onto a board whose geometry no longer matches.

Verification: npm run verify:board is now 42 assertions — the new ones assert the shipped
default is A5 (560 px ≈ A5 · 148mm, from the real settings data, not a number copied into the
test), that opening lands at scale 1 with content within one margin of the top-left corner, and that
every card's real DOM width equals the configured paper width.

1.3.1

  • Fixed: opening a note as a whiteboard showed an empty view. Obsidian's view lifecycle is
    onOpen() and then setState(). onOpen() reads the configured default mode (page) and
    paints the mode classes on the root element; setState() then switches the mode to whiteboard
    because the command asked for it — but nothing repainted the classes. The board was rendered into
    .zr-board-host, which .zr-mode-page .zr-board-host { display: none } hides, and the visible
    layer was the empty page. Symptom: run 编译成白板 / open as a whiteboard and see nothing at all
    (setting the default mode to whiteboard worked, because then onOpen() painted the right classes).
  • The mode classes are now applied inside the render path (renderFile()), not merely while
    building the UI: whichever layer is about to be filled is made visible first. The rule is written
    down next to the code, because "visibility is not a one-time setup" is exactly the sort of
    invariant that silently rots.
  • npm run verify:board now reproduces the bug before asserting the fix (35 assertions): it
    paints the page classes, renders the board without re-aligning them, and asserts that exactly
    0 cards are visible — then re-renders through the real path and asserts all of them are. A test
    that cannot fail is not a test.
  • Board rendering failures are no longer silent: a caught error raises a Notice (and a console
    error) instead of leaving a blank view — on a phone there is no console to open.
  • Keyboard shortcuts (+ - 0) are registered once per view instead of once per UI rebuild,
    so toggling the mode no longer handles the same key twice.

1.3.0

  • Whiteboard mode: the note is compiled into a board, instead of being put on one. The previous
    version rendered the whole note as one tall page inside a zoomable surface. This version adds the
    other reading model: the Markdown itself becomes the board. Every heading turns into a card
    holding that section's content, frontmatter is dropped (it is metadata, not the note), and code
    fences, tables, callouts, quotes, math, images and Mermaid blocks become typed blocks inside their
    card — a # inside a code fence is deliberately not a heading. Cards are laid out as a tidy
    tree (children in the next column, vertically centred against their parent) with bezier
    connectors from the parent's right edge to the child's left edge, so the outline is visible at a
    glance on a phone and readable after a pinch.
  • Heights come from the real DOM, twice. Estimating Chinese text height is guesswork, so the
    board is laid out once from an estimate (the board appears immediately) and again from measured
    offsetHeight values. Tables, images and long paragraphs then take exactly the room they need,
    and no card can overlap another.
  • Deep headings fold into their ancestor card. Chinese notes often run four or five heading
    levels deep, and one column per level turns the board into a thin ribbon: sections deeper than the
    configured depth are folded in as subsections. A card limit folds deeper automatically, so a note
    with hundreds of headings cannot stall a phone, and the root card says how many cards there are.
  • Tap a card title to bring that card to the front, 回到全图 fits the whole board, 回到标题卡
    returns to the root. Links inside a card keep their normal meaning: only the card head and its
    focus button zoom. The board transition is 240 ms, and it is cancelled the moment a pointer goes
    down so dragging never feels laggy.
  • The settings page is bilingual and searchable. Every setting now reads 中文 / English — name,
    description and the options of every dropdown — and on Obsidian 1.13+ the page is declared through
    getSettingDefinitions(), so settings appear in the settings search: typing 双指 or pinch
    jumps straight to the two-finger switch (双指捏合缩放 / Two-finger pinch zoom), which is exactly
    what could not be found before. The content lives in one data module (src/settings-spec.ts) and is
    rendered twice — declaratively on 1.13+, imperatively on 1.5.7–1.12 — so older versions get the
    same page. A new 手势速查 / gesture cheat sheet lists every gesture in both languages.
  • Two-finger pinch is now a setting, with a sensitivity slider. Turning it off leaves two fingers
    panning with their midpoint (handy when an IME or stylus emits a phantom second pointer); the
    slider scales the pinch ratio between 0.5x and 2x.
  • The zoom button on images and diagrams moved to the top-left corner by default. The top-right
    corner is where Obsidian puts its own 编辑源文件 / edit source and more-options controls, and the
    button used to cover them (reported from a real phone). The corner is a setting, so anyone who
    preferred the old position can put it back — and both placement paths (persistent inline button and
    hover singleton) follow it.
  • New settings: 打开笔记时的默认模式 / default mode (page or whiteboard), 卡片宽度 / card width,
    卡片展开层级 / outline depth, 卡片间距 / card spacing, 显示连线 / connectors, 卡片数量上限 /
    card limit, 放大按钮的位置 / zoom button corner.
  • Zoom and position are now remembered per mode (page and whiteboard have different sizes, so
    sharing one transform made them fight). Whiteboard positions use the same data.json, with a
    #board suffix.
  • Whiteboard mode is reachable from the command palette, the ribbon icon, the view toolbar, and the
    file-list context menu (编译成白板 / open as a whiteboard) — the last one so a phone user can go
    straight from the file list into a board without opening the note first.

Verification: npm test now has 84 unit tests, including the board compiler (fenced code,
frontmatter, table detection, heading level jumps, folding) and a contract test that fails if any
setting is missing its Chinese or English half. npm run verify:board is new: 32 assertions in a
real Chromium, asserting the geometry from the DOM — cards never overlap, every card is inside the
board bounds, every connector lands on its cards' edges, the measured height equals the layout
height (t...

Read more