Cursor 图标系统是怎么做出来的

查看原文 HN 讨论

文章摘要

设计师 Marek Minor(Minor Adventures 创始人)用一篇 16 分钟长文,完整复盘了他为 Cursor 设计整套图标系统的过程:耗时约一年,600 多个图标,两种尺寸、两种样式,每一次探索和每一个最终变体都是手绘的。

起因是 Cursor 正在长出 VS Code 生态的躯壳。它继承来的图标集是 VS Code 的开源图标库 Codicons,外加多年累积、风格略有出入的自定义补充。作者清点时数到 468 个图标,文档却说有 498 个,还有一些码点指向空白——「无人认领的图标集必然漂移」。但更严重的问题是概念覆盖:Cursor 不断引入的一些概念在任何图标库里都不存在,或者存在但从不出现在同一套库里——AI agent、并行与串行执行、单线程与并行线程、不同等级的思考强度、成本与算力、Bugbot 等等。通用图标集能撑一阵,但产品到了某个阶段就需要自己的词汇表。于是任务被定义为三条:把一切重画成一个系统;覆盖只有 Cursor 才有的概念;以图标字体的形式交付,且替换旧字体时不能弄坏任何一处引用。

两种尺寸:16px 是主尺寸,笔画 1.25px,可以缩到 12px 仍保持可读;24px 笔画 1.5px,在空间允许处增加细节。之所以要两套,是因为一个图标能拉伸的范围有限——16px 那套在大约 12px 到 20px 之间成立,到 32px 时 1.25px 笔画会变成 2.5px,远重于该尺寸下应有的画法;同时小图标为小尺寸做过简化,放大后多出的空间只会空着。这与字体设计中的「光学尺寸」(Text 与 Display 分别开模)是同一个思路。1.25px 这个数值找了很久:1px 挨着正文显得太细,1.5px 又太重,1.25px 与 16px 的 Cursor Gothic 并置刚刚好——「到某个时刻,数字只是眼睛早已做出的决定的一份记录」。他也解释了为何不遵循「对齐像素网格」的常规建议:这些图标会在 12、14、16、20px 下渲染,根本不存在唯一的网格可对齐;现代屏幕上 1.25px 笔画依然锐利;他把图标当作符号看待,更接近小 logo 或字体中的字符,而不是固定尺寸的位图。

底层是一套光学形状系统:方形、圆形、横向、纵向,各自的尺寸经过调整,使建立在不同形状上的图标看上去一样大(比如圆必须画得比方稍大才显得等大)。对角线形状在四者中都别扭,就选最接近的(通常是圆)再凭眼睛微调。

构图方法上,这套图标更接近技术制图而非有机造型——「带友好收尾的示意图」。做法一致:先画水平、垂直或 45° 的线,概念需要时才允许其他角度,然后把转角圆角化直到形状贴合含义。云不是由圆拼成的,而是直线段加圆角接头;火也一样。自由曲线或取自圆的曲线在整套图标里极其罕见。正是这套构图逻辑,让 600 多个图标看起来出自同一只手,同时也契合编程工具的气质:精确、工程化,而圆角和圆形笔帽让它不至于冰冷。

风格上还有几条明确的取舍:能闭合就闭合(不用开口来表示元素重叠),保持简单、技术化,也有助于极小尺寸下的可读性;斜杠直接平切穿过形状,不做假阴影;借鉴等宽字体拉伸字符填满横向空间的开发者美学,图标的线条在可能时尽量延长;不把物体硬塞进正方形——铅笔就该又高又窄,钞票就该宽,把所有东西挤成同一个方框正是「玩具感」的来源,而编程工具里的物体应该像它本身。方向上则统一「跟随指针」:Cursor 的指针从左下指向右上,所有可左可右的图标(对角箭头、飞行物体、上下叠放的构图中较小的那个)都朝右上;斜杠反向走,因为斜杠是取消一个方向,理应逆着切。作者补了一句很关键的话:「没人会从屏幕上读出这条规则。但没有这类规则,一整套图标就不再像出自同一处。」

一致性被他称为「基础设施」:文件夹、文件、烧瓶、旗帜、眼睛、箭头、缺口、徽标这些反复出现的元素,每次出现都必须画法一致——这套系统追踪管理了 155 个以上的元素、物件或视觉属性。文中列出的清单长得惊人(动物、箭头、粗体箭头、环形箭头、盒子、建筑、图表、示意图、V 形符、设备、脸、旗帜、手、人、笑脸、多重图标、排版图标、多线图标、git 图标、布局图标、播放控件、开启状态、指针、带斜杠图标、工具、波形、声音……一直到从 A 到 Z 的字母),「每一个都必须在它出现的任何地方看起来还是它自己」。

光学修正是他最偏爱、也是多数图标集会跳过的部分:两条以上线条相交处会因形状堆叠而显得偏黑,于是在交汇处切一个小缺口(optical break),就像字体会把 A 的紧角打开;线条汇集过多的地方还会把部分线条变细(stroke thinning)以分散视觉重量;行末的点、表示「更多」的点、独自浮着的点各需要略微不同的尺寸,系统会记录哪个是哪个;重叠形状之间的空隙(他称为 Cuts)在 16px 网格上不得小于 3 个网格单位,低于 2.5 时形状会开始粘连成一团模糊。他坦承有些方案之间只差 0.25px,在 16px 甚至 12px 下理论上不该有差别,但「感觉就是不一样」——他为一个汉堡菜单图标做了 156 次探索才找到那个对的。他也自问自答了「16px 下你真的看得见吗」:把两版并排几乎说不出差别,但界面会缩放、24px 那套会在更大尺寸下生活,效果作用在「注意不到的层面」,就像字体的墨陷在 10pt 时那样;「而且说实话,有些就是标准问题——那是机器的内部,没人会打开它,但它就该是整齐的」。

交付部分是这篇文章对工程读者最有价值的地方。图标以 Cursor Icons 16 和 Cursor Icons 24 两个字体家族交付,图标字体里每个字形占据一个 Unicode 码点。旧字体有 645 个图标占用 645 个码点,被产品各处引用。规则因此定为:每个旧图标都必须映射到其替代者的同一个码点,没有替代者的则明确退役而非丢失——这样只要换上新字体,arrow-up 仍在 arrow-up 一直所在的位置,替换可以自动完成。为管理这 645 个映射,他专门做了一个迁移看板:每个旧图标处于「待处理 / 已处理 / 已移除 / 已配对」四态之一,看板会对缺失 SVG 和重复码点报警,并以网格展示全集(配对为绿、移除为红),点一下就能前后对比。

交付物不是把文件扔过墙就完事,而是一整个包:Figma 源文件、图标字体、导出的 SVG,以及一个团队日常使用的配套站点。站点主页是全集网格,带尺寸、样式和搜索控件;悬停即可看到放大图、码点和快捷操作(复制 SVG、下载、复制符号);点击进入详情页可缩放查看不同尺寸下的表现并阅读标签。搜索同时基于名称和标签(全集共 1,274 个标签),真正解决的不是「找一个已知图标」,而是「我有个新概念,这套图标里已经有对应的吗」。站点还有一个 Concepts 页面,用表格把每个 Cursor 概念钉死到唯一一个图标上——「『X 该用哪个图标?』这个问题必须永远只有一个答案,否则一套系统会慢慢长出两个表达同一含义的图标,那时它就不再是系统了」。此外还有文件类型映射页(配示例文件名、扩展名列表和配色)和文档。

最后是发布流水线。新增一个图标的流程是:在 Figma 主文件里画(至少一种组合,通常从 16 Outline 开始)→ 全部拍平成单一路径(字体编译器无法处理布尔运算和未轮廓化的描边)→ 发布 Figma 库文件 → 从专用导出面板导出 SVG 放进仓库对应目录 → 运行 ship it。这一条命令替代了一长串工作:登记新 SVG 并分配码点、把所有图标编译成四种字体(两尺寸×两样式,各种格式)、合并样式表、重写字体文件内部的元数据(因为字体编译器爱怎么命名就怎么命名)、重新生成配套站点的数据、重建站点、检查文档里的图标数量是否还停留在三周前,最后提交并推送。手工做完这一切要花一个下午,而且总会漏掉某一步。

结尾点题:整套系统的标准是「图标不应该吸引你的注意」——不过分友好、不装饰、不炫技,实用但不丑陋也不无聊,是做完自己的事就退到后面的小示意图。「你不该注意到它们,但在注意不到的层面,你应该始终知道——不,是感觉到——它们是 Cursor 的。」他把这比作字体:没人读一段文字时会想到字体,但换错字体所有人都会察觉。文章最后一句意味深长:Cursor 是一家 AI 公司,人工智能渗透了他们做的一切;但对于图标,对于那几百个小决定,他们雇了一个人,一个一个手工画出来。

HN 评论精华

这条提交在 Hacker News 上只有 5 分,零条评论,未能进入任何有效讨论。

因此本条目没有社区评论可供翻译总结,这里不虚构任何用户名与发言。原文本身信息密度很高,尤其是「码点级别的向后兼容迁移策略」「用 ship it 单命令打通 Figma 到发布」「Concepts 表把每个产品概念钉死到唯一图标」这三点,对做设计系统工程化的团队有直接参考价值。