Waggle 이란
꿀벌은 8자춤으로 동료에게 먹이가 있는 방향과 거리를 알립니다. Waggle 은 문장으로 Spacemaker 에 공간을 알립니다. 왼쪽에 말하면 오른쪽에 평면이 그려지고, 모델은 Spacemaker 서버가 들고 있습니다. 설치할 것은 없습니다.
시작하기
- 왼쪽 아래 튜토리얼 1번을 누릅니다. 문장이 보내지고 방 넷이 점선으로 그려집니다.
- 단계가 끝나면 체크가 붙고 다음 단계가 노랗게 켜집니다. 순서대로 누르면 방 → 벽 → 문 → 창 → 점검까지 갑니다.
- 언제든 입력창에 직접 문장을 쳐도 됩니다. 이전 대화를 기억하므로 "그 벽을 50 cm 더" 같은 말도 통합니다.
화면
- 층 버튼 — 2층을 올리면 층 버튼이 생깁니다. 눌러서 층을 바꿉니다.
- JSON — 지금 모델을 파일로 받습니다. 세션은 서버 메모리에만 있으니 남길 것은 받아 두세요.
- 대안 고르기 — "집 평면 몇 가지 안으로 만들어 줘" 처럼 고를 것이 있는 요청이면 대화 안에 안별 섬네일이 뜹니다. 하나를 누르면 그 안으로 배치됩니다.
- 재생 — 이 세션이 한 일을 처음부터 애니메이션으로 다시 봅니다. 문장이 자막으로 뜨고, 그 문장이 만든 변화가 한 걸음씩 그려집니다. 슬라이더로 아무 순간이나 잡을 수 있습니다. 2D 든 3D 든 보던 화면에서 재생됩니다.
- SMP — Spacemaker 프로젝트 파일로 받습니다. Spacemaker 앱의 Load 에서 그대로 열립니다. "저장해" 라고 말하면 서버의 프로젝트 목록에도 저장됩니다.
- 되돌리기 — 마지막 요청(또는 모두 지우기) 전 상태로 돌아갑니다. 스무 번까지 거슬러 갑니다.
- 모두 지우기 — 그린 것을 전부 지웁니다. 한 번 누르면 확인 상태가 되고 3초 안에 한 번 더 누르면 지워집니다. 대화는 남습니다. 되돌리기로 복구됩니다.
- 지우기는 말로도 됩니다. "침실 2 지워", "화장실 문 지워", "북쪽 벽 지워", "다 지워" — 도형·문·창·벽·층 전체를 지우는 함수가 있습니다.
- 새 세션 — 모델과 대화를 모두 비웁니다. 처음부터도 같습니다.
- 대화 안의 작은 줄(
create_shape → create)은 모델이 부른 도구입니다. 무엇을 했는지 그대로 보여 줍니다.
방향과 크기
도면의 위가 북쪽, 아래가 남쪽입니다. 판은 30 m × 30 m 이고 건물은 가운데에 놓입니다. 크기는 미터로 말하면 됩니다.
이런 문장이 됩니다
12 m × 8 m 집 1층. 남쪽에 거실 6×5 m, 북쪽에 침실 둘과 화장실 하나. 방만 그려 줘.
지금 그린 방들로 벽을 세워 줘. 그리고 방마다 문을 달아 줘. 현관은 거실 남쪽.
거실 남쪽 벽을 1 m 남쪽으로 밀어 줘. 문과 창은 따라와야 해.
두 번째 침실을 서재로 바꿔 줘. 현관문 위에 유리 캐노피. 거실 남쪽 벽에 발코니.
2층을 1층 복사본으로 올리고, 8 m 간격 기둥 그리드를 4×3 으로 깔아 줘.
허공에 뜬 문이 있으면 지우고 다시 점검해 줘.
알아둘 것
- 모델이 "했습니다" 라고 해도 도면을 보세요. 도구 줄에
error 가 있으면 안 된 것입니다.
- 계단과 자동 가구 배치는 아직 여기서 안 됩니다. Spacemaker 앱에서 됩니다.
- 한 사람당 하루 60턴입니다. 한 턴은 문장 하나이고, 그 안의 도구 호출은 몇 번이든 셈하지 않습니다.
- 브라우저를 닫아도 30일 안에는 같은 세션으로 돌아옵니다. 서버가 재시작되면 세션은 사라집니다.
개발자 가이드 — Waggle 소스로 MCP 앱 만들기
Waggle 은 Spacemaker MCP 를 쓰는 가장 작은 응용 프로그램입니다. 자기 프로그램에서 같은 일을 하려면 아래 세 호출만 있으면 됩니다. 모델(LLM)은 무엇이든 됩니다. 화면도 무엇이든 됩니다.
sessions/create세션을 연다
서버가 모델을 든다
→
tools/call {sessionId,…}도구 하나 실행
서버가 결과를 세션에 적용
→
sessions/get모델 JSON 을 받는다
벽·방·문·창·…
주소와 인증. 엔드포인트는 https://spacemaker.gongvue.com/api/mcp 하나입니다. Spacemaker 가 발급한 키를 Authorization: Bearer <key> 로 보냅니다. 본문은 JSON-RPC 2.0 이고, 응답은 JSON 또는 SSE(data: 한 줄)로 옵니다.
POST /api/mcp
Authorization: Bearer <key>
Content-Type: application/json
{"jsonrpc":"2.0","id":1,"method":"sessions/create","params":{"projectId":"my-app"}}
→ {"result":{"sessionId":"sess_…","state":{"shapes":[],"interactiveWalls":[],…}}}
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"create_shape",
"arguments":{"sessionId":"sess_…","x1":0.3,"x2":0.5,"z1":0.3,"z2":0.5,"name":"거실","spaceType":"living"}}}
→ {"result":{"content":[{"type":"text","text":"{\"op\":\"create\",\"shape\":{\"id\":\"shape_…\",…}}"}]}}
{"jsonrpc":"2.0","id":3,"method":"sessions/get","params":{"sessionId":"sess_…"}}
→ {"result":{"state":{"shapes":[…],"interactiveWalls":[…],"spaces":[…],"interactiveDoors":[…]}}}
도구 호출의 결과는 "플랜" 입니다. tools/call 의 text 안에는 { op: "create" | "edit" | "delete" | "create_opening" | "compose_extrude" | "invoke" | "read" | "error", … } 형태의 JSON 이 있습니다. 세션 모드에서는 서버가 이것을 세션 상태에 적용해 두므로 읽기만 하면 됩니다. op: "error" 면 reason 을 모델에 돌려주면 모델이 고칩니다. op: "read" 는 data 에 조회 결과가 있습니다.
Waggle 소스는 이렇게 읽습니다. 저장소 mcp-package/examples/ 에 있습니다.
| 파일 | 역할 |
vibe-session.mjs | 115줄, 의존성 없음. mcp() 가 위 JSON-RPC 를 보내고, claude() 가 모델을 부르고, 루프가 모델의 tool_use 를 tools/call 로 바꿔 결과를 되돌립니다. 끝에 sessions/get 으로 받은 JSON 을 파일로 씁니다. MCP 앱의 뼈대는 이 파일 하나입니다. |
waggle/server.mjs | 같은 루프를 HTTP 서버로 감쌌습니다. 페이지의 POST /api/waggle/chat 를 받아 도구 호출마다 SSE 로 흘려 줍니다. 세션 하나를 프로세스가 들고 있습니다. |
waggle/index.html | 이 화면. 채팅, 튜토리얼, 캔버스. 캔버스는 sessions/get 의 상태를 그대로 그립니다: interactiveWalls[].p1/p2(정규화 0..1), spaces[].points(평면 단위, (n−0.5)×2000), interactiveDoors/Windows[].x,z,angle,width. |
바꿔 쓰기.
- 다른 LLM.
claude() 만 바꾸면 됩니다. 필요한 것은 도구 목록(이름·설명·JSON 스키마)을 받고 tool_use 를 내는 모델입니다. 도구 목록은 tools/list 로 받되, 모델에는 필요한 것만 주세요(전부는 200 KB).
- 세션 없이(BYOC). 상태를 자기 쪽에 두고 싶으면
sessionId 대신 arguments.context 에 상태를 넣어 부르고, 돌아온 플랜을 직접 적용합니다. 적용 규칙은 mcp-package/lib/applyPlan.js 에 있습니다.
- 모델을 3D 로. JSON 을 Spacemaker 에 열거나, 같은 저장소의
lib/export3dm.js(Rhino .3dm) 와 IFC 내보내기를 쓰면 됩니다.
- 코드 없이, 에이전트로. Claude Code 같은 MCP 에이전트에 우리 서버를 붙이면 그쪽 LLM 으로 짓습니다(우리 API 키를 쓰지 않습니다):
claude mcp add --transport http spacemaker https://spacemaker.gongvue.com/api/mcp --header "Authorization: Bearer <key>". 에이전트는 open_session 으로 세션을 열고 모든 도구에 sessionId 를 넘깁니다. 끝에 get_session 이나 save_smp.
- 키. 파트너 키는 Spacemaker 가 발급합니다. 키마다 세션은 분리됩니다(다른 키의 세션은 보이지 않습니다).
- 기록과 재생. 세션은 상태를 바꾼 호출을 전부 순서대로 기록합니다(
sessions/record). 문장은 자막으로 남깁니다(note_recording 또는 sessions/note). replay_recording 은 기록을 빈 상태에 다시 적용해 어느 순간의 모델이든 돌려주고, frames:true 면 걸음마다의 상태를 다 줍니다. 그것을 차례로 그리면 이 화면의 "재생" 입니다. 기록은 세션 밖으로 가져가 나중에, 다른 프로그램에서 재생할 수 있습니다.
- 삭제와 되돌리기. 삭제는 함수로 있습니다:
delete_shape(s), delete_opening, delete_wall, delete_furniture, delete_stair, delete_elevator, delete_roof, clear_floor_shapes, clear_floor_all. 되돌리기(undo)는 MCP 함수가 아닙니다. 호출 하나가 한 단위이므로 앱이 되돌리기를 갖습니다. Waggle 은 요청 전에 sessions/get 으로 상태를 받아 두고, 되돌릴 때 sessions/set { mode: "replace" } 로 되넣습니다. 자기 앱에서도 같은 두 줄이면 됩니다.
MCP 함수 — Waggle 이 쓰는 것
아래는 이 화면이 모델에 주는 함수입니다. 서버의 현재 정의에서 그대로 읽어 옵니다. 전체 카탈로그(약 100개)는 tools/list 로 받거나 저장소의 mcp-package/PUBLIC-API.md 를 보세요. 좌표는 모두 정규화 0..1, 길이는 cm 입니다. 세션 모드에서는 context 를 보내지 않습니다.