黄一航
← 全部日志

项目 scrub 恢复:Auria / ContractLens / OpenClaw / Sprout

2026-07-07约 2 小时(估算)动效scrub发布会首页复核记录零依赖

目标

站主发现:NoWorries 那一页背景/演示能跟着滚动动,后面的项目段落都只是静态 reveal,不像苹果发布会。目标是:在不引入 GSAP / Framer Motion 等依赖、不破坏 React 19 水合纪律、不牺牲移动端可读性的前提下,让 Auria、ContractLens、OpenClaw、Sprout 每个项目至少有一个桌面端 scrub 场景。

特别说明:这次正确目标不是主目录的 3001,而是 localhost:3100 对应的 Claude worktree:

/Users/huanglaobanban/have_fun/HYH/.claude/worktrees/sweet-darwin-a433e9

Codex 最初误看了主目录 /Users/huanglaobanban/have_fun/HYH,后来通过 lsof 确认 3100 的 cwd 后切回这个 worktree。复核时请以 3100 / 该 worktree 为准。

关键 prompt(原文摘录)

里面的动画效果,除了无事那一页背景是根据滑动能动的,后面的页面都不行,你能不能改改?改的也能动,高级华丽,你可以按照你的需求生成图片,然后每一个项目至少要有一 个 scrub 才像苹果,所以有些项目页面需要你来改改。

那你先按照你计划的来改吧

诶??你为啥改的这个版本是最开始的,Claude已经改过一个版本了挂在local host 3100的,你先看看

localhost:3100/ 我启动了,你看看

重新检查动画效果,我刚看除了无事的页面,别的页面都是残缺或者动效不流程

这两页动画和排版有问题,再改一下

结果

改动集中在首页发布会组件与原生 scrub 引擎:

  • src/lib/keynote-engine.ts

    • 保留 NoWorries 原有主签名 scrub。
    • 新增四个场景注册:scene-auriascene-contractlensscene-openclawscene-sprout
    • 继续沿用 matchMedia("(min-width: 1024px)") 宽度守卫:桌面启用 scrub,移动端不写内联 transform。
    • 宽度守卫改成可响应 resize:先用窄屏打开再拉到桌面宽度时,会重新进入 scrub;从桌面缩回窄屏时清掉引擎写入的 opacity/transform
    • 新增数据钩子:data-auria-chipdata-cls-seg / data-cls-row / data-cls-tracedata-oc-stage / data-oc-tokendata-sp-node / data-sp-line
  • src/components/keynote/scene-auria.tsx

    • 桌面端变成“简历事实卡 → Auria Agent Hub → 个人网站 mockup”的 280vh sticky scrub。
    • 保留 Claude 版珍珠白背景、橙色 accent、三张技术卡和研发中口径。
    • 截图复查后把三列舞台收窄到 280/340/280(xl 为 300/360/300),减少卡片过宽和相互挤压。
    • 移动端仍是正常文档流,所有内容默认可见。
  • src/components/keynote/scene-contractlens.tsx

    • 桌面端变成“合同文档 → 七个分析师芯片 → 审查报告”的 280vh sticky scrub。
    • SVG 证据线用 pathLength=1 + strokeDashoffset 随滚动绘制。
    • 截图复查后把舞台从 1060px 收到 1000px,左合同卡增加安全边距、减少横向 park 位移,避免 1080px 宽度下贴边/裁阴影。
    • 报告行逐条出现,最终回到完整定妆帧。
  • src/components/keynote/scene-openclaw.tsx

    • 桌面端变成“embedding/provider/token 噪声 → 四级降级进度线 → context packet”的 260vh sticky scrub。
    • 更明确地表达 OpenClaw 做的是记忆、检索、上下文预算的工程问题,不只是时间线。
  • src/components/keynote/scene-sprout.tsx

    • 桌面端变成任务树节点和连线逐步生长的 280vh sticky scrub。
    • 保留 680×420 设计盒整体缩放方案,避免破坏 Claude 已修过的移动端对齐。

验证结果:

  • npm run typecheck 通过。
  • npm run lint 通过。
  • 3100 桌面视口 1280×900 浏览器抽查:四个新增场景的 sticky 均生效,滚动中主体不再空白。
  • 3100 桌面视口 1080×875 复查 Auria / ContractLens:无横向滚动;Auria 三列不重叠;ContractLens 合同卡距左边约 36px,芯片与报告不重叠。
  • 先用 390×844 加载 ContractLens、再切到 1280×900:移动端不写 transform,切桌面后滚动会重新写入 scrub 样式。
  • 390×844 移动端检查:body.scrollWidth === 390,四个新增 scene 的 inner wrapper 都是 position: static,没有横向滚动。

二次复查后又做了一轮收敛:第一版虽然每段都有 scrub,但把太多内容塞进 sticky 屏里,Auria 的技术卡/CTA 会被裁,部分元素从 0 透明度开始,看起来像没加载完。最终版本改成“核心演示舞台 scrub,说明卡片普通文档流”,并移除 scrub 元素上的 .reveal,避免 IntersectionObserver 的淡入 transition 和滚动 scrub 抢 opacity/transform。截图反馈后又把 Auria / ContractLens 的中段透明度整体抬高,让滚动任意时刻都像完整画面,而不是元素半加载。

踩坑与纠正

  • 目标 worktree 看错:最初 Codex 改到了主目录 3001,而站主说的是 Claude 已改过、挂在 3100 的版本。用 lsof -nP -iTCP:3100 -sTCP:LISTEN 查到 3100 的 cwd 是 .claude/worktrees/sweet-darwin-a433e9 后,停止继续动主目录,切到正确 worktree。

  • overflow-hidden 会破坏 sticky scrub:四个静态版场景的 <section> 原本都有 overflow-hidden,这会让内部 position: sticky 失效。第一次桌面截图出现大段只有背景、主体滚出视口的空白。NoWorries 注释里其实已经写过这个坑:sticky 的祖先不能裁剪。修法是移除四个 section 的 overflow-hidden,把裁剪只放在装饰层(pearl/aurora 背景层)上。

  • 导航遮住 sticky 舞台顶部:新增场景一开始用 knl:lg:top-0 knl:lg:h-screen,ContractLens/OpenClaw 的标题会钻到固定导航下面。修成 knl:lg:top-16 knl:lg:h-[calc(100vh-4rem)],给导航留 64px 安全区。

  • Auria / ContractLens 中段太像残缺:第一版用较低初始透明度做入场,截图中右侧 mockup / report 会显得“没完成”。修法是保持元素常驻可读,scroll 负责高亮、位移、连线绘制;Auria site baseline 提到 0.78,ContractLens report baseline 提到 0.82。

  • Auria 左侧卡片过度左移:中段 scrub 里简历事实卡被推到视口边缘,文字被裁。把引擎里的 source card 横向 park 从 -76px 收到 -28px,保留层次运动但不裁字。

  • ContractLens 1080px 贴边:合同卡 + 横向 park 在 1080px 宽度下会贴到视口边。把舞台 max width 收到 1000px,合同卡 left-4,report right-4,doc park 从 -54px 收到 -24px

  • 先窄屏后桌面会丢 scrubinitKeynoteEngine() 早期直接在 <1024px return。in-app browser 如果先窄屏加载、再拉宽,会只有 .kn-live 静态布局,没有滚动引擎。修法是初始化时始终注册 scroll/resize,但 tick 内部按 desktopMq.matches 决定是否写样式;跨过 1024 时重置 scene progress 并恢复 scrub。

  • scrub 元素不能再挂 .reveal:二次检查发现元素虽然由引擎写 style.opacity,但同时还被 .reveal/.reveal-in 的 IntersectionObserver transition 和 transition-delay 影响,导致阶段过渡拖泥带水、看着“不流畅”。修法:scrub 舞台内由引擎接管的元素全部移除 .reveal;普通说明卡继续用 .reveal

  • 不要让主体从 0 透明度开始:第一版很多新元素从 opacity:0 淡入,滚动中段会给人“缺块/残缺”的错觉。最终改成较高透明度常驻:元素默认 0.66–0.98 可见,滚动只是高亮、拉近、连线绘制。这样更像 Apple 的 scrub staging,也更抗滚动速度差异。

  • Sprout 树图第二层压字幕:任务树 B-1/B-2 在后段和字幕贴到一起。把第二层节点从 84% 上移到 72%,同步改 SVG 连线终点;桌面 scrub 下树图缩小到 0.78 并给字幕加间距,避免压迫。

  • 浏览器验证钩子读不到__knTick 在这个 in-app browser 的 evaluate 隔离环境里读不到,但真实滚动的 DOM style 明确随滚动变化。复核建议以真实滚动截图和 DOM style(如 ocProgress.style.widthdata-sp-line.style.strokeDashoffset)为准,不要只依赖 window.__knTick

用时与备注

约 2 小时(估算)。本次没有生成新图片,因为 Claude worktree 已经有 public/media/aurora-*.webppearl-*.webp,足够支撑新增 scrub。重点不是堆新素材,而是在已有视觉资产上恢复 Apple-style scroll staging,同时保住移动端静态终态和 SEO/无 JS 可读性。