From Web Game Builder
WGF Studio 브라우저 게임 에디터를 기동해 유니티식 GUI 로 씬·게임오브젝트를 직접 편집하고, 에디터 안에서 Claude 와 협업 편집하며, 2-트랙 스킬을 적용하고, 에디터 내 Play 후 무빌드 정적 게임으로 export 한다. 키워드: 게임 에디터, WGF Studio, 씬 편집, scene.json, 비주얼 편집, 에디터 기동, 레벨 에디터, editor, scene editor, game editor, visual editing.
How this skill is triggered — by the user, by Claude, or both
Slash command
/web-game-builder:wgf-editorThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
브라우저에서 도는 유니티식 게임 에디터 "WGF Studio" 를 기동하고, Claude Code 가 그 안에서
브라우저에서 도는 유니티식 게임 에디터 "WGF Studio" 를 기동하고, Claude Code 가 그 안에서 사용자와 협업 편집하게 한다. 사람은 GUI 로 씬·게임오브젝트를 직접 조작하고, Claude 는 에디터 챗으로 받은 지시를 MCP 도구로 씬에 반영한다. 만든 게임은 에디터에서 바로 Play 하고 무빌드 정적 게임으로 export 한다. web-game-builder 워크플로의 "에디터로 만들기" 레인.
WGF Studio 는 선언형 scene.json 을 단일 진실로 삼는 브라우저 게임 에디터다. 핵심 설계:
engine/scenekit.js(+ scenekit-components.js)
는 Phaser 비의존·결정적 로직코어다(주입 dt 만 소비, 무작위는 RngForge 스트림만).
engine/scenekit-phaser.js 는 그 위에 얹는 브라우저 렌더·기즈모 어댑터다. 코어가 분리돼
있어 Node 헤드리스로 결정성을 검증할 수 있다.editor/server/bridge.mjs 가 라이브 씬 상태·커맨드 로그·Undo/Redo
의 단일 권위자다. 모든 변경은 커맨드 → 직렬 apply → SSE 델타 브로드캐스트.editor/server/mcp.mjs 는 Claude Code 가 .mcp.json 으로 spawn 하는
stdio JSON-RPC 어댑터다. 자체 씬 상태 0 — 모든 도구 호출을 브리지에 localhost HTTP 로
프록시한다. 그래서 "브리지 = 단일 진실" 이 프로세스 수준에서도 성립하고, Claude 세션
재시작에 강건하다.editor/server/export.mjs 가 scene.json → games/<slug>/{index.html, game.js, CREDITS.txt} 정적 게임을 생성한다(번들러 0, <script> vendoring).scene.json 의 edit t=0 트랜스폼 = play 0프레임 = export 0프레임
(계약 H, 동일 코어가 t=0 를 만들므로 구성적 성립). 절차 텍스처 베이크 결정성 +
AnimatedSprite t=0=프레임0 으로 외형까지 동형(계약 H′).자세한 토폴로지는 reference/architecture.md.
비대상: 기존 손코딩 game.js 게임의 역편집은 대상이 아니다. WGF Studio 는 신규
wgf-scene@1 포맷만 다룬다(설계 결정 #4). 손코딩 게임 신규 제작·수정은 web-game-builder 의
손코딩 레인(wgf-make-game 등)이 담당한다.
에디터 UI 셸(Preact + esbuild)은 editor/ui/ 에만 npm 의존이 격리돼 있다. 최초 1회만 빌드한다.
이 디렉터리에서 실행한다:
cd editor/ui
의존 설치:
npm install
번들 빌드(editor/ui/dist/bundle.js 생성):
npm run build
빌드 산출물(dist/)과 node_modules/ 는 .gitignore 로 커밋 제외된다(재생성 가능).
협업 편집 전체 루프를 쓰려면 브리지 서버를 기동한다(127.0.0.1 전용, zero-dep). 프로젝트 루트에서 실행한다:
node editor/server/bridge.mjs 5180
기동이 완료되면 기본 브라우저가 자동으로 다음 주소로 열린다(수동으로 열 필요 없음):
http://127.0.0.1:5180/editor/ui/
자동 실행은 비치명적이라 브라우저가 없거나 헤드리스여도 서버는 계속 뜬다(위 주소를 직접 열면
됨). 자동 실행을 끄려면 WGF_NO_OPEN=1 로 기동한다(PowerShell $env:WGF_NO_OPEN="1"; node editor/server/bridge.mjs 5180). 테스트 하니스(WGF_BRIDGE_PORT=0)에서는 자동으로 생략된다.
기본으로 games/_editor-samples/topdown-min/scene.json 이 로드된다.
WGF_BRIDGE_SCENE 환경변수로 다른 씬을 지정해 기동한다(PowerShell):
$env:WGF_BRIDGE_SCENE="games/wgf-demo-arena/scene.json"; node editor/server/bridge.mjs 5180
bash 계열이면:
WGF_BRIDGE_SCENE=games/wgf-demo-arena/scene.json node editor/server/bridge.mjs 5180
협업 루프·라이브 단일 진실 없이 UI 셸만 띄워 보려면 dev 서버를 쓴다(P1 정적 서빙):
node editor/serve.mjs 5174
브리지와 마찬가지로 기동 시 기본 브라우저가 자동으로 http://127.0.0.1:5174/editor/ui/ 로
열린다(WGF_NO_OPEN=1 로 끄기).
local dev 는 Claude 협업·브리지 단일 진실·Play 권위가 없다(localStorage Save 까지). 협업 편집·Play·export 전체 루프는 3.2 의 브리지 경로를 쓴다.
루트 .mcp.json 에 wgf-editor MCP 서버가 등록돼 있어 Claude Code 가 자동으로
editor/server/mcp.mjs 를 spawn 한다:
{ "mcpServers": { "wgf-editor": { "command": "node", "args": ["editor/server/mcp.mjs"] } } }
MCP 어댑터는 무상태 프록시다 — 브리지가 떠 있어야 도구 호출이 동작한다. 브리지 미기동
시 도구는 "브리지 미기동" 구조화 에러를 반환한다(엔드포인트 파일 부재). 브리지가 기동 시
.omc/wgf-editor/bridge-endpoint.json 에 {port, token} 을 쓰고, MCP 어댑터가 매 호출마다
그것을 읽어 프록시에 사용한다(브리지 재기동에 강건).
사용자가 에디터 챗에 메시지를 보내면 Claude 가 다음 루프로 처리한다(설계서 §4.7):
editor_next_message (long-poll) — 미처리 사용자 메시지 1건을 가져온다. 없으면
브리지가 ~25초 대기 후 message:null 로 응답 → 재호출. 이 호출 자체가 Claude 루프
하트비트(생존 신호)다.scene_add_entity·scene_set_transform·scene_add_component 등으로
지시를 씬에 반영한다(전부 브리지 프록시).editor_reply — 처리 결과(diff 요약)를 에디터 챗에 표시한다. replyTo 에 처리한
메시지 id 를 넣는다.disconnected 로
표시한다. 에디터가 "Claude 연결/대기/끊김" 인디케이터를 보여준다(/api/status 폴링)..omc/wgf-editor/chat-queue.json 에 원자적으로 영속된다. 터미널
강종·재진입에도 미처리 메시지가 무손실 복원된다.도구 목록·시그니처는 reference/tools.md, 워크플로 상세는 reference/workflow.md.
에디터 스킬 메뉴는 두 트랙으로 갈린다(설계 결정 #6):
execFile(배열 인자, 셸 미경유)로 실행하는 화이트리스트
검증 도구. lint-scene·lint-rng·lint-juice·lint-kit-deps·qa-score 5종. MCP 에서는
skill_run_tool 로 호출하고, file/target 에 "current" 를 주면 브리지가 현재 씬을 임시
직렬화해 실행한다. 화이트리스트 외 도구·인자 스키마 위반·경로 traversal 은 브리지가 거부한다.editor_next_message 로
받아 처리.화이트리스트·인자 스키마 상세는 reference/tools.md, 보안 경계는 reference/security.md.
씬 에셋은 두 소스다(설계 결정 #11):
asset_add_procedural(id 필수, desc·w·h·def
선택)로 assets.sprites 에 추가한다.asset_add_cc0(id·url 필수,
license 기본 CC0-1.0·credit·desc·w·h 선택)로 추가한다. javascript:·data:·file:·
vbscript: 스킴 url 은 거부된다(저장형 XSS 방지).추가한 에셋 id 를 엔티티의 Sprite.sprite 필드가 참조한다. asset_list 로 현재 목록을 조회한다.
씬 엔티티에 부착하는 컴포넌트는 정확히 15종 화이트리스트다. lint-scene 이 이 목록
밖(미등록·16번째) 타입에 UNKNOWN_COMPONENT error + exit 1 을 낸다.
| # | 타입 | 단계 | 요약 |
|---|---|---|---|
| 1 | Sprite | P0a | 정적 렌더 메타(sprite ref) |
| 2 | Body | P0a | 충돌 바디(aabb/circle, isStatic) |
| 3 | TopDownController | P0a | 8방향 탑다운 이동(speed·input) |
| 4 | AnimatedSprite | P0b | 프레임 애니메이션(결정적 타이머, t=0=프레임0) |
| 5 | Shooter | P0b | 주기 발사(Projectile 생성) |
| 6 | Projectile | P0b | 직선 이동 발사체(수명·데미지) |
| 7 | EnemyAI | P0b | 적 AI(chase/flee/patrol/shoot) |
| 8 | Health | P0b | 체력·무적·사망 처리 |
| 9 | ContactDamage | P0b | 접촉 데미지 |
| 10 | Pickup | P0b | 수집 아이템(heal/coin) |
| 11 | Spawner | P0b | 주기적 엔티티 생성(template) |
| 12 | CameraFollow | P0b | 카메라 추적 데이터 |
| 13 | AbilityBinding | P0b | 능력 쿨다운/발동 |
| 14 | AudioEmitter | P0b | 오디오 이벤트 누적 |
| 15 | HUDBinding | P0b | HUD 데이터 바인딩 |
각 컴포넌트의 필드·예시는 reference/components.md. 정식 스키마 원본은 games/_editor-samples/SCHEMA.md.
/api/command·undo/redo)는 409 로 거부된다.POST /api/mode {mode} 로 한다(edit↔play).node editor/server/export.mjs <scene.json 경로 또는 slug> [--out <slug>]
예:
node editor/server/export.mjs games/wgf-demo-arena/scene.json
산출물은 games/<slug>/{index.html, game.js, CREDITS.txt}. QA 가능성 계약(필수):
산출 game.js 는 window.<Slug> = { game, input: GAME_INPUT, audio, rng, scene, seed, start, stop, __bakeHash } 를 노출하고 ?autostart=1·?seed=N 을 지원한다. 엔진 로드 순서는
phaser → pixelforge → vectorforge → audio → mobile → joystickkit → scenekit →
scenekit-components → scenekit-phaser → game.js 로 보존된다. 내보낸 게임은 본질적으로
SceneKitPhaser.create(parent, SCENE_DOC, {mode, chrome:false}) 부트스트랩이라 에디터 play 와
동형(계약 H)이다.
참고: MCP
project_export도구는 v1 에서 안내성 스텁이다 — 위 CLI 로 실행한다.
로컬 도구라도 신뢰경계가 있다(설계서 §6). 브리지는 다음을 강제한다:
127.0.0.1 전용(0.0.0.0 금지, LAN 비노출). 기동 시 crypto.randomBytes(24)
무작위 토큰 발급, 모든 /api/* 에 토큰(상수시간 timingSafeEqual 비교) + Origin 검사.games/)로 정규화 후 prefix 검사, ../
traversal·dotfile 세그먼트 거부.execFile(node, [argv]) 배열 인자로만 실행한다(셸 미경유 — ;·&&·$() 등 메타문자
무력화).0o600(소유자 rw only), 보관 디렉터리는 0o700
으로 격리한다(POSIX). Windows 는 read-only 비트만 반영돼 무해.상세·게이트 매핑은 reference/security.md.
7개 헤드리스 하니스가 단계별 수용 게이트를 실제 실행 검증한다(전부 마지막 줄 단일 JSON
{"ok":bool,"pass":n,"fail":n}, 통과 시 exit 0).
| 하니스 | 게이트 | 검증 대상 |
|---|---|---|
skills/wgf-editor/tools/test-scenekit.mjs | 98 | SceneKit 코어 — 결정성·벽 AABB 충돌·15컴포넌트 step·apply/undo·lint-scene |
editor/server/test-bridge.mjs | 38 | 브리지 — 커맨드 라운드트립·Play 권위·SSE Last-Event-ID 복구·백프레셔·traversal·토큰 |
editor/server/test-mcp.mjs | 27 | MCP — initialize·tools/list(22종)·프록시·챗 큐 재진입·하트비트·무빌드 불변식 |
editor/server/test-skill.mjs | 31 | 2-트랙 스킬 — 결정형 exit 0·화이트리스트 거부·인자 traversal·셸 미경유·에셋 ref |
editor/server/test-export.mjs | 24 | export — 동형성 H·QA 가능성 계약·로드순서·lint-rng·replay·qa-score |
editor/server/test-demo.mjs | 13 | 데모(wgf-demo-arena) — lint-scene·export·결정성·생성형 동작·qa-score |
editor/server/test-security.mjs | 16 | 보안 — 바인딩·traversal·화이트리스트·셸 미경유 증명·토큰 타이밍·파일 권한 |
실행(프로젝트 루트에서, 예):
node skills/wgf-editor/tools/test-scenekit.mjs
node editor/server/test-bridge.mjs
게이트 카탈로그 상세는 reference/tools.md.
web-game-builder 워크플로에서 게임 제작 경로가 둘로 갈린다:
wgf-make-game 등으로 Phaser game.js 를 직접 생성·편집.scene.json 을 GUI·Claude 협업 편집 후
무빌드 export. 사용자가 "에디터로 만들래"·"유니티처럼 짜고 싶어" 라고 하면 이 레인.wgf-web-game-builder 오케스트레이터에 에디터 레인 라우팅이 추가된다(병렬 레인 B 소관).
상호 참조는 reference/workflow.md.
| 증상 | 원인 | 해결 |
|---|---|---|
http://127.0.0.1:5180/editor/ui/ 가 빈 화면·404 | UI 셸 미빌드(dist/bundle.js 없음) | cd editor/ui → npm install → npm run build |
| 기동했는데 브라우저가 자동으로 안 열림 | 헤드리스 환경·기본 브라우저 미설정·WGF_NO_OPEN 설정(자동 실행은 비치명적) | stderr 의 브리지 기동 → <url> 주소를 수동으로 연다. 자동 실행을 의도적으로 끄려면 WGF_NO_OPEN=1 |
브리지 기동 시 EADDRINUSE | 포트 5180 점유 | 다른 포트로 기동(node editor/server/bridge.mjs 5200) 또는 점유 프로세스 종료 |
| MCP 도구가 "브리지 미기동" 에러 | 브리지가 안 떠 있음(엔드포인트 파일 부재) | 먼저 node editor/server/bridge.mjs 5180 으로 브리지 기동 |
| Play 중 편집이 409 거부 | Play 권위 read-only(정상) | Stop(/api/mode {mode:'edit'}) 후 편집 |
scene_screenshot 이 "뷰포트 없음" | 브라우저 미오픈(헤드리스) 또는 v1 캡처 파이프라인 미도입 | 헤드리스 편집은 계속 가능. 시각 확인은 SSE 페이지 직접 관찰 |
| SSE 페이지 스크린샷이 정지/타임아웃 | EventSource 스트림 특성(라이브 캡처 함정) | 라이브 스크린샷 대신 /api/scene 동기 GET 으로 상태 확인 |
브라우저에서 GAME_INPUT.<dir>=true 줬는데 안 움직임 | 어댑터가 매 프레임 Phaser 키보드로 GAME_INPUT 덮어씀(합성 쓰기 클로버) | 진짜 KeyboardEvent 를 window.dispatchEvent (browser-verify.md) |
수동 setMode('play') 후 엔티티 정지(스폰·이동 없음) | rAF 스텝 루프는 ?autostart=1→start() 경로만 구동 | ?autostart=1 로 로드해 스텝 구동 확인 |
export 가 "scene.json 을 찾을 수 없습니다" | 경로/slug 오인 | games/<slug>/scene.json 경로 또는 slug 직접 지정, --out 으로 출력 slug 명시 |
web-game-builder 오케스트레이션의 에디터 제작 레인.game-qa(헤드리스 QA·replay·qa-score) ·
ip-license-guard(CC0/IP 안전).sprite-picker(CC0 시각 선택) ·
sprite-forge/vector-graphics(절차 생성).Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub v0o0v/web-game-forge --plugin web-game-builder