用 Claude Fable 5 一次性构建《浣熊大劫案》游戏
英文标题:One-shotting a Raccoon Heist game using Claude Fable 5
作者在四年前曾用 GPT-3 和 DALL-E 生成“浣熊大劫案”游戏概念,如今尝试将当时的推文素材直接交给运行于 Claude Code for web 中的 Claude Fable 5,以一次提示完成整款浏览器游戏。Claude 自主选择了 Three.js,调用 OpenAI 的 gpt-image-2 生成纹理和标题画面,并通过 Playwright 在桌面端和移动端反复截图、测试与修复。最终项目以 7 次提交完成,包含可玩的 3D 潜入玩法、移动端触控支持、巡逻守卫犬等机制。该案例展示了 Agent 式编程工具结合代码执行、视觉检查、GitHub 和图像生成 API 后,能够在较少人工干预下完成从创意素材到可部署原型的完整流程。
81.3 KB
41.6 KB
54.3 KB
111.7 KB
中文
用 Claude Fable 5 一次性构建《浣熊大劫案》游戏
2026 年 8 月 5 日
2024 年时,我曾发推展示由 GPT-3 生成的游戏概念截图,以及由 DALL-E 创作的一些概念“美术”。今天正好是那条推文发布四周年,我决定试试看:运行在 Claude Code for web 中的 Claude Fable 5,能否仅根据那条推文的内容构建整个游戏。它完成得相当不错!
你可以在这里游玩该游戏。这是其 GitHub 仓库,以及一段简短的视频演示:
你的浏览器不支持 HTML5 视频。
我是如何构建它的

我当时给 GPT-3 的提示词是:
Write a detailed product description of a computer game where a team of raccoons go on heists.
那还是文本补全的时代:你让 GPT-3 补全后续文本。它补全出了:
在《浣熊大劫案》中,你和你的盗贼浣熊团队需要完成一系列大胆的劫案。从抢劫银行到盗取无价艺术品,对你这支毛茸茸的队伍来说,没有任何任务太大或太小。你需要运用智慧和技巧躲避警察,并带着赃物干净利落地脱身。凭借刺激的玩法和迷人的角色阵容,《浣熊大劫案》是任何寻找轻松愉快冒险游戏的玩家的完美选择。
我给 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 来绕过这一限制,发现效果非常好。
我的流程如下:
- 在 https://github.com/new 为项目创建一个新仓库——可以是公开仓库或私有仓库,这个技巧对两者同样有效。
- 在 Claude iPhone 或 Desktop 应用中,或者在浏览器的 https://claude.ai/code 中,启动一个 Claude Code for web 会话。
- 告诉 Claude 要做什么,并鼓励它尽快提交一个
index.html页面。这会创建一个名称类似claude/3d-raccoon-heist-game-50n293的分支。 - 前往仓库的 Settings -> Pages 页面(我的仓库中是
github.com/simonw/raccoon-heist/settings/pages),选择“Deploy from a branch”,选取该分支名称,然后点击 Save。
这样就够了!每次推送后约 30 秒内,最新内容就会出现在 yourname.github.io/your-repo/。
如果你对私有仓库这样操作,任何能够猜到仓库名称的人都可以查看已发布的内容。我自己并不太担心这一点。
Fable 5 的提示词
以下是我给 Fable 5 的提示词(在手机的备忘录应用中写的——整个项目都是在移动设备上完成的)。我还附上了原始推文中的两张图片。
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 key 的访问权限,非常适合弥补其能力缺口——在这个案例中,我们需要某种方式生成可用于 3D 模型的纹理图像。Fable 很擅长为图像生成器编写提示词!
我说“独立工作——不要要求我再作出任何设计决策”,是因为我想看看它能否在无需我进一步输入的情况下,产出一款完整且可运行的游戏。
我还说“尽可能频繁地提交和推送,这样我就能预览你的工作”。在 Claude iPhone 应用中使用 Claude Code 时,你会给它一个 GitHub 仓库,它会在一个分支中工作。告诉它“尽可能频繁地推送”,意味着提交会立即开始进入该分支。
我喜欢要求它维护 notes.md,这会增添一点额外趣味——这是最终文件,以及它添加狗时写下的条目:
新的难度升级:从第 3 夜开始,庭院里会出现一只巡逻的守卫犬——一只低多边形棕色猎犬,戴着铆钉红项圈,尾巴会摇摆。它会在随机地点之间游荡;一旦进入 12 个单位范围内,就会捕捉到你的气味并靠嗅觉追踪你(视线无关紧要——全靠鼻子,头顶的 👃 和吠叫会体现这一点)。如果你拉开 17 个单位的距离,它就会放弃追踪。被抓到的信息现在会区分来源:守卫 / 车灯 / 猎犬。已通过自动化测试验证游荡 → 追踪 → 抓获的流程。
审阅记录
你可以访问 Claude Code 共享会话。我还使用自己的 claude-code-transcripts 工具导出了 HTML 版本,你可以在这里查看。
Fable 从一个 index 页面开始,内置了一份 Three.js 副本,随后编写了自己的 gen_textures.py 脚本(副本在这里)。
它生成了纹理,并对其进行了抽样检查,以确认它们看起来没有问题。它为垃圾桶生成的 metal.jpg 文件 看起来如下,不过我认为它在游戏中的应用方式并不完全正确:

随后,它构建了游戏的第一个基础版本,接着
使用 Playwright 在“预装的 Chromium 中进行冒烟测试”。这意味着它可以为自己的成果截图,并
。它对页面的桌面端和移动端宽度都这样做了,然后注意到
,因此它
:
浣熊、垃圾箱藏身处和两只队友浣熊现在都能在移动端完美显示。正在提交这个关键修复。
它决定生成一个标题画面,并使用这个 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 认为它“美极了”)——不过我注意到,在桌面端显示时,它被裁剪得只剩顶部三分之一,浣熊都不见了!

接着是我最喜欢的一项改动:它添加了狗:
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' });

它又作了一些调整,随后宣布自己完成了工作:
《浣熊大劫案》已构建、测试并推送完成——在
claude/3d-raccoon-heist-game-50n293上共完成 7 次提交,全部通过桌面端、竖屏手机和横屏手机视口上的自动化 Playwright 通关测试验证。**游戏内容:**你是一只戴着面罩的浣熊,从团队的垃圾箱藏身处偷偷溜进月光下的死胡同。收集金币、宝石、r
English / 原文
One-shotting a Raccoon Heist game using Claude Fable 5
5th August 2026
Back in 2024 I tweeted screenshots of a game concept generated by GPT-3 and some concept “art” created using DALL-E. Today, on the fourth anniversary of that tweet, I decided to see if Claude Fable 5 (running in Claude Code for web) could build the entire game from the content of that tweet. It did a pretty good job of it!
You can play the game here. Here’s the GitHub repo, and a short video demo:
Your browser does not support HTML5 video.
How I built this
This is the August 5th, 2022 tweet:

My GPT-3 prompt back then was:
Write a detailed product description of a computer game where a team of raccoons go on heists.
This was in the text completion days, where you asked GPT-3 to complete the rest of the text. It completed:
In “Raccoon Heist”, you and your team of thieving raccoons are tasked with pulling off a series of daring heists. From robbing banks to stealing priceless art, no job is too big or too small for your furry crew. You’ll need to use your wits and your skills to avoid the police and make a clean getaway with the loot. With exciting gameplay and a charming cast of characters, “Raccoon Heist” is the perfect game for anyone looking for a light-hearted caper.
My prompt to DALL-E was short:
Screenshot from a video game where a team of raccoons go on a heist
Today’s experiment: can I dump those screenshots into Fable 5 with a prompt telling it to write a game, then leave it to its own devices and get a working game at the end?
Setting Claude Code for web up to use GitHub Pages
A frustrating thing about Claude Code for web is that it can be hard to test what it’s working on while it’s still working.
I’ve been using GitHub Pages to work around that limitation, and found it to work really well.
Here’s my process:
- Create a new repository for the project at https://github.com/new—this can be public or private, the trick works equally well for both.
- Start a Claude Code for web session, in the Claude iPhone or Desktop apps or in the browser at https://claude.ai/code
- Tell Claude what to work on, and encourage it to commit an
index.htmlpage as quickly as possible. This will create a branch with a name likeclaude/3d-raccoon-heist-game-50n293 - Navigate to the Settings -> Pages area for the repository (
github.com/simonw/raccoon-heist/settings/pagesin my case), select “Deploy from a branch”, pick the branch name, and hit Save.
That’s all it takes! Within about 30 seconds of each push the latest content will be visible at yourname.github.io/your-repo/.
If you do this with a private repo, anyone who can guess the name of the repo will be able to view the published content. I don’t worry much about this myself.
The Fable 5 prompt
Here’s the prompt I gave Fable 5 (written in the notes app on my phone—this entire project was conducted on mobile). I accompanied it with the two images from the original tweet.
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.
I didn’t make any technology choices. I assumed (correctly) that it would probably use Three.js based on previous experiments.
Giving Claude access to an OpenAI key turns out to work really well for filling in gaps in its capabilities—in this case we needed some way to generate images to use as textures. Fable is very good at prompting image generators!
I said “Work independently—do not ask me to make any further design decisions” because I wanted to see if it could produce a full, working game without any further input from me.
I also said “Commit and push as often as possible so I can preview your work”. When you use Claude Code in the Claude iPhone app you give it a GitHub repository and it works in a branch. Telling it to “push as often as possible” means commits start landing in that branch straight away.
I like asking for notes.md as a bit of added flavor—here’s that finished file, and the entry it made when it added the dog:
New escalation: from night 3 the yards get a patrolling guard dog — a low-poly brown hound with a spiked red collar and a wagging tail. It wanders between random spots, and within 12 units it catches your scent and tracks you by smell (line of sight is irrelevant — it’s all nose, shown by a 👃 over its head and barking). It gives up if you open a 17-unit gap. Getting caught messages are now source-specific: guard / headlights / hound. Verified wander → track → caught with an automated test.
Reviewing the transcript
You can access the Claude Code shared session, and I also used my claude-code-transcripts tool to export my own HTML version which you can find here.
Fable started with an index page, vendored a copy of Three.js, then wrote its own gen_textures.py script (copy here).
It generated the textures and spot-checked them to make sure they looked OK. The metal.jpg file it generated for the trash can looks like this, though I don’t think it was applied exactly right in the game itself:

Then it built out the first basic version of the game, then
“smoke-test in the pre-installed Chromium” using Playwright. This meant it could take screenshots of its own work and
. It did that for both desktop and mobile widths of the page, then noticed that
at mobile widths, so it
:
The raccoon, dumpster hideout, and both crew raccoons are now perfectly visible on mobile. Committing this critical fix.
It decided to generate a title screen, which it did using this gen_title.py script. Here’s the gpt-image-2 prompt it used for that:
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.
And the resulting image (which Claude thought was “gorgeous”)—though I note that when it’s shown on desktop it gets cropped to just the top third without the raccoon!

Then my favorite change: it added the dog:
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);
},
};
}
And did a round of testing on it using Playwright, including another screenshot.
// 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' });

It made a few more tweaks, then declared itself done:
Raccoon Heist is built, tested, and pushed — 7 commits on
claude/3d-raccoon-heist-game-50n293, all verified with automated Playwright playthroughs on desktop, portrait-phone, and landscape-phone viewports.The game: You’re a masked raccoon sneaking out of your crew’s dumpster hideout into a moonlit cul-de-sac. Grab coins, gems, rings, donuts, and fish (they visibly stack on your back and slow you down), then waddle home and bank them before dawn. Each night raises the goal and the heat: night 1 has one flashlight-sweeping guard, night 2 has two, night 3 adds a scent-tracking hound that ignores line-of-sight entirely. A police cruiser sweeps the street with headlights, homeowners randomly peek out of windows, a seagull periodically dive-bombs your unclaimed loot, pizza slices trigger a 6-second speed FRENZY, and a rare golden TV is worth 120 points if you can haul its weight home. Win ranks: TRASH PANDA ⭐ → CAT BURGLAR ⭐⭐ → MASTER OF DISGUISE ⭐⭐⭐, with your best run saved to localStorage.
How it’s built: Vendored Three.js (no CDN), procedural low-poly characters, and a procedural WebAudio soundtrack (sneaky walking-bass jazz plus all sound effects — zero audio files). All seven ground/wall textures and the title-screen hero art were generated with gpt-image-2 and committed as static assets, so the deployed game makes no API calls. Mobile gets a dynamic touch joystick (appears wherever you touch) plus a DASH button; desktop uses WASD/arrows and Space.
Testing caught two real bugs worth mentioning: the canvas rendered at 2× size on any real phone (a
cssTextassignment was wiping Three.js’s inline sizing — desktop DPR-1 tests masked it completely), and the win screen’s star-rating div inherited the title screen’s full-screen.starsCSS and silently swallowed every tap on the “next night” button. Both are fixed and regression-tested, along with pickup, banking, chase/caught, dawn, night progression, and lose/retry flows.
notes.mdhas the full build log. The game is live on the branch — just serve the repo root and openindex.html.
Is the game any good?
It’s an impressive starting point, but it’s not a good game.
You move your raccoon around a yard collecting items—donuts, fish, gold coins, jewels—while avoiding guards with flashlights and, in later levels, a dog. You have a limited carrying capacity, and once that’s full you need to drop stuff off at the dumpster. If you pick up a pizza slice you get a temporary speed boost.
There are no team mechanics at all—there are two other static raccoons next to the dumpster but they’re purely decoration.
It gets slightly more challenging as the levels progress—the dog introduced in level 3 is the most interesting new mechanic—but it’s very, very easy to beat. It’s also pretty boring—each night has a fixed duration and you can collect all of the items and then have nothing else to do while waiting for the dawn.
I was impressed by the implementation. It’s fully 3D, there are trash cans, the flashlight illumination cones are fun, and it has a reasonably coherent visual style. It works on mobile. The music (“a procedural WebAudio soundtrack (sneaky walking-bass jazz plus all sound effects — zero audio files)” according to Claude) is simple but feels about right.
As a finished game project, it’s mediocre. As a starting point from a single prompt I think it’s very impressive.
I’ve vibe coded up quite a few games now. They’ve all been deeply disappointing from a gameplay perspective—it turns out designing games that are fun remains a uniquely human trait, and one which requires significantly more skill and experience than either Claude or I can bring to bear.
That said, I thoroughly recommend tinkering with game development projects as a way to explore the capabilities of agents. It’s a fun, low-risk way to try out new things. If you stick at it long enough you might even produce something that’s worth playing!