2024년, GPT-3로 생성한 게임 컨셉과 DALL-E로 만든 컨셉 아트 스크린샷을 트위터에 올린 적이 있었습니다. 그로부터 꼭 4년이 지난 지금, 그 트윗 하나만 가지고 Claude Sonnet 4(Claude Code 웹 버전)가 게임 전체를 만들어낼 수 있는지 직접 시험해봤습니다. 결과는 꽤 인상적이었습니다.
2024년, 트위터에 올렸던 GPT-3로 생성한 게임 컨셉과 DALL-E로 만든 컨셉 아트 스크린샷이 있었습니다. 그로부터 꼭 4년이 지난 지금, 그 트윗 하나만 가지고 Claude Sonnet 4(Claude Code 웹 버전)가 게임 전체를 만들어낼 수 있는지 직접 시험해봤습니다. 결과는 꽤 인상적이었습니다!
여기서 게임을 직접 플레이해볼 수 있습니다. GitHub 저장소와 짧은 데모 영상도 확인해보세요:
기반이 된 것은 2022년 8월 5일에 올린 트윗입니다:

당시 GPT-3에 입력했던 프롬프트는 다음과 같습니다:
Write a detailed product description of a computer game where a team of raccoons go on heists.
당시는 텍스트 완성(text completion) 방식의 시대였습니다. GPT-3에게 이어지는 텍스트를 완성해달라고 요청하는 방식이었죠. GPT-3가 완성한 내용은 다음과 같습니다:
"너구리 강도단(Raccoon Heist)"에서 당신은 동료 너구리들과 함께 연속적인 대담한 강도 작전을 수행해야 합니다. 은행 털기부터 귀한 예술품 절취까지, 당신의 털복숭이 팀에게 너무 크거나 작은 임무란 없습니다. 경찰을 따돌리고 전리품을 깔끔하게 챙겨 달아나려면 재치와 기술을 총동원해야 합니다. 흥미진진한 게임플레이와 매력적인 캐릭터들로 가득한 "너구리 강도단"은 유쾌한 도둑 이야기를 즐기고 싶은 모든 분께 딱 맞는 게임입니다.
DALL-E에 입력한 프롬프트는 짧았습니다:
Screenshot from a video game where a team of raccoons go on a heist
오늘의 실험: 원본 트윗의 스크린샷을 Sonnet 4에 넘기고 게임을 만들어달라는 프롬프트 하나만 준 뒤, 이후 과정은 모두 맡겨두면 완성된 게임이 나올까?
Claude Code 웹 버전의 아쉬운 점 중 하나는, 작업이 진행되는 동안 그 결과물을 바로 확인하기가 쉽지 않다는 것입니다.
저는 GitHub Pages를 활용해 이 문제를 해결하고 있는데, 실제로 꽤 잘 작동합니다.
제가 사용하는 방법은 다음과 같습니다:
index.html 페이지를 커밋하도록 안내합니다. 이렇게 하면 claude/3d-raccoon-heist-game-50n293와 같은 이름의 브랜치가 생성됩니다.
github.com/simonw/raccoon-heist/settings/pages)으로 이동해 "Deploy from a branch"를 선택하고, 해당 브랜치 이름을 지정한 뒤 저장합니다.이게 전부입니다! 이후로는 푸시가 이루어지고 약 30초 후면 최신 내용을 yourname.github.io/your-repo/에서 바로 확인할 수 있습니다.
비공개 저장소를 사용하더라도, 저장소 이름을 알아낼 수 있는 사람이라면 누구나 게시된 내용을 볼 수 있습니다. 저는 이 부분을 크게 신경 쓰지 않습니다.
Sonnet 4에 입력한 프롬프트는 다음과 같습니다(휴대폰 메모 앱으로 작성했으며, 이 프로젝트 전체가 모바일에서 진행됐습니다). 원본 트윗의 이미지 두 장도 함께 첨부했습니다.
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 키를 제공하면 부족한 기능을 채우는 데 매우 효과적입니다. 이번에는 텍스처로 사용할 이미지를 생성해야 했는데, Sonnet 4는 이미지 생성 도구에 넘길 프롬프트를 작성하는 데 특히 능숙했습니다!
"독립적으로 작업하고, 추가적인 디자인 결정은 내게 묻지 말라"고 명시한 것은, 아무런 개입 없이 완성된 게임을 만들어낼 수 있는지 확인하고 싶었기 때문입니다.
"가능한 한 자주 커밋하고 푸시해서 진행 상황을 미리 확인할 수 있게 해달라"는 요청도 추가했습니다. Claude iPhone 앱에서 Claude Code를 사용할 때는 GitHub 저장소를 연결하면 브랜치에서 작업이 이루어지는데, "가능한 한 자주 푸시해달라"고 하면 커밋이 바로바로 해당 브랜치에 반영됩니다.
notes.md 파일을 요청하는 것도 즐겨 쓰는 방식입니다. 작업 일지 같은 느낌이 나서 좋거든요. 완성된 파일도 확인해볼 수 있고, 강아지를 추가했을 때 남긴 기록은 다음과 같습니다:
새로운 긴장 요소 추가: 3번째 밤부터 마당에 순찰 경비견이 등장합니다. 빨간 가시 목걸이를 한 갈색의 로우폴리(low-poly) 사냥개로, 무작위 지점 사이를 배회합니다. 12유닛 이내로 접근하면 냄새로 플레이어를 추적하며, 시야와 무관하게 완전히 후각에만 의존합니다(머리 위에 👃 아이콘과 짖는 소리로 표시). 17유닛 이상 거리를 벌리면 추적을 포기합니다. 잡혔을 때의 메시지가 이제 경비원 / 헤드라이트 / 경비견으로 각각 구분되어 표시됩니다. 자동화 테스트로 배회 → 추적 → 포획 흐름을 검증 완료.
Claude Code 공유 세션에서 전체 기록을 확인할 수 있으며, claude-code-transcripts 도구로 직접 내보낸 HTML 버전도 여기서 확인할 수 있습니다.
Sonnet 4는 index 페이지 작성을 시작으로, Three.js를 벤더링(vendoring)한 뒤 자체적으로 gen_textures.py 스크립트를 작성했습니다(사본 확인).
텍스처를 생성한 후에는 결과물을 직접 확인하며 제대로 만들어졌는지 점검했습니다. 쓰레기통을 위해 생성한 metal.jpg 파일은 아래와 같이 나왔는데, 게임 내에서 정확히 적용되지는 않은 것 같습니다:

너구리, 쓰레기통 은신처, 그리고 동료 너구리 두 마리가 이제 모바일에서도 정상적으로 표시됩니다. 이 중요한 수정 사항을 커밋합니다.
타이틀 화면도 자체적으로 생성하기로 결정했으며, 실제로 만들어냈습니다. 사용한 스크립트는 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' });
몇 가지 추가 수정을 마친 후, 작업 완료를 선언했습니다:
너구리 강도단 빌드, 테스트, 푸시 완료 —
claude/3d-raccoon-heist-game-50n293에 총 7개의 커밋이 이루어졌으며, 데스크톱 / 세로 방향 폰 / 가로 방향 폰 뷰포트에서 Playwright 자동화 플레이스루로 전부 검증했습니다.게임 소개: 복면을 쓴 너구리가 동료들의 쓰레기통 은신처를 빠져나와 달빛 아래 막다른 골목 주택가로 숨어드는 내용입니다. 동전, 보석, 반지, 도넛, 생선 등을 수거하고(아이템은 등에 쌓이며 이동 속도가 느려집니다), 새벽이 오기 전에 쓰레기통으로 돌아와 전리품을 보관해야 합니다. 밤이 진행될수록 목표치와 난이도가 올라갑니다. 1밤에는 손전등을 든 경비원 한 명, 2밤에는 두 명, 3밤부터는 시야와 무관하게 냄새로 추적하는 경비견이 추가됩니다. 경찰 순찰차가 헤드라이트로 거리를 훑고, 집주인이 무작위로 창문을 들여다보며, 갈매기가 주기적으로 수거되지 않은 아이템을 낚아채기도 합니다. 피자 조각을 먹으면 6초간 속도 광란(FRENZY) 모드가 발동하고, 희귀한 황금 TV는 무게를 감당하고 집까지 운반하면 120점을 획득할 수 있습니다. 클리어 등급은 TRASH PANDA ⭐ → CAT BURGLAR ⭐⭐ → MASTER OF DISGUISE ⭐⭐⭐이며, 최고 기록은 localStorage에 저장됩니다.
기술 구현: CDN 없이 Three.js를 직접 벤더링했으며, 절차적 방식으로 생성한 로우폴리 캐릭터와 WebAudio 기반 절차적 사운드트랙(몰래 걷는 느낌의 워킹베이스 재즈 및 모든 효과음 포함 — 오디오 파일 없음)을 사용했습니다. 7종의 바닥/벽 텍스처와 타이틀 화면 메인 이미지는 gpt-image-2로 생성해 정적 에셋으로 커밋했으며, 배포된 게임은 API 호출을 일체 하지 않습니다. 모바일에서는 터치 위치에 동적으로 생성되는 가상 조이스틱과 DASH 버튼이 제공되며, 데스크톱에서는 WASD/방향키와 Space 키를 사용합니다.
테스트 과정에서 주목할 만한 버그 두 가지가 발견됐습니다: 실제 폰에서 캔버스가 2배 크기로 렌더링되는 문제(
cssText할당이 Three.js의 인라인 사이징을 덮어쓰고 있었으며, DPR이 1인 데스크톱 테스트에서는 전혀 드러나지 않았습니다)와, 승리 화면의 별점 표시 div가 타이틀 화면의 전체 화면.starsCSS를 상속받아 "다음 밤" 버튼의 탭 입력을 조용히 무시하는 문제였습니다. 두 버그 모두 수정 및 회귀 테스트 완료했으며, 아이템 수거, 전리품 보관, 추격/포획, 새벽, 밤 진행, 패배/재시도 흐름도 함께 검증했습니다.
notes.md에 전체 빌드 로그가 있습니다. 게임은 해당 브랜치에 배포되어 있으며, 저장소 루트를 서빙한 후index.html을 열면 바로 실행됩니다.
인상적인 출발점인 것은 맞지만, 재미있는 게임이라고 하기는 어렵습니다.
너구리를 조종해 마당을 돌아다니며 도넛, 생선, 금화, 보석 등을 수집하고, 손전등을 든 경비원을 피해야 합니다. 후반 레벨에서는 경비견도 등장합니다. 소지할 수 있는 아이템 수에 제한이 있어 가득 차면 쓰레기통에 맡겨야 하며, 피자를 먹으면 일시적으로 이동 속도가 빨라집니다.
팀 플레이 요소는 전혀 없습니다. 쓰레기통 옆에 너구리 두 마리가 서 있긴 하지만, 순전히 장식에 불과합니다.
레벨이 올라갈수록 조금씩 어려워지긴 합니다. 3레벨에서 등장하는 경비견은 그나마 흥미로운 새 요소입니다. 하지만 전반적으로 너무 쉬운 편이고, 솔직히 지루합니다. 각 밤의 지속 시간이 고정되어 있어서 아이템을 모두 수집한 후에는 새벽이 오기만을 기다려야 하는 공백이 생깁니다.
구현 자체는 인상적이었습니다. 완전한 3D로 제작됐고, 쓰레기통도 있으며, 손전등 조명 콘이 꽤 그럴듯합니다. 전반적으로 시각적 통일성도 잡혀 있고 모바일에서도 잘 동작합니다. Claude의 표현을 빌리자면 "절차적 WebAudio 사운드트랙(몰래 걷는 느낌의 워킹베이스 재즈 및 모든 효과음 — 오디오 파일 없음)"인 음악도 단순하지만 분위기와 잘 어울립니다.
완성된 게임으로서는 평범한 수준이지만, 프롬프트 하나에서 나온 출발점으로서는 충분히 인상적입니다.
바이브 코딩(vibe coding)으로 게임을 꽤 많이 만들어봤는데, 게임플레이 측면에서는 매번 실망스러웠습니다. 재미있는 게임을 설계하는 일은 여전히 인간 고유의 영역인 것 같고, Claude도 저도 거기에 필요한 수준의 기술과 경험에는 아직 미치지 못합니다.
그렇더라도 게임 개발 프로젝트는 에이전트의 가능성을 탐색하는 데 아주 좋은 방법입니다. 부담 없이 새로운 것을 시도해볼 수 있는 즐거운 방식이거든요. 꾸준히 파고들다 보면 언젠가 진짜 플레이할 만한 게임이 나올지도 모릅니다!
이 블로그의 긴 형식 아티클만 보고 계신 분들께 안내드립니다. /atom/everything/을 구독하시면 모든 게시물을 받아볼 수 있으며, 다른 구독 옵션도 확인해보세요.