マガジン

「同じ見た目で」と頼んだとき、AIは何を守り、何を変えるのか:守られない要素を探す実験の設計書

遊びをつくる

執筆にClaudeを使用しています。

紙の飛行機が、海辺の小さな街と山の上を飛んでいく絵。
記事のテーマをもとに制作したAI生成イメージ。実際のゲーム画面ではありません。

自作のブラウザゲームに「ゲームオーバー時にベストスコアを出す」機能を足したくて、AIに修正を頼む場面を考えてみます。依頼文の末尾には「見た目は今のまま変えないでください」と添えました。返ってきたコードは動き、ベストスコアも出ます。ところが開いてみると、ボタンの角が少し丸くなっていたり、スコアの文字が一回り小さくなっていたり、押したときの動きが消えていたりします。どれも「見た目を変えて」とは言っていないのに、です。 原因を「AIが指示を無視した」と決めつけるのは早計です。「見た目」という言葉が、色、フォント、余白、文言、動き、画面幅ごとの配置など、多くの要素をまとめて指しているからです。AIがどの範囲を「見た目」と解釈したのかは、結果を並べないとわかりません。 この記事は結果を報告するものではありません。「見た目の保持指示では、どの要素が守られにくいのか」を自分のゲームで確かめるための実験の設計書です。準備、手順、記録の取り方、結果の読み方、誤りやすい点の順に説明します。

この記事の目次
  1. 「見た目」を比べられる単位に分ける
  2. 準備するもの
  3. 手順:3つの条件を、それぞれ3回ずつ
  4. 記録の取り方:計算済みスタイルを書き出して比べる
  5. 結果の読み方:差が出たとき、どう判断するか
  6. 誤りやすい点
  7. 次の行動

「見た目」を比べられる単位に分ける

実験の最初の作業は、「見た目」を一つずつ確認できる要素に分けることです。次の表を出発点にして、自分のゲームに合わせて足し引きしてください。

  • 色(文字・背景・枠)、確認の仕方:計算済みスタイルの比較、自動で拾えるか:拾える
  • フォントの種類・太さ・大きさ、確認の仕方:計算済みスタイルの比較、自動で拾えるか:拾える
  • 余白・角丸・幅と高さ、確認の仕方:計算済みスタイルの比較、自動で拾えるか:拾える
  • 押したときの変化(transition、animation)、確認の仕方:計算済みスタイルの比較と実際に操作、自動で拾えるか:一部拾える
  • 文言(ボタンの文字、説明文)、確認の仕方:目視、または文字列の比較、自動で拾えるか:目視が確実
  • 画面幅を変えたときの配置、確認の仕方:ウィンドウ幅を変えて比較、自動で拾えるか:幅ごとに取り直す
  • 「動きを抑える」設定のときの挙動、確認の仕方:OS側の設定を切り替えて操作、自動で拾えるか:目視
  • キーボード操作・フォーカスの見え方、確認の仕方:Tabキーで移動して確認、自動で拾えるか:目視
  • 効果音・音量、確認の仕方:聞き比べ、自動で拾えるか:目視(耳)で確認

自動で拾える上段の要素は数値で差が出ます。下段は人が確かめます。両方を記録しないと、「CSSは守られたが、動きを抑える設定への対応が消えた」といった差を見落とします。

準備するもの

  1. ベース版のゲーム。1つのHTMLに収まる小さなゲームで十分です。クリック回数を競うもの、反応速度を測るものなど、画面要素が5〜10個程度のものが扱いやすいです。
  2. 主要要素へのid付け。スコア表示、開始ボタン、結果パネルなど、比較したい要素にidを付けます。理由は記録の節で説明します。
  3. 変更依頼の文面を1つ。たとえば「ゲームオーバー時に、これまでのベストスコアを表示する機能を追加してください」のように、既存の見た目に触れなくても実現できる依頼を選びます。全条件で同じ文面を使います。
  4. AIを使う環境。モデルと設定は全条件で固定します。変更のたびに新しい会話を開始し、前の会話の履歴が混ざらないようにします。
  5. 比較用のコード。この記事の後半に、ブラウザで動く短いコードを載せています。

手順:3つの条件を、それぞれ3回ずつ

比べたいのは、保持指示の書き方による差です。次の3条件を作ります。

  • 条件A(対照):変更依頼だけを送ります。見た目についての言及はありません。
  • 条件B(一言):変更依頼の末尾に「見た目は今のまま変えないでください」と添えます。
  • 条件C(列挙):変更依頼の末尾に「色、フォント、文字サイズ、余白、角丸、文言、押したときの動き、画面幅ごとの配置は変更しないでください」と、守りたい要素を並べます。

進め方は次のとおりです。

  1. ベース版のHTML全体を、条件ごとの依頼文とともにAIに渡します。
  2. 返ってきたコードを、条件名と回数を付けた別ファイル(例:B-2.html)として保存します。
  3. 各条件を3回ずつ、計9本のファイルを作ります。3回行うのは、偶然の揺れと毎回起きる差を区別するためです。
  4. ベース版と9本を、それぞれ同じ手順で記録します(次の節)。
  5. 新しく追加された要素(ベストスコアの表示そのもの)は比較対象から外します。比べるのは、もともとあった要素だけです。

条件Aを入れるのは、「保持を頼まなくても変わらない要素」と「頼んでも変わる要素」を切り分けるためです。Aで変わらない要素は、保持指示の効果を測れません。

記録の取り方:計算済みスタイルを書き出して比べる

目視だけでは、1px単位の余白の違いや、色の微妙なずれを見逃します。ブラウザが実際に適用した値(計算済みスタイル)を書き出して、ベース版との差を一覧にします。

まず、各HTMLファイルをブラウザで直接開き、開発者ツールのコンソールに次のコードを貼ります。出力されたJSON文字列をコピーして、ファイルごとに保存してください。

js
(() => {
  const P = ['color','backgroundColor','fontFamily','fontSize','fontWeight',
    'margin','padding','borderRadius','width','height','display',
    'transition','animationName'];
  const out = {}, seen = {};
  document.querySelectorAll('body, body *').forEach(el => {
    const t = el.tagName.toLowerCase();
    seen[t] = (seen[t] || 0) + 1;
    const s = getComputedStyle(el);
    const o = {};
    P.forEach(p => o[p] = s[p]);
    out[el.id || t + '#' + seen[t]] = o;
  });
  console.log(JSON.stringify(out));
})();

次に、ベース版のJSONと比べたいファイルのJSONを、下のページの左右の欄に貼ります。このページは単独のHTMLとして保存し、ブラウザで開くだけで動きます。

html
<textarea id="a" placeholder="ベース版のJSON"></textarea>
<textarea id="b" placeholder="比べる版のJSON"></textarea>
<button onclick="go()">比べる</button><pre id="r"></pre>
<script>
function go(){
  const a = JSON.parse(document.getElementById('a').value);
  const b = JSON.parse(document.getElementById('b').value);
  const lines = [];
  for (const k of Object.keys(a)) {
    if (!(k in b)) { lines.push(k + ' : 消えた'); continue; }
    for (const p of Object.keys(a[k])) {
      if (a[k][p] !== b[k][p]) lines.push(k + ' ' + p + ' : ' + a[k][p] + ' → ' + b[k][p]);
    }
  }
  for (const k of Object.keys(b)) if (!(k in a)) lines.push(k + ' : 増えた');
  document.getElementById('r').textContent = lines.join('\n') || '差なし';
}
</script>

出力の1行は「要素名 プロパティ名 : 元の値 → 新しい値」の形になります。この行を、条件・回数・要素・プロパティの順で表計算ソフトに転記していくと、後で集計できます。

このコードでは、idのない要素は「タグ名#出現順」で名前が付きます。準備の段階で主要要素にidを付けておくのはこのためです。

画面幅の確認は、ウィンドウ幅を2〜3段階(広い、中くらい、スマートフォン程度)に変えて、同じ手順を繰り返します。文言、動きを抑える設定、キーボード操作、効果音は、上の表の「目視」の行を条件ごとにチェックリストにして、変わった・変わらないを書き留めてください。

結果の読み方:差が出たとき、どう判断するか

記録が揃ったら、要素ごとに「A・B・Cの各3回のうち、何回ベース版と違っていたか」を数えます。結果の読み方は次のとおりです。

  • AとBで差の数がほとんど変わらない場合:「見た目は今のまま」という一言は、少なくともその要素には届いていません。「見た目」という言葉が指す範囲を、AIが狭く解釈している可能性があります。
  • BからCで差が減った場合:要素を名指しする書き方が効いています。普段の依頼文に、守りたい要素の一覧を定型文として持っておく価値があります。
  • Cでも残る差:言葉での保持指示では守りにくい要素です。依頼文を長くする方向では解決しにくいので、構造で固定する方法を検討します。たとえば、色やフォントをCSS変数に集めて、その部分をAIに渡さず、機能のコードだけを渡す方法があります。
  • 3回のうち1回だけ出た差:偶然の揺れの可能性が高いです。回数を増やして、再現するかを見ます。
  • 3回とも同じ差が出る要素:系統的な癖です。依頼文の工夫より、変更後に必ず確認する項目として、ご自身のチェックリストに入れておくのが現実的です。

見た目の数値の差が小さくても、文言や動きを抑える設定への対応のような「目視の要素」が消えていたなら、そちらのほうが遊ぶ人への影響は大きいかもしれません。数値の差の数だけで優劣を決めず、どの要素が変わったかの中身を見てください。

誤りやすい点

  • 会話を引き継いでしまう:同じ会話の中で条件を試すと、前の指示が効いてしまいます。条件ごとに新しい会話を始めてください。
  • 変更依頼の文面が条件ごとに違う:機能の説明が違えば、コードの変わり方も変わります。保持指示の部分以外は、一字一句そろえます。
  • 新機能の見た目を差として数える:追加された要素は「増えた」と表示されますが、保持の失敗ではありません。既存要素だけを集計します。
  • 要素の増減で番号がずれる:idのない要素は出現順で名前が付くため、途中に要素が増えると後ろの名前がずれ、実際には変わっていないのに差が大量に出ることがあります。差が不自然に多いときは、まずidの付け忘れを疑ってください。
  • 1回の結果で結論を出す:AIの出力は毎回少しずつ変わります。1回だけで「守られた」「守られなかった」と判断しないでください。
  • 計算済みスタイルだけで安心する:数値が同じでも、動きを抑える設定への対応や、キーボードで操作したときの見え方が消えていることがあります。目視のチェックも省かないでください。

次の行動

まず、手元の小さなゲームに主要要素のidを付け、ベース版の計算済みスタイルを書き出してください。そのうえで、条件Aと条件Bを1回ずつ試せば、「一言の保持指示がどの要素に届くか」の最初の手がかりが得られます。差の出た要素が見つかったら、それを自分用の「守りたい要素リスト」に加え、更新のたびに使う依頼文のひな形にしてください。

アソバースでは、公開済みの作品の内容を更新できます。更新を繰り返す作品ほど、遊ぶ人にとっての見た目の一貫性が効いてきます。このリストは、その更新作業のたびに役立ちます。