Skip to content

原版树图 · 动画记录:参考、数据、故事 ​

状态:2026-10-20 按第三轮的六步流程(reference → data → story → motion → direct → ship)重做原版树图的动画与交互。第 1–3 节在任何东西动之前写下,定下一个点、一个英雄数字与三拍;第 4–6 节是照它做完之后的实现、出入与验证。原型探索,不是规范。树图怎样承载信息、承载哪类回应仍记在 spatial.md;这次改动的动画与交互以本文为准。范本是 home-motion.md(换轮三拍、答一件少一件、回执跟着条目走)与 watch-motion.md(阅读工具的概念层只占两成、只在节拍上动),两层法则与交互标准见 CONCEPTS.md。下面的数都由页面用同一份 scenario.mjs 回放现算,规则见 2.1;推算脚本只留在本机,不入库。

树图与两个概念动画有两处根本不同:它是阅读工具,坐在电脑前一格一格读,静止是默认;它能作答,工作评审的格子里直接有“批准 / 要求修改”。所以概念层约两成、只在两种节拍上动:换轮(←/→、连播、合页顶栏选帧)与作答。“丝滑”来自同一件事的格子在换轮、作答、展开之间位置连续,不靠粒子。

1 参考(reference) ​

1.1 树图现在怎么变 ​

读 app.mjs、styles.css 与 variants/spatial-kit.mjs 的 createFlipBoard 所见(原来的 motion.mjs 是更早的克隆幽灵实现,已经没有页面在用)。格子按 data-id 保留 DOM,FLIP 从旧矩形走到新矩形,一律 320 ms,cubic-bezier(.2,.75,.25,1):

时刻现在怎么动断在哪
换轮留下的格子平移并缩放色块(flip-shape),正文只平移、用 clip-path 裁到色块大小;内容改了的旧正文 0.6 前淡出、新正文 0.18 后淡入;新格子从目标 60% 大小处淡入,延迟 0.18;撤下的原地缩到 55% 淡出;合并的来源飞进目标;旁白、日期、计数一帧硬切;左栏与右栏整块重画,旁白区 180 ms 浮一下全部挤在 0–0.32 秒一起动,没有先后。composite 每轮中位有 11 格在变(见 2.4),眼睛不知道先看哪;数字与格子同一刻变,看不出“因为什么少了一件”;clip-path 的动画留在主线程
作答(格子里批准 / 要求修改,详情里其余)整页重画:格子换成回执一行(og-settle 260 ms 浮入),右栏重画,屏幕底部弹 4.2 秒 toast“你批准了 · 已保存”toast 把视线拉到屏幕底;格子的标题与摘要在重画里闪一下
下一轮整理之后回执按条目与问题 id 查(answers.find(item, cursor, ask.id)),Agent 一换问题就取不到;另弹 toast“Agent 已在 12:00 的整理中收到你的 1 条回应”f22 批准 #13572,f23 这一格换成“三个旧 PR 推到哪天”,回执凭空消失,只剩一句会消失的 toast
详情点格子,右栏整块换成这一件,内容 180 ms 浮一下与被点的格子没有几何联系:格子在中间,详情在右边整块替换,收回也不回到格子;与拨盘、脉冲“沿自己的几何弹出”不是同一标准
悬停只有被裁切或很小的格子 320 ms 后弹一张自写的卡(完整标题与问题)大格子没有概要;与 ix 的概要卡、0.15 秒宽限、停住播放都不是同一套
连播每 3.2 秒一轮(320 ms 过渡 + 2.9 秒读),setInterval悬停、展开都不停;作答也不停,刚按下的回执可能下一秒就被换轮冲走

1.2 从 D 与手表搬什么,不搬什么 ​

要素出处树图
先换字,0.4 秒后才动第一个数;列表按“离场 → 移位 → 进场”依次走D BEATS.turn搬。切点换日期、旁白、整理依据、左栏与右栏的字;0.40 秒英雄数字翻一格;离场 0.40、移位 0.48、进场 0.60,进场错开 40 ms、最多 8 个
你做过的先确认D:回执 0–0.30 秒填实,列表其余不动搬。上一轮按下的回执 0–0.30 秒填实、小字在切点换成“已收到 · Agent 在 12:00 的整理中读到”,格子都还没动
答一件,少一件:卡原地收成回执,下一轮整理读到了才带着让出的份额沉下去D 3.4搬,落在面积上:格子不动、份额不变,只是提问与按钮收成回执、数字减一;份额要等下一轮整理才变,那时它和别的格子一起按真实的下一帧缩放、移位
回执跟着条目走,不随版本消失D 4.4搬。同一个问题重登记仍是回执;问题关上,回执留成格子里的一行小字;换成另一个问题,格子写新问题,下面一行“你批准了上一版 · 已收到”
数字只在节拍上动,差 1 滚一格、差 2 以上一帧硬翻D roll搬到英雄数字;格子上的“N 份”在移位落定(0.84 秒)时翻,不交叉淡化
份额变化沿自身几何长缩手表:64 格逐格换主人;拨盘:扇区沿弧长缩落在矩形上:色块从旧矩形缩放到新矩形,字不随之拉伸(反向缩放保持 1:1),留在色块左上角、被色块裁住;只动 transform 与 opacity
概念层两成,只在节拍上动,静止为零手表:本轮输入化成灰点落向表圈搬,但只画落进格子的。本轮采用且归到板上某一格的输入化成灰点,从左栏流向中间、落进那一格,一条一粒、最多 40 粒;没采用的不画;只用灰,只在换轮的 0–0.50 秒
悬停概要、点击沿自身几何弹出 8 px + 引线 + 详情卡ix.mjs搬。格子四边各外扩 4 px 抬起;引线从格子右沿水平接到右栏;详情卡就是右栏:盖在概览上、从引线接上的那一点沿左沿展开,内容沿用原来的详情(作答卡、为什么在这里、依据、来源处的回应、本轮变化、版本、时间)
自动讲一遍手表:顶层直接打开、不带 ?frame=、没有 referrer 时演一次搬,约 10 秒,见 3.4
4 秒节拍器、首尾循环、粒子云与余辉脉冲、拨盘不搬。树图只在换轮、作答、展开三种时刻动
手势(长按、左滑、下拉跟手)D不搬。桌面上悬停就是概要

2 数据(data) ​

2.1 规则 ​

量怎么算出处
英雄数字:N 件等你回应这一层(默认根层)里 currentAsk(s, id) 不为空、且本页没有对这同一个问题作答的件数variants/shared.mjs currentAsk;app.mjs 的 waiting();与 D 的 compose().waiting 同口径(D 也只数根层)
格子与面积根层 foldLayer 折掉 1 份且不问你的小事成“另有 N 件小事”,layoutFill 按 rank 铺满 64 份,留白是最后一格records[i].state.root.items[].share;spatial-kit.mjs foldLayer;a-layout.mjs layoutFill
本轮动了的格子相邻两帧同一块板(1440×900 下 738×521 px)上:进场(新 id,含从小事块里出来的)、离场(含收进小事块的)、移位或缩放(矩形差 > 0.5 px)、只换字(矩形不变、diff.changes 里有它)同上;records[i].diff.changes
本页作答createAnswerBook:按下即 saved,回放到下一帧变 acknowledged;按条目找最近一条,再与这一帧的 currentAsk 比:同一个问题 = 回执,另一个问题 = “你答过上一版”,没有问题 = 关上后的小字spatial-kit.mjs createAnswerBook;respond.mjs responseStatus
真实作答event.feedback[] 带 ask 指向这个问题同 拨盘 data.json 的 rules.openAsks
灰点本轮 frame.events 里采用且 relatedIds 归到此刻板上某一格的,一条一粒、落进那一格;最多 40 粒,超出按 event.at 排序后等距抽样(不是取前 40);其余不画motion/dial-model.mjs rounds[i].events[].root(与拨盘、手表同一条归属规则);时刻取 frame.events[k].at
新登记的问题这一帧的 currentAsk 的 id 不在上一帧任何格子的问题里frame.asks

2.2 composite:f21 → f22 → 批准 #13572 → f23 ​

composite 每 12 小时一轮。样张取 D 的同一处(home-motion.md 2.4):f22 有一件工作评审正好能在格子里批准,真实的下一步也是批准,f23 是两周最大的一次让位。

时刻事实出处
f21 08-13 12:00「#13567:复用防护可被绕过」97 条输入、采用 31;6 件等你回应(母亲九月住哪、猫的药量、派对人数、Ture 的 VAB、开学同意书、Göran 抬棚屋);格子 9 块,小事块里 12 件frames[21];waiting()
f22 08-14 00:00「热浪第一天:药量超过失明线」172 条输入(两周第二多)、采用 34,其中 26 条归到板上的格子(#13572 那格 8 条);5 件等你回应;母亲 24 份、猫 12 → 24、pr-reviews-0814 新增 6 份(“#13572等你评审,另3个PR待审”,ask-20 approve,格子里有“批准 / 要求修改”)、Ture 3、开学 1,小事块 12 件 → 6 件,留白 2 → 0;离场 5 格:派对、棚屋撤下,#13567 并入 #13572 那格,旧的开学同意书并入新的一格,留白用完frames[22];records[22].diff;currentAsk
本页批准(模拟)5 → 4;那一格原地收成回执“✓ 你批准了 · 已保存,等下一轮整理”,面积不变,别的格子一格不动本页作答
11:38(真实)你在 GitHub 上批准了 #13572:feedback: {ask: ask-20, action: approve, via: source}f23 的事件
f23 08-14 12:00「打了诊所;母亲自己定了」115 条输入、采用 34;3 件等你回应;猫 24 → 12(打了诊所)、母亲 24 → 6(自己定了,问题随改写失效)、master CI 从小事块里出来 1 → 6、#13572 那格 6 份不变但问题换成 ask-22“三个旧 PR 推到哪天再看?”;root.used 64 → 39,留白 0 → 25,两周最大,与拨盘 largestSingleYield 同一处frames[23];records[23]
回执这一格的问题换了,现在的页面取不到回执;照 2.1 的规则,它写新问题,下面一行“✓ 你批准了上一版 · 12:00 已收到”本页作答

这一轮动了几格:f21 → f22 进 2、出 5(其中 2 格是合并飞进目标)、移位 4;f22 → f23 进 2(master CI 从小事块出来、留白长出来)、移位缩放 6。

2.3 story:f03 → f04 → 选「固定模板」→ f05 ​

story 数据集不定时、每轮 3 条输入,没有 approve 的问题,所以作答在详情卡里。样张同 D 的 story 对照(home-motion.md 2.4):

时刻事实出处
f03 10-12 20:30「厨房渗水,物业尚未确定上门时间」4 件等你回应(导出模板、周六见妈妈、API 账单、面谈职责);10 格frames[5]
f04 10-13 09:20「两条提醒来自同一张2910元API账单」3 条输入、采用 2;4 件等你回应(数字不动);两条账单线索 invoice-mail、invoice-chat 并入新的 expenses(6 份),周六 6 → 12frames[6];records[6].diff
本页在详情里选「固定模板」(模拟)4 → 3;导出那格(12 份,ask-03 choose)收成回执,面积不变本页作答
14:34(真实)林苒在团队群里回复“这版先不做模板编辑”:{ask: ask-04, action: fixed, via: reply},指向子事项上的同一问f05 的事件
f05 10-13 14:40「远川两店库存口径不一,总库存暂不承诺」3 件等你回应(数字不动:让出的份额被新问题接走);导出 12 → 6(“导出发布已定固定模板”,问题关上,回执留成小字)、试用 12 → 24(新问题“今天对远川怎样表态?”)、费用 6 → 3,留白 3 → 0frames[7]

2.4 两周的换轮工作量与英雄数字 ​

compositestory
换轮次数2836
板上的格子(含小事块与留白)6–16 块2–10 块
一次换轮动了的格子中位 11、最多 18(f15 → f16);f26 → f27 只换字 2 格,一格不移中位 8、最多 11
其中移位或缩放几乎每轮都过半:条带按 rank 铺,一件变了,同一条带和后面条带都要让同左
从小事块里出来 / 收进小事块一次最多 2 / 5没有小事块
英雄数字0–8:f00 为 0,f04、f08、f15 为 8,f23–f25 为 30–4

试过给条带搜索加一项“离上一帧的位移”代价(λ 从 0.05 到 1),28 轮里移位的格子只从 201 减到 178,代价是更扁的格子;所以不改布局,只把这些移动编排清楚。

3 故事(story) ​

一个点。 面积就是注意力,而它只在整理落地时挪:你在格子里批准一件,它先在原处收成回执,面积一份不让;等 Agent 下一轮整理读到了,份额才连同别的格子一起,从旧位置走到新位置。

英雄数字:N 件等你回应。 composite 的样张是 6 → 5(换轮)→ 4(你批准)→ 3(下一轮整理)。它是这块板唯一的大字(板头左侧,22 px 等宽,位置与字号永不变),回答场景的第一问“这两周里有几件等我”;只在两类时刻动:一轮整理落地,你作答或撤回。D 说的是同一个数,手机上排成卡,这里铺成面积。“本轮动了几格”不做成英雄数字:它几乎每轮都过半,说的是布局,不是你。

3.1 三拍 ​

拍时长发生什么观众此刻
1 换轮约 1.0 秒(另有 1.6 秒的新问题描边)先换字;本轮采用的输入化成灰点从左栏流进格子;0.40 秒数字翻一格;离场 → 移位 → 进场各走一段:撤下的原地缩小淡出、并入的飞进目标、收进小事块的飞进小事块;留下的沿自己的矩形长缩到新位置;新的从小事块里或原地揭开这一轮挪了什么,现在几件等我
2 作答0.46 秒在格子里按“批准”:提问与按钮 0.12 秒收起,回执一行在原处出现、空心勾描出,数字减一;格子不动、面积不变;详情里作答同样,回执也落在格子里我答了,但还没让
3 下一轮约 1.0 秒先确认回执:0–0.30 秒空心勾填实,写“已收到”,其余不动;0.40 秒数字翻;然后份额才让出去:答掉的、失效的缩小沉到后面,接走份额的长大,留白长出来;回执跟着那一格走答掉的去了哪,面积让给了谁

3.2 节拍表(秒,从切点起) ​

节拍切点 0回执 / 概念层英雄数字离场移位进场其他
换轮日期、旁白、整理依据、修订号、左栏、右栏概览、时间轴硬切回执填实 0–0.30;灰点 0–0.500.40 起 0.260.40–0.640.48–0.84:旧字 0.48 起 0.16 淡出,新字 0.60 起 0.24 淡入;“N 份”与“已用 / 留白”0.84 翻0.60 起 0.36,错开 40 ms,最多 8 个新问题描边 0.96 起 1.6
作答回执的文字空心勾 0.12–0.300.20 起 0.26———提问与按钮 0–0.12 收起,回执与“✓ 你批准了”0.10–0.30 出现
撤回——0.10———回执 0–0.10 收起,提问与按钮 0.10–0.30 回来
拖时间轴、对比、改尺寸同换轮无00–0.200–0.320.08 起 0.30同时起步
下钻、放大小事块面包屑无00–0.37经锚点格子缩放 0–0.460.05 起 0.41慢动作把所有时长乘 3

连按 ←/→ 时,上一段直接跳到终态,再从那里开始下一段。prefers-reduced-motion 时一切直接到终态。

3.3 两层与约束 ​

  • 信息层(约八成)。 格子、面积、字、英雄数字、回执、引线与卡。只在节拍上动。颜色沿用树图自己的:格子按根层事项的颜色,墨点 = 登记了回应路径,赭色描边 = 本轮有变化,绿色 = 你的回执。
  • 概念层(约两成)。 只有灰点:本轮采用且归到板上某一格的输入一条一粒,从左栏右沿流向中间、落进那一格、落地即灭,最多 40 粒(超出按输入时刻等距抽样);没采用或归不到板上的不画。只在换轮的 0–0.50 秒出现,静止时为零;不出文字与数字、不用颜色;本轮 0 条输入(story 的两次 review)就不落。
  • 绝不动。 英雄数字的位置与字号;板的边界;排序规则(rank);格子的字号。动画只表现 layoutFill 排出的结果,不发明位置。
  • 每格一次只走一段。 一次节拍里每格从旧矩形到新矩形只有一段运动,不先缩后长;字不拉伸。
  • 先后。 切点换字 → 你做过的先确认(回执)→ 英雄数字 → 离场 → 移位 → 进场 → 新问题描边。
  • 不提前。 下一轮整理落地之前,不动面积,回执不填实;悬停在节拍中途时,概要卡不说出后面节拍的事。
  • 预算。 只动 transform 与 opacity;正文用反向缩放留在色块左上角,不用 clip-path 动画。

3.4 自动讲一遍 ​

只在顶层直接打开、地址不带 ?frame=、没有 referrer 时演一次;任意键或点按跳过,跳过时直接停在终态;视图栏的“重演”在顶层打开时都有。画廊、合页、体验站弹框(都在 iframe 里或带 referrer)与带帧的地址一律静止;prefers-reduced-motion 时也不演。

composite 约 10 秒:停在 f21,0.9 秒后换到 f22(第 1 拍);2.6 秒悬停 #13572 那一格看概要;4.4 秒替你按下“批准”(第 2 拍);6.0 秒换到 f23(第 3 拍);7.8 秒再悬停那一格,概要写“你批准了上一版 · 已收到”和新问题;10 秒收起。story 同样三拍:f03 → f04(两条账单线索并入一格)→ 展开导出那格、在详情卡里选“固定模板”→ 收起 → f05。讲一遍替你按下的回答与真实数据里你的下一步相同,按下后和你自己按的一样,可以撤销;“重演”先撤掉它再演。

3.5 交互(共用 motion/ix.mjs) ​

  • 悬停。 鼠标移到格子上(含格子外沿 10 px 内的板边),或 Tab 到它(每格一个隐藏按钮,在“对比”之后):出概要卡,写来自哪条流、完整标题、几份与本轮怎么变、本轮进了几条输入、开着的问题或你的回执;其余格子降到七成;连播与在途的节拍停在当前时刻。离开 0.15 秒宽限,卡 0.12 秒淡出,再过 0.4 秒接着走。悬停输入栏或概览里的问题,对应格子描边(原有)。
  • 展开。 点格子、点它的概要卡、Tab 后按 Enter,或点输入栏与概览里指向它的条目。0 秒切点:旁白标题切到“这一件 · …”;0–0.3 秒格子四边各外扩 4 px 抬起;0.4–0.6 秒引线从格子右沿水平画到右栏;0.6–0.9 秒详情卡从引线接上的那一点沿右栏左沿展开、再向右铺满,盖在概览上。卡里是原来的详情,作答照常在卡里做,回执同时落在格子里。
  • 收回。 Esc、点空白、再点同一格、卡上的“↶ 概览”:卡 0.2 秒收起、引线 0.15 秒缩回、格子 0.2 秒落回。换轮、连播、合页顶栏选帧、下钻与对比立即收起。键盘打开的,焦点进卡;收回后回到那一格的隐藏按钮。
  • 作答。 格子里“批准 / 要求修改”,详情卡里 A 批准、R 要求修改、其余控件;U 撤销最近一次。不再弹 toast,“已保存”只写在回执里(读屏用一个隐藏的 aria-live)。树图本身能作答,不加“去回答 →”。
  • 钩子。 window.foldTree 有与 foldDial 同名同义的 hover / unhover / open / close / ixAt / paused / pointOf / ixState,另有 index、go(i)、play()、stop()、beatAt(秒)(把在途节拍定在某一刻,null 放开)、answer(id, action)、undo(id)、waiting()、tiles()、pick()、nearOf(id, px)、tell()、skip()。scripts/check-ix.mjs 的 16 项在本页同样跑。

4 动(motion) ​

4.1 文件与分工 ​

  • motion.mjs:只管“一组怎么动”(原来那份克隆幽灵的实现已经没有页面在用,整份重写):节拍表 BEATS 与节拍时钟 createBeat(一次换轮或作答的全部动画挂在同一只表上,可停住、可定格、可跳到终态);按 id 保留格子的板 createBoard(离场 → 移位 → 进场,换了字的格子逐个部件交接);英雄数字滚一格 roll、一行字在节拍上翻 flipText;灰点 planGrains / drawGrains。
  • app.mjs:编排(谁在哪一组、什么时候动);英雄数字;回执跨版本(receiptOf);作答与撤回;可停住的连播;接 ix.mjs(命中、外沿 10 px、概要卡、详情卡的摆位与内容、弹出、降暗、隐藏按钮);讲一遍与“重演”;window.foldTree。
  • styles.css:格子的尺寸类与裁字标记从格子挪到正文上(.pin-tile.is-small … → .pin-tile .is-small …,同样的优先级),旧正文因此保留旧排版;末尾追加英雄数字、回执的勾、新问题描边、弹出的底板、键盘描边、灰点画布、详情卡与 --ix-* 变量。ix.css 由 app.mjs 用 <link> 载入。
  • index.html、explore.mjs、shared.mjs、respond.mjs、spatial-kit.mjs、ix.mjs 都没改;“重演”按钮与隐藏按钮组由 app.mjs 插进视图栏。

4.2 实现的节拍表 ​

秒,从切点起,[起点, 时长];与 3.2 一一对应,motion.mjs 的 BEATS 里同名。

节拍回执 / 概念层英雄数字离场移位换字(旧 / 新)进场(错开 40 ms,最多 8 个)其他
换轮 turn回执填实 0–0.30;灰点 0–0.500.40 起 0.260.40–0.640.48–0.840.48–0.64 / 0.60–0.84;“N 份”、留白数与“已用 / 留白”0.84 翻0.60 起 0.36新问题描边 0.96 起 1.6
作答 answer空心勾 0.12–0.300.20 起 0.26——提问、按钮、标签 0–0.12 / 回执与“✓ 批准了”0.10–0.30—格子不动、面积不变
撤回 undo—0.10 起 0.26——回执 0–0.10 / 提问与按钮 0.10–0.30—
拖时间轴、对比、改尺寸 quick回执 0–0.2000–0.200–0.320–0.12 / 0.10–0.300.08 起 0.30同时起步
下钻、放大小事块 zoom—00–0.37经锚点格子 0–0.460–0.16 / 0.18–0.460.05 起 0.41
交互(ix)时刻
悬停其余格子 0.15 秒降到七成(只降色块,字跟着);概要卡 0.15 秒淡入,贴在格子朝板中线的一侧;离开 0.15 秒宽限,0.12 秒淡出,0.4 秒后在途节拍与连播接着走
展开0 秒旁白标题切到“这一件 · 短名”;0–0.3 秒格子背后一块同色底板四边各外扩 4 px(带一圈墨线与投影,过冲约 3.7 %);0.4–0.6 秒引线从格子右沿水平画到右栏左沿;0.6–0.9 秒详情卡先沿右栏左沿、再向右铺满
收回卡 0.2 秒收起、引线 0.15 秒缩回、底板 0.2 秒落回,然后标题切回

4.3 取舍 ​

  • 字不拉伸、色块裁字。 正文放在色块里面,色块沿自己的矩形平移与缩放,正文按同一采样(每段 14 个关键帧、线性插值)反向缩放,钉在色块左上角、被色块裁住。不用 clip-path,也不在关键帧里写 transform-origin,只动 transform 与 opacity。
  • 换了字的格子逐个部件交接。 内容变了的格子把旧正文留成“幽灵”(旧尺寸、旧尺寸类,所以旧字不重排),新旧正文按 data-part(标签、份数、标题、提问、回执、摘要、页脚)配对:同字的从旧位置滑到新位置,换字的旧淡出、新淡入,份数与留白数在落定时一帧翻,不交叉淡化。
  • 回执只有一个部件名。 回执在格子里(按钮的位置)或标题下一行,答的是这一版、上一版还是已关上的问题都叫 receipt;下一轮读到时新旧回执配成一对,新的一行立刻写“已收到”、实心点 0–0.30 秒放大填进空心勾,再随格子移位,不在半路淡出重来。
  • 回执跟着条目走。 receiptOf 按条目取本页最近一次作答,再与这一帧的问题比:同一个问题 = 回执,问题换了 = “你批准了上一版 · 已收到”,问题关上 = 一行小字(story f05 导出那格“你选了「固定模板」· 已收到”)。读屏用一个隐藏的 aria-live,不再弹 toast(“复制 JSON”的提示保留)。
  • 作答不被停住。 悬停与打开的卡会停住在途的换轮与连播;作答与撤回是你自己的动作,回执在你悬停或看卡时照常画完。
  • 详情卡就是右栏。 ix 的详情放在右栏的位置上、和右栏同高,内容是原来右栏的这一件(作答、为什么在这里、依据、版本……),概览留在它底下;作答在卡里做,回执同时落在格子里,卡里的字原地换掉,位置与滚动不变。右栏在板子下面时(窄屏)卡也在那里,引线向下,打开后把它滚进视野。
  • 弹出不拉字。 外扩 4 px 是格子背后的一块底板按比例放大,格子本身与字不缩放;打开时板子的裁切临时放开,贴边的格子也能外扩。
  • 灰点。 只画采用且归到板上某一格的输入(拨盘的归属规则 rounds[i].events[].root,收在小事块里的落进小事块),一条一粒,从左栏右沿出发、落进那一格、落地即灭;最多 40 粒,超出按 event.at 排序后等距抽样(不是取前 40);没采用或归不到板上的不画,不再半路熄灭。半径 1.2 px、最浓 0.24(初版 1.7 px、0.34 的约七成),时长不变。只在顶层、不对比、左栏在板子左边时画;story 的 review 轮没有输入,就不落。悬停时降到四成。
  • 连播。 一轮 = 换轮 1.0 秒 + 读 max(2.2, 2.9 / 速度) 秒;悬停、打开的卡停住累计,移开 0.4 秒后从停住处接着计时(第一轮也要等满,所以按“播放”后约 3.9 秒才换第一轮,与原来的 3.2 秒相近)。
  • 链入。 ?item= 落地时那一件直接以卡打开(等在途节拍走完);打开卡时地址带上 item,收回时去掉。
  • 减少动态时 不建节拍,一切直接到终态,ix 的弹出、引线与卡也直接到位,不讲一遍。

4.4 与故事的出入 ​

  • composite 那一格自己没有让。 f22 批准 #13572 之后,f23 这一格仍是 6 份(问题换成“三个旧 PR 推到哪天再看”);这一轮让出份额的是母亲 24 → 6、猫 24 → 12,留白 0 → 25 长出来,回执跟着这一格从左下移到上排中间。“答掉的缩小沉下去”在 story 里照字面发生:导出那格 12 → 6、问题关上、回执留成小字。
  • 悬停也停住新问题的描边。 描边是换轮这一拍的最后一段(0.96 起 1.6 秒),讲一遍 7.8 秒的悬停落在它中途,描边就停在半透明处,直到移开。照“悬停停住在途节拍”的规则没有特判。
  • 两个计数。 英雄数字只数这一层的格子(与 D 同口径),右栏概览的“N 个问题等你”数的是全部开着的问题(含子事项);story f04 两者是 4 与 6。没有改右栏。
  • 概要卡里回执写“已收到”的门槛 用本轮输入落定(0.50 秒),不是回执填实的 0.30 秒:ix 的卡只按 inputs / share / asks 三道门槛重写。
  • 引线穿过右边的格子。 引线从被打开那格的右沿水平走到右栏,路上的格子已降到七成,没有绕行。
  • 760–999 px 的版式(右栏在中间一列、最右一列空着)是原有的,卡跟着右栏走,没有改版式。
  • 灰点改少改淡(上线后)。 初版本轮输入两条一粒、最多 120 粒,没采用的也飞出去、在半路熄灭。用户看后嫌换轮时飞的小点多,改成只画落进格子的:采用且归到板上某一格的一条一粒,上限 40,超出按 event.at 等距抽样;半径与最浓各降到约七成(1.7 → 1.2 px,0.34 → 0.24),时长 0–0.50 秒、落地即灭、悬停降四成、减少动态时不画都不变。composite f22 → f23 由 59 粒(落进格子 18、半路熄灭 41)降到 34 粒(这一轮采用的 34 条都在板上);f07 → f08 采用 94 条,只画 40 粒;story f22 → f23 三条都采用,由 2 粒变 3 粒。

5 导(direct) ​

定格用 foldTree.beatAt(秒) 把在途节拍(含之后新起的)定在同一时刻,用 foldTree.ixAt(秒) 定住展开;指针用 CDP 真移、真点。1440 × 900,打开 GPU。静帧只留在本机,不入库。

定格看什么
f21 → f22,0.62 秒英雄数字已翻到 5;撤下与并入的格子已淡去,母亲、猫与 Ture 在长缩,旧标题将尽、新标题刚起;“已用 62 / 64 · 留白 2”要到 0.84 秒才翻
f22 在格子里批准 #13572,0.30 秒 / 终态按钮收起,回执“你批准了 · 已保存 · 等下一轮整理”在原处出现、空心勾描出,“✓ 批准了”换掉标签;数字 5 → 4;别的格子一格不动,右栏概览里同一条也成了回执
f22 → f23,0.30 秒 / 0.70 秒 / 终态0.30 秒回执已写“你批准了上一版 · 已收到”、勾已填实,格子都没动,灰点在落,数字还是 4;0.70 秒猫与母亲在缩,待审 PR 带着回执移到上排;终态数字 3、留白 25
悬停待审 PR(f23)其余降到七成;概要卡写“✓ 你批准了上一版 · 已收到 · 12:00”与新问题
点开待审 PR,0.9 秒底板外扩、引线到右栏,详情卡铺满右栏,卡里是“你批准了(上一版)”的回执与新问题;标题“这一件 · 待审 PR”
story:f03 → f04 → 选「固定模板」→ f05两条账单线索并入新的费用一格;导出那格在详情卡里选「固定模板」,卡里与格子里的回执同时出现,数字 4 → 3;f05 导出那格 12 → 6、问题关上,回执留成“你选了「固定模板」· 已收到”

静帧:composite-* 与 story-* 各 8 张(换轮 0.62 秒、作答 0.30 秒与终态、下一轮 0.30 秒 / 0.70 秒 / 终态、悬停、展开 0.9 秒),只在本机。

6 交付(ship) ​

6.1 性能 ​

无头 Chrome(打开 GPU),1440 × 900,不降速;每一拍从切点起量 2.7 秒 requestAnimationFrame 间隔,每拍量两次(第二次是同一页上再演一遍)。sync 是切点上那一次同步工作(重画左栏、右栏、板,量一次部件位置,建动画)。

节拍格子(移位 / 进场 / 离场 / 换字)sync msfpsp95 ms最长一帧 ms
composite f15 → f16(两周动得最多)11 / 3 / 1 / 926 / 2959.3 / 6016.833(切点)/ 16.8
composite f21 → f224 / 2 / 5 / 418 / 1460 / 59.616.816.8 / 33(切点)
composite f22 → f23(批准之后)6 / 2 / 0 / 620 / 1359.6 / 6016.833(切点)/ 16.8
story f03 → f04、f04 → f05、第 15 → 16 帧8 / 1 / 2 / 4 等—6016.8至多一帧 33(切点)
点开一格的详情卡——6016.816.8
在格子里作答——6016.716.8

长帧只在切点上,至多一帧;之后全程 16.7 ms。页面打开后的第一次换轮另有一帧 230–300 ms(显卡进程第一次建图层),同一页再演就没有。CPU 剖析:切点的同步工作里板占三分之二(fitTile 量字、部件的一次布局读取),其余是左栏与右栏的重画。

6.2 检查 ​

  • make check 通过。
  • node scripts/check-ix.mjs(默认数据与 --data story):本页 16 / 16,其余各页照旧全过(pulse、dial、watch、notation、multiples、timing、yield 各 16 项,home 23 项)。本页的条目追加在 PAGES 末尾:?frame=22 停住、?frame=3 连播,挑板子左沿最大的一格,9 px 外是板子左边的空白,Tab 从“对比”起。
  • node scripts/shoot-forms.mjs --only original,all --gpu --check all-sync(两份数据):没有页面报错,合页逐节报告所在帧、顶栏选帧后全部跟上。
  • npm run site:build 通过;画廊预览 site/previews/original.webp 按工作环境说明的参数重截(英雄数字与视图栏变了)。
  • 讲一遍:顶层直接打开时两份数据各演一次(约 10 秒);第 3 秒按任意键,直接停在 f23(story 为 f05)、回答已在;“重演”先撤掉上次替你按下的回答再演;带 ?frame=、在 iframe 里、减少动态时都不演。
  • 减少动态:换轮、作答、展开都直接到终态,页面上没有在途动画。
  • 点小事块里的一件:铺开小事块,那一件的卡在缩放走完后打开;?item= 链入同样以卡打开。

6.3 没做与拿不准的 ​

  • 切点那一帧要做全部同步工作(重画左栏、右栏、两块板,量一次部件位置,建动画),本机不降速 13–29 ms,常常超过一帧;之后全程 16.7 ms。没有像 D 那样在 4 倍降速下量。
  • Safari:本次只在 Chrome 无头里看过;色块里反向缩放的字、:has() 与 min() 写的不透明度在 Safari 27 里是否一样,需要真机看一眼。
  • 小事块里的一件(1 份、不问你)不在板上,点它仍是铺开小事块、在那一层打开它的卡;收在小事块里时没有自己的概要卡。