不改 ROM,让《汴河烟雨》变成 HD:AI 自己做出高画质素材包
上一篇里,AI 用一句话做出了 2.5D 五子棋《汴河烟雨》。超任的画面只有 256×224,清明上河图被缩成 104 像素高,题签用的是 12 像素的点阵字。
播放器现在支持 HD 素材包:ROM 一个字节都不改,画面上认得的图块和文字,改用素材包里的高分辨率图片来画。这次我们想知道:只给 AI 这个游戏的 ROM,它能不能自己把素材包做出来?


三个步骤
1. 建一个空文件夹,放进自己的 ROM,安装 skill:
mkdir bianhe-hd && cd bianhe-hd
cp ~/games/bianhe.sfc .
npx https://aixsfc.app/skill/aixsfc.tgz
安装程序会放好三个 Claude Code skill(其中 sfc-hd 负责做 HD 素材包)和 MCP 工具(模拟器、读写内存、截图)。
2. 开 claude,说一段话:
bianhe.sfc 是我自己做的五子棋游戏(烟雨汴河)。请用 sfc-hd 帮我做一个 HD 素材包: 上方滚动的清明上河图,改用 Wikimedia Commons 上的高分辨率原图(公有领域)重新取样; 画面上的中文字,用开源授权的字体(例如 Noto Serif TC)重新绘制。 过程中不用问我,倍率你决定。完成后打包成 zip,并记录制作过程报告。
之后没有再补充任何说明。平常 sfc-hd 会先问你:图要怎么放大(本机 AI 放大、AI 重绘、自己画)、字要用哪个字体。这里我们一次说完,所以它全程没有停下来。
3. 播放: 14 分钟后它交回 bianhe-hd-pack.zip(7.8 MB)。打开 aixsfc.app/player,加载游戏,从工具栏的 HD 菜单选“载入 HD 素材包(.zip)…”,就是上面右边的画面。
它做了什么
先看懂画面
它在模拟器里运行游戏、存档,从存档读出显存、调色板和 PPU 寄存器,得出三件事:
- 画面在第 105 条扫描线切开:上半部是普通背景(Mode 1),下半部是透视棋盘(Mode 7)。
- 长卷是背景层,用一个 64 列的环形区域一列一列流式传入显存。
- 题签和“你的回合”这些字不是背景文字,而是 16×16 的精灵。
素材包的“文字识别”只认得背景层上对齐 8×8 网格的字,所以它决定把每个字当成普通图块来替换。效果一样,而且它自己判断出了这点。
长卷:从 ROM 找到原图,再对上博物馆扫描件
- 在 ROM 里找到整条长卷。 图块从
$40000开始,一列 13 块,共 263 列,就是 2104×104 像素。它把提取出来的图和画面上的 429 个图块逐一比对,429 个全部相同。 - 下载原图。 Wikimedia Commons 上的全卷扫描件是 38414×1800 像素、19 MB 的 JPEG。
- 对位。 游戏的长卷是原图裁切、缩小、调色后的版本,所以要先找出两者的对应关系。它先在低分辨率下用相关系数搜索,再细调,得到“游戏 x → 原图 X = 1913 + 16.94x”这样一个线性对应。再把长卷每 64 像素切一段各自搜索,每段的偏移都是 0,所以整条用同一个对应就行。
- 重新取样。 每一个 HD 像素,取原图上对应的约 4.2×4.2 像素做平均,得到 8416×416 的长卷。
- 调色。 原图是博物馆的冷灰色调,游戏是偏暖的绢色。它用最小二乘法算出一组色彩转换,让 HD 长卷保持游戏的色调,按 H 开关时不会突然变色。
- 切成图块。 3419 个图块,每块的 key 是“原图块的点阵+调色板”的哈希值,对应 HD 长卷上同一位置的 32×32 方块。

文字:换成宋体
- 它从 Google Fonts 只下载游戏用到的 29 个字(Noto Serif TC,SIL OFL 授权),再加上红色印章字“胜”“和”。
- 这台电脑上没有现成的字体绘制工具,它就自己写了一个 TrueType 解析器和抗锯齿填色程序。
- 每个字用原本点阵字的墨色范围来对齐,在 0.86–1.06 倍的缩放和 ±1 像素的位移里,找重叠最多的组合。
- 它试了 500、600、700、900 四种字重,选了笔画粗细最接近原作的 600。
- 面板的边框和底色保留原本的像素,只把字换掉。总共 124 个精灵图块。

权限受限时的变通
这次的 Claude Code 只开放读写文件、上网,以及执行 node、python3、curl 这几个命令。解 JPEG 原本想用 macOS 的 sips 或 npm install,但两者都要用户确认,而指示里说了“不用问我”。
所以它直接从 npm registry 用 curl 下载 jpeg-js 的包文件,先核对官方公布的 SHA-1,再用自己写的小程序解开。字体的绘制程序也是因为同样的限制才自己写的。
在播放器里播放
- 工具栏的 HD 菜单有五个选项:关、开、加载文件夹、加载 .zip、移除。手机上选文件夹不方便,用 .zip 最简单。
- 素材包加载一次后,会以“这个 ROM”为单位存在浏览器里。下次开同一款游戏会自动套用,开关状态也会记住。
- 键盘按 H 随时开关,方便对照前后差异。
- 长卷滚动时,新露出的每一列都会换成 HD。素材包比对的是“画面上的图块”,不是 ROM 地址,所以流式传入的图块照样认得出来。

我们在试玩时发现的问题
第一次在播放器里套用时,下半部的棋盘出现了一条条竖纹。原因在播放器:这款游戏在同一帧画面里从 Mode 1 切换到 Mode 7,Mode 7 的扫描线没有清掉上一条扫描线留下的“这个像素来自哪个图块”记录,结果棋盘被当成长卷的图块替换了。
修正只有一行,也加了测试,现在的播放器已经没有这个问题。这也是做这次演示的收获:拿一款真的会在画面中途切换模式的游戏来试,才会遇到这种情况。
还没做到的
- 最右边约 64 像素: 这一段和 Commons 的扫描件对不太上。AI 在报告里推测,原作可能用了别的扫描版本,或者在接缝处做过处理。对照上一篇的制作过程,比较可能的原因是:做游戏时为了让滚动无限循环,长卷的头尾做了交叉淡化,这一段混进了开头的画面。HD 版在这段仍然接得上,只是细节和原本的像素不完全相同。
- 棋盘、棋子、雨丝、光标保持原本的像素:棋盘是 Mode 7,素材包格式不支持;其他精灵不在这次的范围内。
数字
| 给 AI 的指示 | 1 段话(4 句) |
| 总时间 | 约 14 分钟 |
| 工具调用 | 104 次(Claude Opus 5.5,94 条回复) |
| AI 输出 token | 69,082 |
| 处理的 token 总数 | 约 800 万(大部分是缓存读取) |
| 估计费用 | 约 4 美元(按 2026 年 11 月的 Anthropic API 牌价换算;订阅方案计费方式不同) |
| 素材包 | 倍率 4,3543 个图块(长卷 3419、文字 124),zip 7.8 MB |
素材包里有什么
素材包是一个文件夹(或 zip),里面有一个 manifest.json 和几张 PNG。manifest.json 只列出“哪个哈希值对应图片上的哪一块”,所以:
- 素材包里没有 ROM 的任何内容,原本的点阵只以哈希值的形式出现。
- 播放器不会执行素材包里的任何程序,素材包只有数据。
- 比对的是画面上的图块,播放器不需要知道是哪一款游戏。
这个素材包的长卷来自公有领域的画作,字体是 SIL OFL 授权,游戏也是我们自己的,所以可以分享。拿市售游戏做的素材包,属于原作的衍生作品,请只留给自己使用;也不要把 ROM 和素材包放在同一个 zip 里散布。
想自己试试,在空文件夹执行 npx https://aixsfc.app/skill/aixsfc.tgz 再开 claude,说明在首页。
来源与授权
- 画作:张择端《清明上河图》,12 世纪,公有领域;扫描件:Wikimedia Commons,
File:Alongtheriver QingMing.jpg。 - 字体:Noto Serif TC,Google/Adobe,SIL Open Font License 1.1。
- 游戏《汴河烟雨》:见上一篇。本作与任天堂无关,亦未获其背书。