从活字到字体源码(10):AI 改字体时到底在做什么
AI 可以很快写出一条 glyph 替换规则,却不一定发现 == 看起来像三横线。Ligconsolata Next 里,这个错误已经同时通过过替换和宽度检查,最终仍要由样张暴露,再回到生成逻辑修正。
把 AI 用在字体项目里,需要分别安排候选研究、重复生成与结果验收。前两项可以大量自动化,最后一项必须有来自真实字体的证据。
候选研究先区分行为与形状
参考成熟编程字体时,AI 适合整理 feature、样例和边界。例如 Fira Code 哪些操作符采用固定连字,哪些长序列由上下文处理;其他字体怎样展示易混字符、字重、终端与可选样式。
项目已有外部字体参考索引,分别记录 Fira Code、JetBrains Mono、Cascadia Code、Iosevka、Monaspace 和 Intel One Mono 值得研究的方向。索引提供研究入口,不能直接当作默认迁移清单。
每个候选还要回到本项目判断。长箭头机制可以借鉴,轮廓从现有横线与端点派生;整套字母变体、斜体或 texture 调整牵涉不同设计目标,应先研究,不因其他字体具备就自动加入。
重复生成交给脚本,维护入口留在源码
==>、<==、|===> 等组合有可重复的几何关系。脚本可以读取本字体的部件,平移、组合和生成目标路径,同时维护名称、宽度与 feature 顺序。
AI 在这一层的产出更适合是可审阅脚本,而不是一份无法追溯的 TTF。项目的 scripts/update-ligature-glyphs.py 写回 sources/Inconsolata.glyphs,构建工具再生成字体文件。以后调整端点或笔画,仍能从同一个维护源重建。
脚本也会放大错误。把错误的三横线结构复用到几十个组合里,能得到一批稳定重复的错误字形。自动化的价值取决于输入规则是否经过验证。
一次失败要定位到具体层
项目早期的 overview 曾用 Unicode 符号近似展示,图片看起来像连字,却没有经过 ASCII shaping。它无法证明字体实现,于是展示链路改成读取真实字体 outline。
== 的三横线问题发生在轮廓派生层;== 被箭头规则切成片段,则发生在 lookup 和上下文安排层。前者要改几何生成,后者要改规则避让。如果只对 AI 说「图不太对」,很容易在两层之间反复调整。
HarfBuzz 输出回答替换成了什么,fontTools 回答宽度与表结构是什么,样张回答最终形态是否容易误读。浏览器和编辑器还负责揭示实际应用的字体加载、feature 选择与分段行为。
任务要有能被推翻的验收条件
「把箭头做漂亮」很难复核。「支持 <====,保留总宽度,并确保 === 与 i-- 仍命中固定字形」则有明确的输入与反例。实现失败时,能够指出哪一个条件未满足。
注释前缀要检查 // comment 与 https://example.com,块注释边界要检查 /* block */ 与 **/*.{ts,tsx}。每组都包含成功与避让条件,约束的是字符上下文,不能据此宣称字体理解了注释或路径语义。
一次新增可以按小批次推进:先确定几何来源与 feature 归属,生成候选,构建临时字体,检查实际替换及宽度,再在真实字号中审阅。新样例与反例随规则进入回归测试,README 只记录已经成立的范围。
总结
AI 能帮助读参考实现、生成重复逻辑和补齐验证工具,项目仍需有人选择默认行为并判断最终阅读效果。把错误分到轮廓、规则、数据与应用显示层,再给出能复现的输入,反馈才会变成有效修正。让每次生成都经过真实字体的检查,比要求 AI 一次画对整套符号更可维护。