Files
book-comic-library/docs/superpowers/specs/2026-09-08-cbz-chapter-continuous-reading-design.md
T

74 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CBZ 章节化连续阅读(锁章 + 预读)设计 / CBZ chapter-scoped continuous reading design
日期 2026-09-08。分支 `feat/ui-redesign`。状态:已获用户批准(会话内确认)。
## 目标 / Goal
漫画(CBZ)阅读以「章」为单位:一章内无论多少图都视为一段连续的整章内容,
默认不能靠上下滑动越过章界进入下一章(只能点「下一章」),可开「连读」让滑动贯穿章节。
去掉现有 连读/整页/适高 三档概念。锁章时预渲染(挂载+解码)其后 N 章(用户可配置,默认 2),
切章零白屏。
CBZ reading is chapter-scoped: images within a chapter flow continuously; by default scrolling cannot cross a chapter boundary (only the 下一章 button can); an optional 连读 mode lets scrolling flow into following chapters. The three-mode cycle (连读/整页/适高) is removed. The next N chapters (user-configurable, default 2) are pre-rendered while locked so chapter switches are instant.
## 决策记录 / Decisions
- 章节内显示 = 按容器宽度(≤720px)连续滚动、无 snap、无适高一屏一页。用户选定(方案 A)。
- 翻页手势/按键 = 章内翻一屏(`scrollBy ±vh`),不再按图跳页。用户选定。
- 采用「按章节作用域渲染」(方案 A),否决:全书渲染+滚动钳制(手感生硬、浪费加载)、
一章一挂载(书签/进度/量高学习跨章迁移复杂、切章闪烁)。
- 预读实现为隐藏层挂载解码(不增加可滚动高度),不违反锁章语义。用户要求「可预渲染下两章、可配置」。
- 进度滑条/页码/书签/服务端进度均仍为全书页号,locator 形状 `{page}` 不变,无后端/API 改动。
- 扁平包(chapters 为 null)= 整本一章:章按钮与连读开关隐藏,锁章/预读无意义,行为即纯连续滚动。
## 前端 / Frontend(全部改动在 `frontend/src`,纯前端)
### 状态与持久化
- 删除 `PageMode`/`MODES`/`MODE_LABEL`/`useStoredMode` 及 `cbz-mode` 键;PageImg 去掉 `fitH` 分支;
滚动盒去掉 `snap-y snap-proximity`。
- `localStorage("cbz-continuous")`:连读开关,默认关(锁章)。
- `localStorage("cbz-prefetch")`:预读章数 0–3,默认 2。工具栏步进器按钮循环 0→1→2→3→0。
### 区间几何
- 当前章 `ci` 由滚动位置(现 `cur` 所在页 → 章)推出,章起点 `chapters[ci].start`。
- `PageHeights` 仍覆盖全书 `count` 页(复用现有量高/估高/`applyShift` 补偿逻辑)。
- 挂载上限 `mountEnd`:锁章 = 第 `ci+1+prefetch` 章起点(越界取 count);连读 = count。
- 滚动终点 `scrollEnd`:锁章 = `ph.offset(章末) + 章末卡片高`;连读 = 全书末尾。
- 超出 `scrollEnd` 的预读页渲染进一个 `height:0; overflow:hidden` 的绝对定位隐藏层
(子页仍按 `ph.offset(i)` 定位、`aria-hidden`):blob 经 `fetchObjectUrl` 缓存、`<img>` 挂载即解码,
但不参与滚动几何。切章后这些页落入可见区间即直接上屏。
- 纯计算抽为 `lib/virt.ts` 导出 helper(如 `chapterRange(chapters, count, ci, continuous, prefetch)`
→ `{mountStart, mountEnd, scrollEndPage}`),vitest 覆盖。
### 交互
- 点按左右侧区/←→/PageUp·Down:`scrollBy(±vh, smooth)`;锁章时滚动高度天然停在章末卡片。
- 点中间仍唤出工具栏(不变)。
- 章末卡片:锁章时本章末尾一屏「本章完 · 下一章 →」(最终章显示「全书完」),点卡片=切章。
- 切章入口(上一章/下一章按钮、目录行、书签 seek、章末卡片、滑条拖入他章区间):
设 `ci` 并 `jump(page)`;滑条跨章视为显式定位,不算「滑动越界」。
- 恢复进度:由 `initialLocator.page` 反推所在章后定位。
- 闲时「停滚 250ms 预取后 5 页」保留。
## 错误处理 / Errors
- 无新增失败面:页数接口、鉴权取图、失败重试(「本页加载失败」)均沿用。
- `cbz-prefetch` 值非法(手改 localStorage)→ 回退默认 2;`cbz-continuous` 非 `"1"` → 关。
## 测试 / Tests
- `lib/virt.ts` helper 表驱动单测:锁/连读 × 预读 0–3 × 首章/末章/单章扁平包 × 边界页;
断言 mountEnd/scrollEnd 不越过滚动锁、预读不超过 count。
- 现有 `virt` 用例保持绿;`npm run check` 绿。
- 真实浏览器点验:锁章滚不到下章、开连读可滑过、预读下切章无白屏、扁平包无章 UI。
## 文档 / Docs
- `docs/CHANGELOG_web.md` 新增条目(英中各一行),不重复进 `docs/CHANGELOG.md`。
## 不做 / Non-goals
- 后端章节结构改动、章内页号重映射、PDF/EPUB/TXT 阅读器改动、横翻 RTL 模式、
长按拖拽越章「窥视」下一章。