Skip to content

Commit 9c1f615

Browse files
committed
docs(motion): 更正波 D 五处过时的动效标签
1 parent e719894 commit 9c1f615

6 files changed

Lines changed: 36 additions & 22 deletions

File tree

‎app/scripts/gen-tokens.mjs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ export const DURATION_TOKENS = [
9393
{ name: "toast-in", ms: 180, usage: "Toast 进场(规格 §8.4「Toast 180/140」)" },
9494
{ name: "toast-out", ms: 140, usage: "Toast 出场 —— 出场比进场快(规格 §8.4)" },
9595
{ name: "skeleton", ms: 1200, usage: "循环环境动效:骨架微光(规格 §8.4「--dur-skeleton 1200ms」)" },
96-
{ name: "card", ms: 220, usage: "面板 / 视图 / 列折叠(规格 §8.4「--dur-card 220ms」);今日 0 生产消费者,波 C 首次消费" },
97-
{ name: "reveal", ms: 500, usage: "显影 / 编排层(规格 §8.4「--dur-reveal 500ms」);今日 0 生产消费者,波 C 首次消费" },
98-
{ name: "page", ms: 150, usage: "页面切换(规格 §8.4「--dur-page 150ms」);今日 0 生产消费者,波 C 首次消费" },
96+
{ name: "card", ms: 220, usage: "面板 / 视图 / 列折叠(规格 §8.4「--dur-card 220ms」);**已有生产消费者**(T35b 实测 6 处:useColumnFlip / usePhaseFreeze / useScaleGrowth / useRevealMemory / usePlayheadJump / useTriTrackAlign 的档位→时长函数取 ms)" },
97+
{ name: "reveal", ms: 500, usage: "显影 / 编排层(规格 §8.4「--dur-reveal 500ms」);**已有生产消费者**(T35b 实测 7 处:useRevealChoreography 的 standard 档 + 上列 6 个 hook 的档位→时长函数 —— 其中 5 个只在 rich 档取它、useRevealMemory 各档都取)" },
98+
{ name: "page", ms: 150, usage: "页面切换(规格 §8.4「--dur-page 150ms」);🔴 **仍 0 生产消费者**(T35b 实测:波 C 已全部落地而页面切换动效不在规格 §8.6 的六条内 ⇒ 旧措辞「波 C 首次消费」已过期为假)" },
9999
];
100100

101101
/**

‎app/src/motion/controls.ts‎

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,17 @@
1919
* 只能用 `timeline.getChildren()[0]`(把返回值当 tween 用会让「旧 tween 冻结」一类断言**恒真 = 假绿**);
2020
* ② **绝不可**把 jsdom 的 `performance` 挂到 `globalThis`(`Performance-impl.js:14` 自调用 ⇒ 栈溢出)。
2121
*
22-
* 🔴 **使用纪律(波 C 复制本文件时必须遵守)**:本模块**只许经 `await import()` 到达** —— 它自己静态
23-
* `import { gsap } from "./engine"`(见下面的 import 段),所以**静态** import 本文件的首屏模块会把
24-
* **engine(连同其 `gsap`)拉进首屏静态闭包**,`vendor-gsap` 独立懒 chunk 的承诺(规格 §13 风险表)
25-
* 当场落空。判据 = `engine.guard.test.ts` 的「`app/src/**` 静态 import GSAP 家族的文件集合 ∩ 首屏
26-
* 静态可达闭包 = ∅」(**闭包交集**,不是白名单)—— 今天 `controls.ts` 有 **0 个生产消费点**所以安全,
27-
* 波 C 一旦静态引入,**该守卫会红**(不是静默洞);这条纪律与 `engine.ts` 头注的边界句是同一条。
22+
* 🔴 **使用纪律(精确口径 = R60.1 对 R41.3 适用范围的更正;`docs/standards/motion.md` 的「懒加载边界」同款)**:
23+
* **不许从「首屏静态可达」的模块静态 import 本文件** —— 本文件自己静态 `import { gsap } from "./engine"`
24+
* (见下面的 import 段),所以静态引用它的**首屏**模块会把 **engine(连同其 `gsap`)拉进首屏静态闭包**,
25+
* `vendor-gsap` 独立懒 chunk 的承诺(规格 §13 风险表)当场落空。🔴 **惰性视图(`React.lazy` / 注册表驱动)
26+
* 静态 import 本文件是安全的**(T27 实测:`SessionTriTrackView` 经 `views/registry.ts` 惰性到达 ⇒ 那条静态边
27+
* 不进首屏闭包)——「**只许经 `await import()` 到达**」是**过宽**的旧措辞,已按 R60.1 更正。
28+
* 判据 = `engine.guard.test.ts` 的「`app/src/**` 静态 import GSAP 家族的文件集合 ∩ 首屏静态可达闭包 = ∅」
29+
* (**闭包交集**,不是白名单);今天静态消费者 = `views/session/usePlayheadJump.ts`(T31,惰性链上)+ 若干
30+
* `import type`(类型边不进产物),动态消费者 = 5 个 hook(T27/T28/T29/T30/T32);T35b 用该守卫自己的仪器
31+
* 实测:`motion/controls.ts` ∈ 静态∪动态可达(333 文件)而 ∉ 首屏静态可达闭包(89 文件)⇒ 守卫绿。
32+
* 首屏模块一旦静态引入,**该守卫会红**(不是静默洞);这条纪律与 `engine.ts` 头注的边界句是同一条。
2833
*
2934
* reduced-motion(§8.5「系统 `prefers-reduced-motion` 优先于档位」):命中时**直接落终态、不建 tween**
3035
* (`tweenCount(target)` = 0),调用方无需分支;`matchMedia` **自带守卫**(尖刺实测 jsdom 30.0.1 没有它
@@ -37,8 +42,9 @@
3742
* **传进来的属性名**,读数口由调用方给(`test/motionHarness.ts` 的 `animatedProps` 读 `el.style` 内联集合,
3843
* 看不见类规则里的属性);④ 出口**挡不住**绕过它直接调 tween 的写法 —— 那由属性集合审计与评审兜。
3944
*/
40-
/* 🔴 静态边 ⇒ 本模块因此**只能经 `await import()` 到达**(见文件头「使用纪律」;判据 =
41-
* `engine.guard.test.ts` 的闭包交集)。改成动态 import 会把 `startControllable` 变成 async。
45+
/* 🔴 静态边 ⇒ 本模块**不许被「首屏静态可达」的模块静态 import**(R60.1;惰性视图静态 import 是安全的 ——
46+
* 见文件头「使用纪律」;判据 = `engine.guard.test.ts` 的闭包交集)。改成动态 import 会把 `startControllable`
47+
* 变成 async。
4248
*/
4349
import { gsap } from "./engine";
4450
import type { GsapTimeline } from "./engine";

‎app/src/motion/engine.guard.test.ts‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
* @ai-context 产物判据 ①②(R11.5):`app/dist` **不入库** ⇒ 导出树里必然不运行,故取「`runIf(existsSync(dist))`
1616
* 用例 + **真实构建强制命令行** + 未运行计入报告**「未验证」单列**」三轨。🔴 **未运行 ≠ 通过**,本守卫不得
1717
* 静默通过。T3 已在导出树做过注入式正向实测(`void import("./motion/engine")` ⇒ `vendor-gsap-BQLVn3Z6.js`
18-
* 105,584 B / gzip 41,161 B,首屏仍 3 chunk 不含它)⇒ 机理已证;该 chunk **首次真实出现 = 第一个调用点落地时
19-
* (波 B/C)**。今天源图(静态∪动态)到不了 GSAP ⇒ ① 的「存在性分支」**未运行**(用例 `console.warn` 点名)。
18+
* 105,584 B / gzip 41,161 B,首屏仍 3 chunk 不含它)⇒ 机理已证;该 chunk **已真实出现** —— T30(`66f0e4a9`)
19+
* 落了首个运行时调用点(`app/dist/assets/vendor-gsap-BQLVn3Z6.js` = 105,584 B、首屏仍 3 chunk 不含它,T35b 实测)。
20+
* 今天源图(静态∪动态)**已到达** GSAP(`gsapInBuildGraph = true`,T35b 用本文件的仪器实测)⇒ ① 的「存在性
21+
* 分支」**今天真跑**;`dist` 不入库 ⇒ 导出树里仍条件跳过(R11.5 的 `runIf` 不变)。
2022
* @ai-context 插件集合与顺序(R14.7-I-2):ADR-035 `:48` 自称「恰 4 个、**顺序逐字**」⇒ 对拍必须是**逐序数组
2123
* 相等**(集合相等测不出纯换序)。四插件「真的注册了」的**行为级**判据在 `engine.test.ts`(B3/B4/B5)。
2224
* @ai-context 仪器:剥注释复用 `ui/primitives/sliceScan.ts` 的状态机(R8.7);静态图遍历是**正则级**(不认
@@ -219,14 +221,15 @@ interface BudgetJson {
219221

220222
describe("①② 产物判据(R11.5:runIf(existsSync(dist));🔴 未运行 ≠ 通过)", () => {
221223
it.runIf(hasDist)(
222-
"① 产物独立性:源图到达 GSAP ⇔ 出现独立的 vendor-gsap-*.js(今天源图未到达 ⇒ 存在性分支未运行,见报告「未验证」单列)",
224+
"① 产物独立性:源图到达 GSAP ⇔ 出现独立的 vendor-gsap-*.js(今天源图已到达 ⇒ 存在性断言真跑)",
223225
() => {
224226
if (!gsapInBuildGraph) {
225-
// 今天的真相:源图(静态∪动态)零边到达 GSAP ⇒ 下面那条存在性断言今天**跑不到**(R11.5:不计入绿)
227+
// 🔴 今天**不走**这个分支(T30 `66f0e4a9` 之后源图已到达)⇒ 走到这里 = 调用点被回退或遍历漏判,先查这两处
228+
// 再看下面的 warn(R11.5:本分支的读数**不计入绿**,因为存在性断言根本没跑)。
226229
console.warn(
227-
"[guard①] 存在性分支今天未运行:源图未到达任何 GSAP 静态 importer ⇒ 本分支计入报告「未验证」单列。" +
230+
"[guard①] 存在性分支未运行:源图未到达任何 GSAP importer ⇒ 本分支计入报告「未验证」单列。" +
228231
"机理已证(T3 注入树:vendor-gsap-BQLVn3Z6.js 105,584 B / gzip 41,161 B,首屏 3 chunk 不含它);" +
229-
"首次真实出现 = 第一个调用点落地时(波 B/C)。",
232+
"该 chunk 已于 T30(66f0e4a9)随首个调用点真实出现 ⇒ 今天读到本行 = 静态∪动态边被回退或遍历漏判。",
230233
);
231234
} else {
232235
expect(gsapChunks, "源图已到达 GSAP ⇒ 产物必须出现 vendor-gsap-*.js;实得零个").not.toEqual([]);

‎app/src/motion/tone.test.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020
* **不**把 jsdom 的 `performance` 挂到 `globalThis`;GSAP 家族的**静态** import 只许在 `motion/engine.ts`
2121
* ⇒ 本文件经 `await import("./engine")` 取引擎(同 `engine.test.ts` 的口径)。
2222
* 副作用:只读磁盘(生成物)+ 给 `window.matchMedia` 打桩 + 建**游离**元素(不挂进 document,不产生动画)。
23-
* 边界:① 本文件**不**判 `data-tone` 的落点接线(那是波 B/C)⇒ 今日 `app/src` 生产代码里 `data-tone` 仍 0 命中;
23+
* 边界:① 本文件**不**判 `data-tone` 的落点接线(判据在落点自己的测试里)⇒ 今日 `app/src` 生产代码里 `data-tone`
24+
* 已有 **4 处属性落点**(T35b 实测):`components/review/DueScale.tsx:134`(T30,条件式 `instrument`)·
25+
* `components/review/ReviewSessionPanel.tsx:252`(T30,`instrument`)· `views/session/SessionTriTrackView.tsx:277`
26+
* (T27,`instrument`)· `components/session-detail/SessionRawView.tsx:105`(T28,`paper`)—— 旧措辞「生产 0 命中」
27+
* 描述的是 T8 当时的真相,**已过期**;本文件仍只造**游离元素**验基调契约;
2428
* ② `CustomEase` 的曲线控制点是**手感参数**,本文件只保证「单调不减 + 端点正确」,**不保证视觉正确**。
2529
*/
2630
import { describe, expect, it } from "vitest";

‎app/src/shell/kbCommands.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
* · 错误是 `String`(`Result<_, String>`)⇒ IPC 拒绝值即可读中文串,不是结构化错误体;
1313
* · Rust 侧行为:空白 query ⇒ `Ok(vec![])`(不报错)· `query.chars().count() > 500` ⇒ `Err("查询过长(≤500 字符)")`
1414
* · `limit` 缺省 10 且 `.min(50)`(命令层**只夹上界**;下界 1 在引擎层 `kb_search.rs:107` 的 `.clamp(1, 50)`)。
15-
* ⚠️ 本任务**不增删命令**(`kb_search` 早已注册,见 `check-command-registry.mjs` 的 312/312)。
15+
* ⚠️ 本任务**不增删命令**(`kb_search` 早已注册,见 `check-command-registry.mjs` 的 **313/313/0** —— T35b 实测;
16+
* 该计数是**活的**:批 6 期间它从 312 涨到 313 ⇒ 读它请跑脚本,别照抄本行)。
1617
*
1718
* 防御性(AGENTS.md §3.4:系统调用必须有超时/重试/降级):
1819
* · 查询串空白 ⇒ **不发 IPC**,返回空列表(Rust 侧对空白串也返回空,但省一次往返);

‎app/src/ui/tokens.gen.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ export const DURATION_TOKENS = [
8080
{ name: "toast-in", ms: 180, usage: "Toast 进场(规格 §8.4「Toast 180/140」)" },
8181
{ name: "toast-out", ms: 140, usage: "Toast 出场 —— 出场比进场快(规格 §8.4)" },
8282
{ name: "skeleton", ms: 1200, usage: "循环环境动效:骨架微光(规格 §8.4「--dur-skeleton 1200ms」)" },
83-
{ name: "card", ms: 220, usage: "面板 / 视图 / 列折叠(规格 §8.4「--dur-card 220ms」);今日 0 生产消费者,波 C 首次消费" },
84-
{ name: "reveal", ms: 500, usage: "显影 / 编排层(规格 §8.4「--dur-reveal 500ms」);今日 0 生产消费者,波 C 首次消费" },
85-
{ name: "page", ms: 150, usage: "页面切换(规格 §8.4「--dur-page 150ms」);今日 0 生产消费者,波 C 首次消费" },
83+
{ name: "card", ms: 220, usage: "面板 / 视图 / 列折叠(规格 §8.4「--dur-card 220ms」);**已有生产消费者**(T35b 实测 6 处:useColumnFlip / usePhaseFreeze / useScaleGrowth / useRevealMemory / usePlayheadJump / useTriTrackAlign 的档位→时长函数取 ms)" },
84+
{ name: "reveal", ms: 500, usage: "显影 / 编排层(规格 §8.4「--dur-reveal 500ms」);**已有生产消费者**(T35b 实测 7 处:useRevealChoreography 的 standard 档 + 上列 6 个 hook 的档位→时长函数 —— 其中 5 个只在 rich 档取它、useRevealMemory 各档都取)" },
85+
{ name: "page", ms: 150, usage: "页面切换(规格 §8.4「--dur-page 150ms」);🔴 **仍 0 生产消费者**(T35b 实测:波 C 已全部落地而页面切换动效不在规格 §8.6 的六条内 ⇒ 旧措辞「波 C 首次消费」已过期为假)" },
8686
] as const satisfies readonly DurationToken[];
8787

8888
/** 时长短名的字面量联合:门面收窄入参用(拼错必须编译期报错,不是运行期静默取不到值) */

0 commit comments

Comments
 (0)