deepseek-harness/.agents/notes/implemented/feature/2026-08-12-hero-fish-hover-swim-morph.zh.md
Yif ececf8c170 fix(web): address hero fish hover review feedback
Move hover enter/leave from the svg element to the stationary fishHitbox
span so the CSS sway and SMIL morph share the same trigger surface and the
animation cannot flicker when sway displaces the svg from the pointer.
Gate the morph with (hover: hover) to match the CSS and prevent tap-sticky
loops on touch devices.

Remove residual headline changes unrelated to this PR: white-space: pre on
.headlineText, data-testid="hero-headline", and corresponding getByTestId
test assertions — these belong to #2397.

Fix Agent Note coverage claim (was "asserting render states", now accurately
"slot contract") and compress blowhole paragraph to current-state fact.
2026-08-28 19:29:31 +08:00

3.1 KiB
Raw Blame History

Agent Note:主页鲸鱼 hover 游动变形

Status: implemented

English | 中文

问题

hover New Session 主页的鲸鱼(dsh-client-ui-conversation 的 EmptyHero.tsx)原本只播放一次整个 svg 的刚性 CSS 摇摆。用户希望鲸鱼有真实的游动感——尾巴摆动、嘴巴曲线上扬,这要求对路径几何本身做变形。CSS transform 无法弯曲路径中的部分曲线,且 logo 以单一 FISH_LOGO_PATH 字符串存放在 dsh-client-ui-primitives。

决定

通过 SMIL <animate attributeName="d"> 做真实曲线变形,按与 CSS 摇摆相同的 1.6s 周期循环 静止 → 尾上摆 → 静止 → 尾下压 → 静止;CSS 摇摆改为持续循环(infinite),指针停留多久就游多久。两个变形目标由程序生成(在 /tmp 运行的脚本,未入库):解析 FISH_LOGO_PATH 的绝对 M/C/L/Z 命令,尾部区域绕支点做带 smoothstep 衰减权重的旋转,嘴巴/鳍的内侧曲线以距身体锚点的权重平方做竖直弯曲(微笑式上扬,而非刚性摆动——刚性旋转看起来与身体脱节),并输出结构完全一致、SMIL 可插值的命令串。烘焙出的路径常量与组件放在一起,并在注释中记录生成参数。SMIL 无法响应 CSS 媒体查询,因此用经 matchMedia('(prefers-reduced-motion: reduce)') 判定的 hovering 状态控制变形挂载,CSS 摇摆则在 @media (hover: hover) and (prefers-reduced-motion: no-preference) 之下。

变形鲸鱼以 conversation.hero.brand.mark slot 的 fallback 身份进入主页;没有任何发布包占据该 slot——dsh-client-ui-brand-official 只填充侧栏槽位,因为 feature 插件不得跨包 value-import HeroFish(client 跨包规则),而 fallback 本身就是官方标志。FISH_LOGO_PATH 与 FISH_LOGO_VIEWBOX 从 dsh-client-ui-primitives 导出,供围绕同一几何自行组装 svg 的消费方使用。

考虑过的替代方案

用矢量工具编辑路径做变形。 流程中没有可交互的工具;选择程序化加权变形,因为它保证 SMIL d 插值所要求的完全一致的命令结构,且振幅是可评审的数字。

hover 气孔喷水。 按用户要求移除;hover 只保留形状变形与摇摆。

让官方标志占据主页 slot。 即先前的安排;否决,因为静态 occupant 会遮住动画 fallback,而给 occupant 加动画又需要被禁止的跨包 value import。

影响

hover 游动是纯装饰(aria-hidden)且对 reduced-motion 安全(hover 保持静态 logo)。摇摆 CSS 作用于外层静止的 .fishHitbox,因此换成 slot occupant 也会摇摆;身体变形只存在于 fallback 的 HeroFish 中。覆盖由 skeleton.client.spec.tsx 断言 slot 合约(名称、owner props、fallback 存在性);keyless 快照体系记录对话转录而非浏览器动画,变形的视觉验证仍需人工。重新生成变形目标需要对 FISH_LOGO_PATH 重跑(未入库的)变形脚本;若 logo 几何将来变化,烘焙常量必须随之重新生成。