首页
/ React Bits 动画评审方法学:十条不可妥协标准、升级触发器与一套高门槛的 Motion Code 审查框架

React Bits 动画评审方法学:十条不可妥协标准、升级触发器与一套高门槛的 Motion Code 审查框架

2026-09-05 21:47:59作者:郜逊炳

本文以 react-bits 仓库中的 review-animations 技能定义为核心,完整拆解这套面向 AI Agent 与人类评审者的动画代码审查框架:它的十条不可妥协标准(Non-Negotiable Standards)、14 条"见之即报"的激进升级触发器、九级修复偏好层级,以及"Findings 表格 + 分级裁决"的强制输出格式。读完后,你将掌握一套可以直接落地到任意前端代码库的动画评审清单,并能引用仓库内 精确数值参考表 给出曲线、时长、弹簧参数的精确值,而非"感觉不对"式的模糊反馈。

1. 这套评审技能是什么:只做一件事的"设计工程评审者"

AGENTS/SKILLS/review-animations/SKILL.md 定义了 react-bits 仓库 AGENTS/SKILLS/ 目录下的一个专用评审技能。它的第一句话就划定了边界:

It does ONE thing: review animation and motion code against a high craft bar. It does not write features, fix unrelated bugs, or review non-motion code.

只做一件事:把动画与 motion 代码对照一条"高工艺门槛(high craft bar)"进行评审。不写功能、不修无关 bug、不评非动效代码;如果被要求评审普通代码,应当拒绝并指向通用评审技能。

该技能的 Front Matter 元数据同样信息量很大:

  • name: review-animations —— 技能名,也是其他技能交叉引用它时使用的调用名;
  • description —— 一句话说明:对照源自 Emil Kowalski 设计工程哲学的工艺标准评审动画代码,"Default to flagging; approval is earned."(默认标记,通过是挣来的,不是假设的);
  • disable-model-invocation: true —— 禁止模型自动触发,只能由用户显式调用。这一点很关键:一条"默认判不通过"的评审规则如果允许模型自作主张地触发,会在不合适的场景制造噪音。

1.1 工作姿态:偏向"感觉对",而不是"能跑"

技能文档要求评审者以"一位对工艺有残酷眼光的资深设计工程师"自居,其偏向是 motion that feels right(感觉正确的动效),而非 motion that merely runs(仅仅能跑的动效)。原文的定义值得逐字引用:

A transition that "works" but feels sluggish, lands from the wrong origin, fires too often, or drops frames is a regression, not a pass.

也就是说:一个"能跑"但感觉迟钝、落点原点错误、触发过于频繁或掉帧的 transition,是回归问题(regression),不是通过。评审的默认动作是标记(finding),通过(approval)必须被挣得。

技能文档还交代了两条"血统":实质性的评审门槛(标准本身)来自 Emil Kowalski 的动画哲学;而评审方法——不可妥协标准、升级触发器、修复层级、分级输出、显式通过条件——改编自激进的代码质量评审(aggressive code-quality review)。完整的规则目录(缓动曲线、时长表、弹簧配置、手势、clip-path、性能、无障碍)全部放在配套的 STANDARDS.md,要求"每当 finding 需要精确数值或引用时,必须加载该文件"。

2. 十条不可妥协标准(Non-Negotiable Standards)

SKILL.md 的核心是十条标准:diff 中的每一个动画都要对照它们衡量,违反即 finding。以下逐条完整展开(含文档中的原始判定语义与仓库内可对照的实现)。

标准 1 — 动效必须有正当理由(Justified motion)。 每个动画必须能回答"为什么动?"——空间一致性、状态指示、反馈、解释说明,或防止突兀变化。对高频出现的元素说"它看起来很酷"直接判 Block。这条是后续所有标准的总闸门:先问"该不该动",再问"动得好不好"。

标准 2 — 频率匹配(Frequency-appropriate)。 动效强度必须与出现频率匹配:

出现频率 判定
每天 100+ 次(键盘快捷键、命令面板开关) 无动画。永远不。
每天十几次(hover 效果、列表导航) 移除或大幅缩减
偶尔(弹窗、抽屉、toast) 标准动画
罕见/首次(引导、反馈、庆祝) 可以加入 delight(愉悦感)

配套文档 STANDARDS.md 中进一步给出例证:Raycast 的命令面板没有开/关动画,这对一个每天使用几百次的东西来说是正确的。

标准 3 — 响应式缓动(Responsive easing)。 进入/退出的元素使用 ease-out 或强自定义曲线;UI 上出现 ease-in 直接判 Block——它慢启动,恰好拖慢了用户最关注的那一瞬间(200ms 的 ease-out 主观上比 200ms 的 ease-in 更快)。内置 CSS 缓动曲线被认为"太弱",评审时应当预期看到自定义 cubic-bezier。

标准 4 — UI 动画 300ms 以内(Sub-300ms UI)。 UI 动画控制在 300ms 内;任何慢于 300ms 的 UI 动效必须给出理由,否则就是 finding。逐元素的时长预算表见 STANDARDS.md

标准 5 — 原点与物理正确性(Origin & physical correctness)。 Popover/dropdown/tooltip 必须从触发器缩放(transform-origin),而不是从中心;永远不要从 scale(0) 开始——从 scale(0.9–0.97) + opacity 起步(弹窗 Modal 豁免——它们居中出现在视口中央,保持居中语义)。

标准 6 — 可中断性(Interruptibility)。 快速触发或手势驱动的 motion(toast、开关、拖拽)必须可中断:使用能从当前状态**重定向(retarget)**的 CSS transitions 或 springs,而不是从零重启的 keyframes。

标准 7 — 仅动画 GPU 友好属性(GPU-only properties)。 只动 transformopacity。动画 width/height/margin/padding/top/left,或在页面负载下使用 Framer Motion 的 x/y/scale 简写属性,都是性能 finding。

标准 8 — 可访问性(Accessibility)。 prefers-reduced-motion 必须被尊重——注意语义是"更温和,而非清零":保留 opacity/颜色反馈,去掉位移;hover 动效必须用 @media (hover: hover) and (pointer: fine) 门控(触屏会在点击时触发虚假 hover)。

标准 9 — 进入/退出的非对称计时(Asymmetric enter/exit)。 用户做决定的动作(按压、长按、破坏性确认)动画更慢,系统响应则"啪"地到位。在按压-松开或长按交互上使用对称计时,是 finding。

标准 10 — 一致性(Cohesion)。 动效要与组件个性及整个产品一致: playful 的产品可以更有弹跳,仪表盘保持干脆利落。个性错配、或"该用轻微 blur 桥接两个状态却用生硬 crossfade",都是 finding。原文的收尾句值得单独引用:

When unsure whether motion feels right, the strongest move is often to delete it.

不确定动效对不对时,最强的一招往往是删掉它

3. 激进升级触发器:见之即报的 14 种写法

SKILL.md 的第二部分是一组"Flag these on sight, hard(见到就硬标记)"的触发器。这 14 条把标准 1–10 转译成了可以直接 grep 的语法特征,是整套框架中最接近"规则引擎"的部分:

  1. transition: all(无边界属性的动画);
  2. scale(0),或没有初始 transform 的纯淡入入场;
  3. 任何 UI 交互上的 ease-in;刻意的动效上使用弱内置缓动;
  4. 键盘快捷键、命令面板开关、每天 100+ 次操作上的动画;
  5. 无说明理由的 >300ms UI 时长;
  6. 触发器锚定的 popover/dropdown/tooltip 上的 transform-origin: center;
  7. toast、开关等快速增删/触发元素上的 keyframes;
  8. 动画布局属性(width/height/margin/padding/top/left);
  9. 页面繁忙时运行的 Framer Motion x/y/scale 属性;
  10. 通过更新父元素上的 CSS 变量来驱动子元素 transform(样式重算风暴);
  11. 位移动画缺失 prefers-reduced-motion 处理;
  12. 未做门控的 :hover motion;
  13. 按压-松开或长按交互上对称的进入/退出计时;
  14. 应当使用 30–80ms stagger 却"全员齐上"的入场动画。

值得注意的是第 10 条:它针对的不是"属性对不对",而是驱动方式——在父元素上改 CSS 变量会让所有子元素重算样式,正确做法是直接在被移动元素上设置 transform。这说明该框架的评审粒度细到"动画值从哪条路径写到 DOM"这一层。

4. 修复偏好层级:从"删除"到"打磨"的九级阶梯

发现问题之后怎么修?SKILL.md 给出了一个有严格先后顺序的修复偏好层级(Repair Preference Hierarchy)——越靠前越优先,这实际上把"克制的审美"编码成了算法:

  1. 删除动画(高频 / 无目的 / 键盘触发);
  2. 缩减——更短时长、更小 transform、更少的动画属性;
  3. 修缓动——ease-inease-out/自定义曲线;换一条强 cubic-bezier;
  4. 修原点/物理性——纠正 transform-origin;用 scale(0.95)+opacity 替换 scale(0);
  5. 让它可中断——keyframes → transitions;手势驱动 motion 换 spring;
  6. 移到 GPU——布局属性 → transform/opacity;简写 → 完整 transform 字符串;程序化 CSS 动作用 WAAPI;
  7. 非对称计时——刻意的阶段放慢,响应阶段"啪"地收;
  8. 打磨——用 blur 遮蔽 crossfade、给群组加 stagger、用 @starting-style 处理入场、给"鲜活"元素上 spring;
  9. 可访问性与一致性——补 reduced-motion 与 hover 门控;按组件个性调参。

这个层级与第 2 节的标准形成闭环:标准 1(正当理由)对应第 1 级(删),标准 3/4 对应第 2/3 级,标准 5 对应第 4 级,标准 6/7 对应第 5/6 级……它同时也是一份"最小改动原则"——能用第 3 级解决的,就不要动到第 8 级。

5. 强制输出格式:Findings 表格 + 分级裁决

SKILL.md 规定评审输出必须分两部分、按序给出,这是整套技能中"可机器消费"程度最高的设计。

5.1 Part 1 — Findings 表格(必填)

一张 markdown 表,一个问题一行,禁止"Before:/After:"式的散列列表。文档给出的示例行(完整继承):

Before After Why
transition: all 300ms transition: transform 200ms ease-out 指定确切属性;all 会动画化 GPU 之外、未被预期的属性
transform: scale(0) transform: scale(0.95); opacity: 0 现实中没有东西"从虚无中出现"——scale(0) 看起来像凭空冒出来
dropdown 上的 ease-in ease-out + 自定义曲线 ease-in 拖慢用户最关注的瞬间;感觉迟钝
popover 上的 transform-origin: center var(--radix-popover-content-transform-origin) popover 应从触发器缩放,不是中心(Modal 豁免)

5.2 Part 2 — Verdict 裁决(必填)

剩余评论按影响层级(impact tier)从高到低分组,空层级省略:

  1. Feel-breaking regressions —— 迟钝的缓动、凭空出现、在高频/键盘动作上触发;
  2. Missed simplifications —— 应当被删除或大幅缩减的动画;
  3. Performance —— 非 GPU 属性、掉帧风险、重算风暴;
  4. Interruptibility & timing —— 该用 transitions/springs 却用了 keyframes;该非对称却对称的计时;
  5. Origin, physicality & cohesion —— 原点错误、个性错配、生硬的 crossfade;
  6. Accessibility —— reduced-motion 与指针/hover 门控。

最后必须以显式决定收尾,且通过条件被逐条列明:

  • Block —— 存在任何 feel-breaking regression、键盘/高频动作上的动画、UI 上的 scale(0)/ease-in、或"GPU 修复很容易"的非 GPU 动画;
  • Approve —— 无 feel-breaking regression、没有明显该删的动效、时长与缓动在预算内、需要可中断的地方已处理、reduced-motion 被尊重。

同时要求"具体,并引用 file:line";凡是需要数值的地方(曲线、时长、弹簧配置),必须STANDARDS.md 取精确值,不得近似。这条"禁止近似"贯穿了 react-bits 全部三个动效技能,是其规则目录的可信度基石。

6. STANDARDS.md:精确数值参考目录

AGENTS/SKILLS/review-animations/STANDARDS.md 是 SKILL.md 的配套参考,标题即 Animation Standards Reference,定位是"评审背后的精确数值、曲线与规则——在 findings 中引用它们,而不是近似"。以下把其中可直接引用的关键数值完整整理。

6.1 缓动:决策顺序与强自定义曲线

缓动选择有明确的决策顺序:进入/退出 → ease-out(快启动、感觉响应快);屏上移动/形变 → ease-in-out;hover/颜色变化 → ease;恒定运动(跑马灯、进度) → linear;默认 → ease-outUI 上永远不用 ease-in

内置缓动太弱,应使用强自定义曲线:

--ease-out: cubic-bezier(0.23, 1, 0.32, 1);        /* UI 用的强 ease-out */
--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);    /* 屏上移动的强 ease-in-out */
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);     /* iOS 风格抽屉曲线(Ionic) */

文档建议到专门的缓动曲线库(easing.dev、easings.co 这类站点)找曲线,不要徒手滚。

这一点在 react-bits 源码里有直接印证:仓库自身的动效 token 就定义在 src/css/variables.css,三条曲线与 STANDARDS.md 完全一致:

--ease-out: cubic-bezier(0.23, 1, 0.32, 1);
--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);

紧随其后的时长 token 也落在标准预算内:--dur-press: 120ms--dur-tooltip: 160ms--dur-menu: 200ms--dur-panel: 280ms——分别对应下表中的按压反馈(100–160ms)、tooltip(125–200ms)、菜单(150–250ms)档位,且全部 <300ms。可以说,评审标准不是外挂在仓库上的一层文档,仓库自身的样式体系就是这套标准的示范实现。

6.2 时长预算表

元素 时长
按钮按压反馈 100–160ms
Tooltips、小 popover 125–200ms
Dropdowns、selects 150–250ms
Modals、drawers 200–500ms
营销/解释性内容 可以更长

规则:UI 动画保持在 300ms 以内。 文档还给了几条感知心理学注脚:180ms 的下拉比 400ms 的"感觉"更响应;spinner 转得快会让加载感觉更快(实际时间相同);首次出现后的 tooltip 跳过延迟与动画,工具栏会显得更快。

6.3 物理性:scale(0)、原点与按压反馈

  • 永远不用 scale(0)——从 scale(0.9–0.97) + opacity: 0 起步;
  • 原点感知的 popover——从触发器缩放,不同组件库取对应的 CSS 变量:
.popover { transform-origin: var(--radix-popover-content-transform-origin); } /* Radix */
.popover { transform-origin: var(--transform-origin); }                       /* Base UI */

Modal 豁免——它出现在视口中央,transform-origin: center 在那里是正确写法(配套的 AUDIT.md 也明确要求"不要报告弹窗上的 center 原点");

  • 按钮按压反馈::activetransform: scale(0.97),transition: transform 160ms ease-out,幅度控制在 0.95–0.98,适用于一切可按压元素。

6.4 弹簧:两种配置形态与 bounce 纪律

弹簧模拟物理、无固定时长(靠参数收敛),适用于:带惯量的拖拽、"鲜活"元素(如 Dynamic Island 类)、可中断手势、装饰性鼠标跟随。推荐 Apple 风格配置(更易推理):

// Apple 风格(推荐,更易推理)
{ type: "spring", duration: 0.5, bounce: 0.2 }

// 传统物理参数(控制力更强)
{ type: "spring", mass: 1, stiffness: 100, damping: 10 }

bounce 保持克制(0.1–0.3);大多数 UI 避免 bounce,留给 drag-to-dismiss 和 playful 交互。弹簧被中断时保留速度(keyframes 则从零重启),所以用户中途反转向的手势首选弹簧。鼠标跟随类交互:用 useSpring 插值,而不是把值直接绑到鼠标坐标(直绑=生硬、无惯性)——且仅限装饰性 motion 才这么做。react-bits 的依赖里同时存在 motion(Framer Motion 继任者)^12.23.12 与 gsap,因此这条"简写属性非硬件加速"的规则对仓库自身组件同样适用。

6.5 可中断性:transitions vs keyframes,与 @starting-style

CSS transitions 可以在动画中途被打断并从当前状态重定向;keyframes 从零重启。凡快速触发的(toast 堆叠、开关)必须用 transitions 或 springs:

/* 可中断——适合动态 UI */
.toast { transition: transform 400ms ease; }

/* 不可中断——动态 UI 避免 */
@keyframes slideIn { from { transform: translateY(100%); } to { transform: translateY(0); } }

不用 JS 做入场的现代方案是 @starting-style:

.toast {
  opacity: 1; transform: translateY(0);
  transition: opacity 400ms ease, transform 400ms ease;
  @starting-style { opacity: 0; transform: translateY(100%); }
}

旧环境回退:useEffect(() => setMounted(true), []) + data-mounted 属性。

6.6 非对称计时:一个 200ms / 2s 的例子

"用户在做决定的地方慢,系统响应的地方快":

.overlay { transition: clip-path 200ms ease-out; }            /* 松开:快 */
.button:active .overlay { transition: clip-path 2s linear; }  /* 按压:慢而刻意 */

这正是"长按确认(hold-to-confirm)"类交互的标准写法,也出现在 find-animation-opportunities 技能 的配方里(按压 2s linear 填充、松开 200ms ease-out 回弹)。

6.7 性能清单:GPU、CSS 变量陷阱与 Framer Motion 简写

  • 只动 transformopacity——跳过布局/绘制、跑在 GPU 上;padding/margin/height/width/top/left 触发全部三个渲染步骤;
  • 不要用父元素上的 CSS 变量驱动子元素 transform——会让所有子元素重算样式:
element.style.setProperty('--swipe-amount', `${d}px`); // 差:所有子元素重算
element.style.transform = `translateY(${d}px)`;        // 好:只影响本元素
  • Framer Motion 的 x/y/scale 简写不是硬件加速的——走主线程 rAF,页面繁忙时掉帧;应使用完整 transform 字符串:
<motion.div animate={{ x: 100 }} />                          // 繁忙时掉帧
<motion.div animate={{ transform: "translateX(100px)" }} />  // 硬件加速
  • 负载下 CSS 优于 JS——CSS 动画脱离主线程运行;rAF 动画在浏览器加载/脚本/绘制期间会卡顿。预定 motion 用 CSS,动态/可中断 motion 用 JS;
  • WAAPI 兼得 JS 控制权与 CSS 性能(硬件加速、可中断、无依赖):
element.animate([{ clipPath: 'inset(0 0 100% 0)' }, { clipPath: 'inset(0 0 0 0)' }],
  { duration: 1000, fill: 'forwards', easing: 'cubic-bezier(0.77, 0, 0.175, 1)' });

6.8 transform 与 clip-path 工具箱

  • translate 百分比相对元素自身尺寸——translateY(100%) 恒等于自身高度(Sonner/Vaul 就是靠它定位 toast/drawer 的),优先于写死 px;
  • scale() 会连子内容一起缩放(字体、图标)——按压反馈里这是特性而非 bug;
  • 3D 深度: rotateX/Y + transform-style: preserve-3d,无 JS 实现深度/轨道/翻转;
  • clip-path: inset(t r b l) 是强力动画工具:每个值从对应侧"吃掉"。用途:滚动显现(inset(0 0 100% 0)inset(0 0 0 0))、长按删除覆盖层、标签页颜色无缝切换(复制一份 + clip 激活层)、对比滑块。

6.9 手势与拖拽:速度阈值、边界阻尼、指针捕获

  • 动量释放:不要要求跨越距离阈值——计算速度 Math.abs(distance)/elapsedMs,大于约 0.11 即释放。一次甩动就应当足够;
  • 边界阻尼:拖过自然边缘后,越远移动越少(真实物体停前会减速);
  • 拖拽开始后指针捕获(setPointerCapture),指针出界手势不丢;
  • 多点触控保护:拖拽开始后的额外触点一律忽略(if (isDragging) return),防止跳变;
  • 摩擦优于硬停——允许过拖并递增阻力,而不是隐形墙。

6.10 掩盖不完美 crossfade 与 stagger

  • 当调过缓动/时长后 crossfade 仍暴露两个重叠状态,在过渡期间加轻微 filter: blur(2px) 把两个状态融成一个感知上的变换;blur 保持 <20px(重 blur 昂贵,尤其 Safari);
  • 群组入场加 stagger,项间 30–80ms,更长会感觉慢;stagger 是装饰——永远不阻塞交互:
.item { opacity: 0; transform: translateY(8px); animation: fadeIn 300ms ease-out forwards; }
.item:nth-child(2) { animation-delay: 50ms; }
.item:nth-child(3) { animation-delay: 100ms; }
@keyframes fadeIn { to { opacity: 1; transform: translateY(0); } }

6.11 可访问性:reduced-motion 是"更少更柔",不是零

@media (prefers-reduced-motion: reduce) {
  .element { animation: fade 0.2s ease; } /* 保留 opacity/颜色,去掉 transform 位移 */
}
@media (hover: hover) and (pointer: fine) {
  .element:hover { transform: scale(1.05); } /* 门控 hover motion——触屏点击会触发虚假 hover */
}

JS 侧配合 Framer Motion 的 useReducedMotion() 分支切换 transform 值:

const reduce = useReducedMotion();
const closedX = reduce ? 0 : '-100%';

6.12 调试方法:慢放、逐帧、真机、第二天

STANDARDS.md 最后一段规定"当评审者对'手感'存疑时,在 review 中建议":

  • 慢放:把时长调大 2–5×,或用 DevTools 动画检查器;检查颜色是否干净交叉、缓动是否突然停止、transform-origin 是否正确、协同属性是否保持同步;
  • 逐帧:Chrome DevTools 的 Animations 面板能暴露协同属性之间的时序漂移;
  • 真机:手势(drawer、swipe)必须连手机、用 IP 访问 dev server、走 Safari 远程调试;
  • 第二天用新鲜的眼睛:开发期间不可见的瑕疵事后才会浮现。

一致性(Cohesion)一节则给出定性判据:动效要匹配组件个性——playful 可以更弹,专业仪表盘干脆快速;Sonner 之所以"感觉对",部分原因是缓动、时长、设计乃至命名都处于和谐(略慢、用 ease 而非 ease-out 以显优雅)。也坦承没有公式的场景:"进出列表的 opacity + height 只能试错,调到感觉对为止。"

7. 收尾准则与在技能体系中的位置

SKILL.md 末尾的两条 Guidelines 是给评审者的技术选型建议与诚实性要求:

  • 技术选型:预定 motion 优先 CSS transitions / @starting-style / WAAPI;动态的、可中断的、手势驱动的 motion 才用 JS/弹簧;
  • 诚实性:无法确定手感对不对时,建议慢放/逐帧复审、第二天用新鲜眼睛再看——而不是猜

AGENTS/SKILLS 目录结构看,review-animations 是 react-bits 三个动效技能组成的流水线中的一环,职责边界彼此咬合:

技能 职责 只读性
review-animations 评审单个 diff 的动画代码,输出 findings 表 + Block/Approve 裁决 评审,不修改
improve-animations 全库勘察 → 审计 → 验证 → 写自包含实施计划(plans/NNN-short-slug.md),自己永不改源码 严格只读
find-animation-opportunities 寻找该动而未动的位置,每条建议过"频率/目的/速度/功能"四问闸门,并必须列出被拒绝的候选 只报不实现

improve-animations 的调用表甚至显式回链到本技能:execute <plan> 变体会派发执行子代理实现计划,然后review-animations 的门槛评审其 diff 并给出裁决——也就是说,本文拆解的十条标准与升级触发器,是该仓库动画改进流水线最终关卡的实际执行标准。此外还有 apple-design 技能提供 Apple 流式界面设计(响应、直接操控、可中断性、弹簧物理)的知识底座,三个技能共享同一套来自 Emil Kowalski 哲学的数值语言。

8. 如何复用这套框架

把本文当作可执行清单时的最短路径:

  1. 评审单个 diff——逐条过第 2 节的十条标准,命中第 3 节 14 条触发器中的任一条立即记 finding;修复建议按第 4 节九级阶梯取最靠前的一级;
  2. 输出——按第 5 节格式:一张 Before/After/Why 表 + 六个影响层级的分组评论 + 显式 Block/Approve;所有数值从 STANDARDS.md 抄取,引用 file:line;
  3. 对仓库自身动效做全量审计——参照 improve-animations 的 SKILL.mdAUDIT.md(八个审计类别、quick/standard/deep 三档深度),或直接 grep 触发器词表(transition: allscale(0)ease-intransform-origin: center)在 src/content/src/tailwind/ 各组件变体中检索;
  4. 验证手感——按第 6.12 节的慢放/逐帧/真机/次日流程,机制正确不等于手感正确,feel check 不可省略。

这套框架的价值在于:它把"动效好不好"这种高度主观的判断,压缩成了可 grep、可引用 file:line、可复核精确数值的工程流程,同时用"默认标记、通过需挣得"的姿态和"删除优先"的修复阶梯,保留了克制的设计审美。

登录后查看全文
热门项目推荐
相关项目推荐