SDTTTTT

2026-10-22

维护记录

完成的工作

  • 首页 hero 标题「海边」粒子化:新增 layouts/partials/home-title.html,<h1 class="home-title"> 里保留真实文字(SEO / 屏幕阅读器 / 无 JS 兜底)+ aria-hidden 的粒子 canvas + #pt-title-config;list.html 的首页第一页分支改为调用该 partial ✅
  • 新增 assets/js/home-title.js:从 DOM 文字读 computed 宋体栈 / 颜色 / 字号,离屏 canvas 画加粗描边的字形蒙版(按 DOM 基线对齐),交给 WASM alloc/build 撒成 1.5 CSS px 网格的粒子 ✅
  • 入场用 0.35s 交叉淡入(文字 opacity 0 / canvas opacity 1),粒子先 settle() 直接落位,不播 build() 的飞入 —— 标题画布太小,飞入会先出现「字没了、粒子还在几百 px 外」的空窗 ✅
  • 常驻 30Hz 固定步长 tick() + putImageData;document.hidden、标题滚出视口、待机屏保 pt-bg-on 时暂停,恢复时重置计时 ✅
  • 缩放(150ms 防抖)与深色切换(MutationObserver 监听 html.class)时重建字形与粒子,保持 .is-particle,不重播交叉淡入 ✅
  • WASM 引擎 ripple_on 新增 mode 2:相位只取粒子目标位 x,横向 sin / 纵向 cos 组成很扁的椭圆轨道,叠加一个不可通约的次波;相位写成 kx − phase 保证浪从左向右推(4.2s 一圈、±0.8 / ±2.2 CSS px)✅
  • custom.css:.home-title 加系统宋体栈,canvas 上下各外扩 0.6rem、pointer-events: none、默认 opacity 0;.is-particle 做交叉淡入,reduced-motion 去掉过渡、print 强制文字并隐藏 canvas ✅
  • 降级:无 JS / wasm 失败 / build 失败 → 纯文字;?pt-title=off、saveData 不拉 wasm;prefers-reduced-motion 只画一帧静态粒子、不跑循环。诊断写在 html[data-pt-title] 与 data-pt-title-particles|-step|-size ✅
  • 窄屏适配(最初 375 档只有 2.25rem / 36px):1.5 CSS px 网格在 dpr 2 下是 step 3 / 边长 2,宋体细横画被采成噪点;JS 在「字号 < 40px 且 dpr 2」时退到 2px 无缝网格(step 2 / 边长 2),桌面 48px 与 dpr 3 手机仍保留缝隙 ✅
  • 单测新增 4 项:同列相干、位移有界且相位前进、零振幅静止、向右传播;cargo test 44 项全部通过 ✅
  • 重建 particles.wasm + particles.sha256(34,118 字节)与 Tailwind 产物;./bin/preflight.sh 全绿 ✅
  • 首轮实拍 1280 / 375 两档(@2x,字号放大前):粒子字形可辨、文字已淡出、canvas 尺寸 1360×145(桌面)/ 622×118(窄屏);?pt-title=off 与粒子模式的 h1 盒子完全一致(292.5,120,680,53.328125),零位移 ✅
  • 首轮 CDP 实测:粒子数 792 / step 3 / size 2,画布哈希 0.9s 内持续变化;深色切换后粒子颜色 23,23,23 → 255,255,255 且不重播淡入;滚出视口后哈希不变、滚回后恢复 ✅
  • 应用户反馈把 hero 字号放大一倍:桌面 3rem → 6rem(96px)、窄屏 2.25rem → 4.5rem(72px);粒子数 792 → 2662 / 468 → 1587,canvas 1360×252 / 622×198;窄屏 72px 不再触发 2px 无缝回退,恢复留缝颗粒,字也更好认 ✅
  • AGENTS.md 增加硬性约束:模型不得读取 / 分析任何图片(截图、设计稿、照片等),除非用户当次明确要求;界面验收改用 DOM / computed style / CDP 文本与单元测试等可复现证据,截图只生成给用户看 ✅
  • 应用户反馈把粒子排列打散:WASM 新增 jitter_on(amp),build 后按 hash01(i) 给每颗粒子的目标位叠加一次确定性抖动(先 0.8 CSS px,后加到 1.0,dpr 2 下 ±2 设备 px;重复调用不叠加、重建可复现),字形仍是同一张蒙版,行波相位照旧取 tx;诊断新增 data-pt-title-jitter ✅
  • 应用户反馈继续加强随机与流动:新增 size_jitter_on() 把统一 2px 方块变成 1–3px 混合、wobble_on() 给每颗粒子独立相位微动(±0.6 / ±0.9 CSS px,3s 循环,叠加在相干行波上,浪照旧向右推);诊断新增 data-pt-title-sizeJitter / wobble;单测 +3(48 项),wasm 37,327 字节 ✅

遇到的问题

  • 宋体细横画在 2px 采样网格上会漏采,3rem 下「边」字明显断续 ⚠️ - 离屏蒙版加 ink: 0.6 的 strokeText(lineJoin: round),并把 pitchCss 从 2 调到 1.5;dpr 2 下 step 3 / 边长 2,字形完整且仍看得出颗粒。
  • sin(kx + phase) 的浪实际向左跑,与验收的「从左滚到右」相反 ⚠️ - 改成 kx − phase,并加单测 ripple_wave_mode_travels_to_the_right 把方向锁住。
  • 最初按墨迹包围盒在画布居中,实测粒子比 DOM 文字高 3.4 CSS px,交叉淡入时文字会往上跳 ⚠️ - 用 line-height + fontBoundingBoxAscent/Descent 算出与 DOM 相同的基线再落笔,实测墨迹中心差 <0.5 CSS px。
  • canvas 是 replaced element:绝对定位下 left/right + width:auto 不会撑开,会退回 300×150 固有尺寸 ⚠️ - 显式给 width: 100% 与 height: calc(100% + 1.2rem)。
  • --screenshot --virtual-time-budget 下 rAF 与 CSS 过渡都不推进,截到的是「文字尚未淡出」的静态帧,差点误判为粒子没生效 ⚠️ - 改用 CDP 实时驱动(导航 → 等 2.5s → Page.captureScreenshot / Runtime.evaluate),并读取 data-pt-title 与 canvas 像素。
  • 用 deno 直接跑任务会被本机 mise shim 拦下(未设置全局版本)⚠️ - 用仓库 vendored 的 .tools/deno/bin/deno(bin/lib.sh 本来就是这么做的)。

下次建议

  • 若后续觉得起伏太克制,可把 waveAmpX/Y 调到 1.2 / 3;想更「颗粒」就把 pitchCss 调回 1.8–2.0(粒子会更少、缝更大),不必动引擎。
  • 可选的 hover 散开:引擎已有 pointer_set,给标题 canvas 接一段 pointermove 即可复用屏保的斥力场。
  • 标题文案将来若变化,建议在 375 与 1280 各截一张图做字形回归(?pt-title=off 对照最直观)。