3줄 요약
- 웹 애니메이션 쇼케이스인
Automated Cloud Factory는 제약 및 보틀링 공정을 세밀한 건축 단면 펜화로 구현한 Canvas 2D 작업물이다. 구름 공장이라는 유머러스한 제목과 달리, 분말을 분쇄하고 로터리 타정기로 알약을 만드는 과정부터 36스테이션 회전식 병입기로 병에 담고 역운동학 로봇팔로 포장하는 과정까지 묘사한다. - 번들링되지 않은 17개 자바스크립트 파일에는 제작 과정의 흔적이 곳곳에 남아 있다. 상상만으로 좌표를 계산하기보다, 1536×1024 해상도의 원본 펜화(
ref/drawing.png)를 밑그림으로 사용했다는 흔적이다. 밑그림을 반투명하게 겹쳐 대조하면서 코드로 복원한 것으로 읽힌다. - 5단계 제작 과정에서는 컴퓨터 비전으로 단면 벽체(
poché) 폴리곤을 추출하고, 공용 제도 키트와 2관절 역운동학 인체 리그로 그림과 동작을 구현한다. 헤드리스 브라우저 시각 검증 하네스로 결과를 확인하며, 정적 그림은 오프스크린 버킷에 미리 그려 저장한다. 위상 동기화 시계는 각 동작이 같은 위상을 따르도록 맞춘다.
구름 공장이라는 농담과 제약 공정 단면도
Automated Cloud Factory(원본 사이트, 줌인아웃 및 드래그 팬을 추가한 복제본)는 건물 외벽을 인형의 집처럼 도려내고 내부 기계와 작업자들을 흑백 잉크 선화로 보여 주는 인터랙티브 웹 애니메이션이다. 지붕 위로 솟은 나뭇잎 무늬 굴뚝이 들썩거릴 때마다 해칭(평행선 음영)으로 그려진 뭉게구름이 하늘로 피어오른다. 하지만 건물을 채운 9개 구역 모듈(js/parts/*.js)의 소스 코드를 열어 보면, 이 건물은 수증기를 생성하는 시설이라기보다 제약 및 보틀링 공장(Pharmaceutical Tablet, Capsule & Bottling Plant)이다. 내부 설비는 알약과 캡슐을 성형해 병에 담고 상자에 포장한다.
시각적 양식은 데이비드 맥컬레이(David Macaulay)의 <도구와 기계의 원리(The Way Things Work)>와 스티븐 비스티(Stephen Biesty)의 단면 도해(Incredible Cross-Sections)를 따른다. 유럽의 리뉴 클레르(Ligne Claire) 건축 단면 펜화 전통도 이어받았다. 이 작업물은 사람이 손으로 일일이 좌표를 계산해 그린 개인 아트워크가 아니다. AI 에이전트 코딩 루프가 만들어 낸 산출물이다. index.html 첫머리 HTML 주석을 열어 보면 https://netlify.new/?utm_campaign=loops&utm_source=ai-legible이라는 캠페인 주소가 나온다. 에이전트가 반복 실행 루프(loops)로 고밀도 시각 코딩을 어디까지 해낼 수 있는지 시연하려고 만든 프로젝트다.1

| 공정 순서 | 구역 및 담당 모듈 | 실제 설비와 세부 동작 |
|---|---|---|
| 1. 원료 분쇄와 제어 | 상단 호퍼 홀 및 제어실 (top.js) | 분쇄기(Mill)가 원료 분말을 갈고 체인 컨베이어로 캡슐을 이송하며, 옆 제어실에서 작업자가 모니터와 레버를 조작함 |
| 2. 타정 및 캡슐 배출 | 상부 중앙 프레스 홀 (press.js) | 로터리 타정기가 둥근 알약(pillow tablet)과 4개 중 1개꼴(k % 4 === 1)의 투톤 캡슐을 홈통 컨베이어로 쏟아냄 |
| 3. 시약 실험과 슬라이드 | 우측 다락방 및 별관 (east.js) | 삼각 플라스크와 교반기, 피펫을 다루는 시약 실험실(reagent jar lab)과 우측 별관 선별대로 이어지는 대형 캡슐 미끄럼틀 |
| 4. 사일로 저장과 수작업 | 중층 좌측 사일로 홀 (silo.js) | 원뿔형 대형 사일로 2개가 스네이크 컨베이어로 알약을 배출하고, 작업대(bench)에서 작업자들이 수작업으로 병입 및 마개 결합을 수행함 |
| 5. 회전식 고속 병입 | 중층 중앙 캐러셀 홀 (fill.js) | 36스테이션 회전식 보틀 필러(N = 36)가 빈 유리병에 내용물을 채우고 캐퍼와 3관절 픽앤플레이스 로봇팔이 마개 결합 및 이송을 처리함 |
| 6. 상자 포장과 적재 | 하층 우측 포장 홀 (pack.js) | 제함기에서 세운 상자에 로봇팔 2대가 자루를 담고 스탬프 날인, 폴 스캐너 판독, 테이핑을 거쳐 팔레트에 적재함 |
| 7. 트럭 상차와 출하 | 하층 좌측 상차 도크 (dock.js) | 롤업 셔터 도어 앞에서 배기구 연기를 뿜으며 대기 중인 박스 트럭에 지게차(forklift)가 완성 팔레트를 실어 나름 |
결정적 단서: ref/drawing.png 밑그림에서 출발한 역공학
어떻게 코딩 에이전트가 수백 개의 배관과 계단, 원뿔형 사일로, 회전 타정기의 비례를 어긋남 없이 Canvas 2D 좌표로 그려냈을까. 개발용 검사 스크립트(dev.js)와 제도 키트(kit.js), 인체 리그(rigs.js)의 상단 주석을 읽어 보면 그 비결을 알 수 있다.
/* dev.js — URL switches for checking parts (loaded before the engine).
?only=a,b draw only these layer ids ("room" matches "room:worker1")
?skip=a,b hide these layer ids
?ref=0.5 overlay the original drawing
?hits outline hover areas
?hover=a,b force hover on these layers
?t=12 start every clock 12 s in
?still draw one settled frame and stop */
URL에 ?ref 쿼리 파라미터를 붙여 실행하면 dev.js 20행이 ref/drawing.png 이미지를 불러와 기본 투명도 0.5로 캔버스 위에 겹쳐 그린다.2 또한 kit.js와 rigs.js, ink.js 곳곳에 원본 정적 도면을 실측해 코드로 복원했음을 입증하는 기록이 남아 있다.
| 파일 및 위치 | 소스 코드 및 주석 기록 | 제작 공정상의 의미 |
|---|---|---|
dev.js 20행 | dev.ref = { src: 'ref/drawing.png', alpha: 0.5 } | 원본 밑그림(ref/drawing.png)을 캔버스 위에 반투명하게 겹쳐 픽셀 오차를 비교함 |
ink.js 2~6행 | All drawing happens in artboard space: 1536 × 1024, the size of the drawing. | OpenAI gpt-image-1 계열의 가로형(3:2) 기본 생성 해상도인 1536 × 1024 도면을 기준 좌표계로 삼음 |
kit.js 3~5행 | HOUSE STYLE — match the drawing: a crisp black-ink technical illustration on white, NOT a doodle. | 원본 도면에서 평면 회색 톤이 쓰인 유리창, 지붕 싱글, 타이어, 기계 하단 그림자에서만 4단계 회색(K.G1~K.G4)을 허용함 |
rigs.js 39~40행 | Measured from the drawing's people. s = 1 is exactly 50 px from the cap top to the soles. | 원본 도면에 그려진 작업자들의 키를 픽셀 단위로 실측해 모자 꼭대기부터 신발 밑창까지 정확히 50px을 기본 스케일(s = 1)로 정의함 |
이 네 가지 단서를 종합하면 전체 제작 방식이 명확해진다. 이 작업에서는 고밀도 흑백 건축 단면 일러스트인 ref/drawing.png(1536×1024)를 밑그림으로 먼저 준비했다. 빈 캔버스에 상상만으로 공장 도면을 코딩하는 대신, 컴퓨터 비전으로 도면을 분해하고 헤드리스 시각 루프로 대조하면서 벡터 Canvas 2D 코드와 절차적 애니메이션으로 복원한 것이다.

코드 흔적으로 재구성한 5단계 제작 파이프라인
17개 자바스크립트 파일의 호출 순서와 주석을 따라가면, 정적 도면 한 장을 작동하는 공장 애니메이션으로 바꾼 다섯 단계 공정이 드러난다.
1단계: 컴퓨터 비전으로 추출한 검은 단면 벽(poché) 마스크
건축 단면도를 그릴 때는 수직으로 잘린 두꺼운 벽체와 층간 슬래브 단면을 검은 잉크로 꽉 채워 칠하는데, 이를 건축 제도에서 포셰(poché)라고 한다. 작업은 파이썬 스크립트(tools/trace-poche.py)로 원본 도면에서 검은 단면 벽체 윤곽을 추출해 data-poche.js를 생성하는 데서 시작한다.
?only=poche 파라미터로 렌더링한 structure.js(z = 80)의 검은 단면 벽체 마스크. 내부 방들의 테두리를 덮어 마감하는 액자 역할을 한다.
/* data-poche.js — generated by tools/trace-poche.py:
the solid black section cut, as rings [x0,y0,x1,y1,…]
in artboard px (outer rings and holes; fill with "evenodd"). */
data-poche.js의 좌표 배열을 보면 [1296.25, 857.0, 1296.25, 946.0, 1303.75, 946.75, ...]처럼 모든 숫자의 소수부가 .0, .25, .5, .75(1/4 픽셀 단위)로 양자화되어 있다. 1536×1024 원본 이미지를 4배(6144×4096)로 확대한 뒤 OpenCV findContours 등으로 윤곽선을 검출하고, 좌표를 다시 1/4로 축소해 서브픽셀 정밀도를 확보한 흔적이다.3
structure.js는 이 검은 벽체 폴리곤을 거의 모든 레이어보다 앞선 z = 80에 배치하고 evenodd 규칙으로 검게 칠한다. 왜 굳이 벽체를 가장 나중에 그리는지 kit.js 12행 주석에 이유가 적혀 있다.
Room contents sit behind the section cut (poché, drawn on top at z 80), so draw them a few px past the cut line rather than short of it.(각 방의 내부 요소는 z=80에 그리는 단면 벽체 뒤에 가려진다. 따라서 절단선을 몇 픽셀 지나도록 그려라.)
9개의 복잡한 다각형 방 내부에 타일과 배관, 선반을 그릴 때 매번 불규칙한 벽 테두리에 맞춰 선 끝을 자르는 일은 까다롭고 오차가 나기 쉽다. 대신 검은 단면 벽체를 z = 80의 최상단 마스크로 그리면, 각 방(z = 15~79)의 선 끝을 벽 두께 내부까지 넉넉히 연장할 수 있다. 각 방을 코딩하는 세션에서 이렇게 그려도, 검은 벽체가 돌출된 선 끝을 덮어 모든 방의 이음매를 깔끔하게 마감한다.
2단계: 공용 제도 키트(ink.js, kit.js)와 역운동학 인체 리그(rigs.js)
여러 방을 개별 파일로 분리해 구현하더라도 선 굵기나 음영 방향, 캐릭터 생김새가 방마다 달라지면 한 장의 펜화로 보이지 않는다. 개별 방을 코딩하기 전에 ink.js(248줄), kit.js(981줄), rigs.js(875줄) 세 파일로 공통 그리기 규칙과 물리 연산 도구를 먼저 마련해 둔 까닭이다.
| 모듈 | 핵심 구성 요소 | 세부 사양 및 엔지니어링 원리 |
|---|---|---|
kit.js (981줄) | 팔레트, 4단계 펜 굵기, 제도 도형 | 배경 종이색(#fdfdfb), 잉크색(#151515), 4단계 무채색 회색(G1: #ecebe7~G4: #4b4a48)만 사용한다. 선 굵기는 실루엣 bold(1.4px), 일반선 line(1.0px), 세부 묘사 fine(0.7px), 해칭 hair(0.42px)로 고정한다. 좌상단 광원을 기준으로 45도 평행선 해칭을 그리는 함수(hatch, hatchRect)도 제공한다. 이 밖에 원통 음영(cylinder), 파이프(pipe), 플랜지(flange), 컨베이어 트랙(track)을 그리는 함수가 있다. |
ink.js (248줄) | 결정론적 난수, 2D 노이즈, 스프링 물리 | 매 프레임 Math.random()을 쓰면 선이 지글거리는 현상(boil)이 생긴다. 이를 방지하기 위해 시드 기반 의사난수(FAB.rand), 고정 순열 테이블(시드 1979)을 사용하는 2D 그래디언트 노이즈(FAB.noise, FAB.wobble), 감쇠 스프링 물리(FAB.spring)를 사용한다. 프레임이 바뀌어도 펜선의 질감을 안정적으로 유지하는 방식이다. |
rigs.js (875줄) | 50px 작업자 리그, 17종 포즈, 2관절 IK | 키 50px(s = 1) 기준 작업자(FAB.rig.person)에 가운, 앞치마, 셔츠 복장과 안전모 옵션을 조합하며 stand, walk, work, type, lever, carry, talk, inspect, reach, bend, push, sit, crank, point, wipe, climb, lift 등 17종 기본 동작을 내장한다. |
rigs.js (R.ik) | 코사인 법칙 해석적 역운동학 및 로봇팔 | 작업자의 손끝이 위치해야 할 목표 월드 좌표(handN, handF)만 넘기면 R.ik() 함수가 상완(upper: 6.2)과 전완(fore: 5.8) 길이로 코사인 법칙을 풀어 팔꿈치 좌표를 즉시 역산한다. 3관절 산업용 로봇팔(FAB.rig.robot)과 콜리플라워 형태의 해칭 연기 퍼프(FAB.rig.puff)도 함께 제공한다. |
이 공용 키트를 사용하면 각 방의 코드를 작성할 때 복잡한 베지어 곡선이나 삼각함수를 직접 계산할 필요가 없다. 예를 들어 작업자가 밸브 핸들을 돌리는 장면을 만들 때는 밸브 위 원운동 좌표만 계산해 handF에 넘기면 R.ik가 알아서 어깨와 팔꿈치를 자연스럽게 굽혀 손을 밸브에 고정한다.

3단계: 헤드리스 시각 대조 및 영역 크롭 하네스 (dev.js, stage.js)
제도 키트가 준비된 다음에는 각 방의 그림을 ref/drawing.png 밑그림과 대조하며 정밀하게 맞추는 시각 피드백 루프(Visual Loop) 하네스가 작동한다. dev.js와 stage.js에는 에이전트와 헤드리스 브라우저를 위해 설계된 전용 URL 스위치와 카메라 API가 들어 있다.
| 구분 | 스위치 / API | 동작 및 시각 검증 루프에서의 역할 |
|---|---|---|
| 레이어 필터 | ?only=a,b / ?skip=a,b | 특정 방이나 개별 레이어 프리픽스(예: press, fill:line)만 단독으로 켜거나 숨김 |
| 원본 오버레이 | ?ref=0.5 | 원본 도면 ref/drawing.png를 지정한 투명도(기본 0.5)로 캔버스 위에 겹쳐 픽셀 오차 확인 |
| 정지 캡처 | ?still&steps=30 | 실시간 루프를 멈추고 스프링 물리를 30프레임(0.5초) 안정화한 뒤 1프레임을 그리고 document.title = 'ready' 설정 |
| 히트박스와 호버 | ?hits / ?hover=a,b | 마우스 호버 영역을 파란색과 초록색 외곽선으로 표시하거나 특정 레이어의 호버 가속을 강제 활성화 |
| 카메라 크롭 | FAB.film(w, h) / FAB.view(x0, y0, vw) | 1536×1024 전체 도면 중 특정 방 영역 (x0, y0, vw)만 잘라내어 오프스크린 캐시 없이 순수 벡터로 선명하게 렌더링 |
| 수동 진행 | FAB.step(n, fps) / FAB.profile() | 헤드리스 하네스에서 프레임을 지정한 횟수만큼 수동 진행하거나 레이어별 평균 렌더링 소요 시간(ms) 측정 |
특히 stage.js 295~300행의 ?still 처리와 303~342행의 drawFilm() 구현은 코딩 에이전트의 시각 루프가 어떻게 실행되었는지 그대로 보여 준다. 1536×1024 전체 화면을 한꺼번에 캡처해 비전 모델에 넣으면 개별 방의 밸브나 실험 기구 디테일이 너무 작아 형태 오차를 분별하기 어렵다. 대신 FAB.film과 FAB.view(x0, y0, viewW)로 작업 중인 방 하나만 고해상도 벡터로 확대한다. 이어 ?only=press&ref=0.5&still&steps=30을 호출하고, document.title === 'ready'가 되면 헤드리스 브라우저로 화면을 캡처한다. 이렇게 저장한 이미지에서는 밑그림과 현재 코드가 일치하지 않는 부분을 픽셀 단위로 확인하고 교정할 수 있다.
4단계: 9개 방 모듈의 공간 분할과 3단계 Z-index 설계 (js/parts/*.js)
검은 단면 벽체(poché)로 구분된 구획을 따라 건물 전체를 9개의 방 파일(각 530~770줄, 30~40KB)과 1개의 벽체 파일(structure.js)로 분할했다. 각 파일 첫 줄에는 자신이 책임지는 아트보드 좌표 범위와 레이어 구성이 명시되어 있어, 다른 방의 코드를 건드리지 않고 독립적으로 구현할 수 있다.
| 모듈 (줄 수) | 담당 좌표 범위 (Artboard px) | 주요 구역 및 핵심 애니메이션 요소 |
|---|---|---|
exterior.js (664줄) | 건물 외곽 전체 (y: -120~1024) | 지붕 싱글, 들썩이는 나뭇잎 굴뚝과 해칭 연기, 회전식 루프 벤틸레이터, 외벽 그림자 |
top.js (543줄) | x 405~875, y 120~352 | 상단 호퍼 홀(진동 분쇄기, 체인 벨트 엘리베이터, 호이스트 훅) 및 우측 제어실 |
left.js (632줄) | 좌측 코어 다층 구역 | 소형 작업실, 화물 리프트 수직 통로, 사무실 칠판, 프레스 옆 로봇 셀, 창문 밖 구름, 보관 랙 |
press.js (647줄) | x 600~1000, y 295~580 | 로터리 타정기, 터렛 호퍼, 알약 및 투톤 캡슐 배출 홈통 컨베이어, 경사로 작업자 4명 |
east.js (746줄) | 동측 다락방 및 우측 별관 | 경사 지붕 아래 시약 실험실(플라스크, 교반기, 피펫팅), 계단실, 별관 물탱크와 캡슐 수취대 |
silo.js (675줄) | x 350~668, y 462~705 | 2연 원뿔형 대형 사일로(배출 게이트 진동), 스네이크 컨베이어, 수작업 병입 및 캐핑 벤치 |
fill.js (765줄) | x 596~1292, y 556~808 | 36스테이션 회전식 보틀 필러, 캐퍼, 픽앤플레이스 로봇팔, 우측 대형 투톤 캡슐 슬라이드 |
pack.js (771줄) | x 598~1186, y 736~990 | 상자 제함, 자루 투입 로봇팔 2대, 라벨 스탬프, 폴 스캐너, 테이핑 테이블, 전면 지게차 |
dock.js (539줄) | x 125~612, y 686~948 | 좌하단 상차 도크, 롤업 셔터 도어, 배기구 연기를 내뿜는 박스 트럭, 지게차와 유도 작업자 |
structure.js (22줄) | 단면 벽체 전체 (z = 80) | data-poche.js의 단면 폴리곤을 evenodd로 채우고 0.5px 외곽선으로 마감하는 포셰 마스크 |
중앙 프레스 홀(press.js), 원뿔 사일로(silo.js), 36스테이션 보틀 필러(fill.js), 다락방 시약 실험실(east.js), 하단 포장 라인(pack.js)의 확대 화면. 수만 개의 해칭 선과 역운동학 캐릭터들이 방마다 맞물려 작동한다.
각 방 내부의 레이어들은 index.html 29~39행 주석에 정리된 전역 Z-index 규약을 일관되게 따른다. 수만 개의 0.42px 해칭 선을 매 프레임 다시 그리다 보면 초당 60프레임을 유지하기 어렵기 때문에, 정적 배경과 동적 설비, 전경 차폐물을 Z-index로 명확히 분리했다.
| Z-index 구간 | 계층 분류 및 캐싱 (still) | 렌더링 방식 및 깊이감(오클루전) 설계 |
|---|---|---|
z = 0~14 | 건물 외부 배경 (exterior.js, 정적 및 동적 혼합) | 최후방 지붕과 외벽 패널(z = 2), 들썩이는 굴뚝(z = 3.5)과 그 바로 뒤에서 피어오르는 연기(z = 3.4) |
z = 15~39 | 실내 정적 배경 및 고정 설비 (still: true, 오프스크린 캐싱) | 벽면 패널, 창문, 바닥 타일, 고정 배관, 탱크 본체 등 고정된 요소다. stage.js의 buildBuckets()는 연속된 still 레이어들을 바운딩 박스(box) 크기의 오프스크린 캔버스에 최초 1회만 그려 저장한다. 이후에는 매 프레임 drawImage로 복사하므로 드로잉 연산 비용이 거의 0으로 줄어든다. |
z = 40~69 | 동적 기계, 컨베이어, 작업자 (실시간 벡터 렌더링) | 회전 타정기와 보틀 필러, 컨베이어 위 알약과 유리병, 로봇팔, 작업자(z = 55~65)를 매 프레임 시계에 맞춰 실시간으로 그림 |
z = 70~79 | 실내 전경 차폐물 (정적 및 동적 혼합) | 작업자 다리 앞의 안전 난간(top:guards, z = 72), 작업대 앞면(silo:bench, z = 72), 전면 플라스크(east:lab-flask, z = 73)를 작업자 위에 덧그려 입체감을 만든다. pack.js는 작업자 몸통을 z = 26에, 상자를 z = 42에 그린 뒤 작업자의 두 손만 z = 45에 다시 그려 손이 상자를 감싸 쥐는 효과를 낸다. |
z = 80~89 | 단면 벽체 마스크 및 외부 전경 (still: true) | z = 80에서 검은 포셰(poché) 단면 벽체가 모든 방의 테두리를 덮어 마감하고, z = 81~89에 단면 전면에 돌출된 우측 별관 지붕과 외부 물탱크가 배치됨 |
5단계: 위상 동기화 시계(L.clock)와 호버 가속(heat, boost)
화면 하단의 안내 문구(hover anything to make it work faster)처럼, 사용자가 마우스 포인터를 특정 기계나 작업자 위에 올리면 해당 구역의 작업 속도가 부드럽게 빨라진다. 이 상호작용을 지탱하는 핵심 장치가 stage.js의 레이어별 독립 시계(L.clock)와 공정 라인의 위상 동기화(Phase-locked clock) 설계다.
stage.js 201~221행의 프레임 루프에서는 포인터가 가리키는 레이어의 호버 그룹(group)을 확인한다. 같은 그룹에 속한 레이어들은 가열 상태값인 L.heat(0에서 1 사이의 실수)를 공유한다. 포인터가 진입하면 스프링 감쇠 계수 k = 4.5에 따라 hover 값이 부드럽게 증가하고, 포인터가 떠나면 k = 1.6에 따라 서서히 감소한다. 각 레이어의 진행 속도 L.speed는 1 + L.heat * L.boost로 계산되며, 기본 boost = 3일 때 평상시 속도의 최대 4배까지 가속된다.
// fill.js 25~26행: 보틀링 라인 전체가 공유하는 단일 마스터 위상(phase)
let line = null; // master layer (fill:line)
const phase = () => (line ? line.clock * V : 0);
여기서 까다로운 동기화 문제가 발생한다. 예를 들어 fill.js의 보틀링 라인에서는 빈 병 투입구, 36스테이션 회전식 필러, 마개를 씌우는 캐퍼, 병을 집어 올리는 로봇팔, 긴 컨베이어 벨트가 서로 다른 레이어로 분리되어 있다. 만약 각 레이어가 자기 시계를 따로 쓰거나 전역 시간 stage.t를 참조하면, 사용자가 마우스를 올리고 뗄 때마다 컨베이어 위의 병 위치와 로봇팔 그리퍼가 내려오는 타이밍이 어긋난다. 그러면 로봇팔이 병 대신 허공을 집게 된다.
| 공정 라인 (호버 그룹) | 마스터 시계 및 기준 속도 | 단일 위상(phase / 경로 거리 s)으로 맞물리는 하위 동작 |
|---|---|---|
보틀링 라인 (fill-line) | fill:line 레이어의 line.clock * V (V = 22.5 px/s, 병 간격 GAP = 15 px) | 빈 병 투입 간격, 36스테이션 캐러셀 회전각(CX = 742.5), 병 내부 액체 해칭 수위 상승, 캐퍼 하강(CAP_X = 839), 픽앤플레이스 로봇팔의 IK 목표 좌표(PICK_X = 890) |
포장 라인 (pack-line) | 컨베이어 벨트 시계에서 산출한 상자별 이동 거리 s (SPEED = 14 px/s, GAP = 42 px) | 상자 펼치기(BX0 = 640), 1번 로봇팔의 자루 투입(ST_DROP = 672), 2번 로봇팔의 상자 덮개 접기(ST_PRESS = 807), 라벨 스탬프(ST_LABEL = 847), 작업자의 폴 스캐너 이송 및 테이핑(ST_TAPE = 1003) |
사일로 배출 라인 (silo-feed) | silo-feed 그룹 공유 시계 | 작업자가 당기는 배출 레버 각도, 원뿔 사일로 2개의 본체 진동과 하단 게이트 개폐, 스네이크 컨베이어로 쏟아지는 알약 입자 궤적 |
모든 설비와 작업자의 위치는 마스터 레이어의 누적 시계 하나를 기준으로 결정론적 함수로 계산한다. 따라서 호버 가속과 감속이 아무리 빈번하게 일어나도 병과 상자, 로봇팔, 작업자의 손끝은 단 1픽셀도 어긋나지 않고 맞물려 작동한다.

가장 흥미로운 지점
17개 파일을 읽으며 내 시선이 머문 곳은 에이전트의 코딩 실력 자체보다 문제를 다루기 쉬운 형태로 재구성한 설계였다. 보통 1536×1024 크기의 정밀한 건축 단면 애니메이션을 코드로 짜라고 하면, 많은 이들이 거대한 단일 캔버스 루프로 수천 줄의 좌표를 직접 맞추려다 문맥 한계와 위치 오차에 가로막힌다.
반면 이 프로젝트의 파이프라인은 문제를 에이전트가 검증할 수 있는 단위로 철저히 쪼갰다. 먼저 원본 도면에서 검은 단면 벽체(poché)를 추출해 z = 80에 덮어 둠으로써, 9개의 방을 서로 간섭하지 않는 독립 작업 공간으로 분리했다. 이어서 선 굵기 4종과 해칭 함수, 50px 키의 역운동학 인체 리그를 공용 어휘(kit.js, rigs.js)로 고정해 어떤 방을 코딩하든 동일한 펜화 화풍이 나오도록 제약을 걸었다. 마지막으로 FAB.film과 ?only=...&ref=0.5&still 스위치를 통해 방 하나만 1:1로 잘라 밑그림과 겹쳐 보는 시각 루프를 실행했다. 이 코드는 정교한 에이전트 작업물을 완성하는 데 모델의 추론 능력과 함께 어떤 도구가 필요한지 보여 준다. 검증 하네스(dev.js, stage.js)로 오차를 눈으로 확인하고, 건축적 마스킹(poché)을 사용해 방마다 독립적으로 수정할 수 있었다.
출처
- 원본 사이트: Automated Cloud Factory (https://automated-cloud-factory.netlify.app/)
- 줌인아웃(마우스 휠, 핀치, 버튼) 및 드래그 팬을 추가해 복제 발행한 Pages 버전: https://pages.eiaserinnys.me/d/automated-cloud-factory
- 분석 대상 소스:
Automated Cloud Factory프로덕션 패키지(index.html및js/dev.js,js/ink.js,js/stage.js,js/kit.js,js/rigs.js,js/data-poche.js,js/main.js,js/parts/*.js등 17개 JS 파일) - 치비 서소영 삽화 4장은 「느낌적인 느낌을 숫자로 옮기는 일」의 치비 서소영 라인아트를 참조해 gpt-image-2.5-flare로 따로 생성했다.
배포된 사이트는 번들러나 난독화 도구를 거치지 않은 순수 바닐라 자바스크립트 파일 17개로 구성되어 있다.
index.html을 제외하면 총 8,491줄이다. 분석 노트에는 주석 및 공백 정리 기준으로 10,837줄 규모라고 집계되어 있다. 각 파일 상단에는 담당 좌표 범위와 레이어 번호, 설계 의도가 상세한 영문 주석으로 적혀 있어 에이전트와 사람이 함께 코드를 읽고 수정하기 좋은 구조(ai-legible)를 갖췄다. ↩︎프로덕션 배포 서버에서는 원본 파일인
ref/drawing.png가 제외되어 있어 실제로?ref=0.5를 호출하면 이미지 로더가 404 응답을 받는다. 그러나stage.js67~68행과 245~250행에는 여전히refImg를 생성해ctx.drawImage(refImg, 0, 0, W, H)로 화면 전체에 반투명하게 덮어 그리는 코드가 온전히 남아 있다. ↩︎data-poche.js의FAB.data.poche배열은 9개의 복합 폴리곤 링으로 구성되며, 꼭짓점은 총 752개다.dock.js등 각 방 모듈에는 개별 방의 구멍(hole)을 나타내는 폴리곤도 인라인으로 복사되어 있다. 이들까지 합치면 건물 전체의 단면 구획 30여 개에 해당하는 윤곽이 된다.structure.js는 이 폴리곤을 그린 뒤ctx.lineWidth = 0.5로 얇은 외곽선을 한 번 더 덧그려(soften the stair-steps of the trace) 픽셀 추적 과정에서 생긴 미세한 픽셀 단차를 부드럽게 감춘다. ↩︎
