切换外观
两周小倍数 · 动画记录:参考、数据、故事与实现
状态:已实现。2026-10-19 起草,原型探索,不是规范。按第三轮的六步流程(reference → data → story → motion → direct → ship),前三步(第 1–3 节)审阅通过后,第四到六步落在 multiples.mjs、multiples.css 与 multiples.html,审阅定下的改动与实现的取舍记在第 4–6 节;第 1–3 节保留审阅时的原文,与第 4 节不一致处以第 4 节为准。形式在动画之前怎样工作见 review-a.md 的“08 两周小倍数”一节;两层法则与交互标准见 CONCEPTS.md 的“第三轮:概念动画”、份额拨盘 story 与 整理脉冲 story,交互的宿主契约在 motion/ix.mjs 文件头。
帧号默认指 composite(Jonas Berglund 的两周,f00–f28,每 12 小时一轮);story(林苒的两周,cold-00–f34,不定时)单独标出。
1 参考:这张图现在怎样讲“移动”
它靠什么讲
multiples.mjs 把每一帧画成同尺度的 8×8 小方阵:按本地日期分行,一行两格(00:00、12:00),左列第一周、右列第二周;一格一份,按 state.root.items 的排名从左上填起,空格是未分配;两周累计份额前 8 件各一色(sketches/live.mjs 的 topRoots),其余灰;黑点是“这件事此刻有问题开着”,一件一点,点在它的第一格。
“移动”是读者自己用眼睛读出来的:同一个尺度、同一种填法、颜色两周不变,相邻两格一比,就知道哪块大了、哪块没了。悬停一格让这件事在 29 帧里同时亮起、其余变成浅灰,是它最好用的一招:一件事两周的轨迹一眼看全。这些都是静帧并排的价值,动画不能碰。
页面里已经有一点动:空格键每 900 ms 走一帧,播放框滑过去(260 ms),右栏放大方阵的格子按身份(条目#k)滑到新位置(380 ms),新来的淡入、走的淡出,黑点在格子落定后出现。它已经是一段延时,只是没有节拍,也没有一个数说明这一轮动了多少。
哪里讲不动
数字的口径见第 2 节。
- 太满,看不出空。 两周 28 轮共 1792 格,1689 格有主(94%),13 轮用满 64。第一周 f02–f09 八轮里六轮用满,另两轮是 63 与 58。变化只表现为满方阵里色块边界挪了一点,没有“空出来”可看。
- 按排名填,格子每轮都在重排。 同份额的事按最近更新排在前(
engine.mjs的rankItems),上面一块变了大小,下面所有块都要移位。逐位置比,28 轮共有 941 格换了主人,而份额真正易手的只有 357 格(2.6 倍);按前 8 件的颜色看是 675 对 284。最明显的三轮:f11 只多了一件 1 份的小事,17 格换了主人;f25 份额只动了 6 格,位置变色 37 格;f23 64 格全部变色,真正换手 30 格。静帧里这不算错,读者比的是块的大小;可一旦把同一种填法逐格动起来,眼睛看到的大半是重排,不是注意力在动。 - 灰的看不见移动。 1689 格里 555 格(33%)属于前 8 件以外的 52 件,全是同一种灰,它们之间的此消彼长画不出来。
- 相邻帧不总相邻,最后一行在屏外。 f13(8/9 12:00)在第一周列底,f14(8/10 00:00)在第二周列顶,比这两帧要跨半张图。1440×900 下 composite 最后一格的底边在 946 px,story 在 1012 px,“一眼看完两周”其实要滚一下。
- 没有一个数说“这一轮动了多少”。 页头是两周的总数(29 次整理、60 件、同一时刻最多 26 件、13 次用满),右栏是此刻的存量(11 件 · 用 39 / 64 · 3 个问题开着);变化量只能自己数。
- 问题按件数。 右栏的“N 个问题开着”和黑点都是一件一个(
data.asks以根层条目为键)。composite 没有挂在子层上的问题,两种数法一样;story 差得多:f01 开着 6 个问题,页面写 4 个(拨盘的openAsks记 6)。 - 图例用此刻的长标题(“Mamma已交回…”被截断);拨盘与脉冲用的是稳定的短名
categories[id].short(母亲换水管、猫看病)。
从拨盘第二拍与整理脉冲搬什么
拨盘第二拍(f02→f25)把 24 轮压进 9 秒,每轮 0.375 秒:扇区每轮跳一次,计数连滚,日期在切点硬翻,概念层跨切点不断。整理脉冲每轮 4.25 秒走完涌入、折叠、一问三拍,节奏依据见各自的 dial/spec.md 与 pulse/spec.md。
| 来源 | 节奏 | 怎样处理 | 理由 |
|---|---|---|---|
| 拨盘第二拍 | 每轮只跳一次,在节拍上落定,不连续漂 | 搬 | 放大方阵每轮只落定一次;播放框是离散量,一帧硬切到下一格 |
| 拨盘第二拍 | 每轮 0.375 秒 | 改成 0.6 秒 | 拨盘一件事是一段弧,角度一眼可读;方阵一轮要动几十个小格,0.3 秒动、0.3 秒停才数得清 |
| 拨盘第二拍 | 计数连滚(逐轮硬翻像闪烁) | 不搬 | 小倍数的英雄数字是本轮的量,不累计;每轮在格子落定时翻一次,翻的时候正好解释刚看到的动作 |
| 拨盘第二拍 | 一涨一缩同时落定,不画成谁推谁 | 搬 | 回执不记录谁让给谁;走、滑、长三个动作同时发生,不分先后,也不画从一块到另一块的线 |
| 拨盘 | 首次打开静 0.4 秒;切后 0.4 秒没有焦点 | 只在开片与三个停顿处搬 | 28 轮每轮都空 0.4 秒,就多出 11 秒空白 |
| 拨盘 | 游标在一个问题上停 19 轮 | 换成黑点 | 底片上一件事的黑点连着出现几格,就是问题开了几轮(最长是“派对回几个人?”f01–f22,21 轮) |
| 拨盘 | 概念层一直动、跨切点不断 | 不搬 | 见下面的占比 |
| 整理脉冲 | 余辉 | 搬 | 走掉的格子在原位留一个灰影再散掉:哪里空出来、哪里被填上看得见 |
| 整理脉冲 | 焦点最慢:周围越忙,焦点越稳 | 搬 | 快放时只有方阵、播放框和一个数在动,旁注只在三个停顿处换 |
| 整理脉冲 | 先整屏压暗 0.3 秒,再让一处成为唯一亮点 | 搬到第三拍 | 高潮时底片只留一对前后帧,其余压到七成 |
| 整理脉冲 | 一颗粒子就是一条事件 | 搬原则 | 描边的格数就是换手的格数,不多画一格 |
| 整理脉冲 | 每轮 4.25 秒、三层错拍时钟、黑底辉光、朱红 | 不搬 | 28 轮 × 4.25 秒是两分钟,复盘用不起;没有常驻的概念层就不需要错拍;纸白底是比较的底色;八种身份色里已有两种偏红,问题仍用黑点 |
概念层占多少
约一成,而且只在放映时出现:放映时动的东西里约一成是概念层,停下或放完就是零,画面回到今天的静帧。理由有三条:
- 读法不同。 拨盘和脉冲是官网首屏,给第一次看的人 20 秒;小倍数是复盘工具,盯着看几分钟、来回比较。一直在动的质感会和比较抢眼睛。
- 量已经有了。 那两页的概念层负责“量”(字形碎片、粒子云);小倍数一屏就是 29 × 64 = 1856 格真实份额,数据本身就是密度,再加质感只会让格子更难读。
- 它的价值在静。 动画只能是放映,不能改底片。
概念层只有两样,都用灰,都长在信息层的几何上:放大方阵里走掉的格子在原位留下的灰影(个数就是本轮让出的格数),和底片上播放框刚离开的两格外沿的淡灰拖尾(帮眼睛跟上换行与跨列)。
2 数据
口径
数字由本机脚本算出,脚本直接 import 页面自己的模块(variants/shared.mjs 的 records,即 engine.mjs 的 replayScenario;forms/sketches/live.mjs;forms/motion/dial-model.mjs),与页面同一份回放、同一套推导;脚本不入库。
| 量 | 来源字段与推导 |
|---|---|
| 件数、用 / 64、未分配 | records[i].state.root.items.length、state.root.used;未分配 = 64 − used。只看根层 |
| 份额轨迹 | 每帧 state.root.items[].share,不在根层记 0 |
| 前 8 件 | live.mjs 的 topRoots:根层累计份额(facts.cum,逐帧 active 根层 share 之和)最多的 8 件;短名取 scenario.categories[id].short |
| 换手 N | 相邻两帧的 64 格里最少有几格换了主人,未分配也算一个主人:对每件事与未分配求 Σ max(0, 本帧 − 上帧),即两帧份额向量 L1 距离的一半,也等于 max(长出, 让出)。与格子怎样排无关 |
| 位置变色 | 按今天的填法(multiples.mjs 的 cellsOf:排名顺序,空格在后),64 个位置里颜色类别(前 8 件各一类、其余灰、未分配)与上一帧不同的格数 |
| 问题 | currentAsk:ask 已登记,且登记时的条目版本 = 此刻的 updated_at;含子层。“关”“新”按 ask id 与上一帧比;怎样关上取 live.mjs 的 askPaths 与 pathStatus;你的回应写法取 actionSentence |
| 黑点 | 有问题开着的根层件数(页面今天的数法,multiples.mjs 的 data.asks) |
| 流 | live.mjs 的 streamOf:这件事所引输入里最多的 event.stream |
composite:前 8 件
| # | 事项 | 流 | 两周累计 | 在根层 | 峰值 | 最大的一次变动 | 逐帧份额(f00 起) |
|---|---|---|---|---|---|---|---|
| 1 | 母亲换水管 | 家庭 | 429 | 28 轮(f01–f28) | 24(f03 等 12 帧) | f23 24→6(−18) | 0 12 12 24 24 24 24 24 24 24 12 12 12 12 12 12 12 12 24 24 24 24 24 6 3 3 3 3 3 |
| 2 | 猫看病 | 家庭 | 195 | 28 轮(f01–f28) | 24(f22) | ±12:f01 0→12、f22 12→24、f23 24→12 | 0 12 12 12 12 3 1 1 1 1 1 1 1 1 1 6 3 3 12 12 12 12 24 12 12 12 6 6 3 |
| 3 | master CI | 工作 | 139 | 28 轮(f01–f28) | 12(f02) | ±6:f01 0→6、f02 6→12、f03 12→6 | 0 6 12 6 3 6 6 6 6 3 3 3 6 6 6 6 6 6 3 1 1 1 1 6 6 6 6 6 6 |
| 4 | 主水管 | 家庭 | 102 | 13 轮(f16–f28) | 24(f26、f27、f28) | f26 12→24(+12) | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 1 1 1 1 1 1 6 12 24 24 24 |
| 5 | 小龙虾派对 | 家庭 | 90 | 22 轮(f01–f28) | 6(f01 等 8 帧) | f01 0→6(+6) | 0 6 3 3 3 3 3 3 3 3 3 3 3 3 6 6 6 6 6 6 6 3 0 0 0 0 0 0 3 |
| 6 | NDEBUG | 工作 | 79 | 13 轮(f03–f15) | 12(f08、f09) | ±6:f08 6→12、f10 12→6 | 0 0 0 3 6 6 6 6 12 12 6 6 6 6 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 |
| 7 | 9/14 航班 | 生活 | 58 | 14 轮(f08–f21) | 6(f08 等 8 帧) | f08 0→6(+6) | 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 6 3 3 1 1 1 1 0 0 0 0 0 0 0 |
| 8 | 幼儿园开园 | 家庭 | 42 | 9 轮(f06–f14) | 6(f10 等 5 帧) | f15 6→0(−6) | 0 0 0 0 0 0 3 3 3 3 6 6 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 |
- 两周里单件最大的一次变动是母亲换水管 f23 24→6(−18),与拨盘 data.json 的
largestSingleYield一致。 - 28 轮里有 15 轮某件事占 24 份,正好是方阵的前三整行:母亲换水管 12 轮(f03–f09、f18–f22),猫看病 1 轮(f22,与母亲换水管同时,两件共 48 格、六行),主水管 3 轮(f26–f28)。前三行两周换过三个主人,都是家里的事。
- 按流(
streamOf):家庭的事两周占了有主格的 1031 / 1689(61%),家庭输入只占 388 / 3196(12%);工作的事占 576 格(34%),工作输入占 1676 条(52%)。28 轮里 27 轮家庭的格多于工作,唯一的例外是 f02(工作 34、家庭 27)。这是“按流”配色要讲的事,动画不另讲。
composite:逐轮
“问题”一列是开着的问题数(上一帧→本帧),括号里是本轮关上与新登记的个数;composite 的黑点数与问题数逐帧相同。
| 帧 | 时刻 | 旁白 frame.title | 件数 | 用 / 64 | 换手 N | 位置变色 | 问题 | 本轮最大的变动 |
|---|---|---|---|---|---|---|---|---|
| f00 | 8/3 00:00 | 还没有整理过任何输入 | 0 | 0 | — | — | 0 | — |
| f01 | 8/3 12:00 | 母亲来电、猫打喷嚏,#13350 等复审 | 10 | 57 | 57 | 57 | 0→5(新 5) | 母亲换水管 0→12;猫看病 0→12;master CI 0→6 |
| f02 | 8/4 00:00 | master CI 变红,答应母亲的电话没打 | 13 | 64 | 18 | 46 | 5→6(新 1) | master CI 6→12;定时器重构 0→6;小龙虾派对 6→3 |
| f03 | 8/4 12:00 | 母亲楼里换水管:14 日前选住处 | 13 | 63 | 18 | 25 | 6→7(关 1、新 2) | 母亲换水管 12→24;master CI 12→6;etag 修复 6→3 |
| f04 | 8/5 00:00 | 他开 #13484;Kajsa 嫌六周太长 | 14 | 64 | 4 | 10 | 7→8(新 1) | master CI 6→3;NDEBUG 3→6;vdns 搬迁 0→1 |
| f05 | 8/5 12:00 | 约好兽医,vdns 合并 | 14 | 58 | 10 | 33 | 8→6(关 2) | 猫看病 12→3;master CI 3→6;vdns 搬迁 1→0 |
| f06 | 8/6 00:00 | 回环连接提速;Göran 说九月来抬棚屋 | 17 | 64 | 12 | 15 | 6→7(新 1) | 定时器重构 6→3;抬棚屋 0→3;回环提速 0→3 |
| f07 | 8/6 12:00 | #13500 cookie 修复,CI 全红 | 18 | 64 | 6 | 18 | 7→7 | PSL cookie 0→6;抬棚屋 3→1;H2 push 3→1 |
| f08 | 8/7 00:00 | 最忙的一天,航班改经拉纳卡 | 16 | 64 | 14 | 26 | 7→8(新 1) | PSL cookie 6→0;NDEBUG 6→12;9/14 航班 0→6 |
| f09 | 8/7 12:00 | 母亲办不了 BankID;#13513 接替 #13484 | 17 | 64 | 3 | 14 | 8→7(关 1) | master CI 6→3;头虱 0→3 |
| f10 | 8/8 00:00 | 可以改签当天晚些的直飞 | 18 | 50 | 18 | 49 | 7→7(关 1、新 1) | 母亲换水管 24→12;NDEBUG 12→6;幼儿园开园 3→6 |
| f11 | 8/8 12:00 | 周六上午:猫在番茄盆里刨土 | 19 | 51 | 1 | 12 | 7→6(关 1) | EDNS 0→1 |
| f12 | 8/9 00:00 | 8.22.0-rc1 发布,功能冻结 | 21 | 63 | 13 | 24 | 6→7(新 1) | rc1 0→6;master CI 3→6;钓鱼短信 0→3 |
| f13 | 8/9 12:00 | 回城日:rc1 的接缝 | 23 | 64 | 4 | 9 | 7→7 | rc1 6→3;Windows 支持 0→3;骑车 0→1 |
| f14 | 8/10 00:00 | 回城,给母亲打了 24 分钟电话 | 21 | 62 | 6 | 11 | 7→7 | NDEBUG 6→3;小龙虾派对 3→6;拼写检查 1→0 |
| f15 | 8/10 12:00 | 周一上午:看兽医,#13528 请他评审 | 25 | 62 | 12 | 23 | 7→8(新 1) | 幼儿园开园 6→0;猫看病 1→6;NTLM 复用 0→3 |
| f16 | 8/11 00:00 | 车道边是湿的;不改签 | 23 | 61 | 14 | 26 | 8→7(关 2、新 1) | 开学文件 0→6;猫看病 6→3;9/14 航班 6→3 |
| f17 | 8/11 12:00 | 评审排队:#13528、#13530 | 26 | 64 | 3 | 3 | 7→7 | header API 0→1;合并 8/11–13 0→1;牙医 0→1 |
| f18 | 8/12 00:00 | 猫可能吃了双倍抗生素 | 19 | 64 | 26 | 38 | 7→5(关 3、新 1) | 母亲换水管 12→24;猫看病 3→12;开学文件 6→3 |
| f19 | 8/12 12:00 | 诊所回电没接到 | 19 | 64 | 6 | 8 | 5→6(新 1) | 机票退款 0→3;Ture 发烧 0→3;开学文件 3→1 |
| f20 | 8/13 00:00 | Ture 发烧被接回,Kajsa 的后刹失灵 | 18 | 64 | 6 | 14 | 6→6(关 1、新 1) | 后刹 0→6;机票退款 3→0;漫画 3→1 |
| f21 | 8/13 12:00 | #13567:复用防护可被绕过 | 19 | 62 | 9 | 9 | 6→6(关 1、新 1) | 复用绕过 0→6;后刹 6→1;小龙虾派对 6→3 |
| f22 | 8/14 00:00 | 热浪第一天:药量超过失明线 | 11 | 64 | 19 | 18 | 6→5(关 3、新 2) | 猫看病 12→24;复用绕过 6→0;待审 PR 0→6 |
| f23 | 8/14 12:00 | 打了诊所;母亲自己定了 | 11 | 39 | 30 | 64 | 5→3(关 3、新 1) | 母亲换水管 24→6;猫看病 24→12;master CI 1→6 |
| f24 | 8/15 00:00 | 车道边湿了一整周 | 15 | 51 | 15 | 31 | 3→3 | 主水管 1→6;母亲换水管 6→3;骑车 0→3 |
| f25 | 8/15 12:00 | 周六早上:水表在转 | 14 | 52 | 6 | 37 | 3→3 | 主水管 6→12;骑车 3→0;FTPS 计时 3→1 |
| f26 | 8/16 00:00 | 车道下的铜管裂了 | 14 | 63 | 19 | 42 | 3→5(新 2) | 主水管 12→24;猫看病 12→6;FTPS 计时 1→6 |
| f27 | 8/16 12:00 | 周日上午:Kajsa 算账 | 14 | 63 | 0 | 0 | 5→5 | 一格没动 |
| f28 | 8/17 00:00 | 两周结束:水管还没回 | 14 | 64 | 8 | 13 | 5→7(新 2) | 开学文件 1→6;待审 PR 6→3;猫看病 6→3 |
composite:三个问题的回答
- 前 8 件的轨迹与最大的一次变动:见上面的前 8 件表。母亲换水管两次占满前三行(f03–f09、f18–f22),中间退到一行半(f10–f17),f23 一次让出 18 格;主水管从 f16 的 3 份起,f24–f26 连长三轮(1→6→12→24)。
- 格子在哪几轮变得最多:按换手 N,是 f01 57(从空长出)、f23 30、f18 26、f22 19、f26 19、f02 / f03 / f10 各 18;按今天的位置变色,是 f23 64、f01 57、f10 49、f02 46、f26 42、f18 38。28 轮里一半(14 轮)换手不超过 10 格,f27 一格没动(合计 357 格,中位 11)。换手 18 格以上的 8 轮里,除了起步的 f01 和工作上的 f02(master CI 6→12、定时器重构 0→6),其余 6 轮都是家里一件事整块变大或变小 12 份以上。
- 哪一轮开着的问题最多:f04、f08、f15,各 8 个;最少是 f23–f25 的 3 个。f23 一轮关上 3 个(“Smilla 多吃了药:打诊所?”:你给诊所打了电话;“#13572 堵复用绕过:批准?”:你在 GitHub 上批准了 #13572;“母亲九月住哪?”:f03 登记、期限 8/14 23:59,开了 20 轮后改写失效),新登记 1 个(“三个旧 PR 推到哪天?”)。两周结束时(f28)仍开着 7 个。
story:前 8 件与逐轮
story 没有 stream,“按流”配色禁用。10 件事到过根层,前 8 件占有主格的 98.6%,灰几乎不出现。
| # | 事项 | 两周累计 | 在根层 | 峰值 | 最大的一次变动 | 逐帧份额(cold-00 起) |
|---|---|---|---|---|---|---|
| 1 | 试用 | 438 | 34 轮(f01–f34) | 24(f05 等 7 帧) | f15 24→6(−18) | 0 0 0 12 12 12 12 24 24 12 12 12 12 12 24 24 24 6 6 6 6 12 12 12 24 24 12 12 6 6 6 6 12 12 12 12 6 |
| 2 | 妈妈 | 351 | 35 轮(cold-02–f34) | 24(f15 等 4 帧) | f19 24→6(−18) | 0 0 6 6 6 6 12 12 12 12 12 12 12 12 12 12 12 24 24 24 24 6 6 6 6 3 3 3 3 3 3 3 12 12 12 12 6 |
| 3 | 发布 | 324 | 36 轮(cold-01–f34) | 24(f25、f26、f27) | f25 6→24(+18) | 0 6 12 12 12 12 12 6 6 3 6 6 6 12 12 12 12 3 3 3 3 12 6 6 6 6 6 24 24 24 12 12 6 6 6 6 3 |
| 4 | 筛选 | 264 | 30 轮(f01–f30) | 24(f07) | ±12:f07 12→24、f08 24→12 | 0 0 0 6 12 12 12 12 12 24 12 12 12 12 6 6 6 6 6 6 6 6 6 6 6 12 12 6 6 6 6 6 6 0 0 0 0 |
| 5 | 厨房 | 180 | 32 轮(f03–f34) | 12(f09 等 8 帧) | f09 3→12(+9) | 0 0 0 0 0 3 3 3 3 3 3 12 12 12 6 6 6 6 12 12 12 12 12 6 6 3 3 3 3 3 3 3 3 3 1 1 1 |
| 6 | 费用 | 166 | 31 轮(f04–f34) | 12(f20 等 9 帧) | f20 1→12(+11) | 0 0 0 0 0 0 6 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 12 6 6 6 6 6 3 |
| 7 | 链路 | 91 | 25 轮(f01–f34) | 12(f28、f29、f30) | f31 12→3(−9) | 0 0 0 1 1 1 1 1 1 6 3 3 0 0 0 0 0 0 0 0 0 3 3 3 3 1 1 1 6 6 12 12 12 3 3 3 1 |
| 8 | 苏禾 | 69 | 25 轮(f01–f34) | 12(f33、f34) | f33 3→12(+9) | 0 0 0 3 3 3 3 3 3 1 1 1 0 0 0 0 0 0 0 0 0 3 1 1 1 1 1 1 1 1 1 3 3 3 3 12 12 |
“问题”一列先写全部问题(上一帧→本帧,括号里是关上与新登记),再写页面今天按件数画出的黑点数。
| 帧 | 时刻 | 件数 | 用 / 64 | 换手 N | 位置变色 | 问题(全部 · 黑点) | 本轮最大的变动 |
|---|---|---|---|---|---|---|---|
| cold-00 | 10/12 08:30 | 0 | 0 | — | — | 0 · 0 | — |
| cold-01 | 10/12 08:42 | 1 | 6 | 6 | 6 | 0→1(新 1) · 1 | 发布 0→6 |
| cold-02 | 10/12 08:52 | 2 | 18 | 12 | 12 | 1→2(新 1) · 2 | 发布 6→12;妈妈 0→6 |
| f01 | 10/12 09:10 | 8 | 49 | 31 | 37 | 2→6(关 2、新 6) · 4 | 试用 0→12;账单 0→6;筛选 0→6 |
| f02 | 10/12 13:40 | 8 | 55 | 6 | 40 | 6→6 · 4 | 筛选 6→12 |
| f03 | 10/12 20:30 | 9 | 58 | 3 | 7 | 6→6 · 4 | 厨房 0→3 |
| f04 | 10/13 09:20 | 8 | 61 | 12 | 61 | 6→6(关 2、新 2) · 4 | 妈妈 6→12;账单 6→0;费用 0→6 |
| f05 | 10/13 14:40 | 8 | 64 | 12 | 61 | 6→6(关 3、新 3) · 3 | 试用 12→24;发布 12→6;费用 6→3 |
| f06 | 10/13 18:20 | 8 | 64 | 0 | 0 | 6→6 · 3 | 一格没动(检查) |
| f07 | 10/14 09:10 | 8 | 62 | 19 | 52 | 6→4(关 2) · 3 | 试用 24→12;筛选 12→24;链路 1→6 |
| f08 | 10/14 18:10 | 8 | 50 | 15 | 50 | 4→4 · 3 | 筛选 24→12;链路 6→3;发布 3→6 |
| f09 | 10/15 09:40 | 8 | 59 | 9 | 59 | 4→6(新 2) · 4 | 厨房 3→12 |
| f10 | 10/15 14:30 | 6 | 55 | 4 | 5 | 6→5(关 1) · 3 | 链路 3→0;苏禾 1→0 |
| f11 | 10/15 21:00 | 6 | 61 | 6 | 61 | 5→5(关 2、新 2) · 4 | 发布 6→12 |
| f12 | 10/16 10:00 | 6 | 61 | 12 | 60 | 5→4(关 4、新 3) · 3 | 试用 12→24;厨房 12→6;筛选 12→6 |
| f13 | 10/16 17:40 | 6 | 61 | 0 | 24 | 4→2(关 2) · 2 | 一格没动(只是重排) |
| f14 | 10/16 21:20 | 6 | 61 | 0 | 0 | 2→2 · 2 | 一格没动(检查) |
| f15 | 10/17 10:00 | 6 | 46 | 27 | 58 | 2→2(关 1、新 1) · 2 | 试用 24→6;妈妈 12→24;发布 12→3 |
| f16 | 10/17 21:30 | 6 | 52 | 6 | 22 | 2→4(新 2) · 3 | 厨房 6→12 |
| f17 | 10/18 08:00 | 6 | 52 | 0 | 0 | 4→4 · 3 | 一格没动(定时) |
| f18 | 10/18 17:20 | 6 | 52 | 0 | 0 | 4→2(关 3、新 1) · 2 | 一格没动 |
| f19 | 10/19 09:10 | 8 | 55 | 21 | 37 | 2→4(新 2) · 4 | 妈妈 24→6;发布 3→12;试用 6→12 |
| f20 | 10/19 15:30 | 8 | 58 | 11 | 34 | 4→5(关 1、新 2) · 4 | 费用 1→12;发布 12→6;苏禾 3→1 |
| f21 | 10/19 20:50 | 8 | 52 | 6 | 28 | 5→4(关 1) · 3 | 厨房 12→6 |
| f22 | 10/20 09:40 | 8 | 64 | 12 | 52 | 4→6(关 1、新 3) · 3 | 试用 12→24 |
| f23 | 10/20 14:00 | 8 | 62 | 8 | 27 | 6→6 · 3 | 筛选 6→12;厨房 6→3;妈妈 6→3 |
| f24 | 10/20 19:30 | 8 | 50 | 12 | 50 | 6→1(关 5) · 1 | 试用 24→12 |
| f25 | 10/21 09:15 | 8 | 62 | 18 | 62 | 1→2(新 1) · 2 | 发布 6→24;筛选 12→6 |
| f26 | 10/21 17:30 | 8 | 61 | 6 | 7 | 2→1(关 1) · 1 | 试用 12→6;链路 1→6 |
| f27 | 10/22 08:00 | 8 | 61 | 0 | 0 | 1→1 · 1 | 一格没动(定时) |
| f28 | 10/22 10:20 | 8 | 55 | 12 | 31 | 1→3(新 2) · 2 | 发布 24→12;链路 6→12 |
| f29 | 10/22 18:40 | 8 | 51 | 6 | 25 | 3→3(关 1、新 1) · 2 | 费用 12→6;苏禾 1→3 |
| f30 | 10/23 09:40 | 8 | 60 | 15 | 60 | 3→4(关 1、新 2) · 3 | 妈妈 3→12;发布 12→6;试用 6→12 |
| f31 | 10/23 18:20 | 7 | 45 | 15 | 36 | 4→2(关 2) · 2 | 链路 12→3;筛选 6→0 |
| f32 | 10/24 10:30 | 7 | 43 | 2 | 8 | 2→2 · 2 | 厨房 3→1 |
| f33 | 10/24 20:00 | 7 | 52 | 9 | 40 | 2→2(关 1、新 1) · 2 | 苏禾 3→12 |
| f34 | 10/25 19:40 | 7 | 32 | 20 | 34 | 2→2(关 1、新 1) · 2 | 试用 12→6;妈妈 12→6;费用 6→3 |
- 最大的一次变动:三件并列 18 份:试用 f15 24→6、妈妈 f19 24→6、发布 f25 6→24。36 轮里也有 15 轮某件事占前三行:试用 7 轮、妈妈 4 轮(f15–f18)、发布 3 轮(f25–f27)、筛选 1 轮(f07)。
- 格子在哪几轮变得最多:按换手 N,是 f01 31、f15 27、f19 21、f34 20、f07 19、f25 18(合计 353,中位 9);按今天的位置变色,是 f25 62、f04 / f05 / f11 61、f12 / f30 60(合计 1146,是换手的 3.2 倍:story 件少块大,排名一换就整片移位)。一格没动的 6 轮里,f13 份额一格没变,位置变色却有 24 格,全是同份额按最近更新的重排。
- 哪一轮开着的问题最多:按全部问题数,是 6 个,在 f01–f06、f09、f22、f23;页面今天按件数只画到 4 个(f01–f04、f09、f11、f19、f20)。最少是 1 个(cold-01、f24、f26、f27)。
两套对照
| composite | story | |
|---|---|---|
| 帧 / 轮 | 29 / 28 | 37 / 36 |
| 到过根层的件数 | 60 | 10 |
| 底片上有主的格 | 1689 / 1792 | 1910 / 2304 |
| 前 8 件占有主的格 | 1134(67%) | 1883(98.6%) |
| 换手 N:合计 / 中位 / 最大 | 357 / 11 / 57(f01) | 353 / 9 / 31(f01) |
| 起步之后换手最多的一轮 | f23 30(未分配 0→25) | f15 27(未分配 3→18) |
| 位置变色合计(今天的填法) | 675 | 1146 |
| 某件占 24 份(前三行)的轮数 | 15 | 15 |
| 开着的问题最多 | 8(f04、f08、f15) | 6(f01–f06、f09、f22、f23);黑点最多 4 |
| 单件最大的一次变动 | 母亲换水管 f23 −18 | 试用 f15 −18、妈妈 f19 −18、发布 f25 +18 |
3 故事
论点。 注意力不是慢慢漂的,是成块挪的:多数轮只换手几格;少数几轮,一件家里的事整块占走前三行,或整块放下,放下的地方空着,不被别的事填满。
英雄数字:本轮换手的格数 N(composite 每轮 0–57,中位 11)。它是唯一直接量“移动”的数:每轮的存量(件数、用了几份)几乎不变,N 却大起大落,这种不对称就是论点。它与格子怎样排无关,所以不受重排干扰。静帧样张取 f23:换手 30(其中 25 格空出来)。
- 位置与字:放在此刻方阵右边,字高约为方阵边长的三分之一(约 50 px),等宽、墨色,下面一行小字“换手 · 格”;f00 写“—”。停着时也一直在,补上“哪里讲不动”第 5 条。
- 什么时候变:每轮在格子落定的那一刻翻一次,不滚动、不预告。
- 回声:同一刻,放大方阵和底片上当前那一格里,换了主人的 N 格加一圈墨线:每件长大的事末尾新长的几格,加上新空出来的格(空格在后,取紧挨着已分配部分的那几格)。按 N 的定义,这两部分加起来正好是 N 格;数、放大方阵、底片三处同一帧说同一件事。
兼顾:底片一格不动。 29 个小方阵的位置、尺寸、填法与配色在放映前后完全相同。未播的帧不隐藏、不变淡:变淡会和“悬停时其余变淡”混淆,变成空格会冒充未分配。放映只加四样:播放框(每轮一帧硬切到下一格)、当前格的换手描边、第三拍的压暗、概念层的灰影与拖尾;放完或停下,这些都收掉,画面就是今天的静帧,播放框停在最后一帧。放大方阵就是播放框里那一格放大,填法相同,两层共用同一套 8×8。高潮停在一对并排的静帧上:f22 与 f23 在 8/14 同一行左右相邻,第三拍把其余 27 格压到七成。动画的最后一拍,是一次同尺度比较。
三拍(composite 约 24 秒;括号里是 story,约 28 秒。帧号写在页面代码里,按数据集各一组,同拨盘的做法)
| 拍 | 时长与帧 | 发生什么 | 观众此刻 | 放大方阵 / 底片 / 面板 |
|---|---|---|---|---|
| 1 填满 | 0–4.6 秒,f00→f03(cold-00→f05,约 6 秒) | 静 0.4 秒;f01 的 57 格从左上按排名逐格长出(每格 20 ms),母亲换水管、猫看病各 12;f02 补满 64;f03 母亲换水管长到 24,正好前三行,停 2 秒 | 这是一张 64 格的尺子,大事整块占行 | 计数 57、18、18;f03 旁注“母亲换水管 · 24 格 · 前三行” / 播放框 f00→f03 / 问题 0→5→6→7 |
| 2 整块挪 | 4.6–17.0 秒,f04→f22 每轮 0.6 秒,f22 落定后多停 1 秒(f06→f14) | 19 轮里 10 轮换手不到 10 格;f10 母亲换水管 24→12,空出 14 格;f18 又回到 24、猫看病 3→12,换手 26;f22 猫看病也到 24,两件家里的事占 48 格、六行 | 大多时候只换几格;家里的事一来就是一大块 | 计数逐轮翻:4 10 12 6 14 3 18 1 13 4 6 12 14 3 26 6 6 9 19;f22 旁注“母亲换水管 24 · 猫看病 24” |
| 3 放下 | 17.0–24.0 秒,f23 走完整一轮 4 秒,再 f24→f28 每轮 0.6 秒(f15 一轮 4 秒,f16→f34 每轮 0.6 秒) | 旁白“打了诊所;母亲自己定了”;母亲换水管 24→6、猫看病 24→12,30 格换手,25 格空出来,两周最多;开着的问题 5→3,两周最少;之后主水管 6→12→24 重新占满前三行(f26),f27 一格没动,停在 f28“两周结束:水管还没回” | 放下了,空出来的就空着;然后下一件又来 | 计数 30,旁注“空出 25 格”;问题面板划掉三行(你给诊所打了电话……);底片只留 f22、f23 两格,其余压到七成 / f27 计数 0 |
story 的三拍:拍 1 到 f05 停 2 秒(试用 12→24,第一次占满前三行,也是第一次用满 64);拍 2 的 f06→f14 里有三轮一格没动(f06、f14 是检查,f13 只是重排),f07 筛选接走前三行,f12 试用拿回来,f14 停 1 秒;拍 3 的 f15 是“陪妈妈改约周日11点,双方已确认”:妈妈 12→24、试用 24→6、发布 12→3,换手 27,空出 15(3→18),底片只留 f14、f15(上下相邻两行);之后快放到 f34,停在两周里最空的一帧(未分配 32)。
一轮怎样走。
- 快放(0.6 秒):0 切点,播放框硬切到下一格,日期与旁白翻,上一轮的描边撤掉 → 0–0.3 秒三件事同时发生:走的格子褪成灰影,留下的滑到新位置,新来的在终点长出(ease-out,过冲不超过 4%)→ 0.3 秒英雄数字翻、N 格描边出现、黑点落下 → 0.3–0.6 秒静。
- 停顿:f03 与 f22 照快放走完,再多停 1.4 秒与 1 秒,旁注在 0.6 秒出现。f23(story 的 f15)走完整一轮 4 秒:0 切点 → 0–0.4 秒没有焦点 → 0.4–1.0 秒同样的三件事放慢 → 1.0 秒数字与描边 → 1.3 秒旁注(本轮最大的两三处变化,用短名)与问题面板的增删 → 1.6–1.9 秒底片压暗 → 静到 4.0 秒,下一轮切点撤掉压暗。
- 第一个动作:开片静 0.4 秒后,放大方阵左上第一格长出来(f01 的母亲换水管),小、贴着锚点,再按排名一格一格铺开;f01 从空长出 57 格,这一轮用 1.6 秒,计数在最后一格落定时出现。
两层,叠而不打架。
- 信息层(约九成,只在节拍上动):29 个小方阵与播放框、放大方阵、英雄数字与描边、黑点、日期与旁白、问题面板、前 8 件走势里的“此刻”线。每个数在第 2 节有出处,页面用同一推导现算。
- 概念层(约一成,只在放映时有):灰影,即走掉的格子在原位留下的灰框(快放 0.4 秒、停顿 0.6 秒散掉);拖尾,即播放框刚离开的两格外沿一圈淡灰(两轮内散掉)。只用灰,不出字、不出数、不带身份色,不进英雄数字与面板。
- 规则:灰影画在格子下面;灰影只在真有格子走掉时出现,个数等于本轮让出的格数;不画任何从一块到另一块的线;第三拍压暗时,概念层一起降。
动起来之前的约束。
- 绝不动:底片 29 格的位置、尺寸、填法与配色;8 种身份色的归属(两周累计排定,不随播放变);“空格 = 未分配”这个含义。
- 每轮只动一次:放大方阵落定、英雄数字、描边、黑点。
- 描边的格数 = 英雄数字;灰影的格数 = 本轮让出的格数;不画回放里没有的格子。
- 一个黑点 = 一个开着的问题:一件事有几个问题,就在它的前几格点几个(只有 story 会出现);问题计数也按问题数,不按件数。黑点仍是黑的,朱红在这里会撞上两种偏红的身份色。
- 不承载作答;只读
scenario.mjs回放,不为动画加字段,不改契约。 - 放映时整张底片要在一屏里:页头收成一行(1440×900 下 composite 要省出约 50 px,story 约 110 px);还不够时,旁注行收起,悬停才出现。
prefers-reduced-motion:不滑、不留灰影与拖尾,每轮直接切到终态,节拍不变。
交互(与拨盘、脉冲同一套标准;触发、节拍与收回用 motion/ix.mjs,它正由另一个代理从两页里抽出来,小倍数只提供自己的几何)
- 悬停一帧
- 触发:小方阵下的时刻、右边的旁注行,或小方阵的边框(格子之外);Tab 到小方阵;触屏轻点一下就是悬停。
- 出什么:概要卡,纸底、墨框、等宽字,与拨盘同一套:帧号与时刻;旁白;“换手 30 格 · 空出 25”;“11 件 · 用 39 / 64 · 3 个问题开着”;本轮最大的三处变化(“母亲换水管 24→6 · 猫看病 24→12 · master CI 1→6”);本轮关上与新登记的问题,关上的写成你的动作(“你给诊所打了电话”“你在 GitHub 上批准了 #13572”“母亲九月住哪?改写后失效”)。这一格同时显出它的 N 格描边,和放映时一样;底片其余不变。
- 悬停一格
- 触发:小方阵或放大方阵里的格子、图例与问题面板里的一行。
- 出什么:上面那张卡下面加这一件:“母亲换水管 · 家庭 · 本帧 6 份(24→6)· 两周累计 429 格”,以及它此刻开着的问题与期限。这件事在 29 格里同时亮起、其余格变成浅灰,放大方阵里同一件也亮。这里保留今天的做法,比拨盘的“其余降到七成”更强:要在 29 格里追一件事,七成不够。
- 两种悬停在放映时都让时钟停在当前时刻:离开后宽限 0.15 秒,卡 0.12 秒淡出,再过 0.4 秒接着放。卡上的数守本轮节拍:停在格子落定之前,只写“这一轮还在动”,不提前给 N。
- 展开那一件
- 触发:点小方阵或放大方阵里的一格,或概要卡上的条目名、问题面板与图例里的一行;Tab 到后按 Enter。
- 动什么:0 秒是切点:放映停住,播放框硬切到被点的那一帧,底片锁定这一件的轨迹(其余浅灰,直到收回),此刻面板的标题改成“这一件 · f23 · 8/14 12:00 / 母亲换水管”。0–0.3 秒,放大方阵里这件事的格子沿“方阵中心 → 这块重心”的方向整体外推 8 px(ease-out,过冲 3.7%;重心离中心不到一格时向下推,朝向面板),其余格降到七成。0.4–0.6 秒,从这块离面板最近的一格引出引线,先沿格缝(格与格之间 2 px 的缝)走到方阵下沿,再直下到面板上沿。0.6–0.9 秒,“这一件”面板从引线末端展开,先竖后横,替换此刻文字、开着的问题与前 8 件三块。
- 收回:Esc、点空白、再点同一件:面板 0.2 秒收起、引线 0.15 秒缩回、格子 0.2 秒落回,一帧切回三块面板,底片解除锁定;之前在放映的,0.4 秒后接着放。点另一件,先收回再展开那一件。
- ←/→ 不收起:这一件留着,逐帧走它的历史。面板一帧硬切到新帧的这一件,外推的块跟着到新位置;这一帧它不在根层时,面板写“这一帧不在根层”,引线收起。这一点与拨盘不同(拨盘按 ←/→ 先收起),因为复盘最常做的就是逐帧看一件事,今天的详情抽屉也是这样。空格、选帧与合页顶栏选帧会收起并照常执行。
prefers-reduced-motion时直接到终态。
- 面板“这一件”,从上到下:
- 头:短名、流、本帧份额与变化(“6 份 · 24→6 变小”)、两周累计(429)。
- 摘要:本帧版本,两行;有子层时列出子层与份额(story)。
- 份额逐帧:29 根小条(0–24),本帧加墨框,有问题开着的帧在条顶点一个黑点。这一行就是这件事两周的移动,与底片上它亮起的 29 格一一对应。
- 本轮进了它的输入:条数,加至多 5 条(来源 · 标题截断),取
dial-model.mjs的itemFacts(i, id).inputs(按relatedIds)。 - 问题:这件事登记过的每条回应路径,按时间排:问法、哪一帧登记、期限、开了几轮、怎样关上、在哪一帧关上(答后关上 / 改写后失效 / 换成新问题 / 随事项撤下 / 随事项并入),以及你的回应(
actionSentence,不贴原文)。关上的问题旁是“看那一轮 →”:播放框跳到关上的那一帧,这一件留着。例:“母亲九月住哪? · f03 登记 · 期限 8/14 23:59 · 开了 20 轮 · f23 改写后失效”。 - 折叠:版本与站、来源原文(看原文)、原始 JSON,沿用今天抽屉
dossierHTML的内容。
- “去回答 →”:只给两周结束时(composite 的 f28,story 的 f34)仍开着的问题,链到最后一帧的 D 手机首页(
../index.html?variant=d&frame=28),字样写“去回答 · 8/17 00:00 仍开着 →”。例:“主水管:挖开换还是免挖?”(f26 登记,期限 8/17 10:00)。composite 末帧仍开着 7 个,story 2 个。理由:小倍数是唯一同时看得见每一帧“之后”的形式。读者在 f08 点开母亲换水管时,已经看得见这个问题在 f23 失效了,再给“去回答”就自相矛盾;复盘发生在两周之后,能回答的只剩最后一帧还开着的。这与拨盘、脉冲的“同一帧的 D”不同,列在下面待定。
键盘与入口。 空格放映或暂停:从当前帧放到最后一帧,在最后一帧按空格就从开头重放。←/→ 逐帧:停住放映,按快放的 0.6 秒走一轮。Home / End 到头尾;C 切换配色,放映照常,描边按当前排法画;?play=1 打开即放一遍,供演示与截图。默认不自动放映,画廊与合页里也不放;合页顶栏选帧会让放映停下并跳到那一帧。
拿不准、要你定的。
- 底片的排法要不要动。今天同份额按最近更新排在前,份额没变也会重排:composite 的 f11 换手 1,却有 17 格换了主人;story 的 f13 换手 0,位置变色 24。建议改成同份额按首次出现排:静帧几乎看不出差别,放映时这类空转没了(composite 941→867、story 1149→1124 次位置换主;f11 17→1,f17 16→3,story f13 24→0)。再进一步,“前 8 件按名次固定从左上排、其余从右下倒着排、空格夹在中间”能降到 724,但左上就不再是此刻最大的那件,改的是静帧的读法。本文的故事按今天的排法写,不依赖这项改动。
- “去回答 →”链到哪一帧:最后一帧(本文的选择)还是同一帧(拨盘、脉冲的标准)。
审阅的决定见第 4 节开头:第 1 条改成同份额按首次出现排;第 2 条链到同一帧,但只给开到最后的问题。
4 动画(motion)
审阅后定下的
- 排法只改一处:同份额并列时按首次出现排(
motion/dial-model.mjs的orderOf:最早出现的帧,再按那一帧的排名),不把前 8 件固定在左上。份额从大到小仍在左上,静帧几乎看不出差别;逐位置换主人的格数 composite 941 → 867、story 1149 → 1124,空转的几轮没了:composite f11 17 → 1、f17 16 → 3,story f13 24 → 0(页面按新排法现算,与第 3 节的估算一致)。 - “去回答 →”链到被点那一帧的 D(
../index.html?variant=d&frame=<i>,带上数据集,与拨盘、脉冲同写法),只给这一帧开着、而且一直开到两周结束的问题;之后答掉或失效的不给链接,卡上注一句“之后在 f23 关上 · 改写后失效”(怎样关上取live.mjs的pathStatus,答掉的写成你的动作)。不链到最后一帧。 - 问题按含子层的口径数:一个开着的问题一个黑点,点在它所属根层事项的前几格;右栏的计数、面板与卡片都按问题数,story 的 f01 是 6 个(以前画 4 个)。同一个问题同时登记在一件事和它的子项上(story 的 f01–f04 有两对:“导出模板是否允许编辑?”“周六什么时候见妈妈?”),面板里合成一行写“×2”,黑点仍是两个。
- 自动放映:只在顶层直接打开、地址不带
?frame=时放一遍;任意键跳过(停在最后一帧,那个键不再做别的事),“▶ 放一遍”从头重放。带?frame=、画廊缩略图、合页 all.html 与体验站弹框里的嵌入、从别处链来的(站内链接都带frame)一律静止。外壳在形式载入前就给地址补上?frame=,所以multiples.html在页头先记下打开时的地址(window.foldEntry)。 - 交互接
motion/ix.mjs,不另写:时序用IX的常数,卡片用 ix 的结构与类名,钩子window.foldMultiples与foldDial同名同义(player、rounds、hold、startPlay、startHero、perf、resetPerf、geom与 ix 的hover / unhover / open / close / ixAt / ix / paused / pointOf / ixState),另有startShow、skip、freeze(t)、setMode、plan()。 - 换帧走节拍过渡:←/→、Home/End、顶栏的 ‹ › 与刻度、合页
followFrames同步都演一轮 0.6 秒的过渡(走的褪成灰影、留下的滑过去、新来的长出,0.3 秒落定);跨好几帧的跳转也演这三件事,描边与数字给目标帧自己的 N。 - 两套数据都能演:节拍按数据集各写一组帧号(composite f03 / f22 / f23,story f05 / f14 / f15),别的数据集按 N 最大的一轮自动取第三拍。
时间线(页面 foldMultiples.plan())
| 段 | composite | story | 发生什么 |
|---|---|---|---|
| 开片 | 0–0.4 秒,f00 | 0–0.4 秒,cold-00 | 静 |
| 第一拍 · 填满 | 0.4–4.58 秒:f01 从空长出 57 格(每格隔 20 ms、各长 0.2 秒,这一轮 1.58 秒),f02、f03 各 0.6 秒,f03 再停 1.4 秒 | 0.4–6.6 秒:cold-01 长出 6 格,到 f05 再停 1.4 秒 | f03 旁注“母亲换水管 · 24 格 · 前三行” |
| 第二拍 · 整块挪 | 4.58–16.98 秒:f04–f22 每轮 0.6 秒,f22 再停 1 秒 | 6.6–12.4 秒:f06–f14,f14 再停 1 秒 | f22 旁注“母亲换水管 24 · 猫看病 24” |
| 第三拍 · 放下 | 16.98–20.98 秒 f23 一轮 4 秒,再 f24–f28 每轮 0.6 秒,23.98 秒到末帧 | 12.4–16.4 秒 f15,再 f16–f34,27.8 秒到末帧 | 0.4–1.0 秒放慢的三件事;1.0 秒数字 30 与 30 格墨框;1.3 秒旁注“空出 25 格 · 母亲换水管 24→6 · 猫看病 24→12 · master CI 1→6”,问题面板划掉三行;1.6–1.9 秒其余 27 格压到七成 |
| 收尾 | 再 0.6 秒:拖尾与底片上的墨框淡出,回到静帧 | 同左 | 播放框停在末帧 |
一轮 0.6 秒:0 切点(播放框硬切、日期与旁白翻、上一轮的墨框撤掉,数字与计数仍是上一轮的)→ 0–0.3 秒走的格子先褪成灰影(0.15 秒),灰影 0.4 秒内散掉,留下的滑到新位置(ease-out),新来的在终点长出(过冲 3.7 %)→ 0.3 秒数字翻、N 格墨框出现(放大方阵与底片当前那一格同时)、黑点落下、面板换成这一轮 → 静到 0.6 秒。整段由一个放映时钟驱动(requestAnimationFrame 里按分段表现算位置),悬停停表、定格(freeze(t))与 ?slow= 都只动这一个时钟,任意时刻的静帧都一样。prefers-reduced-motion 时不滑、不留灰影与拖尾,每轮在切点直接到终态,节拍不变。
两层落在哪里
- 底片不动:29 个小方阵每种配色只建一次,放映不重绘它们。放映加的东西画在底片上面的一层 SVG 里(播放框、拖尾、当前那一格的 N 格墨框),第三拍的压暗是 27 个方阵的不透明度;放完这一层清空、压暗撤掉,画面就是静帧。
- 信息层:放大方阵(64 格按身份
条目#k移动)、N 格墨框、英雄数字、黑点、播放框、日期与旁白、计数、旁注、问题面板、前 8 件走势里的“此刻”线;都在节拍上动,每轮只动一次。 - 概念层,只在放映时、只用灰:灰影是走掉的格子在原位留下的灰方块(16 % 灰底、1 px 灰边,画在格子下面,个数等于本轮让出的格数,0.4 秒散掉,第三拍 0.6 秒);拖尾是播放框刚离开的两格外的一圈灰框(从 0.55 淡到 0,1.2 秒,即两轮),第三拍压暗时一起降。两者都从放映的分段表现算,不另存状态。
- 一屏:页头收成一行(标题、“▶ 放一遍”、配色开关),日子的行距收紧;一天超过三帧的旁注在放不下时收起(story 的 10/12,
.is-tight,悬停那一帧看旁白)。1440×900 下两套数据的整张底片都在一屏里(舞台 848 px,内容 848 px)。右栏:件数、用了几份、几个问题开着挪到英雄数字下面;前 8 件放在问题之前,逐轮长短不一的问题清单在最下面,换帧时上面的块不跳;旁注是旁白下面一个固定两行的位置,静止时写“变化最大:…”,放映时只在三个停顿处写。 - 数字的出处:页面现算,与第 2 节同口径:N = 各主人(含未分配)份额增量之和;“其中空出”= 上一帧用的份数减这一帧的;问题来自
currentAsk(含子层),关上与新登记按问题 id 与上一帧比。
交互(接 motion/ix.mjs)
- 什么算一件:根层事项的 id,以及
@<帧号>表示一帧(小方阵的边框与空格、它下面的时刻、右边的旁注行,以及放大方阵的空格)。命中按几何算:放大方阵按格子坐标,四边外放宽 12 px;小方阵按 8 px 的格距;图例与问题面板的一行认它的事项。悬停小方阵里的一格,卡片讲的是那一帧的那件事。 - 悬停一帧:概要卡写帧号与时刻、旁白、“换手 30 格 · 空出 25”、件数与开着的问题、本轮变化最大的三处、本轮关上(划掉,写你的动作或怎样失效)与新登记的问题;这一格同时显出它的 N 格墨框,底片其余不变。
- 悬停一格或一行:卡片写帧与流、“猫看病 24 份”、怎样变与两周累计、本轮进了几条输入、它此刻开着的问题,末行是这一轮的换手与问题数;这件事在 29 格与放大方阵里亮起、其余变浅灰(沿用以前的做法)。两种悬停都让放映停在当前时刻,按 ix 的 0.15 秒宽限、0.12 秒淡出、0.4 秒后接着放;格子落定之前,卡上写“这一轮还在动”“本轮的份额还没落定”,不提前给 N。
- 展开这一件:点放大方阵里的格子、图例或问题行,或 Tab 到它按 Enter。0 秒是切点,右栏标题改成“这一件 · f23 · 8/14周五 12:00”;0–0.3 秒它在放大方阵里的格子沿“方阵中心 → 这块重心”外推 8 px(离中心不到一格时向下推);0.4–0.6 秒引线从这块最低一行中间那格出来,沿格缝走到方阵下沿,再直下到面板;0.6–0.9 秒“这一件”从引线末端展开(ix 的标准:先沿接上的那条边、再向外),盖住右栏方阵以下的部分(此刻的旁白、图例与问题),内容多时在里面滚动。内容:短名、流、本帧份额与怎样变、两周累计;摘要两行;子层(story);28 轮的份额小条,本帧墨色、有问题开着的轮次在条顶加一道黑;“整块挪动 N 次:f03 12→24 · …”(变动 6 格以上的轮次);本轮进了它的输入(按来源);这一帧开着的问题(链接或“之后在 fXX 关上”);你的回应;折叠的版本、依据与原文(沿用以前抽屉的
dossierHTML)。 - 点别的帧:点一帧(时刻、旁注、边框或空格)是跳到那一帧,走一轮节拍;点另一帧里的一格,先硬切到那一帧,再在那里展开这一件。
- 键盘:每件一个视觉上隐藏的按钮(这一帧的事项在前,29 帧在后):Tab 到事项出概要、Enter 展开;Tab 到一帧出那一帧的概要(虚线框),Enter 跳过去。空格放映 / 停住(从当前帧放到末帧,在末帧按空格从头放),Home / End 到头尾,C 切换配色,←/→ 由外壳处理。
- 共用模块不改:两张卡的内容由页面自己给(ix 宿主契约里的
peekHTML、detailHTML,与批次记谱同一个口子),因为一帧的概要和“之后在 fXX 关上”的注记超出了itemFacts;结构与类名照用 ix 的。scripts/check-ix.mjs加了小倍数一项,tabFrom是[data-inspect="state"](顶栏在概念卡按钮后面还有“状态”)。
与故事的出入
- ←/→ 会收起“这一件”。故事写的是 ←/→ 不收起、逐帧走它的历史;ix 的标准是导航立即收起(
check-ix的“→ 换轮:立即收起”),这里按标准做。要逐帧看一件事,用详情里的 28 轮小条与“整块挪动”一行,或在下一帧再点它。 - 默认不放映改成直接打开时放一遍(审阅第 4 条);
?play=1没有做,截图与检查用foldMultiples.freeze(t)定格。 - f01 的计数:故事写“计数在最后一格落定时出现”,照做;这 1.58 秒里右栏的件数与问题数仍是 f00 的 0。
- 问题面板的划掉每一帧都有(本轮关上的问题),不只第三拍;第三拍它在 1.3 秒随旁注一起换,快放时在 0.3 秒换。
5 导演(direct)
用 1440×900 的定格逐拍看过之后改了这些:
- 第三拍的旁注原来放在英雄数字下面的窄列里,折成四行、把右栏往下推;改成旁白下面固定两行的位置。
- 计数原来是右栏里单独一行,问题清单在图例之前;清单的行数逐轮不同,快放时图例跟着上下跳。计数挪到数字下面,图例提到问题之前。
- 关上的问题原来两行(划掉的原句 + 怎样关上),第三拍三条就把右栏顶出屏幕;改成一行“
短问法→ 你给诊所打了电话”,原句在悬停提示里。 - 详情原来按内容长短,下面露出图例与问题的残片;改成盖满右栏方阵以下,此刻的旁白也隐去。
- 定格到任意时刻时,数字可能还是上一次画的;改成切点先写上一轮的数、落定再翻,拖尾也从分段表现算。
还拿不准的:
- 灰影很淡(16 % 灰),近看清楚,投到大屏上可能看不见;要不要加深,等你看实际放映。
- 一轮里几十格同时滑动会彼此穿过,0.3 秒里读起来像洗牌;排法的改动去掉了空转,但大块变动的轮次(f18、f23)仍然乱一下。
- 1440×900 以下底片放不进一屏,放映时播放框可能走出视野,没有做自动滚动。
6 交付(ship)
- 验证:
make check;node scripts/check-ix.mjs(脉冲、拨盘、小倍数,composite 与 story 各 16 项全过);node scripts/shoot-forms.mjs --only multiples,all --gpu --check all-sync(两套数据,页面无报错,合页逐节跟帧);npm run site:build。合页与画廊里小倍数静止,顶栏选帧时演一轮过渡再停住。 - 性能:放映全程(1856 格同屏,放大方阵 64 格逐帧移动)无头 Chrome 60 fps,每帧脚本平均 1.4–1.7 ms、p95 2.5 ms(显卡与软件渲染各测一次)。
- 预览图:
site/previews/multiples.webp按 docs/development.md 的参数重截(f26,收起概念卡)。 - 静帧在本机,不入库:第一拍 f02 用满、第二拍 f17→f18 滑动中、第三拍 f23 数字 30 与压暗、放完回到 f28 的静帧、悬停一格、悬停一帧、展开 0.9 秒。