One-shotting a Raccoon Heist game using Claude Fable 5

Simon Willison

Claude Fable 5で『Raccoon Heist』をワンショットで作ってみた

原文は Simon Willison により に公開されました。 このブログを購読する

2022年に、GPT-3に生成させたゲームコンセプトとDALL-Eで作ったコンセプト“アート”のスクリーンショットをツイートしました。ちょうど4年後の今日、そのツイートの内容からClaude Fable 5(Claude Code for web上で動作)にゲーム全体を作らせられるか試してみることにしました。なかなか良い出来でした!

こちらからプレイできます。GitHubリポジトリはこちら、短いデモ動画もどうぞ:

作り方

これが2022年8月5日のツイートです:

Simon Willison @simonw - 新しい趣味:GPT-3とDALL-Eを組み合わせて60秒でビデオゲームのプロトタイプを作ること。こちらが『Raccoon Heist』。2枚の画像——1枚目はGPT-3のplaygroundのスクリーンショット(プロンプトは下記)、右側は明らかにDALL-Eが生成した、ほぼアイソメトリックな3Dコンピューターゲームの画像で、2匹のアライグマが未来的な建物の脇の通りを何かを盗もうとしているかのように忍び足で進んでいる。

当時GPT-3に与えたプロンプトはこうでした:

Write a detailed product description of a computer game where a team of raccoons go on heists.

これはまだテキスト補完の時代のことで、GPT-3に文章の続きを書かせるという使い方でした。GPT-3はこう返してきました:

『Raccoon Heist』では、あなたと泥棒アライグマのチームが、大胆な強盗を次々と成功させる任務を担います。銀行強盗から高価な美術品の窃盗まで、毛むくじゃらの仲間たちにとって大きすぎる仕事も小さすぎる仕事もありません。警察をかわし、戦利品を持って鮮やかに逃げ切るには、知恵と腕が試されます。エキサイティングなゲームプレイと魅力的なキャラクターたちで、『Raccoon Heist』は気軽な泥棒稼業を楽しみたい人にぴったりのゲームです。

DALL-Eへのプロンプトは短いものでした:

Screenshot from a video game where a team of raccoons go on a heist

今回の実験はこうです。あのスクリーンショットをFable 5に投げ込み、ゲームを作るようプロンプトで指示したら、あとは放っておいて最後に動くゲームができあがるのか?

Claude Code for webをGitHub Pagesで使えるようにする

Claude Code for webの厄介な点は、作業中の内容をリアルタイムでテストするのが難しいことです。

私はこの制限を回避するためにGitHub Pagesを使っていますが、これがとてもうまく機能しています。

手順は次のとおりです:

  1. https://github.com/newでプロジェクト用の新しいリポジトリを作成します——公開でも非公開でも、この方法はどちらでも同じように使えます。
  2. Claude iPhoneアプリやデスクトップアプリ、あるいはブラウザのhttps://claude.ai/codeでClaude Code for webのセッションを開始します。
  3. Claudeに何を作るか指示し、できるだけ早くindex.htmlページをコミットするよう促します。するとclaude/3d-raccoon-heist-game-50n293のような名前のブランチが作成されます。
  4. リポジトリのSettings -> Pagesエリア(私の場合はgithub.com/simonw/raccoon-heist/settings/pages)に移動し、「Deploy from a branch」を選択して、ブランチ名を選んでSaveを押します。

これだけです!プッシュするたびに約30秒で最新の内容がyourname.github.io/your-repo/で表示されるようになります。

非公開リポジトリでこれを行うと、リポジトリ名を推測できた人は誰でも公開された内容を閲覧できます。私はあまり気にしていませんが。

Fable 5へのプロンプト

以下がFable 5に与えたプロンプトです(スマホのメモアプリで書きました——このプロジェクト全体をモバイルで完結させています)。元のツイートの2枚の画像も添えました。

Build this 3D game, for the browser.

This repo is configured to serve static files so make sure there is an index.html that loads everything else.

Make sure it is mobile-friendly (touch controls, works well on small screens).

You have an OpenAI API key and access to their image generation model APIs, use that for textures to use with your 3D models. Docs here: https://developers.openai.com/api/docs/guides/image-generation - use gpt-image-2

Work independently - do not ask me to make any further design decisions. Make sure the game is fun, a little surprising, has good raccoon heist vibes, and is visually pleasing.

Commit and push as often as possible so I can preview your work - start with an index.html that presents a title screen, then build from there.

Append to a notes.md file as you work, including your changes to that as part of every commit.

技術選定は一切しませんでした。過去の実験から、おそらくThree.jsを使うだろうと(正しく)予想していました。

ClaudeにOpenAIのAPIキーを渡しておくと、足りない機能を補うのにとてもよく機能することがわかりました——今回は3Dモデルのテクスチャに使う画像を生成する手段が必要でした。Fableは画像生成へのプロンプトがとても上手です!

「自律的に作業して、これ以上デザインの判断を求めないで」と伝えたのは、一切追加の指示なしで完成した動くゲームを作れるか見たかったからです。

「できるだけ頻繁にコミットしてプッシュして、作業内容をプレビューできるようにして」とも伝えました。Claude iPhoneアプリでClaude Codeを使うと、GitHubリポジトリを渡してブランチで作業させます。「できるだけ頻繁にプッシュして」と指示しておくと、すぐにコミットがそのブランチに反映され始めます。

ちょっとしたおまけとしてnotes.mdへの追記を頼むのが気に入っています——こちらが完成したファイルで、犬を追加したときの記述がこれです:

新たなエスカレーション:3日目の夜から庭に見回りの番犬が登場——トゲ付きの赤い首輪をしたローポリの茶色い猟犬で、尻尾を振っている。ランダムな地点の間をうろつき、12ユニット以内に入ると匂いを嗅ぎつけて追跡してくる(視界は関係なし——完全に鼻頼みで、頭上に👃が表示され吠える)。17ユニット離れれば諦める。捕まったときのメッセージも原因別になった:警備員/ヘッドライト/猟犬。徘徊→追跡→捕獲の流れを自動テストで検証済み。

トランスクリプトを振り返る

Claude Codeの共有セッションはこちらから見られますし、私のclaude-code-transcriptsツールを使ってエクスポートしたHTML版もこちらで公開しています。

Fableはまずインデックスページから始め、Three.jsをベンダー化し、次に独自のgen_textures.pyスクリプトコピーはこちら)を書きました。

テクスチャを生成して目視でチェックし、見た目が問題ないか確認しました。ゴミ箱用に生成したmetal.jpgファイルはこんな見た目ですが、ゲーム内では正確に適用されていないように思います:

濃い青灰色のリベット打ちされた金属パネルのゲーム用テクスチャアトラス。左上に取っ手付きの円形ハッチ、中央にリブ付きの波板パネル、左下に無地の円形プレート、上下に平らな帯状のストリップが描かれている。文字は見えない。

続いてゲームの最初の基本バージョンを構築し、Playwrightを使って「プリインストールされたChromiumでスモークテストする」ことにしました。これにより自分の成果をスクリーンショットに撮って目視確認できるわけです。デスクトップ幅とモバイル幅の両方で試したところ、モバイル幅ではアライグマが見えなくなっていることに気づき、修正しました

アライグマ、ゴミ箱のアジト、そして仲間のアライグマ2匹が、モバイルでも完璧に見えるようになりました。この重要な修正をコミットします。

次にタイトル画面を生成することにし、このgen_title.pyスクリプトを使って実行しました。その際に使ったgpt-image-2のプロンプトがこちらです:

Video game key art, low-poly 3D render style, moody nighttime scene: a cute low-poly raccoon wearing a tiny black burglar mask sneaking on its hind legs carrying a glowing gold coin, next to a tipped-over metal trash can, suburban house with warm glowing windows in the background, deep blue night, full moon, fireflies, cinematic rim lighting, charming heist caper mood. No text, no words, no logos.

そして出来上がった画像がこれです(Claudeは「素晴らしい」と評していました)——ただしデスクトップで表示すると上部3分の1だけに切り取られてアライグマが見えなくなってしまうのですが!

倒れたゴミ箱の横で金貨を抱えるポリゴン調のアライグマ、背景に家と月。

そして私のお気に入りの変更点、犬の追加です:

export function makeDog() {
  const g = new THREE.Group();
  const BROWN = 0x8a6440, DARK = 0x5e4128;
  const body = new THREE.Mesh(new THREE.SphereGeometry(0.42, 10, 8), M(BROWN));
  body.scale.set(0.9, 0.8, 1.5);
  body.position.y = 0.55;
  body.castShadow = true;
  g.add(body);
  const head = new THREE.Mesh(new THREE.SphereGeometry(0.3, 10, 8), M(BROWN));
  head.position.set(0, 0.85, 0.62);
  g.add(head);
  const snout = new THREE.Mesh(new THREE.SphereGeometry(0.16, 8, 6), M(DARK));
  snout.scale.set(0.9, 0.7, 1.3);
  snout.position.set(0, 0.76, 0.9);
  g.add(snout);
  const nose = new THREE.Mesh(new THREE.SphereGeometry(0.06, 6, 6), M(BLACK));
  nose.position.set(0, 0.78, 1.08);
  g.add(nose);
  for (const s of [-1, 1]) {
    const ear = new THREE.Mesh(new THREE.SphereGeometry(0.12, 6, 6), M(DARK));
    ear.scale.set(0.7, 1.3, 0.5);
    ear.position.set(0.2 * s, 1.08, 0.55);
    g.add(ear);
    const eye = new THREE.Mesh(new THREE.SphereGeometry(0.05, 6, 6), M(0x1a1a1a, { emissive: 0x331111 }));
    eye.position.set(0.13 * s, 0.92, 0.86);
    g.add(eye);
  }
  const tail = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.09, 0.5, 6), M(DARK));
  tail.position.set(0, 0.8, -0.62);
  tail.rotation.x = 0.8;
  g.add(tail);
  // spiked collar
  const collar = new THREE.Mesh(new THREE.TorusGeometry(0.22, 0.05, 6, 12), M(0xc0392b));
  collar.position.set(0, 0.78, 0.5);
  collar.rotation.x = Math.PI / 2.4;
  g.add(collar);
  const legGeo = new THREE.CylinderGeometry(0.07, 0.09, 0.34, 6);
  const legs = [];
  for (const [x, z] of [[-0.22, 0.35], [0.22, 0.35], [-0.22, -0.35], [0.22, -0.35]]) {
    const leg = new THREE.Mesh(legGeo, M(DARK));
    leg.position.set(x, 0.17, z);
    g.add(leg);
    legs.push(leg);
  }
  let phase = Math.random() * 10;
  return {
    group: g,
    animate(dt, speed) {
      phase += dt * (3 + speed * 10);
      const amp = Math.min(0.6, 0.1 + speed * 0.6);
      legs[0].rotation.x = Math.sin(phase) * amp;
      legs[3].rotation.x = Math.sin(phase) * amp;
      legs[1].rotation.x = -Math.sin(phase) * amp;
      legs[2].rotation.x = -Math.sin(phase) * amp;
      tail.rotation.z = Math.sin(phase * 1.5) * 0.4;
      body.position.y = 0.55 + Math.abs(Math.sin(phase)) * 0.04 * (0.3 + speed);
    },
  };
}

そしてPlaywrightで一連のテストを行い、さらにスクリーンショットも撮りました。

  // walk near the dog
  await page.evaluate(() => { const d = window.__rh.dog; window.__rh.teleport(d.x + 6, d.z); });
  await page.waitForTimeout(2000);
  info = await page.evaluate(() => JSON.stringify({ dog: window.__rh.dog, state: window.__rh.state, player: window.__rh.debug().player }));
  console.log('after approach:', info);
  await page.waitForTimeout(3000);
  info = await page.evaluate(() => JSON.stringify({ dog: window.__rh.dog, state: window.__rh.state }));
  console.log('after chase:', info);
  await page.screenshot({ path: __dirname + '/shot-dog.png' });

ゲームのスクリーンショット。3日目の夜、アライグマが中央で犬と重なっている。『Busted! The Guard shooed you off!』というメッセージが表示され、画面の端は赤く染まっている。

いくつか微調整を加えた後、完了を宣言しました

Raccoon Heistはビルド、テスト、プッシュ完了claude/3d-raccoon-heist-game-50n293に7回コミット、すべてPlaywrightによる自動プレイテストで検証済み(デスクトップ、縦向きスマホ、横向きスマホの各ビューポート)。

ゲーム内容:あなたはマスクをしたアライグマとなり、仲間が潜むゴミ箱のアジトから月明かりの袋小路へ忍び出します。コイン、宝石、指輪、ドーナツ、魚をかき集めましょう(背中に目に見えて積み重なり、重くなるほど動きが鈍くなります)。ヨチヨチ歩きでアジトに戻り、夜明けまでに戦利品を確保します。夜ごと目標と難易度が上がります。1日目は懐中電灯で照らす警備員が1人、2日目は2人、3日目には視界を完全に無視して匂いで追跡する猟犬が加わります。パトカーがヘッドライトで通りを照らして巡回し、住人がランダムに窓から覗き、カモメが定期的に放置された獲物を急降下で奪い、ピザを拾うと6秒間のスピードFRENZYが発動し、レアな金のテレビは重さに耐えて持ち帰れば120点の価値があります。勝利ランクはTRASH PANDA ⭐ → CAT BURGLAR ⭐⭐ → MASTER OF DISGUISE ⭐⭐⭐で、ベスト記録はlocalStorageに保存されます。

仕組み:Three.jsをベンダー化(CDNなし)、プロシージャルなローポリキャラクター、そしてプロシージャルなWebAudioサウンドトラック(忍び足のウォーキングベース・ジャズとすべての効果音——音声ファイルはゼロ)。7種類の地面・壁テクスチャとタイトル画面のヒーローアートはすべてgpt-image-2で生成し、静的アセットとしてコミットしているため、デプロイされたゲームはAPIを一切呼び出しません。モバイルでは触れた場所に現れるダイナミックなタッチジョイスティックとDASHボタン、デスクトップではWASD/矢印キーとスペースで操作します。

テストで見つかった特筆すべきバグは2つ:実機のスマホではキャンバスが2倍サイズで描画される問題(cssTextへの代入がThree.jsのインラインサイズ指定を消してしまっていた——デスクトップのDPR-1テストでは完全に見逃されていました)と、勝利画面の星評価divがタイトル画面の全画面.stars CSSを継承して「次の夜へ」ボタンのタップをすべて黙って奪ってしまう問題。どちらも修正し、アイテム拾得、バンク、追跡/捕獲、夜明け、夜の進行、敗北/リトライの各フローとともにリグレッションテスト済みです。

notes.mdに全ビルドログがあります。ゲームはブランチ上で公開中です——リポジトリのルートを配信してindex.htmlを開くだけで遊べます。

ゲームは面白いのか?

出発点としては印象的ですが、良いゲームとは言えません。

庭をアライグマで動き回り、懐中電灯を持った警備員や、後半のレベルでは犬を避けながらアイテム——ドーナツ、魚、金貨、宝石——を集めます。運べる量には上限があり、いっぱいになったらゴミ箱まで戻って降ろす必要があります。ピザを拾うと一時的にスピードが上がります。

チームとしての仕掛けは一切ありません——ゴミ箱の横に2匹の仲間アライグマがいますが、完全に飾りです。

レベルが進むにつれて少しだけ難しくなります——レベル3で登場する犬が最も面白い新要素ですが、クリア自体は非常に、非常に簡単です。しかもかなり退屈です——各夜は時間が固定されているため、アイテムを全部集めてしまうと夜明けを待つ間やることがなくなってしまいます。

実装には感心しました。完全な3Dで、ゴミ箱もあり、懐中電灯の光の円錐も楽しく、ビジュアルスタイルにもそれなりに一貫性があります。モバイルでも動作します。音楽(Claudeいわく「プロシージャルなWebAudioサウンドトラック(忍び足のウォーキングベース・ジャズとすべての効果音——音声ファイルはゼロ)」)はシンプルですが、雰囲気に合っています。

完成したゲーム作品としては平凡です。しかし、単一のプロンプトからの出発点としては非常に印象的だと思います。

これまでにかなりの数のゲームをバイブコーディングしてきましたが、ゲームプレイという観点ではどれも深くがっかりさせられるものでした——結局のところ、楽しいゲームをデザインすることは依然として人間に特有の能力であり、Claudeにも私にもない、はるかに多くのスキルと経験を要するのだとわかります。

とはいえ、エージェントの能力を探る手段としてゲーム開発プロジェクトで遊んでみることは強くおすすめします。楽しく、リスクの低い新しいことの試し方です。長く続ければ、実際に遊ぶ価値のあるものが生まれるかもしれません!

追記 2026年8月7日: 同じプロンプトをGPT-5.6 Sol Ultraを搭載したOpenAI Codex Desktopに投げたところ、はるかに良い結果が得られました——GPT-5.6 Solはアライグマの強盗団という重要性をきちんと汲み取り、博物館で2匹の仲間を救出し、その上に積み重なって金のイワシを盗むゲームを作ってくれました。

この記事は「muse-spark-1.2-contributor」を使用して翻訳されました。

コメント