全流程实录,约 3 分半,无声。不是录屏:页面操作由脚本在无界面浏览器里完成,模型的部分按工具记下的会话记录回放,Unity 画面是 Play 模式下逐帧录的。这里是压缩到 720p 的版本。
概览
给一张按规范画的 PSD,一条命令得到 Unity 原生 UGUI 的界面资源:Prefab、控件、九宫格切图、给程序用的绑定类,外加一份设计稿与引擎截图的像素对比报告。可以在浏览器里预览和修改,修改直接写回 PSD;不按规范画的稿子,先由模型整理成标准稿。
乱稿 →(模型判断,程序执行)→ 标准 PSD → 检查器 → 切图、界面描述、绑定类 → Unity 生成 Prefab → 离屏截图 → 与设计稿对比 → 报告
Unity 全程 -batchmode,不开任何窗口。只用 Unity 原生 UGUI 和 TextMeshPro。
AI 只在一个地方
这个工具最重要的设计决定是把模型关在一个很小的范围里。
转换器是确定性的程序,里面没有 AI:语义全部来自图层名里的标记。模型只做一件事——判断乱稿里每个图层是什么,写成一份带理由的决定清单。改 PSD、核对结果都由程序做。
这样分工之后,转换的结果可以复现、可以测量;模型出错的地方被限制在“命名和分组”上,而且每一条都看得见。
输入:图层名就是全部输入
规范只管命名和分组,不要求设计师换工具。
| 写法 | 结果 |
|---|---|
名字@btn |
Button。组内同名、状态不同的图层(底:normal 底:pressed 底:disabled)合并成一个 Image,其余状态成为 Sprite Swap 的图 |
名字@tabs / @toggle |
ToggleGroup + Toggle,:on / :off 图层随状态切换 |
名字@list / @grid |
子组是条目:结构相同、等间距。方向、列数、间距从稿子量出;第一个条目存成 Prefab,其余都是它的实例 |
图层@9s / @9s=左,上,右,下 / @raw |
九宫格:按容差找边距 / 指定边距 / 不切 |
名字@fx |
投影、发光、选中框:不计入节点矩形 |
名字@anchor=横-纵 |
指定锚点;不写时按节点在父节点里的位置自动推断 |
名字#id |
给程序用的 id,成为绑定类的强类型字段 |
文字是活文字:TextMeshProUGUI,字体、字号、颜色、字距、行距取自 PSD。
输出与还原度
参照图是 PSD 内嵌的合成图,也就是 Photoshop 自己的渲染;引擎图是 Unity 按设计分辨率离屏渲染。任一通道差大于 16/255 记为差异像素。



| 稿子 | 图层 | 切图(去重前 → 后) | 按钮 / 页签 / 列表 | 非文字区域差异 | 整图差异 |
|---|---|---|---|---|---|
| ConfirmPopup | 21 | 12 → 12 | 3 / 0 / 0 | 0.000% | 0.203% |
| Lobby | 76 | 39 → 31 | 3 / 0 / 1 | 0.000% | 0.516% |
| Bag | 517 | 340 → 109 | 4 / 5 / 1 | 0.023% | 0.659% |
| Quest(模拟手绘质感) | 94 | 52 → 43 | 6 / 3 / 1 | 0.000% | 0.344% |
合格线是非文字区域 ≤ 1%、整图 ≤ 5%。文字区域内的差异来自两个渲染器的抗锯齿不同,不设合格线;点文字的位置偏差在 0.6 px 以内。Bag 稿从读 PSD 到 Unity 截图完成约 10 秒。
除了 Prefab 和切图,每个界面还会生成一个绑定类,带 #id 的对象都是强类型字段:
|

规范检查器
“标准稿”的定义就是检查器零错误。错误分两类:转出来的画面会和设计稿不一样的(图层样式、混合模式、调整图层、剪贴蒙版……),和写下的标记无法兑现的(未知标记、互相冲突、id 重复……)。有错误时转换不会启动。
每条发现都指到具体图层,预览页里点一条就选中那个图层,名字上的问题可以直接在页面里改。

为什么需要它:把这张坏稿强行转换,再逐图层和 Photoshop 的画面比,6 个画面类违规里 5 个明显不同(差异像素 20% – 41%)——但整张图的判定仍然是“合格”,因为违规图层面积小,摊到整图上过不了 1% 的线。只看整图数字拦不住这些问题。

在浏览器里预览和修改
一个只监听本机的小服务加一个页面。页面按图层拼出画面,标出转换器识别到的控件;点选图层后可以改名字、id、控件类型、状态、九宫格、锚点和位置。
- 保存就是写回 PSD,没有旁路文件;写入前先校验,不合法的拒绝
- 每次写入前自动备份,页面上可以按备份恢复
- 不覆盖别人的修改:文件在页面读取之后被别的程序改过,写入会被拒绝并重新读取
- “生成到 Unity”触发完整转换,是否合格、数字和三张对比图直接显示在页面里



直接改 PSD 是有风险的,所以这件事先单独验证过:改名、移动、归组之后,Photoshop 打开无报错,文字仍是文字图层、智能对象仍是智能对象,重新渲染的画面与预期相差不到 0.1% 的像素。对照实验里,移动时如果不同步文字变换和蒙版矩形,Photoshop 重新渲染后文字会跳回原位 42 px——这个检查抓得到问题。
乱稿规范化:模型判断,程序执行
不按规范画的稿子画面是对的,只是程序读不出含义:默认图层名、没有标记、控件没成组。
- 模型做判断:这一层是什么(按钮的底、按下态、发光、列表条目……)。它不直接改 PSD,只写一份决定清单:改名、归组、解散组、移动,每条带一句理由。拿不准的列为“待确认”
- 程序执行并把关:只改名和调整分组,不动像素。会让重叠图层上下颠倒、或改变显隐和不透明度的操作一律拒绝。写完再读回来,逐图层比像素和文字数据,逐像素比合成画面
- 像素层面的问题不处理:图层样式、混合模式只报告,留给 Photoshop

怎么测的:盲测
乱稿是从标准稿打乱出来的,答案是已知的。所以判断交给全新的子代理:每张稿子一个,只拿到 skill 说明和乱稿,被禁止读标准稿、测试和报告。交回的决定清单由程序重新执行,再和标准稿逐个控件按矩形比对。
| 命中 / 有偏差 / 漏判 / 误判 | 标准稿里有 | 第一轮 | 第二轮 | 第三轮 |
|---|---|---|---|---|
| 按钮 | 16 | 12 / 4 / 0 / 5 | 15 / 1 / 0 / 5 | 15 / 1 / 0 / 5 |
| 页签 | 8 | 8 / 0 / 0 / 0 | 8 / 0 / 0 / 0 | 8 / 0 / 0 / 0 |
| 列表 | 3 | 3 / 0 / 0 / 0 | 3 / 0 / 0 / 0 | 3 / 0 / 0 / 0 |
@fx 图层 |
133 | 133 / 0 / 0 / 1 | 133 / 0 / 0 / 1 | 133 / 0 / 0 / 1 |
@9s 图层 |
18 | 6 / 0 / 12 / 8 | 18 / 0 / 0 / 15 | 18 / 0 / 0 / 15 |
规范化之后四张稿子都能转换,非文字区域差异最大 0.85%(来自故意留下的一个图层样式和一个滤色混合),Play 模式检查 7 / 7 通过。模型整理一张稿子用时 39 – 125 秒。
误判的 5 个按钮是导航列表的五个条目——模型把条目本身也标成了按钮,这是读法不同而不是错。多标的 @9s 是进度条和条目底板,对画面没有影响。
这个测试的边界
- 第一轮之后改了工具的看图方式和 skill;其中“只有一张非灰色的隐藏底图时判为按下态”这一条是看过答案之后加的,第二轮在这一条上不算盲测
- 三轮用的是同四张稿子
- 乱稿是从标准稿打乱出来的:像素干净,一个图层一个用途。真实的乱稿会更糟
- 三轮里程序没有拒绝过任何操作,所以“拒绝后改用别的归组方式”这条路在盲测里没有走到
还验证了什么
- Play 模式检查:Unity 以 batchmode 进入 Play 模式,一个虚拟指针通过标准输入模块和射线检测去点按钮、切页签、拖列表。四张稿子全部通过
- 预览服务:34 项接口检查全部通过;另有一段 16 步的页面脚本会话,每步核对 PSD。最后恢复最早的备份,文件与原稿逐字节相同
- 九宫格:切完按原尺寸拼回,与原图比较,四张稿子最大通道误差不超过 2 / 255
已知限制
- 没有图集,也还没有进度条、滑条、输入框
- 示例稿不是人画的:由 HTML 渲染再经 Photoshop 脚本生成,图层结构比真实设计稿规整
- 还原度的合格线拦不住小面积的错误,见上面的坏稿实验
- 段落文字换行可能不同:一行放不下时 Photoshop 会挤压标点排进一行,TextMeshPro 会换行
- 文字只支持单一样式、横排、无旋转;描边和投影没有还原
- 锚点推断是启发式的,Bag 稿有三处靠手动指定
- 带渐变或颗粒的图不裁小;带颗粒的中段拉伸后会成横纹
- 操作都由脚本完成:Unity 里是虚拟指针,页面是无界面浏览器,没有真人点过,也没有真机
- 只在一台机器上跑过:Unity 2022.3.62f3,Photoshop 2021,Chrome
示例稿里有三张取材自我另一个作品 Driftglass UI Showcase 的界面:那边是把界面在引擎里搭出来,这边是让同样的界面从 PSD 自动生成。