AI x SFC Player

記事 · · English · 繁體中文 · 简体中文

ROM はそのまま、『汴河煙雨』を HD に:AI が高画質素材パックを自分で作った

前回の記事では、AI がひとことで 2.5D 五目並べ『汴河煙雨』を作りました。スーパーファミコンの画面は 256×224。清明上河図は高さ 104 ピクセルに縮められ、題字は 12 ピクセルのドットフォントです。

プレイヤーは HD 素材パック に対応しました。ROM は 1 バイトも変えず、画面上で見分けられたタイルと文字を、パックの高解像度画像で描き直します。今回知りたかったのは、ゲームの ROM だけを渡して、AI がパックを自分で作れるかどうかです。

元の画面
元の画面(256×224 を 2 倍で表示)。
HD 素材パックを適用した画面
HD 素材パック適用後(4 倍、1024×896):絵巻は原画の細部、文字は Noto Serif TC。
30 秒の動画:HD オフ 5 秒、オン 10 秒を 2 回(プレイヤーのエミュレーターから直接出力、ゲームの BGM 付き)。H キーでこう切り替わります。

3 つのステップ

1. 空のフォルダを作り、自分の ROM を入れて、skill をインストール:

mkdir bianhe-hd && cd bianhe-hd
cp ~/games/bianhe.sfc .
npx https://aixsfc.app/skill/aixsfc.tgz

インストーラーは Claude Code の skill を 3 つ(HD 素材パックを作るのは sfc-hd)と、MCP ツール(エミュレーター、メモリの読み書き、スクリーンショット)を入れます。

2. claude を起動して、ひと段落伝える(実際は中国語で書きました。以下は訳です):

prompt>

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)を読み込む…」を選ぶと、上の右側の画面になります。

AI がしたこと

まず画面を理解する

エミュレーターでゲームを動かしてステートを保存し、そこからビデオメモリ、パレット、PPU レジスタを読み出して、3 つのことを突き止めました。

素材パックの「文字認識」は、背景レイヤー上で 8×8 グリッドにそろった文字しか見つけられません。そこで AI は、1 文字ずつ普通のタイルとして置き換えることにしました。結果は同じで、この判断も自分で下しています。

絵巻:ROM から元絵を見つけ、美術館のスキャンに合わせる

  1. ROM の中で絵巻全体を見つける。 タイルは $40000 から、1 列 13 枚で 263 列、つまり 2104×104 ピクセル。取り出した絵を画面上の 429 枚のタイルと照合し、429 枚すべて一致。
  2. 原画をダウンロード。 Wikimedia Commons の全巻スキャンは 38414×1800 ピクセル、19 MB の JPEG。
  3. 位置合わせ。 ゲームの絵巻は原画を切り抜き、縮小し、色を調整したものなので、まず両者の対応を求めます。低解像度で相関を探索してから微調整し、「ゲームの x → 原画の X = 1913 + 16.94x」という 1 本の線形対応を得ました。64 ピクセルごとに区切って個別に探索してもずれはすべて 0 で、全体を同じ対応で扱えます。
  4. リサンプル。 HD の各ピクセルは、対応する原画の約 4.2×4.2 ピクセルの平均。8416×416 の絵巻になります。
  5. 色合わせ。 スキャンは美術館らしい冷たい灰色、ゲームは暖かい絹の色。最小二乗法で色変換を求め、HD の絵巻をゲームの色調にそろえました。H キーで切り替えても色が急に変わりません。
  6. タイルに切る。 3419 枚。それぞれのキーは「元タイルのドット+パレット」のハッシュで、HD 絵巻の同じ位置の 32×32 ブロックを指します。
絵巻の一部、上が元のピクセル、下が HD
絵巻の同じ部分:上はゲームのピクセル(4 倍)、下は HD 素材パック。船上の人々、軒、綱まで見えるようになりました。

文字:明朝体に

文字の拡大、左が元のドット文字、右が HD
左:元の 12 ピクセルのドット文字(4 倍)。右:Noto Serif TC。

権限が限られた中での工夫

今回の Claude Code に許したのは、ファイルの読み書き、Web へのアクセス、node・python3・curl の実行だけです。JPEG のデコードには macOS の sips や npm install を使おうとしましたが、どちらもユーザーの確認が必要で、指示には「質問しないで」とありました。

そこで npm registry から curl で jpeg-js のパッケージを直接ダウンロードし、registry が公開している SHA-1 と照合してから、自作の小さなプログラムで展開しました。フォントの描画プログラムを自分で書いたのも同じ理由です。

プレイヤーで遊ぶ

絵巻が川辺の船のあたりまで流れた HD 画面
絵巻が川辺の船のあたりまで流れたところ。下の碁盤は Mode 7 で素材パックの対象外なので、元のピクセルのままです。

試遊で見つかった問題

プレイヤーで初めて適用したとき、下半分の碁盤に縦の縞が出ました。原因はプレイヤー側です。このゲームは同じフレームの途中で Mode 1 から Mode 7 に切り替わりますが、Mode 7 の走査線が、上の走査線の「このピクセルはどのタイルが描いたか」という記録を消していませんでした。そのため碁盤が絵巻のタイルで置き換えられていたのです。

修正は 1 行で、テストも追加し、いまのプレイヤーではもう起きません。画面の途中で本当にモードを切り替えるゲームで試したからこそ見つかった問題で、これだけでも今回のデモをやった価値がありました。

まだできていないこと

数字

AI への指示ひと段落(4 文)
所要時間約 14 分
ツール呼び出し104 回(Claude Opus 5.5、返信 94 件)
AI の出力トークン69,082
処理したトークンの合計約 800 万(ほとんどがキャッシュ読み込み)
推定費用約 4 米ドル(2026 年 11 月の Anthropic API の定価で換算。サブスクリプションは課金方法が異なります)
素材パック4 倍、タイル 3543 枚(絵巻 3419、文字 124)、zip で 7.8 MB

素材パックの中身

素材パックは、manifest.json と数枚の PNG が入ったフォルダ(または zip)です。manifest.json には「どのハッシュが、どの画像のどのブロックに対応するか」しか書かれていません。つまり:

このパックの絵巻はパブリックドメインの絵画から、フォントは SIL OFL、ゲームも私たち自身のものなので、共有できます。市販のゲームから作ったパックは原作の二次的著作物です。自分だけで使い、ROM とパックを同じ zip に入れて配布しないでください。

自分で試すには、空のフォルダで npx https://aixsfc.app/skill/aixsfc.tgz を実行してから claude を起動します。説明はトップページにあります。

出典とライセンス