设计工程实战指南:用 Emil Kowalski 的工艺哲学打磨 Sim 的界面动效与细节
【免费下载链接】simSim is the collaborative workspace to build, deploy, and monitor AI agents and workflows. Used by 100,000+ builders.项目地址: https://gitcode.com/GitHub_Trending/sim16/sim
本指南以
.agents/skills/emil-design-eng/SKILL.md为核心骨架,完整讲解动画决策框架、缓动曲线选择、组件构建原则、CSS Transform 与 clip-path 动效技法、手势交互、性能规则、可访问性与 Sonner 组件设计原则;并结合当前仓库 globals.css 等真实源码印证这些原则在 Sim 项目中的落地方式。读完你将掌握一套可复用的"设计工程审查清单",能独立判断一段 UI 动效该不该做、怎么做、做多快。
一、核心哲学:细节的复利
品味是训练出来的,不是天生的
好的品味不是个人偏好,而是一种被训练出来的直觉——能看穿表面、识别什么让体验升级。它不是靠天赋,而是靠三件事积累:大量接触优秀作品、深入思考"为什么它让人感觉好"、持续刻意练习。
当你构建 UI 时,不要只满足于"能用"。要研究顶级界面为什么给人那样的感觉:逆向工程它的动画、检查它的交互细节、保持好奇心。这正是 SKILL.md 对设计工程师的第一条要求。
看不见的细节会复利
大多数细节用户永远不会刻意注意到——这恰恰是重点。当一个功能完全按照用户的假设运转时,用户不会多想,直接继续使用。这就是目标。
"所有这些看不见的细节组合在一起,产生出令人惊叹的效果,就像一千个几乎听不见的声音在齐声歌唱。" —— Paul Graham
下面要讲的每一项决策都源于同一个信念:无数"正确得隐形"的细节聚合起来,会创造出用户说不出理由但就是喜欢的产品。
美感是杠杆
人们选择工具时看的是整体体验,而不只是功能。好的默认值和好的动画是真正的差异化因素。美感在软件中被严重低估了——把它当作让你脱颖而出的杠杆。在 Sim 这类 AI 工作流产品中,用户每天在画布、执行日志、表格之间切换,动画与细节的打磨直接决定了产品"专业感"的体感。
二、Review 格式:Before | After | Why
在实际工作中,评审 UI 代码时建议用一张Before | After | Why三列的 Markdown 表格呈现所有发现,每个问题一行:
| Before | After | Why |
|---|---|---|
transition: all 300ms | transition: transform 200ms ease-out | 指定确切属性,避免all |
transform: scale(0) | transform: scale(0.95); opacity: 0 | 现实世界里没有东西是从无到有出现的 |
ease-in用于下拉菜单 | ease-out+ 自定义曲线 | ease-in显得迟钝;ease-out给出即时反馈 |
按钮没有:active状态 | :active时transform: scale(0.97) | 按钮必须对按压有响应 |
popover 用transform-origin: center | transform-origin: var(--radix-popover-content-transform-origin) | Popover 应从触发器缩放(modal 除外,保持居中) |
这个格式既适合设计评审,也适合代码 Review 记录,能让每条反馈"可执行、可追责"。
三、动画决策框架
在写任何动画代码之前,按顺序回答下面四个问题。
1. 该不该动?——按频率决策
核心问题:用户多久会看到一次这个动画?
| 使用频率 | 决策 |
|---|---|
| 100+ 次/天(键盘快捷键、命令面板开关) | 永远不要动画 |
| 几十次/天(hover 效果、列表导航) | 移除或大幅削减 |
| 偶尔(模态框、抽屉、toast) | 标准动画 |
| 罕见/首次(引导流程、反馈表单、庆祝效果) | 可以增加愉悦感 |
绝不要为键盘触发的操作添加动画。这些操作每天被重复数百次,动画会让它们显得缓慢、延迟、与用户动作脱节。Raycast 的打开/关闭没有动画——这是每天使用数百次的工具的最优体验。
2. 目的是什么?
每个动画都必须能回答"它为什么要动"。合理的目的包括:
- 空间一致性:toast 从同一方向进出,让滑动关闭显得直觉
- 状态指示:形态变化的反馈按钮展示状态切换
- 解释说明:展示功能如何运作的营销动画
- 反馈:按钮按下时缩小,确认界面听到了用户
- 防止突兀变化:元素无过渡地出现/消失会显得像坏了
如果目的只是"看起来酷"且用户会频繁看到,就不要动画。
3. 用什么缓动?
判断逻辑如下:
- 元素在进入/退出?→
ease-out(起步快,感觉响应迅速) - 否 → 元素在屏幕上移动/变形?→
ease-in-out(自然的加速/减速) - 是hover/颜色变化?→
ease - 是恒定运动(跑马灯、进度条)?→
linear - 默认 →
ease-out
关键:使用自定义缓动曲线。内置 CSS 缓动太弱,缺少那种让动画显得"有意为之"的冲击力:
/* 适合 UI 交互的强 ease-out */ --ease-out: cubic-bezier(0.23, 1, 0.32, 1); /* 适合屏幕内移动的强 ease-in-out */ --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1); /* iOS 风格抽屉曲线(源自 Ionic Framework) */ --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);永远不要在 UI 动画中使用 ease-in。它起步缓慢,让界面显得迟钝和不响应。同一个 300ms 的下拉,用ease-in比用ease-out感觉更慢——因为 ease-in 延迟了最初的位移,而那一刻恰恰是用户盯得最紧的瞬间。
这一原则在 Sim 仓库中有直接印证:globals.css 的动画变量全部使用自定义三次贝塞尔曲线而非内置ease/ease-in,例如:
--animate-slide-in-bottom: slide-in-bottom 400ms cubic-bezier(0.16, 1, 0.3, 1); --animate-hero-cursor-press: hero-cursor-press 340ms cubic-bezier(0.23, 1, 0.32, 1); --animate-collapsible-down: collapsible-down 300ms cubic-bezier(0.4, 0, 0.2, 1);其中cubic-bezier(0.16, 1, 0.3, 1)正是文档推荐的"强 ease-out"变体(y2 为 1,起步即快速响应),被用于 modal 进入、文件拖入、节点弹出等入场动画;cubic-bezier(0.4, 0, 0.2, 1)则是标准的 Material 风格过渡曲线。注意 Sim 甚至为 collapsible 动画写了注释:"故意比 tw-animate-css 默认的 200ms ease-out 更慢"——这说明团队在时长与缓动上是逐条决策的,而非直接套用框架默认值。
缓动曲线资源:不要从零造曲线。用 easing.dev 或 easings.co 寻找标准缓动的更强自定义变体。
4. 要多快?——时长对照表
| 元素 | 时长 |
|---|---|
| 按钮按压反馈 | 100-160ms |
| Tooltip、小 popover | 125-200ms |
| 下拉、select | 150-250ms |
| 模态框、抽屉 | 200-500ms |
| 营销/说明性动画 | 可以更长 |
规则:UI 动画应控制在 300ms 以内。一个 180ms 的下拉比 400ms 的感觉更灵敏。转得快的 spinner 会让应用显得加载更快——即使实际加载时间完全相同。
感知性能
动画的速度不仅关乎"利落感",还直接改变用户对应用性能的感知:
- 转得快的 spinner让加载显得更快(加载时间相同,感知不同)
- 180ms 的 select动画比 400ms 的感觉更跟手
- Tooltip 第二次出现即瞬间显示(跳过延迟 + 跳过动画)让整个工具栏显得更快
速度感知与实际速度同样重要。缓动放大了这一点:同样的 200ms,ease-out比ease-in感觉更快,因为用户看到了即时的位移。
四、Spring 动画
Spring 模拟真实物理,比基于时长的动画更自然。它们没有固定时长——根据物理参数"沉降"到静止。
何时使用 Spring
- 带惯性的拖拽交互
- 应该"有生命感"的元素(如 Apple 的灵动岛)
- 可被中途打断的手势
- 装饰性的鼠标追踪交互
Spring 化的鼠标交互
把视觉变化直接绑定到鼠标位置会显得生硬,因为它缺乏运动。用 Motion(原 Framer Motion)的useSpring对数值变化做插值,而不是即时更新:
import { useSpring } from 'framer-motion'; // 没有 spring:生硬、瞬时 const rotation = mouseX * 0.1; // 有 spring:自然、有惯性 const springRotation = useSpring(mouseX * 0.1, { stiffness: 100, damping: 10, });之所以有效,是因为这个动画是装饰性的——它不承担功能。如果是银行应用里的功能图表,不做任何动画反而更好。要清楚装饰何时有帮助、何时是妨碍。
Spring 配置
Apple 风格(推荐,更易推理):
{ type: "spring", duration: 0.5, bounce: 0.2 }传统物理参数(控制力更强):
{ type: "spring", mass: 1, stiffness: 100, damping: 10 }使用 bounce 时保持轻微(0.1-0.3)。多数 UI 场景避免 bounce。它适合拖拽关闭和俏皮的交互。
可中断性优势
Spring 被打断时会保持速度——CSS 动画和 keyframes 被打断则从零重启。这让 spring 成为用户可能中途改变手势的交互的理想选择:点击展开一个条目后立刻按 Escape,spring 动画会从当前位置平滑反向。
五、组件构建原则
按钮必须对按压有响应
在:active上加transform: scale(0.97)。这给出即时反馈,让 UI 感觉真正在"听"用户说话:
.button { transition: transform 160ms ease-out; } .button:active { transform: scale(0.97); }这条适用于任何可按压元素。缩放要轻微(0.95-0.98)。
永远不要从 scale(0) 动画
现实世界里没有东西会完全消失再重新出现。从scale(0)动画的元素看起来像凭空冒出来的。从scale(0.9)或更高起步,并配合 opacity。即使一个几乎看不见的初始缩放也会让入场更自然——就像瘪掉的气球也有可见的形状:
/* 差 */ .entering { transform: scale(0); } /* 好 */ .entering { transform: scale(0.95); opacity: 0; }让 Popover 感知来源方向
Popover 应从触发器方向缩放进来,而不是从中心。默认的transform-origin: center对几乎所有的 popover 都是错的。例外:模态框。模态框应保持transform-origin: center,因为它们不锚定在特定触发器上——它们在视口居中显示:
/* Radix UI */ .popover { transform-origin: var(--radix-popover-content-transform-origin); } /* Base UI */ .popover { transform-origin: var(--transform-origin); }用户是否单独注意到这个差异并不重要。在聚合层面,看不见的细节会变得可见。它们会复利。
Tooltip:后续 hover 跳过延迟
Tooltip 应该延迟出现,防止误触发。但一旦一个 tooltip 打开,hover 相邻的 tooltip 应立即打开、无动画。这感觉更快,又不破坏初始延迟的意义:
.tooltip { transition: transform 125ms ease-out, opacity 125ms ease-out; transform-origin: var(--transform-origin); } .tooltip[data-starting-style], .tooltip[data-ending-style] { opacity: 0; transform: scale(0.97); } /* 后续 tooltip 跳过动画 */ .tooltip[data-instant] { transition-duration: 0ms; }动态 UI 用 CSS 过渡而非 keyframes
CSS 过渡可以在动画中途被打断并重新定向。Keyframes 则从零重启。对于任何会被高频触发的交互(连续添加 toast、切换状态),过渡产生更平滑的结果:
/* 可中断——适合 UI */ .toast { transition: transform 400ms ease; } /* 不可中断——避免用于动态 UI */ @keyframes slideIn { from { transform: translateY(100%); } to { transform: translateY(0); } }用模糊来掩盖不完美的过渡
当两个状态之间的交叉淡入在试过各种缓动和时长后仍然别扭时,在过渡期间加一点filter: blur(2px)。
为什么 blur 有效:没有 blur,你会在交叉淡入中看到两个独立的对象——旧状态和新状态重叠在一起,看起来不自然。Blur 通过混合两个状态弥合视觉间隙,欺骗眼睛把它感知为一次平滑的形态变化,而不是两个对象的切换。
把 blur 与按压缩放(scale(0.97))结合,实现精致的按钮状态过渡:
.button { transition: transform 160ms ease-out; } .button:active { transform: scale(0.97); } .button-content { transition: filter 200ms ease, opacity 200ms ease; } .button-content.transitioning { filter: blur(2px); opacity: 0.7; }Blur 保持在 20px 以内。过重的 blur 很昂贵,尤其在 Safari。
用 @starting-style 动画入场状态
无需 JavaScript 即可动画元素入场的现代 CSS 方式:
.toast { opacity: 1; transform: translateY(0); transition: opacity 400ms ease, transform 400ms ease; @starting-style { opacity: 0; transform: translateY(100%); } }它取代了常见的 React 模式:在初始渲染后用useEffect设置mounted: true。浏览器支持允许时优先用@starting-style;否则回退到data-mounted属性模式:
// 传统模式(仍然处处可用) useEffect(() => { setMounted(true); }, []); // <div>/* 无论抽屉多高都有效 */ .drawer-hidden { transform: translateY(100%); } /* 无论 toast 多高都有效 */ .toast-enter { transform: translateY(-100%); }优先用百分比而非硬编码像素值。它们更不容易出错,且自适应内容。
scale() 也会缩放子元素
与width/height不同,scale()会同时缩放元素的子元素。按压缩放按钮时,字号、图标和内容按比例缩放。这是特性,不是 bug。
3D 变换营造深度
rotateX()、rotateY()配合transform-style: preserve-3d能在 CSS 中创造真正的 3D 效果。环绕动画、硬币翻转、深度效果都可以不写 JavaScript 实现:
.wrapper { transform-style: preserve-3d; } @keyframes orbit { from { transform: translate(-50%, -50%) rotateY(0deg) translateZ(72px) rotateY(360deg); } to { transform: translate(-50%, -50%) rotateY(360deg) translateZ(72px) rotateY(0deg); } }transform-origin
每个元素都有一个变换执行的锚点,默认是中心。把它设置到触发器所在位置,实现感知来源的交互。
七、用 clip-path 做动画
clip-path不只是用来裁剪形状,它是 CSS 中最强大的动画工具之一。
inset 形状
clip-path: inset(top right bottom left)定义一个矩形裁剪区域。每个值从对应方向"吃进"元素:
/* 从右侧完全隐藏 */ .hidden { clip-path: inset(0 100% 0 0); } /* 完全可见 */ .visible { clip-path: inset(0 0 0 0); } /* 从左到右揭示 */ .overlay { clip-path: inset(0 100% 0 0); transition: clip-path 200ms ease-out; } .button:active .overlay { clip-path: inset(0 0 0 0); transition: clip-path 2s linear; }完美颜色过渡的 Tabs
复制一份 tab 列表。把副本样式设为"激活"(不同的背景、不同的文字颜色)。裁剪副本让只有激活的 tab 可见。切换 tab 时动画裁剪区域。这会创造出逐项动画颜色过渡永远无法达到的无缝颜色变化。
按住删除模式
在彩色覆盖层上用clip-path: inset(0 100% 0 0)。:active时用 2s linear 过渡到inset(0 0 0 0)。释放时用 200ms ease-out 弹回。再在按钮上加scale(0.97)提供按压反馈。
滚动进入的图片揭示
从clip-path: inset(0 0 100% 0)(从底部隐藏)起步。元素进入视口时动画到inset(0 0 0 0)。用IntersectionObserver或 Framer Motion 的useInView加{ once: true, margin: "-100px" }。
对比滑块
叠放两张图。用clip-path: inset(0 50% 0 0)裁剪上方那张。根据拖拽位置调整右侧 inset 值。无需额外 DOM 元素,完全硬件加速。
八、手势与拖拽交互
基于动量的关闭判定
不要要求拖过阈值。计算速度:Math.abs(dragDistance) / elapsedTime。如果速度超过约 0.11,无论距离多少都关闭。快速一甩应该就够:
const timeTaken = new Date().getTime() - dragStartTime.current.getTime(); const velocity = Math.abs(swipeAmount) / timeTaken; if (Math.abs(swipeAmount) >= SWIPE_THRESHOLD || velocity > 0.11) { dismiss(); }边界阻尼
当用户拖过自然边界时(例如抽屉已经在顶部还继续往上拖),施加阻尼。拖得越狠,元素动得越少。现实中的东西不会突然停下,它们先减速。
拖拽的指针捕获
拖拽一旦开始,让元素捕获所有指针事件。这确保即使指针离开元素边界,拖拽也能继续。
多点触控保护
初始拖拽开始后忽略额外的触摸点。没有这一步,拖拽中途换手指会导致元素跳到新位置:
function onPress() { if (isDragging) return; // 开始拖拽... }用摩擦代替硬停
与其完全阻止向上拖拽,不如允许它并增加摩擦。这比撞上一堵看不见的墙更自然。
九、性能规则
只动画 transform 和 opacity
这两个属性跳过布局和绘制,在 GPU 上运行。动画padding、margin、height、width会触发全部三个渲染阶段。
CSS 变量是可继承的
在父元素上改变 CSS 变量会为所有子元素重算样式。在有很多条目的抽屉里,更新容器上的--swipe-amount会导致昂贵的样式重算。改为直接在该元素上更新transform:
// 差:触发所有子元素重算 element.style.setProperty('--swipe-amount', `${distance}px`); // 好:只影响这个元素 element.style.transform = `translateY(${distance}px)`;Framer Motion 硬件加速的注意事项
Framer Motion 的简写属性(x、y、scale)不是硬件加速的。它们用主线程上的requestAnimationFrame。要硬件加速,使用完整的transform字符串:
// 不是硬件加速(方便,但负载下掉帧) <motion.div animate={{ x: 100 }} /> // 硬件加速(主线程忙碌时也保持流畅) <motion.div animate={{ transform: "translateX(100px)" }} />这在浏览器同时加载内容、运行脚本或绘制时尤其重要。在 Vercel,dashboard 的 tab 动画使用 Shared Layout Animations,在页面加载期间掉帧。改成 CSS 动画(离开主线程)后修复了。
负载下 CSS 动画胜过 JS
CSS 动画在主线程之外运行。当浏览器忙于加载新页面时,Framer Motion 动画(用requestAnimationFrame)会掉帧,CSS 动画依然流畅。预定好的动画用 CSS;动态、可中断的用 JS。
用 WAAPI 做编程式 CSS 动画
Web Animations API 给你 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)', });Sim 的样式代码同样遵守"只动画 transform/opacity"原则——globals.css 中的跑马灯动画注释明确说明:为什么用transform: translateX(-26px)而不是background-position(后者会让浏览器每帧在亚像素偏移下重新栅格化渐变,导致边缘闪烁),这正印证了文档"只动画 transform"与"理解每帧成本"的思想。
十、可访问性
prefers-reduced-motion
动画会引起晕动症。减少动态意味着更少、更温和的动画,而不是零动画。保留辅助理解的 opacity 和颜色过渡。移除位移和位置动画:
@media (prefers-reduced-motion: reduce) { .element { animation: fade 0.2s ease; /* 不用 transform 位移 */ } }const shouldReduceMotion = useReducedMotion(); const closedX = shouldReduceMotion ? 0 : '-100%';触屏设备的 hover 状态
@media (hover: hover) and (pointer: fine) { .element:hover { transform: scale(1.05); } }触屏设备会在点击时触发 hover,造成误报。把 hover 动画关在媒体查询后面。
十一、Sonner 原则:构建受人喜爱的组件
这些原则来自构建 Sonner(周下载量 1300 万+)的经验,适用于任何组件:
- 开发者体验是王道。无 hooks、无 context、无复杂配置。插入一次
<Toaster />,从任何地方调用toast()。采用摩擦越小,使用的人越多。 - 好的默认值比选项更重要。开箱即美。多数用户从不自定义。默认的缓动、时长和视觉设计必须出色。
- 命名创造身份。"Sonner"(法语"鸣响")比 "react-toast" 更优雅。在适当的时候用可记忆性换可发现性。
- 隐形地处理边界情况。标签页隐藏时暂停 toast 计时器。用伪元素填补堆叠 toast 之间的空隙以维持 hover 状态。拖拽时捕获指针事件。用户永远不会注意到这些——这正是对的。
- 动态 UI 用过渡而非 keyframes。Toast 被快速连续添加。Keyframes 被打断时从零重启。过渡则平滑重新定向。
- 建一个优秀的文档站。让用户先摸到产品、玩一玩、理解它。带现成代码片段的交互示例能降低采用门槛。
凝聚力至关重要
Sonner 的动画之所以令人满足,部分因为整个体验是凝聚的。缓动和时长契合库的气质。它比典型 UI 动画稍慢,用ease而非ease-out来显得更优雅。动画风格与 toast 设计、页面设计、名字——一切都和谐一致。
选择动画数值时,考虑组件的性格。俏皮的组件可以更有弹性。专业 dashboard 应该干脆利落。让运动匹配情绪。
opacity + height 的组合
当条目进入和离开列表时,opacity 变化必须与 height 动画配合好。这常常要靠试错。没有公式——调到感觉对为止。
第二天再复查你的工作
用新鲜的眼光复查动画。开发时漏掉的瑕疵,第二天你会注意到。用慢动作或逐帧播放动画,找出全速下看不见的时序问题。
非对称的进出时长
按下可以慢——当它需要是刻意的(按住删除:2s linear);但释放永远要利落(200ms ease-out)。这个模式广泛适用:用户在决策的地方慢,系统在响应的时刻快:
/* 释放:快 */ .overlay { transition: clip-path 200ms ease-out; } /* 按下:慢而刻意 */ .button:active .overlay { transition: clip-path 2s linear; }十二、Stagger 动画
多个元素同时入场时,交错它们的出现。每个元素在前一个之后以小延迟进入。这会创造出比同时出现更自然的级联效果:
.item { opacity: 0; transform: translateY(8px); animation: fadeIn 300ms ease-out forwards; } .item:nth-child(1) { animation-delay: 0ms; } .item:nth-child(2) { animation-delay: 50ms; } .item:nth-child(3) { animation-delay: 100ms; } .item:nth-child(4) { animation-delay: 150ms; } @keyframes fadeIn { to { opacity: 1; transform: translateY(0); } }Stagger 延迟保持短促(条目间 30-80ms)。过长的延迟让界面显得慢。Stagger 是装饰性的——绝不要让 stagger 动画阻塞交互。
十三、调试动画
慢动作测试
用降低的速度播放动画,找出全速下看不见的问题。临时把时长放大到正常的 2-5 倍,或用浏览器 DevTools 的动画检查器降低播放速度。
慢动作下要观察:
- 颜色过渡是否平滑,还是能看到两个独立状态重叠?
- 缓动是否正确,还是开始/结束突兀?
- transform-origin 是否正确,元素是否从错误的点缩放?
- 多个动画属性(opacity、transform、color)是否同步?
逐帧检查
在 Chrome DevTools 的 Animations 面板逐帧步进动画。这会暴露协同属性之间全速下看不见的时序问题。
在真实设备上测试
触摸交互(抽屉、滑动手势)要在实体设备上测。手机通过 USB 连接,用 IP 地址访问本地开发服务器,用 Safari 的远程 devtools。Xcode Simulator 是备选,但真实硬件更适合手势测试。
十四、Review 检查清单
评审 UI 代码时,逐条核对:
| 问题 | 修复 |
|---|---|
transition: all | 指定确切属性:transition: transform 200ms ease-out |
scale(0)入场动画 | 从scale(0.95)+opacity: 0起步 |
UI 元素上的ease-in | 换成ease-out或自定义曲线 |
popover 的transform-origin: center | 设为触发器位置或使用 Radix/Base UI CSS 变量(modal 豁免——保持居中) |
| 键盘操作的动画 | 完全移除动画 |
| UI 元素时长 > 300ms | 减到 150-250ms |
| 没有媒体查询的 hover 动画 | 加@media (hover: hover) and (pointer: fine) |
| 高频触发元素上的 keyframes | 用 CSS 过渡获得可中断性 |
负载下的 Framer Motionx/y属性 | 用transform: "translateX()"做硬件加速 |
| 进出速度相同 | 让退出比进入更快(如进入 2s、退出 200ms) |
| 元素同时全部出现 | 加 stagger 延迟(条目间 30-80ms) |
结语:让细节复利
这份指南的核心主张可以浓缩为一句话:当所有人的软件都"够用"时,品味就是差异化。动画决策框架帮你判断"该不该动",缓动与时长表帮你回答"怎么动、多快",组件构建原则和 clip-path/手势技法给出具体的实现手段,性能与可访问性规则保证打磨不伤害体验,而 Sonner 原则提醒你:好的默认值、开发者体验和凝聚力才是组件被广泛采用的根本。
在日常工作中,你可以把这份 SKILL.md 直接当作设计工程师的"肌肉记忆训练手册":写动画前先过一遍决策框架,评审时用Before | After | Why表格输出,交付前用慢动作逐帧自检。当无数"看不见的正确细节"在聚合层面复利时,用户说不出为什么,但他们知道——这个产品感觉对了。
【免费下载链接】simSim is the collaborative workspace to build, deploy, and monitor AI agents and workflows. Used by 100,000+ builders.项目地址: https://gitcode.com/GitHub_Trending/sim16/sim
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考