Overview
dsh-screenshot
README / EN
Package documentation
Registry summary
dsh.pub verifies the pinned bundle contract, runtime facts, and distribution semantics. The complete README remains in the source repository.
Read the full README on GitHubLIMITATIONS
Known limitations
- **仅在本机 Windows + DSH `desktop` profile 实测**,其他平台/版本未验证。 - 长截图的 auto 模式**优先投递滚轮**(不动光标),判定靠"下一张画面变没变"。投递要投给 **点位下面那个控件**:投给顶层窗口时 Chromium 认、**WinForms 等旧式应用不认** (实测:顶层窗体只触发自己的 MouseWheel,内容不滚;投给 `WindowFromPoint` 的叶子才滚)。 不认时自动降级成移光标。Qt / Java / Electron 的自绘滚动容器**尚未逐个实测**。 - 长截图**一次滚一格滚轮,不是滚"一屏的 80%"**(R58 改的)。滚轮的 `delta` 单位是 1/120 格, 应用再按自己的行高翻(WinForms 默认 3 行/格):以前按像素发(520px 区域 → `-416`), 被读成 3.5 格 ≈ 10 行,**一次滚掉 811px,比一屏还高** —— 两帧之间没有重叠,拼接器只能猜。 现在按格发;一格的位移由目标应用决定。 - 但**一格能滚多远是应用决定的**:40pt 大字一帧 ≈ 237px,而 10pt 小字一帧只有 **60px**。于是 "一帧固定一格"能覆盖的总高 = 帧数上限 × 一格 —— 后者在密集小字页面上只够 ~2900px,一张 3840px 的页面会被**静默截掉一截**(R60 实测:40 帧停在 2880px,`stopReason` 还是空的,用户 看到的就是一张"正常"的长图)。现在**每帧滚几格按实测位移自适应**(R60):滚过一帧就知道一格 值多少像素,把步长调到区域高度的 ~45%(上限 3 格,重叠仍剩一大半);同一张 3840px 页面 **18 帧**到底、每条色带 160px 一条不差。撞到帧数上限时 `stopReason='max-frames'`, 客户端会明说"后面可能没截完",不再说"已经到底了"。 - 拼接器**不接受"没有重叠的两帧"**:残差超过阈值就报错并保留会话("滚得太多了,分两次滚"), **不会**再静默拼出一张又高又像真的错图(R58 用探针量到过 +479px 的静默重复内容)。 只差几个像素的重复帧(光标闪烁、时钟跳秒)会被识别成"同一张画面"直接跳过,不再塞进一段重复内容。 - 拼接偏移在缩小图上粗搜之后,再做一次**全分辨率精修**:粗搜的量化误差是 ~4px/像素, 以前每条接缝会因此偏 2px(重复/丢掉 2px 内容),现在缝落在像素上(探针断言每条色带 79px)。 - 长截图的区域**外缘**如果有会自己动的东西(滚动条拇指、缩放手柄、贴边浮层),那些列在帧间 就不一致。拼接器现在**两遍(粗搜 + 精修)都先裁掉外缘**(宽度的 6%,至少 6px、至多 40px)再找 重叠(R59),所以滚动条可见也能拼。实测:R58 的真实帧在未裁边时精修残差 **0.20–0.22**(左缘在闪 的光标),裁边后 **0.00**,偏移不变;合成的"右侧 14px 滚动条 + 拇指每帧移动"四帧,偏移 237/237/237 与真值一致(不裁边时同一组会挑错偏移)。 - 区域**内部**有东西自己动(视频、转圈、每帧重画的图表)时,**整块区域在帧间永远不一致**。拼接器 先按普通残差找接缝;判成"没有重叠"时才走第二条路 —— 它看的不是"残差降下来了没有",而是 **分歧长在哪儿**:动画是一块紧凑区域,错的偏移是满屏字都对不齐(R63)。实测:一块 220×130 每帧 重画时,真值处的普通残差是 **29.29**(远高于 8.00,任何残差都不可能接受它),而"分歧外接框"只占 重叠的 **0.48**、框内 **49%** 像素超阈值;错偏移是 **1.00** / 27%。这条判据在**真实屏幕纹理**上 也是对的(`dev/stitch-tex-probe.mjs`:四条臂的偏移逐帧精确,动画块之外的成品与真值**逐像素相同**)。 ⚠️ R61 用的是"去掉最差 30% 的行"的评分,它在色带夹具上成立,但在真实纹理上会**偏向最窄的重叠** (真值 237 px,裁剪评分选 386 / 397 / 509,还静默多贴过 +160 px)—— 这是 R63 换掉它的原因。 - **窄到几行的重叠不算证据**(R63):27 行真实文字能巧合地给出 **2.37** 的平均差,于是错了 256 px 还"看起来像真的"。重叠不足区域高度 35% 时,只有**逐像素精确**(残差 ≤ 1.0)才作数 —— 色带夹具 真的会一格滚掉 75%,它每次都精确到 0.00,所以这条不会误伤真截图。 - **窄重叠"精确"也可能落在错的偏移上**(R65,真实纹理上抓到的真 bug):一页应用(一次滚一屏减一行, 25% 重叠)某一对帧有两个**逐像素精确**的候选 —— 真值 390(130 行证据)与 477(43 行,因为页面上 43 行内容自己重复了 87 px)。粗搜在 2.6:1 的缩小签名上偏好 477(43 行缩成 16 行签名全等,而 390 落不到签名行上),旧规则又把它当"精确"接受 → 成品 4117 而不是 4030(**静默 +87 px**、243 523 个 像素错)。现在窄重叠会**重判一次**:在这些候选里取**最深的最小值**,一样深时取**重叠最多**的 (`py/stitch.py#find_exact_shift`)。实测同一条夹具 4117 → **4030 且逐像素相同**。 另一半也是实测的:同一条臂上另一种错法(386,"只比真值差 4 px")也被这条规则挡住 —— 它落在容差里 但不是最深的最小值。 - **窄重叠 + 重叠带里有东西在动 = 诚实的拒绝**(R65):重叠只剩 25%、而那块每帧重画的区域正好压在 重叠带里时,这一带**没有任何可用证据**(真值处残差 37.98 > 8.00),结构判据又**故意**不看 35% 以下 的重叠(R63:11 行文字满足过它,并挑了个错的 509 px)。所以它会报 `no-overlap`、退出 3、**不出文件**, 而不是拼一张看起来对的图。自动滚的步长是区域高 45%,正常不会走到这里;真遇到就"分两次滚"。 - 同位置重复帧**仍然先判后拼**("内容没前进、只有那一小块在变")。顺序反了会把重复帧按猜出来的 偏移贴进去 —— R63 实测:色带夹具 + 动画那条臂因此多出 **158 px** 重复内容。 - **已知边界**:在动的那块会在成品上留一道"重影"(每帧各贴了一次),这是拼接的必然结果;这种情况 自动滚也认不出"到底"(整帧永远在变),会话会走到帧数上限并如实报 `max-frames`("后面可能没截完"), 但成品本身是完整的。 - 上面这几条现在有**真实纹理**上的独立探针(R63,R65 扩到六条臂):`dev/texreplay.py` 拿一张真截屏 造长页面、切出已知帧,六条臂分别断言"偏移逐帧精确 / 成品与真值逐像素相同(动画块那几列除外)/ 同位置帧跳过 / 跳太远必须报错 / 窄重叠也精确 / 窄重叠+动画必须拒绝"。它第一次跑就抓到两个真 bug (上面两条 ⚠️),R65 加窄重叠臂时**又抓到第三个**(上面那条 +87 px)。 - 改拼接器时先看 `texreplay.py landscape`(R64):它把**每个评分的前几名**和**真值处的四个数** 摆在一起(`python dev/texreplay.py landscape --dir <build 出来的目录> --pair <第几对>`)。R63 那四个 bug 没有一个能从产品 JSON 里看出来 —— 每个评分都只报"一个数字"。实测(真实纹理、真值 237): 普通滚动时真值是唯一 0.00、结构判据在 486 个位移里**只认它一个**;动画页里真值处普通残差 **29.33**(任何残差都不能接受),而按行裁剪与普通评分都会选到 **511**(最窄重叠),结构判据仍只认真值。 - 夹具(`dev/longshot-backdrop.ps1`)默认藏滚动条;`-Scrollbar 1` 保留它,探针的第四条臂就是 用这个跑一遍 auto,证明上面那条不是纸面结论。 - **剪贴板是全机独占资源**:别的程序正占着时截图复制会失败(实测报「所请求的剪贴板操作失败」)。 助手会重试 4 次;仍失败时**客户端会明说"没复制成功"并留下诊断**,不会假装复制过。 - 「截图时隐藏 DSH 界面」靠**标题**找窗口(`DeepSeek Harness` 子串匹配);窗口标题被改得 面目全非时只会不藏(截图照常),不会报错。 - 私有备份仓:按 `.gitignore` 排除了 `node_modules`、运行时缓存、调试 dump 与备份文件;要复现运行请自行 `npm install`(如有依赖)。 - 文档中出现的 `$DSH_WORKSPACE`、`$TK_ROOT`、`%USERPROFILE%` 等是**占位符**,使用前需替换成本机实际路径。
