@memef1f1y/dsh-plugin-tts 0.6.2 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -27
- package/README.zh.md +290 -263
- package/docs/USER-GUIDE.md +72 -17
- package/docs/acceptance-checklist.md +3 -3
- package/docs/scroll-follow-v2.md +102 -0
- package/lib/client.js +242 -130
- package/lib/index.mjs +86 -8
- package/package.json +1 -1
- package/tests/client-load.mjs +33 -20
- package/tests/smoke.mjs +55 -0
package/docs/USER-GUIDE.md
CHANGED
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
> 你可以只读自己需要的部分:
|
|
5
5
|
> - **只想让 AI 回复能朗读** → 看第 3 节(约 5 分钟)
|
|
6
6
|
> - **想用自己训练的音色朗读** → 看第 4 节(约 30 分钟,含 4.2 的服务启动)
|
|
7
|
-
> -
|
|
8
|
-
> -
|
|
7
|
+
> - **想用一段录音克隆声音**(本机参考音频 / 提示音频)→ 看第 5 节(Index-TTS2)或第 6 节(CosyVoice)(约 15 分钟)
|
|
8
|
+
> - **想用谷歌付费音色** → 看第 7 节(约 10 分钟,需自备 API Key)
|
|
9
|
+
> - **想下载别人分享的音色** → 看第 8 节(约 10 分钟)
|
|
10
|
+
> - 出问题 → 看第 10 节(按症状查)和第 11 节(术语字典)
|
|
9
11
|
|
|
10
12
|
---
|
|
11
13
|
|
|
@@ -15,10 +17,11 @@
|
|
|
15
17
|
|
|
16
18
|
- 每条 AI 回复下面多一个 🔈 喇叭按钮:点一下朗读,再点一下停止;
|
|
17
19
|
- 输入框左边有一个喇叭开关:打开后,每条新回复**自动朗读**;
|
|
18
|
-
- 朗读的声音可以是微软的免费音色(Edge TTS),也可以是**你自己训练的 RVC
|
|
19
|
-
|
|
20
|
+
- 朗读的声音可以是微软的免费音色(Edge TTS),也可以是**你自己训练的 RVC 音色**、
|
|
21
|
+
**一段录音还原的本地音色**(Index-TTS2 参考音频 / CosyVoice 提示音频零样本克隆),
|
|
22
|
+
**谷歌付费音色**,或**从网上下载的音色包**。
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
全程在你自己的电脑上运行(除了微软 / 谷歌在线朗读本身),你的声音模型与参考音频不会上传到任何地方。
|
|
22
25
|
|
|
23
26
|
---
|
|
24
27
|
|
|
@@ -150,7 +153,7 @@
|
|
|
150
153
|
|
|
151
154
|
1. 回到最下面「试听测试」,输入一句话,点 ▶。
|
|
152
155
|
2. **成功**:几秒后(首次可能十几秒,是在加载模型+自动测速)听到**你的音色**在朗读。
|
|
153
|
-
3. **失败**:出现红字提示 → 对照第
|
|
156
|
+
3. **失败**:出现红字提示 → 对照第 10 节的排查表。
|
|
154
157
|
|
|
155
158
|
### 4.5 长文本自动分段
|
|
156
159
|
|
|
@@ -160,7 +163,53 @@
|
|
|
160
163
|
|
|
161
164
|
---
|
|
162
165
|
|
|
163
|
-
## 5.
|
|
166
|
+
## 5. 用一段录音还原声音(Index-TTS2,本机)
|
|
167
|
+
|
|
168
|
+
**给谁用**:有一段几秒~几十秒的清晰人声(wav/mp3),想让朗读直接用这个声音,
|
|
169
|
+
不想训练模型的人。
|
|
170
|
+
|
|
171
|
+
1. 双击本地包里的「**启动api服务.bat**」,黑窗口**别关**(默认端口 `7880`)。
|
|
172
|
+
2. 设置 → 插件 → 语音 → TTS提供者切到「**本地音色(Index-TTS2)**」→
|
|
173
|
+
点「**刷新音色**」,下拉里选你的参考音频(没有就用「上传参考音频」传一段)。
|
|
174
|
+
3. 回到底部「试听测试」输一句话点 ▶,听到参考音频的音色即成功。
|
|
175
|
+
4. 长文本同样自动分段(一格约 15 秒音频的块),其余与 RVC 一致。
|
|
176
|
+
|
|
177
|
+
> 情感、清洗文本等细项见 [《Index-TTS2 指南》](INDEX-TTS2-GUIDE.md);连不上服务
|
|
178
|
+
> 先看那份指南的疑难排查。
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 6. 用提示音频零样本克隆(CosyVoice,本机)
|
|
183
|
+
|
|
184
|
+
**给谁用**:有一段 5~20 秒的人声,想零样本克隆(连参考音频都不用"注册",即选即用)的人。
|
|
185
|
+
|
|
186
|
+
1. 双击本地包里的「**启动cosy服务.bat**」,黑窗口**别关**(默认端口 `7890`)。
|
|
187
|
+
2. 设置 → 插件 → 语音 → TTS提供者切到「**本地克隆(CosyVoice)**」→
|
|
188
|
+
点「**刷新音色**」选提示音频(没有就上传一段)。
|
|
189
|
+
3. **最关键一步**:「提示音频文字稿」必须把提示音频里说的内容**按顺序全文填写**
|
|
190
|
+
(中英日混的提示音三段都要写;缺一段,模型会把缺的那段复读一遍再读新文字)。
|
|
191
|
+
4. 回到底部试听,听到克隆音色即成功;语速 0.5~2.0,种子填 0 为每次随机。
|
|
192
|
+
|
|
193
|
+
> 细节见 [《CosyVoice 指南》](COSYVOICE-GUIDE.md),尤其是「提示音频与文字稿」一节。
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## 7. 用谷歌付费音色(Cloud TTS)
|
|
198
|
+
|
|
199
|
+
**给谁用**:想要中文标准/波形音色、愿意自备 API Key 并按量付费的人
|
|
200
|
+
(中文标准音色每月前 400 万字符免费,Wavenet/Neural2 每月前 100 万字符免费)。
|
|
201
|
+
|
|
202
|
+
1. 在 Google Cloud Console 建项目 → 启用 Text-to-Speech API → 创建 API Key。
|
|
203
|
+
2. 设置 → 插件 → 语音 → TTS提供者切到「**Cloud TTS**」→ 粘贴 Key 点「**保存配置**」
|
|
204
|
+
(输入框会清空;Key 只存本机 Host 文件,可点「测试连接」验证)。
|
|
205
|
+
3. 选音色试听即成功;用量在「本月用量(本地计数)」里按档查看,
|
|
206
|
+
每月 1 号清零(官方账单以 Google Cloud Billing 为准)。
|
|
207
|
+
|
|
208
|
+
> Key 与计费细节见 [《Cloud 指南》](CLOUD-GUIDE.md)。
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## 8. 第三步:下载别人分享的音色(音色包)
|
|
164
213
|
|
|
165
214
|
> 音色包 = 模型 + 可选的紧凑索引 + 说明,打成一个"仓库",一个网址就能分享。
|
|
166
215
|
|
|
@@ -178,7 +227,7 @@
|
|
|
178
227
|
|
|
179
228
|
---
|
|
180
229
|
|
|
181
|
-
##
|
|
230
|
+
## 9. 日常使用小知识
|
|
182
231
|
|
|
183
232
|
- **停止朗读**:再点一次喇叭按钮;关闭自动朗读开关会停止自动朗读(不影响手动)。
|
|
184
233
|
- **长回复**:自动分段、边读边合成,进度显示「第 x/y 段 · 边播边合成」。
|
|
@@ -187,7 +236,7 @@
|
|
|
187
236
|
|
|
188
237
|
---
|
|
189
238
|
|
|
190
|
-
##
|
|
239
|
+
## 10. 出问题了?按症状查
|
|
191
240
|
|
|
192
241
|
| 症状 | 最常见原因 | 怎么办 |
|
|
193
242
|
|---|---|---|
|
|
@@ -198,9 +247,11 @@
|
|
|
198
247
|
| 首次朗读等十几秒 | 正常:加载模型 + 自动测速 | 等它;之后会快 |
|
|
199
248
|
| 音色不够像 | 没填索引,或索引权重太低 | 填 .index;「索引权重」调向 100% |
|
|
200
249
|
| 报 403 / 合成失败(Edge 模式) | 微软端点临时限制 | 过一会儿重试;看 README 疑难排查 |
|
|
201
|
-
| 试听按钮一直转 | 网络或服务没起来 |
|
|
250
|
+
| 试听按钮一直转 | 网络或服务没起来 | 看红字提示;RVC 确认 4.2 窗口在运行,Index/Cosy 确认各自的启动窗口在运行 |
|
|
251
|
+
| 提示"无法连接本地 Index-TTS2 / CosyVoice 服务" | 对应的 `.bat` 窗口没开 / 被关了 | 按第 5 节(Index)/ 第 6 节(Cosy)启动并保留窗口;确认「服务地址」端口(7880/7890) |
|
|
252
|
+
| Cloud 提示 Key 无效 / 未启用接口 | Key 贴错,或 Text-to-Speech API 没启用 | 重贴完整 Key;去 Cloud Console 启用接口;见第 7 节 |
|
|
202
253
|
|
|
203
|
-
###
|
|
254
|
+
### 10.1 反馈朗读问题时请附带这两样
|
|
204
255
|
|
|
205
256
|
1. 在出问题的页面按 F12 打开控制台,把 `[tts]` 开头的行复制发过来;
|
|
206
257
|
2. 在控制台运行 `copy(JSON.stringify(__dshTtsDebug.dump()))`,把剪贴板内容一并发过来。
|
|
@@ -209,7 +260,7 @@
|
|
|
209
260
|
|
|
210
261
|
---
|
|
211
262
|
|
|
212
|
-
##
|
|
263
|
+
## 11. 术语小字典(看见不懂的词查这里)
|
|
213
264
|
|
|
214
265
|
| 词 | 是什么意思 |
|
|
215
266
|
|---|---|
|
|
@@ -219,15 +270,19 @@
|
|
|
219
270
|
| 索引(.index) | 让音色更像原声的可选文件;很大,但可以压缩 |
|
|
220
271
|
| 紧凑索引 | 把几百 MB 的索引缩到几 MB(设置里「压缩索引」按钮) |
|
|
221
272
|
| 免索引 | 不填索引直接用(效果略降,但省事) |
|
|
222
|
-
| 音色包 | 模型+索引+说明打包,一个网址即可分享(见第
|
|
273
|
+
| 音色包 | 模型+索引+说明打包,一个网址即可分享(见第 8 节) |
|
|
223
274
|
| 仓库地址 | 音色包清单(manifest.json)所在的网址 |
|
|
224
275
|
| sha256 | 文件的"指纹";下载后自动核对,防止文件损坏或被改 |
|
|
225
276
|
| 原声 | 转换前的朗读(Edge TTS 按消息文本自动合成) |
|
|
226
277
|
| 底噪 | 上面"原声"的技术叫法;界面里已改成"原声" |
|
|
278
|
+
| 参考音频(Index-TTS2) | 决定朗读是谁的声音的那段音频,存在本机包的 api/ckyp 目录,可上传新增(见第 5 节) |
|
|
279
|
+
| 提示音频(CosyVoice) | 同上,但存在 prompts 目录;必须配"提示音频文字稿"且按顺序全文填写(见第 6 节) |
|
|
280
|
+
| SSML 计费口径 | Cloud 按实际发送的 SSML 字符数(含标签)计费,本地按此计数(见第 7 节) |
|
|
281
|
+
| 预热(prewarm) | 长文本开播前先合成好的前几段;Edge/Cloud 只等第 1 段就开播,本地链路等 2 段防卡顿 |
|
|
227
282
|
|
|
228
283
|
---
|
|
229
284
|
|
|
230
|
-
##
|
|
285
|
+
## 12. 进阶:给音色作者 —— 怎么做一个音色包
|
|
231
286
|
|
|
232
287
|
1. **准备文件**:模型 `model.pth`;可选一个紧凑索引(用设置里「压缩索引」生成,
|
|
233
288
|
10k ≈ 31MB)。
|
|
@@ -261,12 +316,12 @@
|
|
|
261
316
|
- 免索引的音色包:不写 `indexes` 即可。
|
|
262
317
|
3. 把整个目录放到**任意静态托管**(GitHub Pages / 对象存储 / 网盘直链等),
|
|
263
318
|
保证上面 url 能直接下载。
|
|
264
|
-
4. 把仓库地址(manifest.json 所在目录的网址)发给用户,他们按第
|
|
319
|
+
4. 把仓库地址(manifest.json 所在目录的网址)发给用户,他们按第 8 节操作。
|
|
265
320
|
5. ⚠️ 版权:只发布你有权分发的音色(自己训练的、或已获授权的)。
|
|
266
321
|
|
|
267
322
|
---
|
|
268
323
|
|
|
269
|
-
##
|
|
324
|
+
## 13. 便携运行时(免装 RVC WebUI 也能用)
|
|
270
325
|
|
|
271
326
|
**给谁用**:只有音色模型、但不想装整套 RVC WebUI 的人(比如收到别人分享的音色包)。
|
|
272
327
|
|
|
@@ -324,7 +379,7 @@ E:\...\RVC20240604Nvidia\runtime\python.exe `
|
|
|
324
379
|
## 附:开发/测试命令
|
|
325
380
|
|
|
326
381
|
```sh
|
|
327
|
-
node tests/smoke.mjs # 冒烟测试(
|
|
382
|
+
node tests/smoke.mjs # 冒烟测试(126 项)
|
|
328
383
|
node tests/mock-registry.mjs <目录> [端口] # 本地音色包仓库
|
|
329
384
|
node tests/e2e-real-rvc.mjs # 真实 RVC 端到端(需 4892 服务)
|
|
330
385
|
node tests/e2e-compact-index.mjs # 紧凑索引端到端(需 4892 服务)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# dsh-plugin-tts
|
|
1
|
+
# dsh-plugin-tts 功能验收基线(常驻)
|
|
2
2
|
|
|
3
3
|
> 验收对象:**toast 报错落地点(组 A)· RVC 降级(组 B)· 智能分句硬化(组 C)· 建议 #2 回归(组 D)· 审批语音提醒(组 E)**
|
|
4
|
-
> 基线:`npm run test:all`
|
|
5
|
-
> 适用版本:本地 `lib/`
|
|
4
|
+
> 基线:`npm run test:all` 全绿(实测:smoke 133 · client-load 73 · i18n 6;live / patch 以各自套件实际输出为准)
|
|
5
|
+
> 适用版本:本地 `lib/` 为最新代码(见 §0 代码同步)
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# 朗读跟随滚动 v2(Scroll-follow v2)——设计与分级实施
|
|
2
|
+
|
|
3
|
+
> 状态:P0、P1 实施完毕并全量测试通过;P2(文案/测试)完毕;真机验收待用户执行。
|
|
4
|
+
> 背景:v1(`lib/client.js` 跟随链)实测效果有问题:抖动/回拉、冻住、抢夺用户滚动。
|
|
5
|
+
> 本文档是唯一事实源:目标、非目标、架构、每一步的验收标准都在此;改完一项勾一项。
|
|
6
|
+
|
|
7
|
+
## 0. 术语
|
|
8
|
+
|
|
9
|
+
- **跟随(follow)**:朗读时自动滚动对话区,让"正在读的位置"保持可见。
|
|
10
|
+
- **块(chunk)**:服务端切分的一段合成单元(Edge 约 72 字/块)。
|
|
11
|
+
- **锚点(anchor)**:正在朗读的那条消息对应的 DOM 元素。
|
|
12
|
+
- **latch-off**:用户一旦手动滚动,跟随彻底停止,直到用户点"回到跟随"手动恢复。
|
|
13
|
+
|
|
14
|
+
## 1. 现状诊断(v1,`lib/client.js`,行号以 2026-09-26 版为准)
|
|
15
|
+
|
|
16
|
+
| # | 问题 | 位置 | 后果 |
|
|
17
|
+
|---|---|---|---|
|
|
18
|
+
| A | 块内插值按"全文等分成 N 份"估每块时长,实际各块变长 | `ttsLiveRatio` 3559–3564 | ratio 在块边界跳变/回拉,视图往前滑一段又弹回 |
|
|
19
|
+
| B | 暂停/倍速零补偿(`chunkStartedAt` 暂停期老化、`shared.rate` 未用) | 3563–3564,3577 | resume 跳变;1.25x/1.5x 全程落后猛追 |
|
|
20
|
+
| C | 针搜 fallback 找到 `<p>` 即缓存为整消息锚点复用 | 3662–3665 | `ratio×小元素高度`,跟随冻在第一段;短消息(<100 字)指纹重定位直接跳过(3607) |
|
|
21
|
+
| D | 5 秒让步后自动抢回 + 首次 tick 无条件居中 | 3576,3701–3712 | 拔河;auto-read 把正在翻历史的用户拽走 |
|
|
22
|
+
| E | `behavior:"auto"` 瞬时跳 + 永远拉回中线,250ms 纠偏 | 3721–3733 | 步进式 yank;无 smooth、无 reduced-motion |
|
|
23
|
+
| F | 每 tick `innerText` 全扫 + TreeWalker + `getBoundingClientRect`(4Hz 强制 reflow) | 3601–3656 | 长会话卡顿;手机上放大 |
|
|
24
|
+
| G | 流式增长回复:宿主自滚/布局位移被当用户滚动 → 长期 yield;`msgTop` 持续漂移 | 3747–3750,3670 | 边播边长的消息跟不住 |
|
|
25
|
+
| H | 无视觉锚点(句子高亮已删,client-load 还断言了"无高亮") | 测试"sentence shadow highlight removed" | 用户看不出在追哪段 |
|
|
26
|
+
| I | 容器查找靠 class 子串 + 首个 overflow 元素,找不到就摆烂 | 3486–3504 | 窄布局/改版 DOM 下全程 `no-container` |
|
|
27
|
+
|
|
28
|
+
业界对照(Edge Read Aloud / Immersive Reader / 播放器类 App):**仅目标出视口才动**(`block:"nearest"` 或到底翻半页)、**用户接管即 latch-off**(手动恢复)、**高亮与滚动同一开关**、**块/句级步进不做块内伪平滑**、
|
|
29
|
+
`prefers-reduced-motion` 直接关跟随、可见性用 IntersectionObserver(零轮询)。
|
|
30
|
+
|
|
31
|
+
## 2. 总体设计(v2)
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
播放进度(块索引,步进)
|
|
35
|
+
→ 锚点(整消息元素,唯一可信源;click/auto 建立,指纹重建)
|
|
36
|
+
→ 可见性判定(目标块是否出视口;Observer 事件驱动,无轮询)
|
|
37
|
+
→ 最小滚动(scrollIntoView block:"nearest" + smooth;reduced-motion 则 auto/关)
|
|
38
|
+
→ 用户接管即 latch-off(手动"回到跟随"恢复)
|
|
39
|
+
+ 块级高亮(视觉锚点,与跟随同开关)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
设计原则:
|
|
43
|
+
|
|
44
|
+
1. **信号只到块级**:`ratio = (readingIndex-1)/total` 步进式,不再块内插值。
|
|
45
|
+
A/B 类伪平滑误差按构造消失(暂停/倍速不再影响位置)。
|
|
46
|
+
2. **锚点只认整消息**:click 攀爬与 auto 的消息元素是唯一可信源;针搜段落
|
|
47
|
+
fallback 不再缓存为锚点(只用于单次兜底,且标记 `diag.anchor="fragile"`)。
|
|
48
|
+
3. **滚动最小干预**:目标块完全在视口内 → 什么都不做;出视口 →
|
|
49
|
+
`scrollIntoView({block:"nearest", behavior:"smooth"})`;reduced-motion →
|
|
50
|
+
behavior 取 `auto`,若用户要求减少动态则整功能静默关闭。
|
|
51
|
+
4. **让步改 latch-off**:任何确认的用户滚动 → 跟随锁死 off,浮条/按钮出现
|
|
52
|
+
"回到跟随"手动恢复;取消 5 秒自动抢回与首次无条件居中(点击发起的朗读
|
|
53
|
+
保留"首次居中",auto-read 永不主动拽屏)。
|
|
54
|
+
5. **高亮回归**:当前块对应段落加 `.dsh-tts-sentence-active`(与跟随同开关,
|
|
55
|
+
暂停时保留,停止时清除;沿用被删 CSS 类名以便老测试语义延续)。
|
|
56
|
+
6. **移动端四 guard**(mobile-access 是手机浏览器直连同一套 web UI,一套代码):
|
|
57
|
+
- touch 惯性:`touchstart/touchend` 跟踪 + `scrollend` 事件(不支持则回退计时器),惯性余波不刷新让步/不误判自滚;
|
|
58
|
+
- `visualViewport.resize`:地址栏收放导致视口变化时重算容器几何;
|
|
59
|
+
- 容器回退 `document.scrollingElement`(窄布局无内层 overflow div 时);
|
|
60
|
+
- 小屏 overlay 浮条位置复查(compact bar 已收窄,大概率无事,动手时目检)。
|
|
61
|
+
7. **诊断可观测**:沿用 `window.__dshTtsFollowDiag`,计数键更新为
|
|
62
|
+
`in-view / nearest-scrolled / latched-off / fragile / centred /
|
|
63
|
+
reduced-motion / no-anchor / bad-target`(旧 `user-yield/scrolled/
|
|
64
|
+
tiny-skip` 退役)。
|
|
65
|
+
|
|
66
|
+
## 3. 与旧行为的差异(给用户看的)
|
|
67
|
+
|
|
68
|
+
| 场景 | v1(旧) | v2(新) |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| 块内平滑 | 按等长切片估时长插值,块边界跳变 | 步进:整块一切换才动,无伪平滑 |
|
|
71
|
+
| 暂停/倍速 | 暂停后时间轴继续老化,倍速全程落后 | 步进位置与时间/倍速无关,暂停即冻结 |
|
|
72
|
+
| 手动滚动 | 停 5 秒后自动抢回 | 彻底停跟,浮条出现"回到跟随",点才恢复 |
|
|
73
|
+
| 自动朗读 | 首 tick 无条件居中,可能把正在翻历史的用户拽走 | auto-read 永不主动拽屏;只有点击朗读才居中一次 |
|
|
74
|
+
| 滚动幅度 | 永远拉回中线,250ms 纠偏 | 出视口才动,最小位移(nearest),smooth |
|
|
75
|
+
| 减少动态 | 无视系统设置 | 开启后跟随静默关闭 |
|
|
76
|
+
| 当前段提示 | 无(高亮已删) | 当前块段落软背景高亮,随块迁移 |
|
|
77
|
+
| 手机惯性滚动 | 余波刷新 5 秒窗口≈永久让步 | touch/scrollend 识别,余波不误判 |
|
|
78
|
+
| 长会话性能 | 4Hz 全 DOM 扫描 | 事件驱动,零轮询 |
|
|
79
|
+
|
|
80
|
+
## 4. 测试计划
|
|
81
|
+
|
|
82
|
+
- 自动化(已全绿):smoke 133/133(含 spans 断言)、client-load 73/73
|
|
83
|
+
(跟随段重写为 v2 契约:步进信号、无轮询、latch-off、手势源、reduced-motion、
|
|
84
|
+
spans 接线、高亮回归)、i18n 6/6(`follow.resume` 中英齐)。
|
|
85
|
+
- 真机验收(用户侧,HEADLESS 覆盖不到):
|
|
86
|
+
- [ ] 桌面:长文跟随无跳变回拉;手动滚动后停跟出 pill;点 pill 恢复
|
|
87
|
+
- [ ] 桌面:auto-read 新回复不拽屏;暂停/1.5x 不漂移
|
|
88
|
+
- [ ] 桌面:开系统减少动态,跟随全程静默
|
|
89
|
+
- [ ] 手机浏览器:跟随不断;惯性滑动不误判;pill 位置不挡内容
|
|
90
|
+
- [ ] 高亮随块迁移;停止/新读清除无残留
|
|
91
|
+
|
|
92
|
+
## 5. 实施步骤(分级)——已完成 ✅
|
|
93
|
+
|
|
94
|
+
- [x] **P0-1 信号**:块索引步进;删块内插值。
|
|
95
|
+
- [x] **P0-2 锚点**:停缓存段落;针搜标 fragile。
|
|
96
|
+
- [x] **P0-3 滚动+让步**:nearest + latch-off + 手动恢复 pill;居中仅 manual。
|
|
97
|
+
- [x] **P0-4 无障碍**:reduced-motion 门控。
|
|
98
|
+
- [x] **P1-1 高亮**:软背景回归,随块迁移,停止/新读清除。
|
|
99
|
+
- [x] **P1-2 移动端 guard**:touch/scrollend、visualViewport、容器回退。
|
|
100
|
+
- [x] **P1-3 服务端 spans**:`spanParts` + `/speak` 双分支下发 + `__test` 导出。
|
|
101
|
+
- [x] **P2 收尾**:设置文案改行为承诺(中英)+ `follow.resume` 键;诊断计数键换新;
|
|
102
|
+
client-load 跟随段重写;smoke 加 spans 断言。
|