切换外观
峰值保持 · 参考、数据、故事与实现
状态:已实现。2026-10-28 把第四轮候选 07 峰值保持按六步流程(reference → data → story → motion → direct → ship)做成完整形式 sketches/peak.html。第 1–4 节在动手之前写定(参考、数据、故事、交互),第 5–6 节是实现之后补的出入与验证。起点是探索代理的静态草图(只在本机 scratchpad,不入库);两层法则与交互标准见 CONCEPTS.md,同类页面的范本是让位图与两周小倍数,交互取共用模块 motion/ix.mjs。原型探索记录,不是规范。
帧号默认指 composite(Jonas Berglund 的两周,f00–f28,每 12 小时一轮,帧号 fNN 就是序号 NN);story(林苒的两周,cold-00–f34,37 帧,帧号与序号不同)单独标出,必要时写成“f20(序号 22)”。
1 参考:峰值保持在别处怎么讲
看过的四张图(.local/inspiration-r4/,INSPIRATION.md 的编号):
| 出处 | 画面上读到的 | 搬过来 | 不搬 |
|---|---|---|---|
#86 Ardour 电平表(b-ardour-meters.png、b-ardour-recorder.png、b-ardour-67.png) | 混音台每轨一根竖表,亮条是此刻,条上方一道细线停在近期最高;表头一个黑框写峰值的数(-4,5、-16,3、-inf)。录音窗右上单独一个大按钮“Reset Peak Hold”,和走带按钮分开放:峰值一直停着,直到操作者按下 | 一件事一根竖表:实心是此刻,粗横线停在离开期间的最高;表头框写峰值;清峰值是单独的一个按钮,只有人能按 | 绿黄红的电平色、刻度上的 dBFS、仿硬件的凹槽与金属 |
| 电平表的通行做法(同一组图之外的常识) | 指示升得快、落得慢;峰值线不跟着落,另由保持时间或手动清除决定 | 换轮时条“升快落慢”:涨 0.2 秒、落 0.45 秒;峰值线被条顶上去,条落下时它不动 | 自动回落的保持时间:这里峰值只等你清 |
#88 纽约时报选举指针(b-needle-2016.jpg) | 刻度上钉着两道虚线“OBAMA '08”“OBAMA '12”:历史值和此刻值在同一把尺上。指针一直抖,读者把抖动当成新数据,被批评制造焦虑 | 虚线 = 你上次看时的份额,和此刻、峰值同一把尺 | 抖动。静止时画面零运动,只在一轮真的变了时动 |
#87 围棋分段谱(b-kifu-pair.png) | 分段谱只给这一段的新子写手数,从 1 重新编号;此前已在盘上的子不写数 | 峰值旁的圈号 = 离开后的第几轮到峰,从上次看之后的第 1 轮数起;峰值就停在上次看时那一档的,不写号;按“已阅”之后从 1 重新数。表也分两组:上次看时就在的(盘上原有的子)和离开后才来的(这一段新下的子) | 棋盘与黑白子 |
#91 Molnár 叠印(c-molnar-interruptions.jpg) | 两层短线都在的地方更黑,只剩一层的地方变浅,边界只靠密度突变显出来 | 只取读法:两条线(虚线 = 上次,实心顶 = 此刻)都在的地方没变,峰值高出它们的那一段才是“你没看见的” | 随机短线的质感 |
草图怎样讲,哪里讲不动。 草图(composite f26,锚点手选 f20)一排 12 根竖表,按峰值从高到低排,表头框里写峰值,“峰值高过此刻”的表头涂黑;左上大字“3 件”,左下一枚朱红描边的“已阅 · 清掉峰值”。用户看过说可以往下做。往下做之前要改的:
- 黑框和英雄数字说的不是一件事。 草图涂黑的是“峰值高过此刻”,共 7 根(母亲换水管 24 → 24 → 3、后刹 6 → 6 → 3、小龙虾派对 6 → 6 → 0 等也算),英雄数字却是 3。母亲换水管上次看时就是 24,它的落差虚线已经画出来了,不是“看不出来”。改成:只有峰值同时高过虚线(上次)和实心(此刻)的才涂黑,黑框的个数就是英雄数字。
- 按峰值排序,一动就换位。 讲一遍时峰值逐轮被顶高,按峰值排的列会来回换位置。改成分段谱的排法:左组是上次看时就在的(按上次的份额从大到小),右组是离开后才来的(按到来的先后),两组之间一道细竖线;讲的时候左组一根不动,新来的依次在右组落位。
- 锚点写死。
last_seen_at恒为 null,草图手选 f20。要换成能在两套数据上自己推出来的规则(第 2 节)。 - “保持”是时间里的行为。 静图上峰值线和实心之间只是一段斜线;峰值被顶上去、条落下而线不动,只有动起来才看得见“停着”。
- “已阅”只是画出来的。 要真能按、能撤回,按下之后锚点移到此刻、峰值清掉,下一轮再离开时从这里重新累积。
概念层:一成以内,静止为零。 它是复盘工具:会反复打开、逐根比对,画面上不在账上的东西都在跟比对抢眼。所以概念层只有一种东西:条落下时,旧高度到新高度之间留一块灰影,0.6 秒内淡完(“刚落下的那一段”);按“已阅”时,被清掉的斜线段同样化成灰影淡出。它和信息层共用几何与数量:灰影就在那根表的柱身里,高度就是落下的份数。实测换轮时最多占画面约 2.3%,按“已阅”那 0.5 秒最多约 4.3%(第 5 节),不透明度都从 0.3 淡到 0;没有飞点、粒子与余辉,平账后为零。
2 数据:锚点、峰值与圈号
口径。 和页面同一套推导:用 node 直接导入 variants/shared.mjs(records 与 currentAsk)现算,脚本只放在本机,不提交。份额取根层 records[i].state.root.items[].share,不在根层(还没出现、撤下、并入)记 0;问题的开闭用 stage.mjs 的 askLife 同一算法(currentAsk 逐帧求开着的问题,关上时此前有 event.feedback[].ask 指向它的算答掉,否则算失效);名字取 scenario.categories[id].short。
锚点规则(“你上次看”是哪一帧)。首切片不采集用户查看:last_seen_at 与 since_seen 恒为 null,含义是“未采集”,不能制造阅读证据(决策记录“用户阅读”一行)。所以锚点只是页面侧的推定,页面上照写“推定”与理由。按下面的顺序取第一个成立的:
- 地址里的
?seen=fXX(帧号或序号),或左栏下拉选的那一帧;它必须在此刻之前,否则不用。 - 本页按过“已阅”:按下时的那一帧(只在本页内存,可撤回,不写进地址)。此刻退到它之前时不用,退回推定;之后你又在 Fold 里回应过(第 3 条给出的帧更晚)也不用,取更晚的那一帧。
- 你最近一次在 Fold 里回应时屏上的那一帧:取最近的 k ≤ 此刻,
frames[k].events[].feedback[]里有via为button(Fold 里的按钮)或reply(回复 Agent)的一条;锚点 = k − 1。这条回应是第 k 轮整理读到的输入,发出它的时候屏上是第 k − 1 轮。 - 都没有:此刻往前 6 轮(在默认帧上就是“默认帧往前 6 轮”;不足 6 轮取
f00)。
和定规则时的原话“你本人最近一次回应所在的那一帧”有两处不同,理由都来自数据:
- 只认在 Fold 里的回应。 composite 的 160 条反馈链接全是
via: source(在 GitHub 上批准、用 iMessage 回复、给诊所打电话),一条也不在 Fold 里;f02 起几乎每一帧都有。照原话取,锚点永远是上一帧,离开 1 轮,28 帧里升起又落下的一件也没有,形式就不成立。来源处的动作只说明你在 GitHub 或电话上,不说明你看过 Fold;只有在 Fold 里点按钮、回复 Agent,才是看过 Fold 的旁证。story 的 15 条反馈正好全在 Fold 里(reply12、button3)。 - 取回应时屏上那一帧(k − 1),不取回应所在的那一帧(k)。 第 k 帧的状态是读了你的回应之后才算出来的,你没见过它。差一帧在 story 上会挪动结果(见下文 story 一段);composite 不受影响。
两处若要改回原话,只动 peak.mjs 里 inFold 与 anchorOf 两行。
峰值怎样算。 对锚点到此刻(含两端)出现过的每件根层事项,取逐轮份额序列 s(锚点那一轮记作第 0 轮):
- 峰值 = max(s);到峰 = 第一次到达峰值的那一轮;圈号 = 到峰 − 锚点,0 不写号(上次看时就在那一档)。
- 升起又落下 = 峰值 > s[锚点]、峰值 > s[此刻],且峰值 ≥ 3。两套数据的份额都只有 1、3、6、12、24 五档,1 份是留着的最低一档,0 → 1 → 0 只是一条痕迹,不算升起。
- 画哪些表:峰值 ≥ 3 的。只到过 1 份的折成一句“另有 N 件一直只占 1 份”。一帧最多画 24 根,再多的按“升起又落下优先、峰值从高到低”留下 24 根,其余折成一句(两套数据按推定锚点一帧最多 19 根,composite 的 f07 与 f20;只有手选很早的锚点才会碰到)。
- 两组:左组是锚点时份额 > 0 的(按锚点份额、再按峰值从大到小),右组是锚点时为 0 的(按第一次出现的轮次、再按峰值)。
composite · f26(8/16 周日 00:00「车道下的铜管裂了」,默认帧)。 两周里你没在 Fold 里回应过,锚点按第 4 条取 f20(8/13 周四 00:00「Ture 发烧被接回,Kajsa 的后刹失灵」),离开 6 轮。f21–f26 里你在来源处动了 28 次(f21 4、f22 7、f23 5、f24 2、f25 6、f26 4),页面写明它们不算看过 Fold。
| 表 | 上次 → 峰值(圈号)→ 此刻 | 逐轮 f20…f26 | 出处与说明 |
|---|---|---|---|
| 主水管 | 1 → 24 ⑥ → 24 | 1 1 1 1 6 12 24 | driveway-wet;峰值就是此刻,看得出来 |
| 猫看病 | 12 → 24 ② → 6 | 12 12 24 12 12 12 6 | smilla-vet;f22「热浪第一天:药量超过失明线」翻到 24(标题“Smilla剂量疑超失明线,8点打诊所”);f23 08:02 你给诊所打了电话,答掉 ask-16「Smilla 多吃了药:打诊所?」,24 → 12;f26 再 12 → 6 |
| 母亲换水管 | 24 → 24 → 3 | 24 24 24 6 3 3 3 | 上次看时就是 24,虚线画得出这段落差;ask-08「母亲九月住哪?」f23 随改写失效 |
| master CI | 1 → 6 ③ → 6 | 1 1 1 6 6 6 6 | |
| FTPS 计时 | 0 → 6 ⑥ → 6 | 0 0 0 0 3 1 6 | f25 落到 1、f26 又到 6:中途的起落被此刻盖住了,峰值等于此刻,不算 |
| 待审 PR | 0 → 6 ② → 6 | 0 0 6 6 6 6 6 | pr-reviews-0814,f22 新建 |
| 后刹 | 6 → 6 → 3 | 6 1 1 1 1 1 3 | |
| 复用绕过 | 0 → 6 ① → 0 | 0 6 0 0 0 0 0 | issue-13567-sspi;f21「#13567:复用防护可被绕过」新增 6 份,f22 并入待审 PR(records[22].snapshot.items[id].merged_into) |
| 小龙虾派对 | 6 → 6 → 0 | 6 3 0 0 0 0 0 | f22 撤下 |
| 65KB 上传 | 0 → 3 ④ → 3 | 0 0 0 0 3 3 3 | |
| Ture 发烧 | 3 → 3 → 1 | 3 3 3 3 3 3 1 | |
| 骑车 | 0 → 3 ④ → 0 | 0 0 0 0 3 0 0 | joakim-ride-16;f24「车道边湿了一整周」出现,f25 08:40 你回 Joakim 取消(水管漏了),撤下 |
英雄数字 3 件:猫看病 12 → 24 → 6(落差最大,峰值 24 停在第 2 轮)、复用绕过 0 → 6 → 0、骑车 0 → 3 → 0,和候选写的一致。另有 14 件一直只占 1 份不画,其中假关税短信 0 → 1 → 0 是一条痕迹,不计。离开期间从登记到关上都在这 6 轮里的问题有 1 个:ask-20「#13572 堵复用绕过:批准?」f22 登记、f23 11:38 你在 GitHub 上批准后关上。此刻开着 5 个:「VAB 报了吗?」「Signe 的同意书签了吗?」「三个旧 PR 推到哪天?」「主水管:挖开换还是免挖?」「#13596 计时修复:批准?」。
逐帧(推定锚点,件数 / 画出的表):f02 起每一帧都至少有 1 件,28 帧里 27 帧(只有 f01 没有),因为锚点总是往前 6 轮;最多 12 件(f06,锚点 f00 的冷启动期,很多事刚出现又被压到 1 份)。照原话的口径(任何反馈、所在帧、此刻之前):锚点永远是上一帧,28 帧全是 0 件。
story · f20(序号 22,10/19 15:30「API费用预测6400元,本月上限待定」,默认帧)。 10/18 16:59 林苒在 Fold 里回复 Agent「今天去了。妈妈在陶瓷那边待了很久……」(frames[20].events[0],via: reply,答 ask-21「周日 11 点见妈妈」),这条回应是 f18 的输入,发出时屏上是 f17(序号 19,10/18 08:00「无新输入:东馆开放时间待出发前复核」),锚点取 f17,离开 3 轮。
| 表 | 上次 → 峰值(圈号)→ 此刻 | 逐轮 f17…f20 | 说明 |
|---|---|---|---|
| 妈妈 | 24 → 24 → 6 | 24 24 6 6 | 虚线画得出落差 |
| 费用 | 1 → 12 ③ → 12 | 1 1 1 12 | |
| 厨房 | 12 → 12 → 12 | 12 12 12 12 | |
| 试用 | 6 → 12 ② → 12 | 6 6 12 12 | |
| 发布 | 3 → 12 ② → 6 | 3 3 12 6 | f19「暂存口径再次延期,扩大演示范围待决定」到 12(“导出发布是否扩大开放”),同一轮登记 ask-25「周三演示前,开放范围怎么定?」;f20 改写为“导出发布暂不承诺全量开放”,6 份,ask-25 没人答就随改写失效 |
| 筛选 | 6 → 6 → 6 | 6 6 6 6 | |
| 链路 | 0 → 3 ② → 3 | 0 0 3 3 | |
| 苏禾 | 0 → 3 ② → 1 | 0 0 3 1 | f19 新增(“苏禾改约周四晚,设计职责待谈”),f20 压到 1 |
英雄数字 2 件:发布 3 → 12 → 6、苏禾 0 → 3 → 1;ask-25 从登记到失效都在她离开的这 3 轮里,她一次也没看到。逐帧:她在 12 帧里有 Fold 里的回应,锚点多在 1–3 轮之内(最远 4 轮:f10、f29),36 帧里只有 5 帧有升起又落下的事(f04、f08、f09、f10、f20)。这是论点的另一面:常回来看的人,峰值没机会藏起来。照原话的口径,f20 的锚点是 f18(序号 20),件数仍是 2;但 f21 起结果不同:f21 的回应在它自己的输入里,原话口径不认它,锚点仍是 f18,算出“离开 3 轮、2 件”,而她 19:xx 刚回复过 Agent;本页的口径取 f20,0 件。
按“已阅”之后。 composite 在 f26 按下,锚点移到 f26,f27、f28 都是 0 件(f28 猫看病与待审 PR 从 6 落到 3,峰值高过此刻但不高过上次)。story 在 f20 按下,f21–f23 锚点停在 f20,都是 0 件;f24 起你在 Fold 里的回复比“已阅”晚(10/20 19:15 回复 Agent「5200」),锚点跟着回复走,f24 取 f23,一直到 f34 都是 0 件。动手前算的是“已阅”压过 Fold 回应,f24 会因为试用 12 → 24 → 12(第 2 轮到峰)重新攒出 1 件;可那时你刚在 Fold 里回复过,说你没看见说不过去,实现时改了(第 5 节)。
回放里有、图上还没用的。 留白也升起又落下:composite f20–f26 的留白是 0、2、0、25、13、12、1(64 − records[i].state.root.used),8/14 中午一度空出 25 份,此刻看不出来;它不是一件事,英雄数字不算它,这一版不画。子层的起落(story 有子层)只算根层。回放里没有的:真的查看记录。页面的锚点是推定,last_seen_at 接入查看入口之后才有真值。
3 故事
论点。 此刻的状态只记此刻:你不在的时候升起又落下的事,回来时已经看不出来。峰值保持把离开期间到过的最高停在原处,直到你按“已阅”才清掉;翻过不等于看过。
英雄数字:3 件(composite f26)在你离开的 6 轮里升起又落下,落差最大的是猫看病 12 → 24 → 6。它是黑框表头的个数,也是左栏顶上 76 px 的大字;下面三行逐件写“上次 → 峰值 → 此刻”与圈号。story 是 2 件(发布 3 → 12 → 6)。
三拍(composite 约 10.8 秒,停在 f26;story 约 9 秒,停在 f20。帧号是页面常量,按数据集各一组;锚点按第 2 节的规则在故事的末帧上现算,讲的时候固定不动)
| 拍 | 时长与帧 | 发生什么 | 观众此刻 | 在动 / 只在节拍上落定 |
|---|---|---|---|---|
| 0 | 0–0.4 秒,f20 | 画面停在锚点那一帧:每根表的实心顶正好压在自己的虚线上(你就在这里),没有峰值高出来;左栏写“上次看 · f20 8/13 周四 00:00” | 一排表,此刻 = 上次 | 什么也不动 |
| 1 你不在 | 0.4–5.8 秒,f21–f26 每轮 0.9 秒 | 逐轮硬切日期与旁白,左栏的轮次跟着走(“你离开的第 ② 轮 · 8/14 周五 00:00”)。条升快落慢,峰值线被顶上去就停住;新的峰值落定时旁边出圈号;落下的一段留一块灰影 0.6 秒淡完;离开后才来的表在右组依次落位 | 猫看病第 2 轮冲到 24,第 3 轮落回 12,线还停在 24 | 动:条、峰值线被顶起、灰影、新来的表淡入。落定:日期与轮次(切点)、表头数与圈号(到峰那一刻) |
| 2 此刻看不出来 | 5.8–8.2 秒,f26 | 末轮落定后 0.4 秒,三根峰值高过虚线也高过此刻的表,表头从左到右依次反成黑底(每 0.25 秒一根),大字随之 1、2、3,下面逐行写出“猫看病 12 → 24 → 6 ②”;其余不动 | 3 件:此刻的份额里已经找不到它们到过的高度 | 落定:表头反黑、大字逐个加一、三行文字 |
| 3 已阅 | 8.2–10.8 秒,f26 | 朱红的“已阅 · 清掉峰值”被按下(朱红填满 0.15 秒,旁注“演示:替你按一次”);0.15–0.65 秒峰值线落到实心顶上,斜线段化成灰影淡出,虚线移到此刻,圈号淡出;落定时表头切回此刻的份数、大字 3 → 0,写“已阅:锚点移到 f26”。停 1.4 秒后撤回演示:峰值、虚线与圈号 0.3 秒淡回,大字回到 3,按钮回到描边,旁注“讲一遍只是演示,没有替你按;峰值还停着” | 只有按下才清;清了,下一轮离开再从这里攒 | 动:峰值线落下、灰影、虚线移动。落定:表头数、大字、旁注 |
讲完是普通的复盘工具,停在 f26(地址栏 frame=26),峰值停着,按钮等你按。任意键跳过,直接到这个终态。
一轮的时间表。 讲一遍每轮 0.9 秒(story 只有 3 轮,每轮 1.2 秒);空格连播每轮 1.6 秒;→ 逐帧 0.6 秒:
- 0 切点:顶栏日期、帧号与旁白一帧硬切;左栏的轮次硬切。
- 0.05 起:涨的条 0.2 秒到位(ease-out),峰值线贴着条顶被推上去;落的条 0.45 秒到位(ease-in-out),旧顶到新顶之间留灰影,0.6 秒淡完。
- 条涨到新峰值的一刻:表头的数硬切,圈号 0.12 秒淡入(上次看之后第几轮)。
- 锚点换了(连播、逐帧时推定锚点跟着此刻走;按“已阅”;下拉改锚点):虚线 0.3 秒挪到新位置;落出窗口的旧峰值 0.35 秒落到新窗口的最高;圈号随新锚点重新编号,在落定时硬切。
- 0.6(逐帧)/ 0.9(讲一遍)落定:表头黑白、件数与左栏文字在这一刻切换;概念层为零。
- 往回退、一次跳多帧、拖刻度:0.25 秒直接补间到新值,不留灰影、不出圈号的淡入。表的集合变了时,留下的表 0.3 秒挪到新位置,走的淡出,来的淡入。
两层。 信息层(九成以上):竖表的实心、峰值线、虚线、斜线段、表头框与数、圈号、名字与三个数,左栏的大字、逐件三行、锚点说明与按钮,侧栏。只用墨、灰与纸色;只在节拍上落定。概念层(一成以内,静止为零):条落下时与清峰值时的灰影。只用灰,不带文字、数字与颜色;高度就是落下的份数。
动起来之前的约束
- 绝不动:表的顺序(左组按上次、右组按到来)、纵轴的刻度、颜色的含义。
- 静止时零运动:不抖、不呼吸、不循环(纽约时报指针的教训)。
- 朱红只给“已阅”这一个你的动作:按钮的描边与按下时的填充;开着的问题在卡里也用墨色标,不用朱红。
- 不替你按“已阅”:讲一遍里的那一下写明“演示”,讲完撤回;“已阅”只存在本页内存,不写回数据、不进地址栏。
- 只读回放:份额、锚点、问题、回应都从
scenario现算,帧号是页面常量;不改scenario.mjs、shared.mjs、engine.mjs与演示数据,不读 data.json。 prefers-reduced-motion:讲一遍直接到终态,换轮直接到落定,不出灰影。- 合页顶栏选帧、画廊缩略图、体验站弹框、带
?frame=或?seen=的链接、从别的页面链来的:一律静止,不讲。
4 交互
与份额拨盘、让位图同一套标准,状态机、时序、卡的摆位与收回取共用模块 motion/ix.mjs;本页只提供几何:一根表是一件事。
- 悬停:鼠标移到一根表(表头、柱身、名字都算,左右各放宽 10 px,表挨得近时收到两表间距的一半),Tab 到它的隐藏按钮,或触屏轻点一下;左栏逐件三行也认作那根表。出一张概要卡,贴在表的右侧(右边放不下放左侧),与峰值线齐平:名字与“上次 → 峰值 → 此刻”,第几轮到峰与那一轮的时间,此刻开着的问题与期限。其余表降到七成。播放(讲一遍、连播)停在当前时刻;离开 0.15 秒宽限,卡 0.12 秒淡出,再过 0.4 秒接着走。
- 展开:点一根表或它的概要卡,聚焦后 Enter 或空格。0 秒切点,顶栏旁白改成“这一件 · f26 · 8/16 周日 00:00 / 猫看病”,侧栏切到“这一件”;0–0.3 秒表沿自己的轴向上弹出 8 px(ease-out,过冲 3.7 %),其余降到 18 %;0.4–0.6 秒引线从表头框的侧边水平出到详情卡;0.6–0.9 秒详情卡从引线末端展开。卡放在空间大的一侧,不盖住被点的表。
- 详情卡(离开期间这一件):时间、帧号与离开几轮;“猫看病 12 → 24 → 6”;此刻的条目标题;离开期间逐轮的小条图(锚点一根、之后每轮一根,峰值那根加黑,下面写圈号);到峰那一轮的时间与旁白;落下的几轮与那一轮里你在来源处的动作(“你给诊所打了电话”);离开期间关上的问题,写怎么关上的(答掉写动作句,失效写“随改写失效”),不给链接;此刻还开着的问题,旁边“去回答 →”链到当前帧的 D:
../../index.html?variant=d&frame=<序号>(D 读的是序号,frame=f26会被当成 0),经withDataset带上?data=。不承载作答。 - 侧栏“这一件”:两周的份额小条图(离开期间那几轮加框);离开期间逐轮的份额、到峰与落下;这件事两周里登记过的问题;摘要、依据、来源与版本(
itemDetailHTML,折叠)。 - 收回:Esc、点空白、再点同一根:卡 0.2 秒收起、引线 0.15 秒缩回、表 0.2 秒落回,然后一帧切回;0.4 秒后接着播。←/→、选帧、连播、合页顶栏选帧、按“已阅”与改锚点都立即收起。
- “已阅”与锚点:左栏左下的朱红描边按钮,按下即把锚点移到此刻(第 3 拍的那套动作),按钮变成“撤回已阅”,再按回到原来的锚点;左栏的下拉列出此刻之前的每一帧(标出推定的那一帧和有 Fold 回应的帧),选了写进地址
?seen=,选“推定”去掉。 - 键盘与入口:←/→ 逐帧,空格连播,Home / End 到头尾,Tab 逐根看概要,Enter 展开,Esc 收回;任意键跳过讲一遍,顶栏“↺ 重演”重讲。
- 脚本:
window.foldPeak与foldYield同名同义:hover / unhover / open / close / ixAt / paused / pointOf / nearOf / pick / tell / skip / tellAt / play / stop / telling / playing / settled / phase / perf / resetPerf,另有本页的anchor()(此刻的锚点与理由)、peaks()(此刻每根表的数)、read()/undo()(已阅与撤回)、seen(帧)(改锚点)与plan。window.foldSketch照旧。
5 实现与出入
文件与画法。 sketches/peak.html、peak.mjs、peak.css,页头、帧导航、侧栏与键盘取 sketches/stage.mjs,悬停与展开取 motion/ix.mjs。竖表是一张按尺寸建一次的 SVG,每根表一组节点;每帧只改变了的属性(逐节点缓存),左栏与侧栏是 HTML,只在内容变了时重写。份额、锚点、峰值、圈号与问题都在页面里从 records 与 askLife 现算,按(此刻,锚点)缓存;帧号常量只有两组默认帧(composite f26、story f20)。
补间。 一个纯函数 between(from, to, u, P) 把屏上的样子补到落定的样子,按档 P 取时长:讲一遍 TELL(0.9 秒一轮)、连播 PLAY(同样的补间,1.6 秒一轮)、→ STEP(0.6 秒)、跳帧 JUMP(0.25 秒,无灰影)、已阅 CLEAR(0.6 秒,峰值线 0.5 秒 ease-in 落下)。条涨 0.2 秒 ease-out、落 0.45 秒 ease-in-out;峰值线在条涨到它时被顶着走,表头数在顶到的那一刻硬切,圈号 0.12 秒淡入;黑底表头、件数与左栏文字在落定(0.65 秒)时切换。讲一遍是时间的纯函数 tellPhase(s),foldPeak.tellAt(s) 停在任意一刻(成片就是这样拍的),任意控件放开它。
和第 3–4 节的出入
- 时长。 composite 讲一遍 10.6 秒(不是 10.8):第 1 拍 0.4–5.8 秒;第 2 拍 5.8–8.15 秒,三根表头在 6.2、6.45、6.7 秒反黑,再停 1.2 秒;第 3 拍 8.15–10.6 秒,按下 0.15 秒,8.3–8.9 秒清掉,清掉的样子停 1.3 秒,10.2–10.5 秒撤回,10.6 秒结束。story 8.55 秒:3 轮各 1.2 秒,第 2 拍 4.0 秒起,第 3 拍 6.1 秒起。
- 演示的“已阅”里有几根表淡出。 清掉之后峰值等于此刻,峰值不到 3 的按“峰值 ≥ 3 才画”不再画(composite 的小龙虾派对、Ture 发烧、复用绕过、骑车),0.45 秒淡出,演示里其余表原地不动、留着空位;撤回时它们随峰值一起 0.3 秒淡回。真按“已阅”时剩下的表 0.3 秒合拢。第 3 节没写到这一点。
- “已阅”和之后的 Fold 回应取更晚的。 第 2 节锚点规则第 2 条加了一句:按过“已阅”之后你又在 Fold 里回应过,就取回应时屏上那一帧。理由见第 2 节“按‘已阅’之后”。按钮这时回到“已阅 · 清掉峰值”,撤回栈还在。
- 讲一遍时的锚点栏。 左栏写“上次看 · 讲一遍”,下拉锁成“讲一遍中”;演示清掉时写“演示的‘已阅’”。侧栏照推定写(“讲一遍停在 f26,用的是那一帧的推定”)。第 0、1 拍的大字是轮次(“0 / 6 轮”“2 / 6 轮”),第 2 拍起才是件数。
- 侧栏“这一件” 没有逐条列两周里登记过的问题,只在折叠的“摘要、依据、来源与版本 · 登记过 N 个问题”里给个数(
itemDetailHTML里有逐条);离开期间关上的与此刻开着的问题逐条列出。 - 详情卡的逐轮小条图按这一件自己的峰值定高,不用表的 24 份刻度:卡上看起落的形状,表上看大小。骑车 0 → 3 → 0 在 24 份的刻度上只有一个像素高。
- 概念层面积。 第 1 节原写“任何时刻不到 2%”。实测(composite 与 story 全部帧,表宽按当帧):一轮落下的灰影最多约 2.3%(story 序号 17,落 27 份),composite 最多约 1.6%(f23,猫看病 24 → 12、母亲换水管 24 → 6,共 30 份);按“已阅”时清掉的斜线段最多约 4.3%(composite f26,59 份)。不透明度从 0.3 起淡,0.5–0.6 秒到零,在一成之内。
- 画廊卡片的“默认帧”。 画廊读数据集的
sketchFrames,composite 里没有这一页(不改数据),卡片显示 catalog 的frame,即 story 的 f20;页面在 composite 实际停 f26。要对上需要在 composite 的sketchFrames里加peak: 'f26',或让画廊读每页自己的默认帧。 ix.index带上锚点与“这一轮是否落定”,锚点一变(已阅、改锚点)卡上的数就重算;换轮补间未落定时,卡上的数守上一轮,写“本轮还没落定”。- 登记的位置。 照 #34 变形定下的第四轮结构:合页里和变形同在“第四轮:关系的画法”一组(第二轮之后、第三轮之前),CONCEPTS.md 的 07 卡排在 04 之后。形式画廊(
forms/index.html)按 catalog 的sketches铺卡,所以峰值保持和变形一样出现在“第二轮:复盘图”的标题下、编号 12;画廊的第四轮标题要等几个形式一起定,这里没有改。
6 验证
2026-10-28,rebase 到 main(含 #34 变形)之后,本机自起的静态服务(不占 4173),headless Chrome;没有打开 Safari。
make check通过。node scripts/check-ix.mjs:composite 全部 14 页通过(home 23 / 23,其余 16 / 16),peak 挑猫看病;story 13 页通过,peak 挑试用 16 / 16。story 的 C 流动形态时过时不过:全页那一轮挂在“点击展开”(1.1 秒时详情卡还没展开到底),单独重跑一次全过、再一次挂在“Tab 到事项”;这个 PR 没有改 C,rebase 之前那一轮 story 全部通过,composite 那一轮挂过一次批次记谱的同一项。当时机器负载均值在 30–57(别的代理也在跑浏览器与构建),记为既有的时序抖动。node scripts/shoot-forms.mjs --only peak,all --gpu --check all-sync:两套数据都无报错,合页同步通过(峰值保持报告所在帧、跟着顶栏选帧走,不讲开场)。npm run site:build通过,dist/里有本页、previews/peak.webp(640 × 400,24.8 KB)与本记录页;scripts/export-all.mjs的单文件导出带上了本页。行为(自写的 CDP 探针,脚本只在本机):composite 顶层直接打开从 f20 讲起,10.6 秒后停在 f26、地址
frame=26,3 件;讲到 2 秒时按任意键,立即到同一个终态;从画廊链来(referrer 为forms/index.html)、带?frame=26、带?seen=f24、prefers-reduced-motion都不讲,直接是终态,减少动态效果时按“↺ 重演”也直接到终态。story 从 f17(序号 19)讲起,8.55 秒后停在 f20(序号 22),2 件;?seen=f24在 f20 之后,按规则不用、退回推定。下拉选 f22 写进?seen=f22、只剩骑车 1 件,选回推定去掉seen、回到 3 件;“已阅”再点“撤回已阅”回到推定的 f20。按“已阅”之后逐帧的锚点与件数见第 2 节。四组探针都没有页面报错。帧率(
--gpu、?perf=1,rAF 间隔;fps 是平均,最长是单帧间隔):动作 composite story 讲一遍全程 59.9 fps,最长 33 ms(1 帧) 60 fps,最长 17 ms → 逐帧 5 次 60 fps,最长 17 ms 60 fps,最长 17 ms 连播 6 轮(重复 3 次) 59.6–60 fps,最长 67 ms(1 帧) 59.9–60 fps,最长 33 ms(1 帧) 已阅 / 撤回各 3 次 59.8 fps,最长 33 ms(1 帧) 60 fps,最长 17 ms 本页每帧的计算平均 0.2–0.4 ms,最多 7.9 ms(换轮那一帧:
stage.go与侧栏)。负载高时量到过一次连播 51.8 fps、单帧 1.35 秒的停顿,同一时刻页面自己的计算不到 1 ms,重量三次没有再出现。成片(1440 × 900,
--gpu)只在本机 scratchpad,不入库:两套数据的默认帧、讲一遍第 1 拍(composite 第 ② 轮)、第 2 拍三根反黑、第 3 拍清掉与撤回、悬停、展开、按“已阅”之后,以及 story 在 f20 按“已阅”再翻到 f24。