dsh-smooth-stream
Đã xác minh@lynn123411/dsh-smooth-stream · v1.3.0 · MIT · Giao diện web
丝滑流式渲染与零重排跟随引擎。工具卡片内部即时呈现,不逐字揭示。
Cài đặt
dsh plugin add @lynn123411/dsh-smooth-stream Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.
Mã nguồn
Phát hành lên npm mà không có repository công khai. Hãy kiểm tra nội dung package trước khi cài.
Thẻ
Readme
@lynn123411/dsh-smooth-stream
把 AI 的长篇生成变成提词器式的温润流淌:内容呈现与视口运动各自是一条独立的物理状态机,在每一帧 rAF 里连续积分,从而消掉「整段砸在屏幕上」的跳跃感与「scrollTop = scrollHeight 硬跳」的重排抖动。插件同时接管助理回复与其余 Agent 行的入场、增长与跟随;工具行仍然享受入场与跟随,但卡片内部不再逐字打印(译文除外)。
特性
- 逐字揭示(Reveal Engine):按积压深度自适应调节速度($v = 90 + \text{backlog}^{1.25} \times P$),慢速时从容、爆发时平稳追赶;折行处单帧视觉位移限制在 8px 以内。挂载时已经存在的内容直接落盘、只对之后新增的文字逐字 —— 切换会话或切回标签页不会让已经读过的一段从头重播。
- 零重排跟随(Follow Engine):二阶阻尼弹簧($k=130, c=24, m=1$)在合成层做
translate3d补偿,真实滚动容器始终锚定底部,跟随过程不读写触发 Layout 的属性。锚点测量剔除视口滚动增量(scrollDelta),宿主贴底与用户滚动不再被误判为布局推动;流式排水完成的瞬间走快速交接:清空跑道与临时垫高、对齐自然贴底,不启动慢速退休循环。预测跑道只挂在 turn 状态行的margin-top上——即所有内容之下、固定 chrome 之上;没有状态行的视图(侧栏 / 嵌套转录、收尾换场)不开跑道,改由安全绘制空间上限与揭示背压接管,于是内容行之间永远只有宿主自己的间距(16/8px),不会出现随揭示速度浮动的空白。 - 闭环背压:跟随滞后逼近预留空间时反向给揭示引擎施加阻尼(最低 0.55 倍速),防止文字增长冲出视口弹簧范围。
- 工具卡片内部即时呈现:
tool-call行依旧被包装,保留滚动跟随与一次整行淡入,但卡片里的文本以完整长度落盘、不再逐字揭示 —— 所以展开工具、看命令输出时没有打字机延迟。唯一例外是dsh-chat-translate挂上译文的.dsh-tidy-translated-block:译文仍逐字从左到右流入、也按对数曲线由淡变实(工具摘要与思考卡正文都会挂这个块)。 - 揭示挂起:会话流条目带上
data-dsh-reveal-hold时,条目内的揭示队列照常积压、一帧都不提交,对数淡入也不产生新字符;行这一侧整条隐藏由设置标记的插件自己做。被挂起的条目对跟随引擎也不存在——它已被整条移出布局,没有绘制面,所以既不充当安全绘制空间的最后一个面(零 rect 会算出一个假的天花板),也不承载跑道边距。dsh-chat-translate用它把排在待出现行后面的内容(回答正文、思考正文、译文、不翻译的行)一起按住,队首上屏后再按阅读顺序一行一行放出来——所以不会有内容先占住位置、再被迟到的行顶下去,也不会有积压在被按住期间悄悄排空、放行时一次性砸出来。标记只由另一个插件读写,本插件不产生它。 - 单内核适配:只使用当前 DSH 内核提供的接缝 ——
ClientContext用 cordisContext、Chat 节点类型取自@deepseek-ai/dsh-client-ui-chat/client、图片走内核的conversation.message.imagesslot、客户端 store 静态取自模块表 seed,不含旧内核的兼容探针。 - 原生设置命名空间:偏好读写走 DSH 的
settingsScope服务(命名空间lynn-smooth-stream);仅「版本 + 一键更新」保留一条极小的插件 RPC。 - 共享「阅读体验」设置页:本插件的卡片与
dsh-chat-translate等参与者一起挂在同一个设置页里(settings.sectionidreading,参与者可增删)。内核不允许一页被多个插件共同声明,因此每个参与者各持一份逐字节相同的页壳,先加载者当选页面宿主、其余只注册卡片;当选者被卸载后下次启动自动改选。做法与约束见仓库docs/rules/shared-settings-page.md。 - 动效偏好三态:
auto(跟随系统 reduce-motion)/force-smooth/force-reduced。 - 对数淡入:回答正文、译文容器、其余 Agent 行(命令行、上下文、系统提示、工作流面板等)自身正文里新生成的字符,加上每个 Agent 行到达时的整行,都以 240ms 对数曲线显形。字符那层由 CSS Custom Highlight 绘制 —— DOM 文本节点不变,重排、页内查找与选中不受影响;整行那层是同一个公式、同样 32 档的一条
opacity关键帧动画,图标、标题、摘要、后缀一起由淡变实,译文的字符在其中逐字流入,所以同一屏里只有一种淡入。新生判定按字素内容对齐(剥掉公共前缀与后缀后做最长公共子序列):Markdown 行内语法闭合这类重排既不重播也不丢高亮,单次出生的上限是 160 字素。承载淡入的元素基色整段只读一次(每帧重读会让每写一次行内属性就重算一次样式,高速率时正是掉帧的来源),译文块由它自己那层负责、配套淡入根不重复接管。文本即时落盘处(如工具卡片自身文本)自动无淡入;被中断的回合不淡入;引擎不支持 Custom Highlight 时没有字符淡入,逐字揭示与整行淡入照旧。设置卡片可关(关掉即整行也不淡入)。 - 思考卡只淡入「Think」:这次会话里新到的思考卡出现时,「Think」这一组(前导图标 + 标题)按同一条对数曲线淡入;页面刷新、切换会话重放出来的卡片不补这段动画(一屏静止内容里只有它在动,看着就是一次故障)。它右侧那行滚动摘要、以及正文(不分折叠与展开)在任何情况下都不做字符淡入,只走普通的逐字揭示 —— 那两处每帧都在换或每帧都在长,高速率时字符级高亮是这一帧里最贵的部分,逐字本身已经足够表达「正在写」。正文里由
dsh-chat-translate挂上的译文块照旧淡入:那是另一层淡入根,一次成型,不随流速放大。 - 思考块自动展开与回合折叠:流式期间自动展开思考,回合结算后收敛为
已处理 X 秒摘要行。 - 诊断面板:可选的实时 HUD,观测 FPS、字符积压、弹性曲线并微调物理参数。
安装
dsh plugin --profile web add @lynn123411/dsh-smooth-stream
从本仓库源码本地联调(临时装配,改动即时生效):
cd plugins/dsh-smooth-stream
pnpm install
pnpm check # typecheck + 构建 + 客户端装配自检 + 产物门禁
# 然后在 ~/.dsh/profiles/web 里以本地路径依赖加入本包,并写进 dsh.profile.bundles
pnpm smoke(scripts/smoke-client.mjs,零依赖)会把 lib/client.js 按 Web shell 的 __ModuleLoader__ 协议加载一遍,用假的 cordis 服务跑 apply(),断言共享页声明、卡片、诊断面板、助理行接管与语言包都真的注册上了(含「别人已占页时不重复声明」的选举分支)—— 这类「装配线断了但界面只是少个入口」的问题只有它拦得住。