<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Three.js on To the Moon</title><link>https://junstellar.github.io/tags/three.js/</link><description>Recent content in Three.js on To the Moon</description><generator>Hugo -- gohugo.io</generator><language>ko-kr</language><lastBuildDate>Wed, 19 Aug 2026 20:00:00 +0900</lastBuildDate><atom:link href="https://junstellar.github.io/tags/three.js/index.xml" rel="self" type="application/rss+xml"/><item><title>AI로 게임 만들기 #9 — 〈오디세이〉 보기 전 30분, 보고 나서 30분. 버튼 하나로 겪는 오디세우스 (공개빌드 #9)</title><link>https://junstellar.github.io/p/ai-game-lab-build-9/</link><pubDate>Wed, 19 Aug 2026 20:00:00 +0900</pubDate><guid>https://junstellar.github.io/p/ai-game-lab-build-9/</guid><description>&lt;img src="https://junstellar.github.io/p/ai-game-lab-build-9/hero.webp" alt="Featured image of post AI로 게임 만들기 #9 — 〈오디세이〉 보기 전 30분, 보고 나서 30분. 버튼 하나로 겪는 오디세우스 (공개빌드 #9)" /&gt;&lt;p&gt;&lt;a class="link" href="https://junstellar.github.io/p/ai-game-lab-build-8/" &gt;지난 편&lt;/a&gt;의 심해 낚시에 이어, 아홉 번째 게임은 &lt;strong&gt;오디세이아&lt;/strong&gt;입니다. 트로이에서 이타카까지 20년, 그 여정의 여섯 장면을 &lt;strong&gt;버튼 하나로&lt;/strong&gt; 직접 겪는 게임이에요. ⛵&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;영화 보러 가기 전에 하면 예습이고, 보고 나서 하면 복습입니다.&lt;/strong&gt; 저는 보고 나서 만들었으니 후자로 시작한 셈이네요.&lt;/p&gt;
&lt;p&gt;👉 &lt;strong&gt;&lt;a class="link" href="https://junstellar.github.io/games/odyssey/" &gt;오디세이아 직접 하러 가기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="3시간이-하나도-안-지루했습니다"&gt;3시간이 하나도 안 지루했습니다
&lt;/h2&gt;&lt;p&gt;놀란의 〈오디세이〉를 봤습니다. &lt;strong&gt;너무 재밌었습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;일단 &lt;strong&gt;배역이 너무 잘 맞았어요.&lt;/strong&gt; 매트 데이먼의 오디세우스도 그렇고, 페넬로페로 나온 &lt;strong&gt;앤 해서웨이&lt;/strong&gt;가 정말 예쁘게 나왔습니다. 20년을 기다리는 사람의 얼굴이 그래야 할 것 같은 얼굴이었어요.&lt;/p&gt;
&lt;p&gt;한 가지 걸린 건, 하필 그 전 주에 스파이더맨을 봤다는 겁니다. 텔레마코스로 &lt;strong&gt;톰 홀랜드&lt;/strong&gt;가 나오고 아테나로 &lt;strong&gt;젠데이아&lt;/strong&gt;가 나오는데, 머리로는 아는데 자꾸 피터랑 MJ가 겹쳐서 그 대목만 몰입이 좀 깨졌습니다. 😅 (젠데이아의 아테나는 실제로 신인지 오디세우스의 죄책감이 만든 환영인지 열어두고 찍었다더군요. 그건 좋았습니다.)&lt;/p&gt;
&lt;p&gt;그래도 &lt;strong&gt;오디세우스의 서사가 장황할 만큼 멋지게 펼쳐져서&lt;/strong&gt; 3시간이 전혀 지루하지 않았습니다. 극장을 나오는데 오히려 여운이 남았어요.&lt;/p&gt;
&lt;h2 id="그런데-같이-본-사람은-온도가-달랐습니다"&gt;그런데 같이 본 사람은 온도가 달랐습니다
&lt;/h2&gt;&lt;p&gt;나오면서 이야기하다가 알았습니다. &lt;strong&gt;저는 원작 줄거리를 알고 갔고, 같이 본 사람은 몰랐습니다.&lt;/strong&gt; 같은 장면을 보고도 남는 게 달랐어요.&lt;/p&gt;
&lt;p&gt;세이렌 앞에서 왜 자기만 묶여 있는지, 눈앞의 소를 왜 안 잡아먹는지, 마지막에 활을 당기는 게 왜 그렇게 중요한 장면인지 — 알고 보면 &amp;ldquo;아, 저게 그거구나&amp;quot;인데 모르고 보면 그냥 지나갑니다.&lt;/p&gt;
&lt;p&gt;원작을 읽고 가라고 하기엔 부담스럽고, 줄거리 요약을 읽으라고 하기엔 &lt;strong&gt;읽어도 안 남습니다.&lt;/strong&gt; 남의 이야기를 요약해서 읽으면 30분 뒤에 잊어버려요.&lt;/p&gt;
&lt;p&gt;그래서 &lt;strong&gt;직접 겪게 만들면 남지 않을까&lt;/strong&gt; 싶었습니다.&lt;/p&gt;
&lt;h2 id="30분짜리-버튼-하나"&gt;30분짜리, 버튼 하나
&lt;/h2&gt;&lt;p&gt;만든 규칙은 단순합니다.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;스테이지&lt;/td&gt;
					&lt;td&gt;6편&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;조작&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;스페이스 · 클릭 · 탭&lt;/strong&gt; — 셋 다 같은 동작&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;한 편&lt;/td&gt;
					&lt;td&gt;5분 이내&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;전체&lt;/td&gt;
					&lt;td&gt;30분 이내&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;PC·모바일&lt;/td&gt;
					&lt;td&gt;동일&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;버튼을 하나로 묶은 건 제약이 아니라 &lt;strong&gt;선택&lt;/strong&gt;이었습니다. 조작을 배우는 데 시간을 쓰면 이야기가 들어올 자리가 없어집니다. 누를 줄 아는 사람이면 6편을 다 갈 수 있어야 했어요.&lt;/p&gt;
&lt;p&gt;대신 &lt;strong&gt;편마다 그 버튼의 의미를 바꿨습니다.&lt;/strong&gt; 같은 버튼인데 손맛이 다릅니다.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;편&lt;/th&gt;
					&lt;th&gt;장면&lt;/th&gt;
					&lt;th&gt;버튼의 의미&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;키클롭스의 동굴&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;순간에 탭&lt;/strong&gt; — 거인의 손이 비켜난 찰나&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;아이올로스의 바람 자루&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;누르고 있다 놓기&lt;/strong&gt; — 참을수록 빨리 간다&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;세이렌의 노래&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;버티기&lt;/strong&gt; — 놓으면 진다 (2편의 정반대)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;스킬라와 카리브디스&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;틈에 연타&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;헬리오스의 소&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;배분 탭&lt;/strong&gt; — 누구를 먹일 것인가&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;6&lt;/td&gt;
					&lt;td&gt;이타카의 활&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;당겼다 정확히 놓기&lt;/strong&gt; — 단 한 발&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;3편이 특히 마음에 듭니다. 2편은 &lt;strong&gt;누르면 나아가고 놓으면 안전&lt;/strong&gt;한데, 3편은 &lt;strong&gt;누르면 안전하고 놓으면 집니다.&lt;/strong&gt; 같은 버튼의 의미가 뒤집혀요.&lt;/p&gt;
&lt;p&gt;&lt;img alt="세이렌 — 돛대에 묶인 오디세우스, 귀를 막은 부하들, 위쪽에 밀려올 노래가 미리 보인다" class="gallery-image" data-flex-basis="321px" data-flex-grow="134" height="820" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://junstellar.github.io/p/ai-game-lab-build-9/sirens.webp" srcset="https://junstellar.github.io/p/ai-game-lab-build-9/sirens_hu_aaedcaea0245d616.webp 800w, https://junstellar.github.io/p/ai-game-lab-build-9/sirens.webp 1100w" width="1100"&gt;&lt;/p&gt;
&lt;h2 id="여섯-장면이-곧-줄거리다"&gt;여섯 장면이 곧 줄거리다
&lt;/h2&gt;&lt;p&gt;이 게임의 목적은 재미보다 &lt;strong&gt;&amp;ldquo;이 여섯 개만 알면 된다&amp;rdquo;&lt;/strong&gt; 입니다. 보기 전이면 이걸 알고 극장에 들어가는 거고, 보고 난 뒤면 &amp;ldquo;아 그게 이거였구나&amp;quot;를 손으로 다시 확인하는 거예요. 그래서 편마다 신화가 실제로 말하는 것을 그대로 규칙으로 만들었습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1편 · 키클롭스&lt;/strong&gt; — 눈먼 거인이 동굴 입구를 손으로 훑습니다. 양 배에 매달려 나가야 해요. 거인이 눈이 멀었다는 걸 &lt;strong&gt;설명하지 않습니다.&lt;/strong&gt; 감긴 외눈과 더듬는 손으로 보여줍니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2편 · 바람 자루&lt;/strong&gt; — 이타카가 눈앞에 보이는 열흘째 새벽에 잠듭니다. &lt;strong&gt;이건 실패가 아니라 이야기입니다.&lt;/strong&gt; 피할 수 없어요. 부하들이 자루를 열고 배가 왔던 길을 되밀려 갑니다. 진행 게이지가 95%에서 20%대로 빨려 내려가는 걸 보고 있어야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3편 · 세이렌&lt;/strong&gt; — 세이렌은 미녀의 유혹이 아니라 &lt;em&gt;&amp;ldquo;네가 모르는 것을 알려주마&amp;rdquo;&lt;/em&gt; 라고 부릅니다. &lt;strong&gt;지식에 대한 갈망&lt;/strong&gt;이 이 장면의 진짜 유혹이에요.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4편 · 스킬라&lt;/strong&gt; — 키르케의 조언은 냉정합니다. &lt;em&gt;&amp;ldquo;여섯을 잃더라도 스킬라 쪽에 붙어라. 카리브디스는 배째로 삼킨다.&amp;rdquo;&lt;/em&gt; 그리고 오디세우스는 이 사실을 &lt;strong&gt;부하들에게 말하지 않았습니다.&lt;/strong&gt; 말했다면 아무도 노를 젓지 않았을 테니까요.&lt;/p&gt;
&lt;p&gt;&lt;img alt="스킬라 — 여섯 머리가 내려온다. 아래쪽은 카리브디스" class="gallery-image" data-flex-basis="321px" data-flex-grow="134" height="820" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://junstellar.github.io/p/ai-game-lab-build-9/scylla.webp" srcset="https://junstellar.github.io/p/ai-game-lab-build-9/scylla_hu_4a50cda8679725e8.webp 800w, https://junstellar.github.io/p/ai-game-lab-build-9/scylla.webp 1100w" width="1100"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5편 · 헬리오스의 소&lt;/strong&gt; — 굶주림을 못 막으면 부하들이 소를 잡아먹고 제우스의 벼락에 전멸합니다. &lt;strong&gt;이게 오디세우스가 혼자 돌아온 이유입니다.&lt;/strong&gt; 신화대로 지는 게 기본 결말이고, 아주 좁은 길로 살려내면 &lt;em&gt;&amp;ldquo;호메로스에서는 일어나지 않은 일입니다&amp;rdquo;&lt;/em&gt; 라는 카드가 뜹니다.&lt;/p&gt;
&lt;p&gt;&lt;img alt="헬리오스의 소 — 언덕 위의 황금 소, 여섯 개의 굶주림 막대" class="gallery-image" data-flex-basis="321px" data-flex-grow="134" height="820" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://junstellar.github.io/p/ai-game-lab-build-9/cattle.webp" srcset="https://junstellar.github.io/p/ai-game-lab-build-9/cattle_hu_5eb9e46f5631bcc1.webp 800w, https://junstellar.github.io/p/ai-game-lab-build-9/cattle.webp 1100w" width="1100"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6편 · 이타카의 활&lt;/strong&gt; — 20년 만에 거지꼴로 돌아옵니다. 페넬로페의 조건은 &lt;em&gt;&amp;ldquo;오디세우스의 활에 시위를 얹고 도끼 열두 자루를 화살 하나로 꿰뚫는 자&amp;rdquo;&lt;/em&gt;. 그 활은 오디세우스만 당길 수 있습니다. &lt;strong&gt;활을 당기는 순간이 곧 정체를 밝히는 순간입니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="이타카의 활 — 도끼 열두 자루가 원근으로 뚫려 있다" class="gallery-image" data-flex-basis="321px" data-flex-grow="134" height="820" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://junstellar.github.io/p/ai-game-lab-build-9/bow.webp" srcset="https://junstellar.github.io/p/ai-game-lab-build-9/bow_hu_f7b56a6e54e4c81d.webp 800w, https://junstellar.github.io/p/ai-game-lab-build-9/bow.webp 1100w" width="1100"&gt;&lt;/p&gt;
&lt;h2 id="부하-600명이-여섯-편을-관통합니다"&gt;부하 600명이 여섯 편을 관통합니다
&lt;/h2&gt;&lt;p&gt;이게 이 게임의 뼈대입니다. &lt;strong&gt;600명으로 출항해서, 각 편에서 잃은 만큼 줄어든 채로 다음 편에 갑니다.&lt;/strong&gt; 결과 카드마다 마지막 줄에 남은 인원이 적혀요.&lt;/p&gt;
&lt;p&gt;그리고 끝까지 가면 이렇게 끝납니다.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;호메로스의 오디세우스는 &lt;strong&gt;혼자&lt;/strong&gt; 돌아왔습니다.
당신은 &lt;strong&gt;N명&lt;/strong&gt;을 데려왔습니다.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="에필로그 — 여섯 줄로 정리되는 당신의 항해" class="gallery-image" data-flex-basis="321px" data-flex-grow="134" height="820" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://junstellar.github.io/p/ai-game-lab-build-9/epilogue.webp" srcset="https://junstellar.github.io/p/ai-game-lab-build-9/epilogue_hu_21b89ef591488588.webp 800w, https://junstellar.github.io/p/ai-game-lab-build-9/epilogue.webp 1100w" width="1100"&gt;&lt;/p&gt;
&lt;p&gt;에필로그의 여섯 줄은 &lt;strong&gt;당신이 실제로 겪은 것&lt;/strong&gt;을 적습니다. 남의 이야기를 요약하면 에필로그가 아니니까요.&lt;/p&gt;
&lt;h2 id="만들면서--게임이-플레이어에게-거짓말을-하고-있었다"&gt;만들면서 — 게임이 플레이어에게 거짓말을 하고 있었다
&lt;/h2&gt;&lt;p&gt;여기부터가 이번 편에서 제일 많이 배운 부분입니다.&lt;/p&gt;
&lt;p&gt;세 번이나, &lt;strong&gt;화면이 시키는 대로 하면 지는 게임&lt;/strong&gt;을 만들고 있었습니다. 그것도 매번 다른 형태로요.&lt;/p&gt;
&lt;h3 id="첫-번째--버텨라"&gt;첫 번째 — &amp;ldquo;버텨라&amp;rdquo;
&lt;/h3&gt;&lt;p&gt;2편 마지막, 졸음이 몰려오는 구간에서 화면에 &lt;strong&gt;&amp;ldquo;버텨라 / 누르고 있어라&amp;rdquo;&lt;/strong&gt; 가 떴습니다. 그런데 정책별로 돌려서 재보니:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;시킨 대로&lt;/th&gt;
					&lt;th&gt;도달&lt;/th&gt;
					&lt;th&gt;잃은 부하&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;버틴다&lt;/td&gt;
					&lt;td&gt;5.8%&lt;/td&gt;
					&lt;td&gt;36명&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;그냥 손 뗀다&lt;/td&gt;
					&lt;td&gt;8.9%&lt;/td&gt;
					&lt;td&gt;30명&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;시킨 대로 한 쪽이 두 지표 모두 나빴습니다.&lt;/strong&gt; 버티는 동안에도 돛 부하가 살아 있어서, 순순히 따르면 돛이 찢어졌던 거예요.&lt;/p&gt;
&lt;h3 id="두-번째--연타해-젓는다"&gt;두 번째 — &amp;ldquo;연타해 젓는다&amp;rdquo;
&lt;/h3&gt;&lt;p&gt;4편 화면 아래에 &lt;strong&gt;&amp;ldquo;스페이스 또는 화면을 연타해 젓는다&amp;rdquo;&lt;/strong&gt; 라고 적혀 있었습니다. 저는 그 말을 그대로 믿고 연타했고, 계속 죽었습니다. 노는 열심히 젓는데 한쪽 노잡이가 죄다 잡혀가더군요.&lt;/p&gt;
&lt;p&gt;원인을 찾으려고 &lt;strong&gt;연타만 하는 봇&lt;/strong&gt;을 만들어 붙였습니다. 연타만 하면 &lt;strong&gt;9.5초 만에 노잡이 8명이 전부 끌려가고&lt;/strong&gt;, 그 뒤 7초 동안 아무것도 못 한 채 소용돌이에 삼켜졌습니다. 그리고 결과 카드가 이렇게 말했어요.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;&amp;ldquo;노를 멈춘 대가다 — 쉬면 끌려간다&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;한 번도 안 쉰 사람한테요. &lt;strong&gt;안내도 틀렸고 꾸중도 틀렸습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;고친 건 세 가지입니다. 안내를 규칙의 나머지 절반까지 적고(&lt;em&gt;&amp;ldquo;머리가 물러난 사이에만 연타 · 내려오면 멈춘다&amp;rdquo;&lt;/em&gt;), 신호를 &lt;strong&gt;&amp;ldquo;저어라 → 멈춰라&amp;rdquo;&lt;/strong&gt; 두 박자로 가르치고, 시작 직후 1.15초 동안 머리를 멈춰 둬서 첫 수업을 읽을 시간을 줬습니다.&lt;/p&gt;
&lt;p&gt;&lt;img alt="스킬라 — 멈춰라가 뜨는 순간. 아래 안내가 규칙의 나머지 절반을 말한다" class="gallery-image" data-flex-basis="321px" data-flex-grow="134" height="820" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://junstellar.github.io/p/ai-game-lab-build-9/scylla-stop.webp" srcset="https://junstellar.github.io/p/ai-game-lab-build-9/scylla-stop_hu_69999ec5ef6304d5.webp 800w, https://junstellar.github.io/p/ai-game-lab-build-9/scylla-stop.webp 1100w" width="1100"&gt;&lt;/p&gt;
&lt;h3 id="세-번째--설계에-없던-죽음"&gt;세 번째 — 설계에 없던 죽음
&lt;/h3&gt;&lt;p&gt;그런데 더 이상한 걸 발견했습니다. &lt;strong&gt;노잡이를 다 잃으면 죽는 규칙은 설계 어디에도 없었습니다.&lt;/strong&gt; 설계서에는 &lt;em&gt;&amp;ldquo;잘하면 2~3명, 못하면 여섯 이상&amp;rdquo;&lt;/em&gt; 이라고만 적혀 있었어요.&lt;/p&gt;
&lt;p&gt;생각해보면 당연합니다. &lt;strong&gt;배에 부하가 570명이나 타고 있는데 노 자리 여덟 개가 비었다고 배가 죽는 게 말이 되나요.&lt;/strong&gt; 잡혀간 자리는 다른 사람이 채우면 됩니다.&lt;/p&gt;
&lt;p&gt;그래서 자리를 채우게 하고, 지는 길은 카리브디스 하나만 남겼습니다. 같은 연타를 다시 돌리니 &lt;strong&gt;살아서 해협을 통과&lt;/strong&gt;했습니다. 51명을 잃고요.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;손실은 점수지 사망이 아니었습니다.&lt;/strong&gt; 신화의 스킬라도 여섯을 물어 가고 배는 지나갑니다.&lt;/p&gt;
&lt;h2 id="계측이-없었으면-셋-다-못-잡았다"&gt;계측이 없었으면 셋 다 못 잡았다
&lt;/h2&gt;&lt;p&gt;세 번 모두 &lt;strong&gt;제 느낌으로는 안 보였습니다.&lt;/strong&gt; &amp;ldquo;버텨라&amp;quot;는 제가 쓴 문구였고, &amp;ldquo;연타&amp;quot;도 제가 쓴 문구였고, 죽음 규칙도 제가 넣은 겁니다. 만든 사람은 규칙을 아니까 시키는 대로 안 합니다.&lt;/p&gt;
&lt;p&gt;잡아낸 방법은 전부 같았습니다. &lt;strong&gt;정책을 여러 개 만들어서 결과를 표로 뽑는 것.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;시킨 대로 하는 봇 / 안 하는 봇 → 어느 쪽이 나은가&lt;/li&gt;
&lt;li&gt;사람처럼 마구 누르는 봇 → 몇 초 만에 죽나&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;특히 마지막이 중요했습니다. 원래 있던 자동 플레이 함수는 &lt;strong&gt;&amp;ldquo;완벽한 봇&amp;rdquo;&lt;/strong&gt; 이라 안전할 때만 노를 저었습니다. 그래서 4편을 100번 돌려도 문제가 안 보였어요. &lt;strong&gt;사람이 실제로 하는 짓을 흉내내는 봇을 따로 만들고 나서야&lt;/strong&gt; 9.5초 전멸이 나왔습니다.&lt;/p&gt;
&lt;h2 id="그리고-1편을-깼는데-에필로그가-떴다"&gt;그리고 1편을 깼는데 에필로그가 떴다
&lt;/h2&gt;&lt;p&gt;발행 직전에 나온 버그입니다. 1편을 클리어했더니 2편이 아니라 &lt;strong&gt;&amp;ldquo;이 이야기의 나머지는 극장에서 이어집니다&amp;rdquo;&lt;/strong&gt; 가 떴어요.&lt;/p&gt;
&lt;p&gt;원인은 두 겹이었습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;첫째, 캐시.&lt;/strong&gt; 프리뷰 서버가 캐시 헤더를 안 보내서 브라우저가 며칠 전 빌드를 붙들고 있었습니다. 그 빌드는 지금은 지운 옛 파일을 참조하던 버전이라 2~6편을 못 읽었어요.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;둘째, 그리고 이쪽이 진짜 문제.&lt;/strong&gt; 부팅 코드가 &lt;strong&gt;못 읽은 편을 조용히 건너뛰고 남은 것만으로 항로를 짰습니다.&lt;/strong&gt; 그래서 1편짜리 항해가 만들어졌고, 1편을 깨는 순간 &amp;ldquo;마지막 편을 끝냈다&amp;quot;가 되어 에필로그가 뜬 겁니다.&lt;/p&gt;
&lt;p&gt;모자란 채로 굴러가느니 &lt;strong&gt;멈추고 무엇이 없는지 말하는 게&lt;/strong&gt; 낫습니다. 이렇게 바꿨어요.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;스테이지 모듈이 모자랍니다 (5/6) — 없는 것: st3.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;브라우저 캐시를 비우고 새로고침하세요.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="숫자"&gt;숫자
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;코드&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;13,882줄&lt;/strong&gt; (파일 9개)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;외부 에셋&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;0개&lt;/strong&gt; — 도형·소리 전부 코드가 만듭니다&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;스테이지&lt;/td&gt;
					&lt;td&gt;6편, 각자 자기 파일 하나가 통째로 소유&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;한 번도 안 틀렸을 때&lt;/td&gt;
					&lt;td&gt;약 5분&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;처음 하면&lt;/td&gt;
					&lt;td&gt;재시도 포함 25~30분&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;콘솔 에러&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;편마다 파일 하나가 장면·규칙·게이지·결과를 전부 갖게 한 게 이번 구조의 핵심입니다. 3편을 고치다 4편이 깨지는 일이 없었어요.&lt;/p&gt;
&lt;h2 id="개발-후기"&gt;개발 후기
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;&amp;ldquo;영화를 볼 때 알면 좋은 것&amp;quot;을 만들려니 게임 디자인이 거꾸로 됐습니다.&lt;/strong&gt; 보통은 재미가 먼저고 이야기가 따라오는데, 이번엔 &lt;strong&gt;꼭 알아야 하는 여섯 장면이 먼저&lt;/strong&gt; 정해져 있었어요. 그 여섯 개를 각각 어떤 손맛으로 만들 것인가가 전부였습니다.&lt;/p&gt;
&lt;p&gt;그래서 2편이 제일 어려웠습니다. &lt;strong&gt;이타카가 눈앞인데 잠드는 장면&lt;/strong&gt;은 플레이어가 이길 수 없어야 하거든요. 이길 수 없는 판을 &amp;ldquo;재미없다&amp;quot;가 아니라 &amp;ldquo;분하다&amp;quot;로 만들어야 했습니다. 지금은 잠들기 직전까지 진행 게이지가 95%까지 차오르고, 그게 20%대로 빨려 내려가는 걸 지켜보게 됩니다.&lt;/p&gt;
&lt;p&gt;그리고 하나 더. &lt;strong&gt;잘 만든 검사 도구가 오히려 눈을 가릴 수 있습니다.&lt;/strong&gt; 이 게임에는 처음부터 자동 플레이 봇이 붙어 있었는데, 그게 &amp;ldquo;완벽한 봇&amp;quot;이었어요. 규칙을 아는 채로 안전할 때만 눌렀습니다. 그래서 4편을 몇 번을 돌려도 &lt;strong&gt;전부 통과&lt;/strong&gt;했습니다. 정작 화면에 적힌 안내를 그대로 따르는 봇은 없었습니다.&lt;/p&gt;
&lt;p&gt;세 번 연속 같은 종류의 문제가 나온 게 우연이 아니라고 생각합니다. 검사는 &lt;strong&gt;&amp;ldquo;규칙대로 하면 되나&amp;rdquo;&lt;/strong&gt; 가 아니라 &lt;strong&gt;&amp;ldquo;화면에 적힌 대로 하면 되나&amp;rdquo;&lt;/strong&gt; 를 물어야 했습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;이 게임은 여기서 끝이 아닙니다. &lt;strong&gt;애정을 갖고 계속 손볼 생각이에요.&lt;/strong&gt; 이번에 세 번이나 &amp;ldquo;화면이 시키는 대로 하면 지는&amp;rdquo; 걸 잡았는데, 아직 못 찾은 게 더 있을 거라고 봅니다. 편마다 손맛을 다듬고, 모바일도 더 만져서 조금씩 패치해 나가겠습니다.&lt;/p&gt;
&lt;p&gt;아직 안 보셨다면 &lt;strong&gt;극장 가기 전에 30분만&lt;/strong&gt; 써보세요. 여섯 장면이 나올 때 &amp;ldquo;아, 저거&amp;quot;가 되면 성공입니다.&lt;/p&gt;
&lt;p&gt;이미 보셨다면 &lt;strong&gt;보고 나서 30분&lt;/strong&gt;도 괜찮습니다. 저는 이쪽이었는데, 만들면서 오히려 영화가 더 오래 남았어요. 세이렌 앞에서 오디세우스가 왜 그러고 있었는지는 직접 밧줄을 붙잡아 보고 나서야 몸으로 알겠더군요. 😄&lt;/p&gt;
&lt;p&gt;👉 &lt;strong&gt;&lt;a class="link" href="https://junstellar.github.io/games/odyssey/" &gt;오디세이아 하러 가기&lt;/a&gt;&lt;/strong&gt; · &lt;a class="link" href="https://junstellar.github.io/games/" &gt;AI 게임 랩 전체 보기&lt;/a&gt;&lt;/p&gt;</description></item><item><title>AI로 게임 만들기 #7 — 화차를 밀고 당기는 3D 조차장, 에이전트 60명이 놓친 것 (공개빌드 #7)</title><link>https://junstellar.github.io/p/ai-game-lab-build-7/</link><pubDate>Sat, 08 Aug 2026 14:00:00 +0900</pubDate><guid>https://junstellar.github.io/p/ai-game-lab-build-7/</guid><description>&lt;img src="https://junstellar.github.io/p/ai-game-lab-build-7/hero.webp" alt="Featured image of post AI로 게임 만들기 #7 — 화차를 밀고 당기는 3D 조차장, 에이전트 60명이 놓친 것 (공개빌드 #7)" /&gt;&lt;p&gt;&lt;a class="link" href="https://junstellar.github.io/p/ai-game-lab-build-6/" &gt;지난 편&lt;/a&gt;의 우주 진화에 이어, 일곱 번째 게임은 &lt;strong&gt;조차장&lt;/strong&gt;입니다. 화차를 밀고 당겨 정해진 순서로 열차를 편성하는 3D 퍼즐이에요. 🚂&lt;/p&gt;
&lt;p&gt;👉 &lt;strong&gt;&lt;a class="link" href="https://junstellar.github.io/games/shunting/" &gt;조차장 직접 하러 가기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이번 편은 게임 소개보다 &lt;strong&gt;만드는 과정에서 크게 헤맨 이야기&lt;/strong&gt;가 절반입니다. AI 에이전트를 60명 넘게 붙였는데 점수가 오히려 내려간 라운드가 있었고, 그 원인이 제가 예상한 것과 전혀 달랐거든요.&lt;/p&gt;
&lt;h2 id="시작은-남이-만든-게임을-본-것"&gt;시작은 남이 만든 게임을 본 것
&lt;/h2&gt;&lt;p&gt;7월 말에 &lt;strong&gt;클로드 오브 듀티(Claude of Duty)&lt;/strong&gt; 소식을 봤습니다. Matt Shumer가 Claude Opus 5에 프롬프트 하나를 던져서 브라우저 FPS를 통째로 받아냈다는 것이었습니다. Three.js와 WebGL2로 돌아가고, 약 55,000줄에 11개 서브시스템, 그리고 &lt;strong&gt;외부 에셋이 하나도 없습니다&lt;/strong&gt;. 텍스처도 메시도 사운드도 전부 코드가 런타임에 만듭니다. 공개 5일 만에 깃허브 별 2,381개가 붙었습니다.&lt;/p&gt;
&lt;p&gt;부러웠다기보다 &lt;strong&gt;되는지 궁금했습니다.&lt;/strong&gt; 저도 해보고 싶었습니다.&lt;/p&gt;
&lt;p&gt;다만 FPS를 따라 만들 생각은 없었습니다. 같은 걸 하나 더 만드는 건 의미가 없고, 무엇보다 저는 총 쏘는 게임을 잘 모릅니다. 그래서 소재를 찾다가 네이버 블로그에서 게임 광고를 하나 봤습니다. 주차장에 차가 빽빽하게 들어차 있고 화살표로 빼내는, 흔한 모바일 퍼즐 광고였습니다.&lt;/p&gt;
&lt;p&gt;저게 무슨 장르인지 물어봤더니 언블록 퍼즐(러시아워 계열)과 소트 퍼즐이 한 광고에 섞여 있는 거라고 하더군요. 그래서 &amp;ldquo;주차 말고 다른 형태로 5개만 뽑아봐라&amp;quot;고 했습니다. 조차장, 광선 미로, 나사 풀기, 엘리베이터 배차, 실타래 풀기가 나왔습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;조차장&lt;/strong&gt;을 골랐습니다. 국내 브라우저 게임에 거의 없는 소재였고, 물리 엔진 없이 순수 로직으로 끝나는 게 마음에 들었습니다.&lt;/p&gt;
&lt;p&gt;미술 방향은 &amp;ldquo;떠 있는 디오라마&amp;quot;로 잡았습니다. 조차장이 땅에서 뜯겨 나온 흙덩이 위에 얹혀 하늘에 떠 있습니다. 위는 잔디와 자갈, 아래는 암반 지층과 늘어진 뿌리. 카메라 화각을 24°로 좁게 잡아서 실제 크기의 세계가 아니라 &lt;strong&gt;손바닥에 올려놓은 모형처럼&lt;/strong&gt; 보이게 했습니다. 맨 위 표지 이미지가 그 결과입니다.&lt;/p&gt;
&lt;h2 id="던진-프롬프트"&gt;던진 프롬프트
&lt;/h2&gt;&lt;p&gt;이게 전부입니다. 이 다음부터는 에이전트들이 알아서 했습니다.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;조차장 아이디어를 가지고 해당 분야 최고의 게임을 만들어 달라.&lt;/p&gt;
&lt;p&gt;모든 면에서 완벽하고 &lt;strong&gt;시각적으로 아름다워야&lt;/strong&gt; 하며, 텍스처부터 물리 효과를 비롯해 생각할 수 있는 모든 요소를 &lt;strong&gt;AAA급 품질&lt;/strong&gt;로 구현해야 합니다. 여러 하위 에이전트를 병렬로 투입하고, 각 에이전트가 개별 요소를 하나씩 담당하게 하여 게임을 완벽하게 만들어 주세요. 각 요소를 반복해서 개선하고, &lt;strong&gt;별도의 하위 에이전트가 시각적으로 검토&lt;/strong&gt;하여 AAA급 품질에 도달했는지 확인하게 하세요. 검토 에이전트는 &lt;strong&gt;매우 엄격하게&lt;/strong&gt; 평가해야 하며, 결과물이 &lt;strong&gt;AAA급으로 보이지 않는다면&lt;/strong&gt; 만족할 때까지 계속 개선해야 합니다.&lt;/p&gt;
&lt;p&gt;각 하위 에이전트가 실제 &lt;code&gt;oskarstalberg.com/Townscaper&lt;/code&gt; 나 &lt;code&gt;krunker.io&lt;/code&gt; 이런 게임들과 비교했을 때 그 품질에 완전히 감탄할 때까지 멈추지 마세요. &lt;strong&gt;실제 게임 화면과 나란히 놓고 블라인드 테스트&lt;/strong&gt;를 진행하여 어느 쪽이 더 좋아 보이는지 판단할 수 있을 정도여야 합니다. 구현 방법에 제한은 없고 현재 PC의 모든 자원을 이용해도 좋으니 완벽해질 때까지 반복해서 개선하세요. 하위 에이전트들을 병렬로 적극 활용하고 최고 수준의 코딩 역량을 투입하세요. 이 개발에 필요한 모든 권한을 승인한다.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;읽어보면 아시겠지만 이 프롬프트에서 품질을 가리키는 단어는 &lt;strong&gt;전부 보는 것에 관한 것&lt;/strong&gt;입니다. 시각적으로 아름답게, 시각적으로 검토, 아름답게 보이지 않는다면, 나란히 놓고 어느 쪽이 더 &lt;strong&gt;좋아 보이는지&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;플레이할 수 있어야 한다&amp;quot;는 말은 한 번도 없습니다. 이 사실이 나중에 정확히 그대로 돌아옵니다.&lt;/p&gt;
&lt;h2 id="어떤-게임인가"&gt;어떤 게임인가
&lt;/h2&gt;&lt;p&gt;조차장은 화물열차를 재배열하는 곳입니다. 도착한 화차를 목적지별로 갈라서 다시 편성합니다. 이 작업을 &lt;strong&gt;입환(入換, shunting)&lt;/strong&gt; 이라고 부릅니다.&lt;/p&gt;
&lt;p&gt;게임은 그걸 그대로 옮겼습니다. 화면 아래에 주문서가 있습니다. &amp;ldquo;출발선에 이 순서로&amp;rdquo; — 유개차, 유조차, 호퍼차. 측선에 흩어진 화차를 그 순서대로 출발선에 세우면 클리어입니다.&lt;/p&gt;
&lt;p&gt;&lt;video src="play.mp4" poster="poster.webp" autoplay muted loop playsinline controls preload="metadata" style="width:100%;max-width:960px;border-radius:12px;display:block;margin:1.4rem auto 0.6rem;"&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;첫 레벨 클리어 전체(3배속). 측선으로 가서 물고 → 출발선에 밀어 넣고 → 분리하고 → 기관차만 빠져나옵니다. 3수.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;조작은 &lt;strong&gt;두 가지뿐&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;선로를 탭한다.&lt;/strong&gt; 기관차가 그 선로로 갑니다. 도착하면 거기 서 있던 화차 &lt;strong&gt;전부와 자동으로 연결&lt;/strong&gt;됩니다. 이게 1수입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;연결기를 자른다.&lt;/strong&gt; 편성 어디서든 끊을 수 있습니다. 끊긴 뒤쪽은 그 자리에 남고, 기관차는 앞쪽만 데리고 갑니다. &lt;strong&gt;수를 소모하지 않습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;끝입니다. 밀기 버튼도, 당기기 버튼도, 속도 조절도 없습니다.&lt;/p&gt;
&lt;h2 id="규칙은-두-개뿐인데-왜-어려운가"&gt;규칙은 두 개뿐인데 왜 어려운가
&lt;/h2&gt;&lt;p&gt;측선은 &lt;strong&gt;막다른 길&lt;/strong&gt;입니다. 한쪽 끝에 차막이가 있어서 드나드는 문이 하나뿐입니다. 자료구조로 말하면 &lt;strong&gt;스택&lt;/strong&gt;입니다. 먼저 넣은 화차가 가장 안쪽에 갇히고, 꺼낼 때는 나중에 넣은 것부터 나옵니다.&lt;/p&gt;
&lt;p&gt;그래서 순서를 바꾸려면 &lt;strong&gt;다른 측선을 임시 보관소로 써야 합니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;두 번째 레벨이 이 개념만 가르칩니다. 이름은 &amp;ldquo;거꾸로 선 두 량&amp;quot;입니다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;시작: 측선1 │ 🟥 🩶 목표: 출발선 │ 🩶 🟥
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;빨강과 회색이 순서대로 서 있는데 주문서는 반대입니다. 그냥 물고 가서 놓으면 순서가 그대로입니다. 하나를 다른 측선에 잠시 내려놓고, 다른 하나를 먼저 출발선에 넣고, 내려놓은 걸 다시 가져와야 합니다. 이게 &lt;strong&gt;par 5&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;여기에 제약이 하나 더 붙습니다. &lt;strong&gt;인상선(引上線)&lt;/strong&gt; — 측선 사이를 오갈 때 반드시 거쳐야 하는 짧은 선로입니다. 여기 들어갈 수 있는 량 수가 정해져 있습니다.&lt;/p&gt;
&lt;p&gt;8레벨부터 이 값이 3으로 조여집니다. 화차 5량을 한꺼번에 끌고 나올 수 없다는 뜻입니다. &lt;strong&gt;나눠서 옮겨야 합니다.&lt;/strong&gt; 이때부터 난이도가 확 오릅니다.&lt;/p&gt;
&lt;p&gt;그리고 마지막 한 가지. 화차를 다 놓아도 &lt;strong&gt;기관차가 출발선에 남아 있으면 끝나지 않습니다.&lt;/strong&gt; 실제 철도에서 기관차를 분리하고 되돌아가는 동작이라 그렇게 만들었는데, 이게 나중에 문제가 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;img alt="선로 이름표와 하단 편성 바" class="gallery-image" data-flex-basis="321px" data-flex-grow="134" height="1044" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://junstellar.github.io/p/ai-game-lab-build-7/ui.webp" srcset="https://junstellar.github.io/p/ai-game-lab-build-7/ui_hu_584ed401ccc8068c.webp 800w, https://junstellar.github.io/p/ai-game-lab-build-7/ui.webp 1400w" width="1400"&gt;
&lt;em&gt;선로마다 번호·이름·현재량/용량이 붙어 있고, 하단 편성 바에서 가위(✂)로 원하는 지점을 자릅니다.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="14개-레벨"&gt;14개 레벨
&lt;/h2&gt;&lt;p&gt;레벨은 손으로 짰고, 각 레벨의 &lt;strong&gt;par(최소 이동 수)는 전부 탐색으로 검증&lt;/strong&gt;했습니다. 하드코딩한 값과 실제 최적해가 하나도 어긋나지 않습니다.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;구간&lt;/th&gt;
					&lt;th&gt;화차&lt;/th&gt;
					&lt;th&gt;par&lt;/th&gt;
					&lt;th&gt;가르치는 것&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1~3&lt;/td&gt;
					&lt;td&gt;2~3량&lt;/td&gt;
					&lt;td&gt;3~6&lt;/td&gt;
					&lt;td&gt;조작, 후입선출, 부분 분리&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4~7&lt;/td&gt;
					&lt;td&gt;4~5량&lt;/td&gt;
					&lt;td&gt;6~9&lt;/td&gt;
					&lt;td&gt;측선 3개 활용&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;8~11&lt;/td&gt;
					&lt;td&gt;5~6량&lt;/td&gt;
					&lt;td&gt;10~13&lt;/td&gt;
					&lt;td&gt;인상선 3량 제약&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;12~14&lt;/td&gt;
					&lt;td&gt;6~8량&lt;/td&gt;
					&lt;td&gt;14~19&lt;/td&gt;
					&lt;td&gt;측선 용량 비대칭&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;이름도 붙였습니다. 아침 첫 입환, 거꾸로 선 두 량, 자갈 열차, 짧은 인상선, 노을 진 조차장, 막차 준비, 야간 조성, 마지막 열차. &lt;strong&gt;시간대가 아침에서 밤으로 흐릅니다.&lt;/strong&gt; 뒤로 갈수록 해가 지고 마지막 레벨들은 가로등이 켜진 밤입니다.&lt;/p&gt;
&lt;p&gt;풀이가 막히면 힌트가 최적 경로의 다음 한 수를 알려줍니다. 최적임을 보장하려고 매번 탐색을 돌리는데, 마지막 레벨(8량)에서 1.5초가 걸렸습니다. 게임이 멈춘 것처럼 보입니다. 상태를 정수로 인코딩하고 역방향 인덱스를 캐싱해서 &lt;strong&gt;최대 블로킹을 7.9밀리초로&lt;/strong&gt; 줄였습니다.&lt;/p&gt;
&lt;h2 id="에셋-0개로-만들기"&gt;에셋 0개로 만들기
&lt;/h2&gt;&lt;p&gt;클로드 오브 듀티에서 제일 인상적이었던 게 이 부분이라 그대로 따라 했습니다. 이미지 파일도, 사운드 파일도, 3D 모델 파일도 없습니다. &lt;strong&gt;전부 코드가 만듭니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;텍스처.&lt;/strong&gt; 자갈은 보로노이 셀을 깔고 셀마다 밝기를 흩뜨립니다. 침목은 방향성 노이즈로 나뭇결을 내고 능선 노이즈로 갈라짐을 넣습니다. 화차 도장은 베이스 컬러 위에 패널 라인·용접 비드·리벳 격자를 높이맵으로 얹고, 모서리에서 페인트가 벗겨져 프라이머와 녹이 드러나게 하고, 리벳에서 녹물이 아래로 흘러내리게 하고, 하단 30%에 흙먼지를 깝니다. 이 높이맵을 소벨 필터로 미분해 노멀맵을 뽑습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;지오메트리.&lt;/strong&gt; 레일은 실제 59kg 레일 단면(넓은 저부 → 잘록한 복부 → 버섯 머리)을 그려서 선로 곡선을 따라 압출합니다. 분기기는 텅레일·크로싱·가드레일·전환간까지 실제 부품으로 만들어서 전환할 때 블레이드가 움직입니다. 화차는 6종인데 &lt;strong&gt;색을 지워도 실루엣만으로 구별&lt;/strong&gt;되게 했습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;소리.&lt;/strong&gt; 연결 충격음은 노이즈 버스트를 340Hz·820Hz·1900Hz 밴드패스 세 개에 병렬로 통과시켜 금속 공진을 만들고, 60Hz 사인 감쇠로 저역 &amp;lsquo;쿵&amp;rsquo;을 얹습니다. 디젤 엔진은 톱니 오실레이터 스택에 실린더 발화 리듬을 진폭 변조로 걸었습니다. 15종을 이렇게 합성했습니다.&lt;/p&gt;
&lt;p&gt;의존성은 &lt;strong&gt;Three.js 하나&lt;/strong&gt;뿐이고 그마저 파일 하나로 넣어뒀습니다. 빌드 스텝이 없습니다. HTML 파일을 열면 그냥 돕니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;움직임&lt;/strong&gt;에도 공을 들였습니다. 연결기마다 유격이 있어서 기관차가 출발하면 뒤 차량이 자기 앞 유격이 다 풀린 뒤에야 끌려옵니다. 정지할 때는 반대로 뒤에서부터 밀려와 닫힙니다. 파도가 편성을 타고 흐릅니다.&lt;/p&gt;
&lt;h2 id="그런데-3라운드가-수렴하지-않았다"&gt;그런데 3라운드가 수렴하지 않았다
&lt;/h2&gt;&lt;p&gt;여기까지가 의도였습니다. 실제로는 이랬습니다.&lt;/p&gt;
&lt;p&gt;설계 문서를 쓰고 에이전트 13명에게 모듈을 하나씩 맡겨 동시에 짰습니다. 약 24,000줄이 나왔습니다. 그다음 &amp;ldquo;매우 엄격한 아트 디렉터&amp;rdquo; 심사 에이전트를 붙여 통과할 때까지 고치고 다시 심사받는 루프를 돌렸습니다.&lt;/p&gt;
&lt;p&gt;3라운드, 에이전트 33명 투입. 점수는 이렇게 움직였습니다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1라운드 4.18 / 10
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2라운드 4.92
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3라운드 4.50 ← 오히려 내려감
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="심사위원-3명이-똑같이-오진했다"&gt;심사위원 3명이 똑같이 오진했다
&lt;/h3&gt;&lt;p&gt;세 라운드 내내 반복된 지적이 있었습니다.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;그림자가 없다. 앰비언트 오클루전이 화면에서 사라졌다. 물체가 전부 떠 보인다.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;그래서 3라운드 내내 AO 반경과 그림자 bias를 만졌습니다. 점수는 안 올랐습니다.&lt;/p&gt;
&lt;p&gt;이상해서 직접 계측했습니다. 기능을 껐다 켜면서 화면이 얼마나 바뀌는지 픽셀 단위로 셌습니다.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;토글&lt;/th&gt;
					&lt;th&gt;변화 픽셀&lt;/th&gt;
					&lt;th&gt;최대 차이&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;SSAO 끔 → 켬&lt;/td&gt;
					&lt;td&gt;19.9%&lt;/td&gt;
					&lt;td&gt;164&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;그림자 끔 → 켬&lt;/td&gt;
					&lt;td&gt;12.5%&lt;/td&gt;
					&lt;td&gt;248&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;둘 다 멀쩡히 돌고 있었습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;진짜 원인은 최종 합성의 톤 커브였습니다. 히스토그램을 재보니 &lt;code&gt;p99 = 179&lt;/code&gt;, 클리핑 0.000%. 씬에서 &lt;strong&gt;가장 밝은 픽셀이 70% 회색&lt;/strong&gt;이었습니다. 순백이 없으니 AO와 그림자가 만든 대비가 전부 뭉개진 것입니다.&lt;/p&gt;
&lt;p&gt;심사위원들은 &lt;strong&gt;증상은 정확히 봤지만 원인을 틀렸습니다.&lt;/strong&gt; 저는 그 진단을 그대로 브리핑에 넣어 33명을 엉뚱한 곳으로 보냈습니다.&lt;/p&gt;
&lt;h3 id="그리고-아무도-게임을-해보지-않았다"&gt;그리고 아무도 게임을 해보지 않았다
&lt;/h3&gt;&lt;p&gt;시각 심사를 마치고 게임을 열었습니다. 첫 반응이 이랬습니다.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;게임 방법을 모르겠는데&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;이어서 &amp;ldquo;클리어 방법이 뭔데&amp;rdquo;, &amp;ldquo;기관차를 어떻게 빼는데&amp;rdquo;, &amp;ldquo;미션이 뭐였는데&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;화면 텍스트를 전부 덤프해봤습니다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LV 01 | 아침 첫 입환 | 0 / par 3 | 편성 목표 | 0/2 | 서 동
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;규칙이 어디에도 없었습니다.&lt;/strong&gt; 레벨 힌트 텍스트는 데이터에 있었고 튜토리얼 함수도 구현돼 있었는데, 화면까지 오지 못했습니다.&lt;/p&gt;
&lt;p&gt;심사 에이전트 9명이 3라운드에 걸쳐 12개 축으로 채점했습니다. 형태, 재질, 텍스처, 라이팅, 그림자, AO, 색, 구도, 환경, 포스트, UI, 통일감. &lt;strong&gt;UI 축에서 6~7점을 줬습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;아무도 &amp;ldquo;규칙을 모르는 사람이 이걸 플레이할 수 있나&amp;quot;를 묻지 않았습니다.&lt;/p&gt;
&lt;p&gt;여기서 앞의 프롬프트로 돌아갑니다. 저는 &amp;ldquo;시각적으로 검토하라&amp;quot;고 했고, &amp;ldquo;AAA급으로 보이지 않는다면 계속 개선하라&amp;quot;고 했습니다. &lt;strong&gt;에이전트들은 정확히 시킨 대로 했습니다.&lt;/strong&gt; 12개 축은 그 프롬프트를 충실히 옮긴 것이었고, 그래서 12개 축 전부가 보는 것에 관한 것이었습니다.&lt;/p&gt;
&lt;p&gt;빠진 건 에이전트의 성실성이 아니라 &lt;strong&gt;제 질문&lt;/strong&gt;이었습니다.&lt;/p&gt;
&lt;p&gt;검증 방식을 바꿨습니다. 소스 코드 열람을 금지한 &amp;ldquo;처음 보는 플레이어&amp;rdquo; 에이전트를 붙였습니다. 화면 스크린샷과 화면 텍스트만 보고 실제로 클리어해야 통과. 붙이자마자 진짜 문제가 쏟아졌습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;화차 분리가 3D 공간의 10px짜리 투명한 구를 클릭하는 게 유일한 방법이었습니다. 모바일에선 불가능합니다.&lt;/li&gt;
&lt;li&gt;숫자키 매핑이 레벨마다 바뀌었습니다. 어떤 레벨에선 &lt;code&gt;4&lt;/code&gt;가 출발선인데 다른 레벨에선 인상선이었습니다.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;기관차를 빼야 끝난다&amp;quot;는 규칙을 알려주지 않아 화차를 다 놓고도 막혔습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;고친 뒤 붙인 테스터 2명은 소스 없이 3개 레벨을 전부 클리어했습니다. 한 명은 par로 풀었습니다.&lt;/p&gt;
&lt;p&gt;&lt;img alt="단계별 튜토리얼 코치 카드" class="gallery-image" data-flex-basis="321px" data-flex-grow="134" height="1044" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://junstellar.github.io/p/ai-game-lab-build-7/tutorial.webp" srcset="https://junstellar.github.io/p/ai-game-lab-build-7/tutorial_hu_7159519e46a8cb31.webp 800w, https://junstellar.github.io/p/ai-game-lab-build-7/tutorial.webp 1400w" width="1400"&gt;
&lt;em&gt;단계별 코치 카드. 손가락 커서가 다음에 누를 곳을 짚고, 건너뛰기 버튼이 항상 있습니다.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="결과"&gt;결과
&lt;/h2&gt;&lt;p&gt;병목을 계측으로 가르고 나니 나머지는 기계적이었습니다.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;전&lt;/th&gt;
					&lt;th&gt;후&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;모바일 fps (중급 폰)&lt;/td&gt;
					&lt;td&gt;6.9&lt;/td&gt;
					&lt;td&gt;약 26&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;드로우콜&lt;/td&gt;
					&lt;td&gt;2,670&lt;/td&gt;
					&lt;td&gt;280&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;품질 전환 정지&lt;/td&gt;
					&lt;td&gt;10,299ms&lt;/td&gt;
					&lt;td&gt;500ms&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;힌트 응답&lt;/td&gt;
					&lt;td&gt;499ms (그마저 오답)&lt;/td&gt;
					&lt;td&gt;7.9ms&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;줌 한 칸&lt;/td&gt;
					&lt;td&gt;거리의 0.12%&lt;/td&gt;
					&lt;td&gt;10%&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;드로우콜이 2,670이었던 이유는 풀 뭉치 227개와 잡초 206개가 &lt;strong&gt;개별 메시&lt;/strong&gt;로 흩어져 각각 본 패스와 그림자 패스로 두 번씩 그려졌기 때문입니다. 인스턴싱으로 묶으니 280이 됐습니다.&lt;/p&gt;
&lt;p&gt;여기서도 계측이 방향을 정했습니다. 해상도를 4분의 1로 줄여도 fps가 안 올랐습니다. 픽셀이 아니라 CPU 문제라는 뜻이었고, 그래서 후처리가 아니라 드로우콜을 팠습니다.&lt;/p&gt;
&lt;p&gt;&lt;img alt="AI 게임 랩 허브 — 구분선 아래 가로로 긴 카드" class="gallery-image" data-flex-basis="227px" data-flex-grow="94" height="1267" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://junstellar.github.io/p/ai-game-lab-build-7/hub.webp" srcset="https://junstellar.github.io/p/ai-game-lab-build-7/hub_hu_22ba7f2d2545bbb.webp 800w, https://junstellar.github.io/p/ai-game-lab-build-7/hub.webp 1200w" width="1200"&gt;
&lt;em&gt;미니게임과 결이 달라서 구분선 아래에 가로로 길게 따로 놓았습니다.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="개발-후기"&gt;개발 후기
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;만드는 데 든 시간보다 진단하는 데 든 시간이 훨씬 길었습니다.&lt;/strong&gt; 24,000줄이 나오는 데는 반나절이 안 걸렸습니다. 그런데 &amp;ldquo;왜 안 예쁜가&amp;quot;를 알아내는 데 사흘이 걸렸고, 그중 이틀은 틀린 진단을 좇느라 썼습니다.&lt;/p&gt;
&lt;p&gt;에이전트를 많이 붙이면 빨라집니다. 그건 사실입니다. 13명이 동시에 짜서 하루 만에 게임 하나가 나왔습니다. 문제는 &lt;strong&gt;틀린 방향으로도 똑같이 빨라진다&lt;/strong&gt;는 것입니다. &amp;ldquo;그림자가 없다&amp;quot;는 오진 하나로 33명이 사흘 치 작업을 엉뚱한 곳에 쏟았습니다. 사람 혼자였으면 세 번째 시도쯤에 &amp;ldquo;이상한데?&amp;rdquo; 하고 멈췄을 텐데, 에이전트는 시킨 대로 끝까지 갑니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;그래서 계측이 전부였습니다.&lt;/strong&gt; 이 프로젝트에서 잘 풀린 순간은 전부 제가 직접 숫자를 재서 브리핑에 넣었을 때였습니다. &amp;ldquo;AO를 켜고 끄면 화면의 19.9%가 바뀐다&amp;rdquo;, &amp;ldquo;해상도를 1/4로 줄여도 fps가 안 오른다&amp;rdquo; — 이런 문장 하나가 들어가면 한 라운드에 해결됐습니다. 반대로 &amp;ldquo;화면이 칙칙해 보인다&amp;rdquo; 같은 인상을 넘기면 몇 라운드를 헤맸습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI 심사는 문제 발견에는 좋고 원인 진단에는 나쁩니다.&lt;/strong&gt; 심사위원들이 &amp;ldquo;뭔가 잘못됐다&amp;quot;고 한 건 매번 맞았습니다. 다만 &amp;ldquo;왜&amp;quot;는 매번 틀렸습니다. 이 둘을 구분해서 쓰면 꽤 쓸 만한 도구입니다. 구분하지 않으면 비싼 소음입니다.&lt;/p&gt;
&lt;p&gt;그리고 제일 뼈아팠던 것. &lt;strong&gt;사용자 한 명이 심사 에이전트 9명을 이겼습니다.&lt;/strong&gt; &amp;ldquo;게임 방법을 모르겠는데&amp;rdquo; 한마디가 아홉 번의 심사보다 정확했습니다. 그 한마디를 듣기 전까지 저는 이 게임이 &amp;ldquo;보기엔 좀 아쉽지만 게임으로는 되는&amp;rdquo; 상태라고 믿고 있었습니다. 사실은 정반대였습니다. &lt;strong&gt;보기엔 그럭저럭이고 게임으로는 안 되는&lt;/strong&gt; 상태였습니다.&lt;/p&gt;
&lt;p&gt;클로드 오브 듀티에 대한 평가 중에 이런 게 있었습니다. &amp;ldquo;돌아가긴 하는데 학생 프로젝트처럼 보이지, 출시할 물건 같지는 않다.&amp;rdquo; 직접 해보니 그 말이 정확히 무슨 뜻인지 알겠습니다. &lt;strong&gt;돌아가는 것과 완성된 것 사이의 거리가 생각보다 멉니다.&lt;/strong&gt; 그리고 그 거리는 코드량으로 좁혀지지 않습니다.&lt;/p&gt;
&lt;h2 id="남은-것"&gt;남은 것
&lt;/h2&gt;&lt;p&gt;아직 안 끝났습니다. 모바일 부팅이 79초 걸립니다. 부팅 직후 검은 화면이 한 번 번쩍이는데 원인만 알고 안 고쳤습니다. 열차의 무게감 연출도 절반쯤입니다. 사운드는 전부 코드로 합성했는데 &lt;strong&gt;아직 아무도 귀로 들어본 적이 없습니다&lt;/strong&gt; — 파형은 측정했지만 그건 다른 문제입니다.&lt;/p&gt;
&lt;p&gt;그래도 게임은 돌아가고, 규칙을 모르는 사람이 클리어할 수 있습니다. 거기까지는 왔습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a class="link" href="https://junstellar.github.io/games/shunting/" &gt;👉 조차장 플레이하기&lt;/a&gt;&lt;/strong&gt; · &lt;a class="link" href="https://junstellar.github.io/games/" &gt;AI 게임 랩 전체 보기&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="참고"&gt;참고
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.navsplace.net/claude-of-duty-single-prompt-fps-20260726/" target="_blank" rel="noopener"
 &gt;Claude of Duty: 55,000 lines of 3D game code from a single prompt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://enterprisedna.co/resources/ai-pulse/ai-pulse-2026-07-27-claude-of-duty-one-shot-fps-demo-gets-a-skeptical-reality-ch/" target="_blank" rel="noopener"
 &gt;&amp;ldquo;Claude of Duty&amp;rdquo; one-shot FPS demo gets a skeptical reality check&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://explainx.ai/blog/claude-of-duty-opus-5-procedural-fps-july-2026" target="_blank" rel="noopener"
 &gt;Claude of Duty — Opus 5 Procedural FPS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>