Skip to content

让位图 · 动起来之前:参考、数据、故事 ​

状态:已实现。2026-10-19 让位图按第三轮的六步流程(reference → data → story → motion → direct → ship)记下前三步,只定故事;审过之后,2026-10-20 做完后三步(第 4–6 节),故事没有改。动的是 sketches/yield.html 本身:它仍是复盘工具,不另开一张官网动画页。两层法则与交互标准见 CONCEPTS.md,范本是份额拨盘与整理脉冲,交互取共用模块 motion/ix.mjs;这张图静态的画法见 review-b.md。

1 参考:这张图现在怎么讲让位 ​

现在的讲法。 一轮一行。左翼是这一轮份额变少的事项和被动用的留白,右翼是变多的事项和退回的留白,中线写这一轮之后的留白;根层永远 64 份,所以两翼等长,一格一份。两翼宽度按刻度 CAP 定,取各行挪动份数的第二大值(composite 是 f23 的 30 份),超过它的行(8/3 冷启动,57 份)整行缩小。1–3 份的让出合成“其余 N 件”;↩ 标出这一轮你答了登记的问题。悬停一块,同一件事在每一行亮起,同轮的对方保持原色,其余淡到 18%;点击固定,侧栏写它每一轮的前后份额和同轮对方,点 ↩ 再写“之后份额让给了谁”。切帧时新的一行先从左翼外端扫到中线(220 ms),中线细线划过、留白数滑入,再从中线扫向右翼外端(260 ms,延迟 230 ms);此刻框 320 ms 滑到新行。

哪里讲不动。

  1. 守恒要人自己比。 “让出 30 = 拿到 30”只写在侧栏;图上是先后扫出的两组色块,半秒扫完,看不出是同一笔份额从左边挪到了右边。
  2. 扫的方向像配对。 左翼扫进中线、右翼从中线扫出,容易读成“猫看病把份额给了主水管”。回执只记每件事增减多少,没有记谁为谁让位,review-b 也写了“读者仍可能读成因果”。
  3. 跨轮的账看不见。 两周里最值得讲的一笔横跨四行:8/14 12:00 那一轮两件事关上、退回 25 份留白,之后一天半留白只减不增,8/16 零点主水管长到 24 份、留白只剩 1。静图上它只是中线上四个小数字(25、13、12、1),没有东西把它们连起来;“之后份额让给了谁”也只列同一轮的拿到方,不跨轮。
  4. 最宽的行不显眼。 f23 是冷启动之外最大的一次让位,正好定了全图刻度,两翼顶到外沿;f01 的 57 份缩到 0.53 后也顶到外沿,两行看起来一样宽。行里的缩放说明只在行高到 30 px 时才显示,1440×900 下看不到,只有侧栏末尾一句。
  5. 让位的主体藏在灰块里。 f22 让出的 19 份里,有 11 份在“其余 9 件”里(派对 3 份,棚屋、航班和几条痕迹各 1 份),图上只是一块浅灰加一条细色带。

从拨盘、脉冲搬什么,不搬什么。 让位图的题目就是拨盘里“一件变大,别的就得让”这句:拨盘第 2 拍让扇区每轮此消彼长,第 3 拍在 f26 把它演成一次。可搬的是节奏,不是画面。

要素出处搬过来不搬
切点拨盘:日期、计数、标题一帧硬切,质感不切日期、帧号、旁白在切点硬切拨盘在切点撤掉注释与线束;这里的行是账,已经落定的东西切点不撤
第一个动作拨盘:切点后 0.4 秒没有焦点。脉冲:第一个动作小、低、贴着锚点讲述时切点后 0.4 秒再动(连播是半速,0.2 秒)。有作答的轮,第一个动作是 ↩ 落在时间旁边(作答本来就是这一轮的输入);没有作答的轮,第一个动作是左翼扫出逐帧(←/→)不留 0.4 秒空白:复盘时会连按方向键,空白就是卡顿
一颗一条脉冲第三版:一颗亮粒子是一条输入一格灰格是一份份额,格数就是这一轮让出的份数粒子云、尘埃、辉光、余辉、整屏压暗
停顿脉冲折叠拍:采用的输入落到根上的格子,停 0.12 秒再化成光灰格全部进中线后停 0.12 秒,再出到右翼收拢弧和光
计数脉冲:N 随粒子落定逐颗计数。拨盘:压缩的轮次里计数连滚,逐轮硬翻会像闪烁讲述和连播时,英雄数字随灰格进中线逐格加一;第三拍把 f24、f25 压到半速逐帧时不逐格滚,平账一刻直接硬切
缓动拨盘:连续量 ease-out,过冲约 3.7%此刻框、色块长出、交互弹出都用这条曲线—
一涨一缩拨盘:同一轮的涨和缩同时落定,不画成谁推谁守同一条底线:不画配对。做法不同:左先右后是账的读法(让出在左、拿到在右),中间经过一个不分你我的池,灰格一进池就去掉身份色不搬“同时落定”:让位图问的就是从哪里来、到哪里去,方向本身是信息
循环两张都是官网首屏,循环或连播—不循环:复盘工具讲一遍就停,停在故事最后一帧
朱红两张都只给回应路径—身份色里已有暖红:猫看病 #b8643a、主水管 #b0704a、Ture 发烧 #a3485a,朱红会被读成某件事。↩ 仍用墨黑

概念层的占比:约一成,静止时为零。 拨盘与脉冲的概念层约占八成,因为官网首屏要先让人感到“量”(上百条输入、成堆的字形),而且多半只看一次。让位图不一样:

  • 它是复盘工具,会反复打开、逐行比对。画面上任何不在账上的东西都在跟比对抢眼,看第二遍就成了噪音。
  • 它没有另外要表达的“量”:它的量就是份数,而份数已经一格一份画在账上。
  • 静图唯一讲不动的,是“这是同一笔份额在挪”。要讲清这一点,只需要在挪的那一秒里有东西在动。

所以概念层只有一种东西:过账时一格一份的灰格,从让出的色块上剥下来,沿行飞进中线,再飞到拿到的色块,带 0.2 秒拖尾。任何时刻都不到画面面积的 2%;平账后为零,不留纹理,也不留余辉。它与信息层共用几何与数量:灰格宽是这一行的一份、高与色块相同,沿行的轴走,池就是中线;灰格数 = 让出份数 = 拿到份数。

2 数据:两周里的让位 ​

这张图现在用哪一帧。 默认数据集是 composite(Jonas 的两周,29 帧,f00 是空状态;帧号 fNN 就是序号 NN)。不带 ?frame= 打开时,composite 停在 scenario.sketchFrames.yield = 'f22'(8/14 00:00「热浪第一天:药量超过失明线」),选帧说明在 scenario.sketchNotes.yield;?data=story 停在 createStage({ storyIndex: 17 }),即林苒的 f15(10/17 10:00「陪妈妈改约周日11点,双方已确认」,frames[17])。catalog.mjs 里的 frame: 'f15' 是为手写情境写的帧号,只在数据集没有 sketchFrames 时作画廊卡片“默认帧”的退路;概念卡的示意,以及“试用让出 18、发布让出 9、妈妈拿到 12、退回留白 15”,也都是手写情境的数。composite 里另有一帧叫 f15(8/10 12:00「周一上午:看兽医,#13528 请他评审」,挪动 12 份),和它无关:在 composite 下打开 ?frame=f15 得到的是这一帧。

口径。 和页面用同一套推导:用 node 直接导入 variants/shared.mjs(replayScenario 得到的 records,以及 currentAsk)现算。脚本只放在本机,不提交。

  • 让位:records[i].state.root.items[].share 与 records[i−1] 之差,变少记左翼,变多记右翼(同 yield.mjs 的 rows)。留白 = 64 − records[i].state.root.used,同样变少记左、变多记右。变少到 0 的,按 records[i].snapshot.items[id].status 分撤下与并入。
  • 一轮的挪动份数 = 左翼合计 = 右翼合计。
  • 问题的开闭用 stage.mjs 的 askLife:答掉 = 上一帧开着、这一帧关上,此前有 event.feedback[].ask 指向它;失效 = 关上但没人答。“伴随答掉的让位” = 问题答掉的那一轮,它所在的根层事项同一轮让出份额。
  • 名字取 scenario.categories[id].short。

两周的总账(composite)。 28 轮的挪动份数中位 11,最大 57(f01 冷启动),其次 30(f23)、26(f18)、19(f22、f26);只有 f27 一格没动。冷启动之后 27 轮共让出 300 份、拿到 300 份;让出的 300 份里,变小 169(56%),撤下或并入 73(24%),留白 58(19%)。58 件事项让出过份额,35 件只让过一次,其中 29 件那一次就是撤下或并入。留白被动用 13 轮、共 115 份(含 f01 的 57),退回 7 轮、共 51 份;64 − 115 + 51 = 0,正是 f28 的留白。

最大的一次让位:f23。 8/14 12:00「打了诊所;母亲自己定了」,让出 30 = 拿到 30。

  • 让出:母亲换水管 24→6(−18),猫看病 24→12(−12)。来源:records[23].state.root.items 对 records[22] 求差。
  • 拿到:留白 0→25(+25),master CI 1→6(+5)。留白 = 64 − records[23].state.root.used(39);25 是空状态之外两周里最大的留白,与拨盘 data.json 的 maxBlank 一致。
  • 伴随:08:02 你给诊所打了电话,答掉「Smilla 多吃了药:打诊所?」(frames[23].events[31],id: fam:A13.1,kind: call_log,feedback[0] = {ask: 'ask-16', action: 'call', meaning: 'act', via: 'source'});11:38 你在 GitHub 上批准 #13572,答掉「#13572 堵复用绕过:批准?」(frames[23].events[113],ask-20),但待审 PR 这一轮仍是 6 份。「母亲九月住哪?」(ask-08,期限 8/14 23:59)随改写失效:母亲自己交了回执,这一轮的声明把母亲换水管改为已办(frames[23].batch.declarations 里 mamma-stambyte 的 kind: done、weight: normal)。所以这 30 份里,12 份来自问题被答掉的猫看病,18 份来自问题失效的母亲换水管。
  • 冷启动不算:f01 挪了 57 份,那是从空状态起步,留白 64→7 分给 10 件新事,不是谁让给谁。页面把这一行缩小到 30/57 = 0.53(yield.mjs 的 CAP = max(18, 第二大挪动份数) = 30)。
  • 单件让出最多的也在 f23:母亲换水管 −18(f24 再 −3,停在 3 份)。并列第二是 f10 的母亲换水管 24→12 与 f23 的猫看病 24→12,各 −12。

让位最频繁:猫看病。 让出 6 轮(f05、f06、f16、f23、f26、f28),共 35 份,全是变小,从没撤下;它也拿到 4 轮(f01、f15、f18、f22),共 38 份,是两周里来回最多的一件。根层份额逐轮是 12、12、12、12、3、1 ……1、6、3、3、12、12、12、12、24、12、12、12、6、6、3(records[i].state.root.items 里 smilla-vet 的 share,f01–f28)。其次是 master CI,让出 5 轮、17 份(f03、f04、f09、f18、f19)。算上留白,最常被动用的是留白本身:13 轮。

伴随答掉的让位。 两周答掉 11 个问题,8 个在同一轮让出份额,合计 32 份(问法取 ask.short):

轮答掉的问题同一轮让出
f03ask-04「水碗多大?回一句尺寸」问答回复 3→1
f05ask-05「Smilla 约上兽医了吗?」猫看病 12→3
f05ask-09「vdns 搬迁:批准合并?」vdns 搬迁 1→0
f16ask-12「改签直飞,还是照旧?」9/14 航班 6→3
f16ask-06「#13473 定时器重构:批准?」定时器重构 1→0
f18ask-14「NTLM 复用修复:批准?」NTLM 复用 1→0
f20ask-17「机票退款回来了吗?」机票退款 3→0
f23ask-16「Smilla 多吃了药:打诊所?」猫看病 24→12

没有在同一轮让出的有 3 个:f09 的 NDEBUG(ask-07,下一轮 f10 才 12→6),f10 的航班号(ask-11),f23 的 #13572(ask-20,待审 PR 6→6)。没有一个问题在答掉的那一轮让事项变大。两次最大的、伴随答掉的让位都是猫看病(f05 −9,f23 −12)。失效也一样:8 个随改写失效的问题里,7 个同一轮让出份额,最大的就是 f23 的母亲换水管 −18。合起来,问题关上 19 次,有 15 次同一轮就让出份额(askLife[i].answered、askLife[i].lapsed)。

故事要用的五行(composite f22–f26)。 示意,不按比例;左翼越靠外越晚列,留白在最外端。

text
整理                 ← 让出                         留白   拿到 →
8/14 00:00     [留白 2][其余 9 件 11][复用绕过 6]     0    [猫看病 12][待审 PR 6][开学文件 1]
8/14 12:00 ↩       [猫看病 12][  母亲换水管 18  ]    25    [master CI 5][     留白 25     ]
8/15 00:00               [留白 12][母亲换水管 3]     13    [主水管 5][其余 4 件 10]
8/15 12:00                   [留白 1][其余 2 件 5]    12    [主水管 6]
8/16 00:00       [留白 11][Ture 发烧 2][猫看病 6]     1    [主水管 12][FTPS 计时 5][后刹 2]
数值来源
f22 让出19:6 件撤下(小龙虾派对 3,抬棚屋、合并 8/11–13、假关税短信、9/14 航班、垃圾改期各 1),4 件并入(复用绕过 6 与旧的待审 PR 1 并入新的待审 PR,头虱 1 与旧的开学文件 1 并入新的开学文件),留白最后 2records[22] 对 records[21];并入的去向是 records[22].snapshot.items[id].merged_into
f22 拿到猫看病 12→24,待审 PR 0→6(新 id pr-reviews-0814),开学文件 0→1(新 id signe-school-start);根层从 19 件剩 11 件,两件各 24 份,留白 0同上;records[22].state.root.items.length
f22 输入172 条,采用 34;声明 14frames[22].events、batch.declarations
f23见上:让出 30,留白 0→25—
f24让出 15:留白 25→13,母亲换水管 6→3;拿到:主水管 1→6,65KB 上传、FTPS 计时、骑车各 +3,风扇 +1records[24] 对 records[23]
f25让出 6:骑车 3→0(撤下)、FTPS 计时 3→1、留白 13→12;拿到:主水管 6→12records[25] 对 records[24]
f26让出 19:留白 12→1、猫看病 12→6、Ture 发烧 3→1;拿到:主水管 12→24、FTPS 计时 1→6、后刹 1→3(与拨盘第 3 拍同一轮)records[26] 对 records[25]
留白 f22–f260、25、13、12、164 − records[i].state.root.used
主水管 f22–f261、1、6、12、24;f16 首次出现(3 份),f18–f23 一直留着 1 份records[i].state.root.items 里 driveway-wet 的 share
f26 新问题ask-23「主水管:挖开换还是免挖?」,期限 8/17 10:00frames[26].asks['driveway-wet'],askLife[26].fresh

这里有一条账面上成立的跨轮连接:f22 的留白是 0,f23 退回 25,此后三轮只减不增,所以 f24–f26 动用的 24 份留白都是 f23 退回的那 25 份;f23 只有母亲换水管和猫看病两件让出,所以这 25 份只能来自它们俩。份额本身不分彼此,这句话说的是账,不是“猫看病把份额给了主水管”。

手写情境(story)对照。 37 帧(cold-00 至 f34,frames[17] 是 f15)。

  • 刻度:CAP = 27,冷启动 f01 挪动 31 份,缩到 0.87。冷启动之后共让出 347 = 拿到 347:变小 201(58%),留白 127(37%),撤下或并入 19(5%)。
  • 最大的一次让位:f15,让出 27 = 拿到 27。让出:试用 24→6、发布 12→3;拿到:妈妈 12→24、留白 3→18。前一帧 f14 有批注“改到周日也可以。这次保留最大的位置给妈妈;发布做成了就让它小一点,但别删掉”(frames[16].annotations);这一轮答掉 ask-17「周六 11 点见妈妈,可以吗?」,回复“改到周日 11 点”(frames[17].events[0].feedback[0],via: reply,action: change)。
  • 之后:f18 答掉 ask-21「周日 11 点见妈妈」,回复“已见到妈妈”(frames[20].events[0]),这一轮一格没动;下一轮 f19,妈妈 24→6、留白 12→9,发布 3→12、试用 6→12、苏禾 0→3、链路 0→3(让出 21)。
  • 让位最频繁:发布,7 轮、45 份;试用 5 轮,但让出最多,54 份。
  • 答掉 11 个问题,只有 3 个在同一轮让出份额,算上下一轮也只有 5 个;还有 2 个答掉的那一轮让事项变大了(f12 试用 12→24;f15 妈妈 12→24,改约之后它成了周末最重要的事)。“答掉就让位”在手写情境里不成立,故事的论点不能写成这样。

回放里有、图上还没用的。 并入记了去向(snapshot.items[id].merged_into),这是回放里唯一记下的“让给谁”;但份数不守恒(f22 两件 7 份并成 6 份、两件 2 份并成 1 份),所以并入也只能经池过账,去向写在卡上。留白是一个账户,从 0 开始、只减不增的那几轮可以跨行连起来(见上)。回放里没有的:其余让位的配对;被预算挡回的批次。

颜色会撞。 猫看病 #b8643a 与主水管 #b0704a 几乎同色(scenario.categories[id].color)。故事第三拍的 f26 正好是猫看病在左翼、主水管在右翼,看起来会像同一件事从左挪到了右。

3 故事 ​

一个点。 份额只在 64 份里挪:一件事变大,拿的是同一轮别处让出的份额或留白;问题一关上,份额先回到留白,再被下一件急事拿走。(composite:8/14 早上你给诊所打了电话、母亲自己交了回执,12:00 那一轮让出 30 份,25 份回到留白;一天半里留白只减不增,8/16 零点主水管长到 24 份,留白只剩 1。)

英雄数字:30。 这一轮让出的份数,也是拿到的份数,等号两边同一个数。每一轮都有一个(composite 28 轮中位 11,只有 f27 是 0),它就是这一行的宽。f23 的 30 是冷启动之外两周最大的一次,也正是全图的刻度,所以 f23 是唯一一行(缩放的 f01 不算)两翼都顶到外沿。数字放在侧栏“这一轮”的顶上,字高 56 px、字重 500,左右两侧小字“让出”“拿到”,中间一个等号。讲述和连播时,它随灰格进池从 0 逐格数到 N,池满即定;入账时下面的“拿到”逐格追上,两数相等的一刻,等号由灰转墨。逐帧时在平账一刻硬切。不放进图里,是因为图上每一行都有自己的宽,再放一个大数会盖住行;也不像拨盘的 64 那样占环心六分之一,复盘工具里它是读数,不是标题。

三拍(composite 共约 15.5 秒,讲一遍就停在 f26。帧号是页面代码里的常量,不写进数据;两拍之间夹着的轮按半速过账,不跳过,账不能缺行)

拍时长与帧发生什么观众此刻在动 / 只在节拍上落定
00–0.4 秒账已画到 f21(21 行静止),此刻框在 f21,侧栏是 f21 这一轮(挪动 9)一张账什么也不动
1 从哪来0.4–3.6 秒,f22 一轮(3.2 秒)此刻框落到 f22;左翼扫出留白 2、其余 9 件 11、复用绕过 6;19 格灰格进池,英雄数字数到 19,再出到右翼:猫看病 12→24、待审 PR +6、开学文件 +1;根层从 19 件剩 11 件满了:同一轮里猫看病翻倍,十件事让出或退场,留白用尽动:此刻框、左翼扫出、灰格、右翼逐格长出。落定:切点的日期与旁白;平账时的留白 0、色块上的名字与份数
2 关上3.6–7.6 秒,f23 一轮,平账后多停 0.8 秒第一个动作是 ↩ 落在时间旁,侧栏“你作答的问题”同时加一行“你给诊所打了电话 · 猫看病”;左翼母亲换水管 18、猫看病 12 扫出,两翼顶到外沿;30 格灰格进池,英雄数字数到 30;出到右翼:master CI +5,留白的虚线框逐格长满 25 格两件事一关上,份额就退了出来,大半回到留白动:↩ 淡入、灰格、英雄数字逐格加一。落定:平账时留白 0→25(两周最多)、等号转墨;问题列表一帧切换:划去「Smilla 多吃了药:打诊所?」与「#13572 堵复用绕过:批准?」,「母亲九月住哪?」转灰并注“失效”,加上新登记的「三个旧 PR 推到哪天?」
3 到哪去7.6–15.5 秒:f24、f25 各 1.6 秒(半速),f26 一轮 3.2 秒,平账后停 1.5 秒中线上从 f23 的 25 往下长出一道 1 px 墨线,每过账一行接上一个数:13、12、1;主水管 f24 +5、f25 +6、f26 +12,长到 24;f26 左翼留白 11、Ture 发烧 2、猫看病 6,右翼主水管 +12、FTPS 计时 +5、后刹 +2;平账后主水管三行的色块描 1.6 px 墨边;侧栏“开着的问题”加上「主水管:挖开换还是免挖? 8/17 10:00 前 · 去回答 →」退回的份额没有消失,一天半后被下一件急事拿走动:墨线逐行延伸、灰格、色块长出。落定:每行平账时的留白数与份数;f26 平账时的新问题

讲完后页面就是普通的复盘工具,停在 f26(地址栏 frame=26),墨线与主水管的描边留到第一次交互为止。

一轮过账的时间表。 讲述按全速(3.2 秒);第三拍中段的 f24、f25 和空格连播用半速(1.6 秒,每个时刻 × 0.5,第一个动作提前到 0.2 秒,28 轮约 45 秒):

  • 0 切点:顶栏日期、帧号与旁白一帧硬切;新一行的时间出现;此刻框下移(0.32 秒,ease-out,过冲 3.7%)。概念层为零。
  • 0.40 第一个动作:这一轮有作答的,↩ 在时间右侧淡入(0.12 秒,不弹不闪),侧栏同时写出动作句;没有作答的轮跳过这一步,下一步提前到 0.40。
  • 0.55 左翼扫出:让出的色块从外端扫向中线(0.30 秒,ease-out),这时还不写份数。
  • 0.90–1.50 出账:从靠中线的一格开始,每块色块一格格剥出灰格,沿行飞进中线(每格飞 0.24 秒;相邻错 12 ms,一翼 0.36 秒内出完,格多时压缩错开,f01 的 57 格约 6 ms)。剥离时色块降到四成,出账结束回到满色:它是账面,不是库存。灰格一到中线就并进中线那条细线,线随池里的份数变粗,满 30 份时与色块同高;侧栏的英雄数字随之加一。
  • 1.50–1.62 池满,停 0.12 秒。
  • 1.62–2.22 入账:灰格一格格从中线吐向右翼(同样每格 0.24 秒、错 12 ms),右翼色块从中线向外长,每到一格长一格、到达即上色;留白的虚线框同样逐格长;“拿到”随之计数。
  • 2.25 平账:拿到等于让出,等号由灰转墨(0.15 秒);中线的留白数一帧硬切到新值;色块写出短名与份数;侧栏的问题列表一帧切换。概念层回到零。
  • 2.25–3.20 静止,留着读;3.20 秒切到下一轮。

逐帧(←/→)用短版,约 0.9 秒:没有 0.4 秒空白;↩ 在 0.05 秒;左翼 0.08–0.24 秒扫出;灰格 0.24–0.52 秒进池(每格 0.16 秒),0.52–0.80 秒出到右翼;0.80 秒平账,所有数字硬切,不逐格计数。按住方向键或一次跳多帧时,沿用现在的依次扫出(每行间隔不超过 45 ms、总长约 320 ms),不飞灰格,数字直接到终态。往回退时这一行照现在淡出(160 ms),不倒放:倒放会像把份额要了回来。

两层。 信息层(约九成):每行的色块与留白框、份数与短名、中线的留白数、↩、此刻框、侧栏的英雄数字与清单、第三拍的墨线与描边。只用身份色、墨黑与灰;只在节拍上落定。概念层(约一成,静止时为零):过账中的灰格、并进中线的池、0.2 秒拖尾。只用灰;不带文字、数字与颜色;每格一份,个数与信息层对得上。规矩:信息层动的时候概念层不另起动作;灰格不进侧栏、不进注释列;概念层不暗示信息层没有的事实,挪动为 0 的轮(composite 的 f27)不飞任何东西,中线只留那条静线。

动起来之前的约束

  • 绝不动:行的位置(一轮一行,固定)、两翼等长、中线的位置、颜色只表示事项身份、此刻之后的行只留淡色时间。
  • 每行只动一次:一行只在被过账时动;过账后不再动,第三拍的墨线与描边除外。
  • 不画配对:灰格进池即去色,出池的先后只按右翼的排列,不与左翼的哪一格对应;并入也走池,去向只写在卡上;卡与侧栏一律写“同一轮让出 / 拿到”,不写“给了”“来自”。左先右后是账的读法,不是因果。
  • 只有留白可以跨行相连:它是一个账户。墨线只在某一轮留白为 0、下一轮退回、之后只减不增时画;composite 的 f22–f26 成立,手写情境没有这样的段,不画。
  • 不加朱红;↩ 仍用墨黑。
  • 只读回放:rows、askLife、responseSentence 现算,故事的帧号是页面常量;不改 scenario、不加字段,不读 data.json(如果 ship 步要逐项对照,再按拨盘、脉冲的样子补一份)。
  • prefers-reduced-motion:直接到终态,不飞灰格。
  • 性能:灰格画在叠在图上的一层 canvas 里,不往行里加节点;切帧的整步重绘仍要留在一帧之内(现在 p95 6.8 ms)。
  • 合页顶栏选帧:立即停止讲述、收起卡,直接到那一帧的终态。

交互(与份额拨盘、整理脉冲同一套标准,悬停卡、弹出、引线、详情卡的时间与样式取共用模块 motion/ix.mjs(正在从拨盘与脉冲里抽出);让位图只提供几何:色块的矩形、弹出方向是行的方向、引线的走法)。悬停与展开都只读同一份回放,都让讲述与连播停在当前时刻;收起后 0.4 秒接着走。

  • 悬停
    • 触发:鼠标移到色块(含展开后的单件)、“其余 N 件”、留白框或中线的留白数、↩ 上;Tab 到它们,↑/↓ 换行(沿用现在的键盘);触屏轻点一下就是悬停。时间与旁白仍是“跳到这一帧”,不出卡。
    • 出什么:一张与拨盘同款的概要卡(纸底、墨框、等宽字),贴在标记上方,贴边时翻到下方。
      • 色块:短名与这一帧的条目标题;这一轮 前→后(±n),让出或拿到;同一轮的另一边(写“同一轮拿到:master CI 5 · 留白 25”);它此刻开着的问题与期限(currentAsk,含子层),这一轮答掉或失效的问题;到此刻让出几轮、拿到几轮。
      • “其余 N 件”:N 件各自的前后份额(现在提示框的内容),“点开逐件”。
      • 留白:留白 n / 64,这一轮动用或退回几份,上一次为 0 是哪一轮。
      • ↩:作答的动作句与问题(“你给诊所打了电话 · 答「Smilla 多吃了药:打诊所?」”),被答问题所在事项这一轮与下一轮的份额(24 → 12 → 12)。
    • 其余怎么变:这件事在每一行的色块描 1.6 px 墨边并保持原亮度,同轮的对方保持原亮度,其余降到七成;过账中的灰格降到四成。七成在 28 行里追不出一条线,所以靠描边追,不靠压暗。
    • 节拍:停在轮中途时,卡守这一轮的节拍:平账(2.25 秒)之前写“本轮还没平账”,不提前说出后值。
    • 收回:离开 0.15 秒后卡 0.12 秒淡出,再过 0.4 秒接着播。
  • 展开
    • 触发:点色块、单件、留白、↩ 或概要卡;聚焦后按 Enter 或空格。
    • 动什么:0 秒是切点,顶栏旁白改写成“这一件 · f23 · 8/14 周五 12:00 / 猫看病”,侧栏切到“这一件”。0–0.3 秒,被点的色块沿行的方向向外弹出 8 px(左翼向左、右翼向右,ease-out,过冲 3.7%),靠中线一侧留出 8 px 空隙,像从账上抽出来;它在别的行的色块保持描边,其余降到 18%(固定时要追一条线,沿用现在固定时的淡法)。0.4–0.6 秒,引线从色块外端沿行出到这一翼外沿之外 8 px,再直角转向卡。0.6–0.9 秒,详情卡从引线末端展开,先沿接上的那条边、再向外。右翼的卡放在注释列一侧;左翼的卡放在这一行上方或下方空间较大的一边,贴左翼外沿;都不盖住此刻行和被点的这一行。点 ↩ 时弹出的是被答问题所在事项在这一行的色块;它藏在“其余”里时先自动展开(沿用现在的 autoOpen)。
    • 详情卡(这一轮这一笔):时间、帧号与方向(“8/14 周五 12:00 · f23 · 让出”);短名与 前→后(“猫看病 24 → 12(−12)”);这一帧的条目标题(“Smilla已减量,24日9:30复诊”);同一轮的另一边;这一轮你的回应(“08:02 你给诊所打了电话,答「Smilla 多吃了药:打诊所?」”);此刻开着的问题与期限,旁边是“去回答 →”;摘要。不承载作答。
    • 面板“这一件”(两周这一件):份额逐轮小条图(28 根,这一轮亮、之后的淡,与整理脉冲详情卡的画法相同);到此刻的账(猫看病在 f23:让出 4 轮 26 份、拿到 4 轮 38 份;两周合计让出 6 轮 35 份,淡色);问题关上的那几轮与前后份额(f05 答「Smilla 约上兽医了吗?」12→3,f23 答「Smilla 多吃了药:打诊所?」24→12);份额往来(现在侧栏的逐轮列表,每轮写同轮对方);从 ↩ 进来时,先写“作答”与“之后份额”(现在的 pinnedLead 段落);最后是摘要、依据、来源与版本(现在的 itemDetailHTML,折叠)。点留白时,“这一件”是留白账户:逐轮留白小条、动用 13 轮 115 份与退回 7 轮 51 份的列表;在 f23–f26 之间打开时,标出那道墨线覆盖的四轮。
    • “去回答 →”:只给此刻开着的问题(currentAsk,含子层),链到同一帧的 D 手机首页,../../index.html?variant=d&frame=<当前序号>,经 withDataset 带上 ?data=;与拨盘、脉冲一致。故事停下的 f26,主水管卡上的「主水管:挖开换还是免挖? 8/17 10:00 前」链到 ?variant=d&frame=26。答掉或失效的问题只写状态与动作句,不给链接:复盘类不承载作答,也不把人带回一个已经关上的问题。
    • 收回:Esc、点空白、再点同一块:卡 0.2 秒收起,引线 0.15 秒缩回,色块 0.2 秒落回,然后一帧切回这一轮的旁白与侧栏,0.4 秒后接着播。点另一块先收回再展开那一件。←/→、选帧、播放键与合页顶栏选帧立即收起并照常执行。prefers-reduced-motion 时直接到终态。
  • 脚本:window.foldYield 给出与 foldDial、foldPulse 同名同义的 hover / unhover / open / close / ixAt / paused / pointOf,名字可用条目 id 或短名;同一件事在很多行出现,所以多带一个帧序号,如 open('猫看病', 23)。window.foldSketch 照旧。

和拨盘、脉冲不同的地方:那两张的元素是一个环或一棵树,一件事只出现一次;这里一件事在 28 行里反复出现,所以悬停靠描边追线,固定时才压到 18%。弹出不是沿半径,而是沿行;侧栏本来就是这张图的仪表,“这一件”切的是侧栏,不另起面板。讲述停的是讲述,不是循环。

手写情境的三拍。 照同一个时间表,从 f14 起(批注那一行已经在账上):拍 1 是 f15(让出 27 = 拿到 27,英雄数字 27,↩“改到周日 11 点”:一次让事项变大的作答);拍 2 是 f16–f18,半速,f17 是定时检查、一格没动,f18 只落一个 ↩“已见到妈妈”,账不动;拍 3 是 f19,全速,妈妈 −18、留白 −3,发布 +9、试用 +6、苏禾 +3、链路 +3,停在 f19,链“去回答 →”的是「周三演示前,开放范围怎么定?」(ask-25,?variant=d&frame=21)。没有墨线(见约束)。共约 13 秒。

审阅后定下的 ​

前三节审过之后定下七条(2026-10-19),实现照做:

  1. 自动讲一遍:只在顶层直接打开、地址不带 ?frame=、也不是从别的页面链过来(document.referrer 是另一页)时演一次,任意键跳过;工具栏的「▶ 讲一遍」可重演,讲的时候它变成「跳过 ▸▸」。带 ?frame=、画廊缩略图、合页 all.html 嵌入、体验站弹框和从别处链来的,一律静止在那一帧(不带帧时是默认帧,composite 的 f22、story 的 f15)。
  2. 失效上账:只在让位图加一个空心记号 ○(↩ 右边,平账时落定),写进图例;回应时序、身份线对“失效”的说法不动。
  3. 颜色不改:edits.json 一处不动;猫看病与主水管靠色块上的名字和第三拍的描边区分。
  4. **「去回答 →」**链到当前查看那一帧的 D(../../index.html?variant=d&frame=<序号>,经 withDataset 带上 ?data=),只给该帧仍开着的问题;已关上的写它怎么关上的(动作句,或“随改写失效:母亲换水管改为已办”),不给链接。
  5. 交互接 motion/ix.mjs,不另写一套;交互的时序常数用 IX;钩子 window.foldYield 与 foldDial 同名同义。
  6. 换帧走节拍过渡(←/→、合页 followFrames 同步),不硬切;静止时概念层为零。
  7. 两套数据都能演,story 的论点照实(第 2 节末、第 3 节末)。

scenario.sketchNotes.yield 没有改:它只在静态草图页(kit.mjs 的 page)显示,让位图用的是 stage.mjs;不带帧时静止的默认帧也仍是它描述的 f22。

4 motion:每一帧都是代码 ​

改动在 yield.mjs、yield.css 与 yield.html(多链一份 motion/ix.css)。只读回放:rows、askLife、responseSentence 现算,三拍的帧号是页面常量 PLAN,不改 scenario、不加字段、不读 data.json。

一轮过账是一只时钟。 post = {i, mode, t},每帧 t += dt,画面上的一切都从 t 推出来(paintPost、paintCells、paintSide、paintMarks),所以改尺寸、悬停停表、拍静帧(foldYield.tellAt(秒))都只是改 t 或不让它走。三张时间表是常数:全速 FULL(3.2 秒,第 3 节的时间表原样),半速是全速 × 0.5(1.6 秒),逐帧 SHORT(0.9 秒,0.80 平账,不逐格计数)。没有作答的轮,第一个动作跳过,后面整体提前 0.15 秒,轮长不变。一翼的灰格错开 min(12 ms, 窗口 ÷ (N − 1)),窗口是 0.36 秒(半速 0.18、逐帧 0.12),f01 的 57 格约 6.4 ms。

层画在哪里动什么
信息层原来的 DOM 行左翼 clip-path 从外端扫向中线,出账时降到四成;右翼 clip-path 按已到的格数一格格放开,到达即上色;中线的数在平账前是上一轮的留白(灰),平账一帧硬切;↩ 在第一个动作淡入 0.12 秒;○、短名与份数在平账落定;此刻框用拨盘的 ease-out(过冲 3.7 %)滑 0.32 秒;侧栏的英雄数字与“拿到”逐格改字,不重绘侧栏
概念层叠在图上的一张 canvas灰格(宽一份、高同色块)沿行飞进中线,再飞向右翼,带 0.2 秒拖尾(半速 0.1、逐帧 0.12),右翼已经入账的格子上不留拖尾;池是中线上一道灰条,满 CAP 份时与色块同高。平账后整张清空

换帧。 stage.onFrame 按来路分:页面自己走(讲述、连播)时带着速度;别人走(←/→、刻度、合页 followFrames)先停讲述与连播、收起卡、清掉讲完留下的墨线与描边,再按距离选过渡:前进一帧用逐帧短版,按住方向键(event.repeat)或一次跳多帧沿用依次扫出(不飞灰格,数字直接到终态),往回只淡出。连播接管了 stage.play / pause / toggle,按半速一轮轮过账,28 轮约 45 秒。

讲一遍。 composite 从 f21 起:静 0.4 秒,f22 全速,f23 全速再停 0.8 秒,f24、f25 半速,f26 全速再停 1.5 秒,共 15.5 秒;story 从 f14 起:f15 全速,f16–f18 半速,f19 全速再停 1.5 秒,共 13.1 秒。墨线不写死:在讲述的几拍里找“上一轮留白为 0、这一轮退回、之后只减不增”的一段(composite 是 f23 → f26,story 没有),描边给这一段里拿得最多、至少出现两轮的那一件(主水管)。墨线是 .y-rows 里一根 1 px 竖线,压在中线数字的纸色底下,每过账一行就在入账那 0.6 秒里接到下一个数。讲完停在 f26,第一次悬停、按键或点按时墨线与描边退场。

接 ix 用了多少。 createIx(...) 一次调用 11 行;宿主回调(命中、has、名字、矩形、两张卡的摆位)约 100 行;两张卡的内容约 90 行;按 ix.frame() 画描边、压暗、弹出与键盘焦点,加 ↑/↓ 换行,约 80 行;“其余 N 件”、↩、○ 与侧栏标签的点击约 40 行。侧栏“这一件”约 100 行是这张图自己的仪表,不算在内。状态机、时序、卡的展开与收回、引线、隐藏按钮、触屏和钩子都是 ix.mjs 的。一件事在 28 行里反复出现,所以 ix 的 id 是“这一行的这一块”:行|翼|事项(翼是 l、r;s 是中线的留白数,a 是 ↩,x 是 ○,事项 * 是“其余 N 件”);描边追踪、同轮对方保持原亮度、其余降到七成(展开时 18 %)由页面按 X.focus / X.dim / X.pop 画。命中按行、再按离中线几份算,外端放宽 10 px。隐藏按钮先列此刻这一行,再从上往下列更早的行;↑/↓ 在相邻两行之间找横向最近的标记。“其余 N 件”点开仍是逐件展开;↩ 和 ○ 点开的是被答(或失效)问题所在事项在这一行的色块(藏在“其余”里就先展开)。这两种点击在捕获阶段先截下,不让 ix 打开它们自己。

宿主契约不够用的只有一处:两张卡的内容。ix 的 peekHTML / detailHTML 读拨盘的 itemFacts(来自哪条流、本轮进了几条输入),让位图的卡要写“这一行这一笔”:前 → 后、同一轮的另一边、这一轮答掉或失效的问题、到此刻让出几轮。这一处 ix.mjs 已经补上了:批次记谱与回应时序合入时加了可选的宿主钩子 peekHTML(f, o)、detailHTML(f, o)(缺省仍是事项卡),让位图照它的签名接,ix.mjs 不再改动。其余照契约:keysIn 放进图里,skip 跳过表头、时间与旁白列,seen() 在平账前把份额与问题标成“还没到”,卡上写“本轮还没平账”。

和故事的出入。

  • 概要卡“贴在标记上方,贴边时翻到下方”照做,只多一条:标记在此刻这一行、下方放得下时挂在下方(下面只有空着的未来行,上面的描边不被盖住)。挂在上方时它会盖住上面几行同一件事的描边,要追线时移开指针或点开固定;讲完停下的 f26 下方放不下,仍在上方。
  • “其余 N 件”点击仍是展开逐件(不出详情卡),沿用原来的用法;悬停给概要卡。
  • ↩ 一栏从 24 px 放宽到 32 px,放得下 ↩₂ 和 ○。
  • 逐帧短版里英雄数字在平账前写 0,平账硬切;讲述与连播里逐格数。
  • 平账前,侧栏“开着的问题”列的是上一轮的问题并注“本轮还没平账”;平账一帧切成这一轮的:标题改为“这一轮的问题 · 关上 N · 开着 M”,答掉划去并写动作句,失效转灰并写怎么失效,新登记的标“新登记”,开着的给“去回答 →”。
  • 右翼入账时,拖尾不压在已经入账的色块上:账写到哪里,哪里就干净。
  • 时间列和旁白列仍是“跳到这一帧”。旁白列保留原来的小提示框(这一轮的标签;行高不到 30 px 时只有这里看得到),不出 ix 的卡。

5 direct:自审与待你短评 ​

拍静帧逐张看过之后改了:拖尾的透明度从 0.32 降到 0.22、高度从六成降到五成,右翼已入账处不留拖尾(第一版整条右翼蒙一层灰);↩ 栏放宽(○ 被左翼第一块盖住了一半);详情卡里答掉的问题不再和“这一轮你的回应”重复,失效的单列一节。

想听你判断的几处:

  1. 英雄数字现在是“让出 [30] 拿到”一行大字,下面一行小字“让出 30 = 拿到 30”,入账时“拿到”逐格追上,平账时等号转墨。第 3 节写的是“左右两侧小字,中间一个等号”,我读成了这样;也可以只留下面一行。
  2. 概要卡在标记上方,会盖住上面几行;放到注释列一侧(和右翼详情卡同侧)就不盖描边,但离左翼的标记远。
  3. 从画廊点进来也算“从别处链来”,不讲;要不要让画廊进入的也讲一遍。
  4. 灰格在左翼起飞时是满高、八成灰,30 格同时在飞时左翼上像一排灰点;想更像“剥下来”,可以起飞时先只有半高。

6 ship:静帧与核对 ​

静帧(1440×900,composite,本机临时目录,不提交):第一拍中途 tellAt(1.32)(f22 的 19 格灰格正从左翼飞向中线,左翼降到四成,英雄数字还是 0);第二拍英雄数字数到 30 tellAt(5.16)(池满、停 0.12 秒的那一刻,“让出 30 = 拿到 0”);第三拍停在 f26 tellAt(15.5)(墨线 25 → 13 → 12 → 1,主水管三行描边,侧栏“主水管:挖开换还是免挖? 8/17 10:00 前 · 去回答 →”);悬停 ?frame=26 的主水管;展开 ?frame=23 的猫看病 ixAt(0.9)。

逐项对过第 2 节的数(页面的 foldYield.rows 现算,与记录一致):CAP 30;冷启动 57,之后 27 轮让出 300 = 拿到 300,只有 f27 为 0;f22 让出 19(6 件撤下、4 件并入、留白 2),拿到猫看病 12 → 24、待审 PR 0 → 6、开学文件 0 → 1;f23 让出 30(母亲换水管 24 → 6、猫看病 24 → 12),拿到 master CI 1 → 6、留白 0 → 25,答掉 ask-16 与 ask-20,ask-08 失效;f24 15、f25 6、f26 19;留白 f22–f26 为 0、25、13、12、1;猫看病让出 6 轮 35 份、拿到 4 轮 38 份;留白动用 13 轮 115 份、退回 7 轮 51 份;主水管 f16 首次出现 3 份。story:CAP 27,冷启动 f01 31 份,之后 347 = 347,f15 让出 27(试用 24 → 6、发布 12 → 3;妈妈 12 → 24、留白 3 → 18),f19 让出 21,没有墨线。

验证:node scripts/check-ix.mjs(整理脉冲、份额拨盘、腕上一瞥、批次记谱、两周小倍数、回应时序、让位图)两套数据每页 16 / 16;node scripts/shoot-forms.mjs --only yield,all --gpu --check all-sync 两套数据无报错,合页逐节跟上所选帧;导出的单文件合页(export-all.mjs)在 file:// 下 all-sync 通过;逐个悬停 composite f28 的 146 个标记、story f36 的 154 个,并展开其中三分之一,无报错。讲述第二拍(30 格过账)在 headless Chrome(GPU)里 60 fps,帧间隔 p95 16.8 ms,每帧脚本 0.17 ms(p95 0.7 ms);逐帧切换的整步重绘脚本 1.3 ms、含样式与布局 2.7 ms。prefers-reduced-motion 下讲述照样按拍前进,每拍直接到终态,不飞灰格。本机负载高时,python3 -m http.server 默认的连接队列(5)会让 Chrome 并行请求模块失败(表现为页面钩子未定义,与页面无关),换成队列更深的本地服务后全部通过。