3줄 요약
- StandRig은 2026년 9월 9일에 공개된 Apache-2.0 오픈소스다. 파츠가 분리된 PSD를 읽어 2D 캐릭터 리그를 만들고 브라우저에서 재생하는 로컬 엔진이다. 사람이 마우스로 메시를 편집하는 대신, MCP에 연결한 AI 클라이언트가 수치 연산으로 편집하도록 설계했다.
- 모든 편집은 트랜잭션 하나를 통과한다. 직전 리비전의 SHA-256 해시와 QA 명세를 함께 보내야 하고, 시험 실행을 먼저 돌려 보고서를 확인한 뒤에야 확정할 수 있다. 확정 직전에 롤백용 체크포인트가 자동으로 만들어진다.
- 이 도구가 못 하는 일은 집요할 만큼 여러 번 밝혀져 있다. 자동 파츠 분리, 이미지 생성, moc3 변환은 제공하지 않는다. 숫자 QA를 통과한 것이 결과물이 완성됐다는 증거는 아니라는 경고도 문서 여러 곳에 되풀이된다.
무엇을 하는 물건인가
작성자는 sayaka-aiart이고, 저장소는 개발자용 초기판 0.2.0이다. TypeScript로 쓰였고 22계열에서는 Node.js 22.12 이상, 24계열에서는 24 이상에서 동작한다. 실행하면 http://127.0.0.1:5180에 로컬 서비스가 뜨고, 브라우저 화면에서 PSD를 읽거나 동봉된 도형 샘플을 열 수 있다.
프로젝트는 프로그램 세 개로 구성되고, 이 저장소에 들어 있는 것은 본체뿐이다.
| 구성 | 배포 형태 | 담당 |
|---|---|---|
| StandRig 본체 | 이 저장소 | PSD 읽기, 모델링, 숫자 QA, 브라우저 재생, 모델 내보내기 |
| StandRig Connect | 별도 저장소, 0.1.0 개발 프리뷰 | 카메라로 얼굴과 시선과 입을 추적, 윈도우 단독 재생, OBS 출력 |
| Cubism API Bridge | 별도 저장소 | Cubism Editor에서 모델 정보를 읽고 일시적으로 자세를 바꾸는 어댑터 |
본체가 받는 입력은 PSD 한 가지다. 그리기 내용이 있는 이미지 레이어가 두 장 이상 필요하고, PNG 직접 읽기, 통합된 한 장짜리 PSD, PSB, 자동 파츠 분리는 지원하지 않는다. README는 레이어 수만으로는 애니메이션에 적합한 분리인지 판정할 수 없다고 덧붙인다.
읽어들인 결과는 레이어의 초기 배치까지다. 완성된 리그가 따라 나오지는 않는다. 움직임은 그다음에 사람이나 AI가 만들어야 한다. README가 굵은 글씨로 적어 둔 문장이 이것이다.
PSD를 읽어들이는 것만으로는 완성된 움직임이 붙지 않습니다.
AI를 어떻게 연결하는가
MCP 서버는 로컬 서비스와 별개의 프로세스로 실행된다. 서비스를 먼저 띄워 두고, AI 클라이언트가 stdio로 packages/mcp/src/cli.mjs를 실행하는 구조다. 설정에는 command에 node를, args에 그 파일의 절대 경로를, STANDRIG_URL에 로컬 서비스 주소를 넣는다. STANDRIG_URL은 루프백 HTTP 출처만 받아들이고 리다이렉트를 따라가지 않는다.
연결하면 standrig_ 접두어가 붙은 도구 13개가 보인다.
| 도구 | 하는 일 |
|---|---|
standrig_context | 첫 조회. 현재 모델의 압축 요약과 리비전 |
standrig_changes | 알고 있는 리비전 이후의 변경 폴링 |
standrig_inspect | 파츠, 디포머, 정의, 검증, 모델링 감사, 포즈, 기법, 추정 역할 |
standrig_modeling_transaction | 시험 실행 또는 QA 게이트를 통과한 확정. 확정 전 체크포인트 자동 생성 |
standrig_qa_check | 저장된 리비전에 대한 숫자 QA |
standrig_render | 240픽셀 스냅샷 한 장, 실패 이미지, QA 이후의 참조 대조표 |
standrig_checkpoint | 영속 체크포인트 생성과 목록 |
standrig_restore | 리비전을 확인하고 복원. 현재 모델을 먼저 다른 체크포인트로 저장 |
standrig_export | 자립형 번들을 쓰고 로컬 경로를 반환 |
standrig_playback_state | 일시 파라미터, 재생 상태, 출력 연결 |
standrig_playback_parameters | 모델을 고치지 않고 자세와 표정만 입력 |
standrig_motion | 네이티브 모션 JSON 읽기, 재생, 일시정지, 정지, 탐색, 설정 |
standrig_playback_control | 재생, 일시정지, 초기화, 재적재, 데모 시작과 정지 |
Cubism Bridge까지 연결하면 standrig_bridge_status, standrig_bridge_read, standrig_bridge_pose 세 개가 더 늘어난다.
MCP 리소스도 여덟 개를 노출한다. 첫 두 개가 standrig://docs/contract와 standrig://docs/guide이고, 앞의 것은 저장소의 AGENTS.md를 그대로 내보낸 것이다. 도구가 자신의 운용 계약서를 에이전트에게 함께 건네는 셈이다. docs/MCP.md는 클라이언트가 MCP 리소스를 읽지 못하면 대응하는 로컬 파일을 대신 주라고 하면서, 계약서를 건너뛰지는 말라고 단언한다.
README에 실린 첫 지시문 예시는 이렇게 생겼다.
StandRig의 MCP 리소스 standrig://docs/contract와 standrig://docs/guide를 읽어 주세요. standrig_context로 현재 모델을 확인하고, 파츠 구성과 설정된 움직임을 설명해 주세요. 아직 모델은 변경하지 마세요.
편집 한 번의 주기
한 부위를 고치는 절차는 여덟 단계로 적혀 있다. 요약하면 이렇다.
- 먼저
GET /api/changes?since=REVISION을 불러 그동안의 변경을 확인한다.resyncRequired가 참이면 문맥을 다시 읽는다. 저널은 메모리에만 있어서 서비스를 재시작하면 재동기화가 필요할 수 있다. - 대상 파츠의 역할과 ID를 확인한다. 역할 추정은 제안일 뿐이고, 파일 이름만 보고 정체를 단정해서는 안 된다.
- 트랜잭션 JSON을 쓴다.
expectedRevision,commit:false, 비어 있지 않은operations, 명시적인qa가 모두 필수다. /api/modeling/transaction에 보내고ok,committed,validation.ok,physicsSafety.pass,qa.ok,qa.failed를 각각 확인한다. 시험 실행이 돌려주는revisionAfter는 후보 값이므로 다음expectedRevision값으로 사용하면 안 된다.- 저장된 리비전이 그대로인지 확인한다. QA가 실패하면 실패한 영역의 이미지만 요청한다. 기본값은 240픽셀 크기의 전후 비교와 차분이다.
- 체크포인트를 만든다. 게이트를 통과한 뒤 저장 직전에 서비스가 자동으로 생성하기도 한다.
- 숫자 검사를 통과하고 허가를 받았으면 같은 본문을
commit:true로 다시 보낸다. 실패한 QA 항목을 목록에서 빼거나 허용 오차를 키워 억지로 통과시켜서는 안 된다. - 저장된 모델로 QA를 다시 돌리고, 실제 최대 자세를 렌더링해 목표 이미지와 눈으로 비교한다.

HTTP와 MCP는 같은 계약 패키지를 쓴다. packages/core/src/operationRegistry.ts 하나에서 35개의 액션 변형을 생성한다. 이들은 type으로 구분되는 합집합을 이루고, 중첩된 객체에 모르는 키가 섞이면 거부한다. 잘못된 요청은 로컬 HTTP 서비스로 가기 전에 MCP 경계에서 거부된다. 문서가 든 예시는 columns에 문자열 "five"를 넣은 경우로, 숫자 타입 오류로 잡힌다.
리비전 충돌은 409, 게이트 실패는 422로 돌아온다. 구 방식의 쓰기 API는 기본값에서 꺼져 있으며, 호출하면 403을 반환한다. 판정 기준도 한 마디로 적혀 있다. 응답 코드가 200이더라도 ok가 거짓이면 그 요청은 실패한 것이고, committed가 거짓이면 편집이 저장되지 않은 것이다.
브러시 여섯 가지와 확장 블렌드 셰이프
deform-brush는 결정적으로 동작하는 2D 변형 연산자 여섯 개를 제공한다. 마우스로 문지르는 브러시 UI를 뜻하지 않는다. 숫자로 호출하는 API다.
| 효과 | 필수 항목 | 의미 |
|---|---|---|
| smooth | strength 0에서 1 | 참조 메시를 기준으로 변위를 매끄럽게 만든다 |
| relax | strength 0에서 1 | 내부 점을 이웃 쪽으로 재배치하고 경계는 고정한다 |
| inflate | 음수가 아닌 distance | 중심에서 바깥으로 방사상으로 민다 |
| pinch | strength, 0이 아닌 axis | 중심을 지나는 축 방향의 선으로 끌어당긴다 |
| bend | angle -180에서 180도, 0이 아닌 axis | 반지름을 브러시 반경과 각도에서 유도해 원호로 휜다 |
| contour-follow | strength, 순서가 있는 vertexIds, guide | 연결된 경계를 호 길이 기준으로 가이드에 맞춘다 |
모든 요청에는 center, 양수 radius, 1에서 50 사이 정수인 iterations, 양수 maxDisplacement, falloff, surface, destination이 함께 필요하다. 이 한도를 반복 횟수마다 새로 주어지는 여유로 읽으면 틀린다. 최대 변위는 이번 연산 전체에서 한 점이 움직일 수 있는 총량을 말한다. 같은 연산을 다시 부르면 편집이 또 한 번 쌓인다. 같은 값을 다시 설정하는 멱등 연산으로 동작하지 않는다.
삼각형이 뒤집히거나 퇴화하면 연산 전체를 거부한다. 잠긴 정점과 보호된 파츠는 그대로 둔다. 결과 보고서 deformReports는 변경된 점의 개수, 최대 변위, 잘린 점의 개수, 최소 삼각형 면적 비율, 잠긴 점의 개수를 담는다. docs/DEFORM.md는 이것을 숫자 증거로만 취급하라고 명시한다. 눈으로 합격시킨 결과와 혼동하지 말라는 뜻이다.
blend-shape-set은 파츠, 디포머, ArtPath, Glue에 소유자 국소 셰이프를 붙인다. 한 소유자당 셰이프는 최대 128개, 한 점이 가질 수 있는 바인딩은 최대 16개다. 이동과 핀 오프셋은 픽셀, 회전은 도, 스케일은 곱하는 배율이다. 더하는 차이로 읽으면 값이 틀어진다. 스케일 채널은 가중치 w에 대해 scaleX의 w 제곱을 곱한다. 나머지 채널에는 델타에 w를 곱한 값을 더한다. 셰이프를 지우는 전용 연산은 아직 없어서, 체크포인트로 되돌리거나 채널을 0으로 덮어써야 한다.
문서가 거듭 밝히는 한계
이 저장소에서 가장 자주 반복되는 문장 형태는 “이것은 저것의 증거가 아니다"이다.
AGENTS.md는 PSD에 첫 모델링 쓰기를 하기 전에 프로젝트 안에 목표 이미지 세 벌을 만들어 두라고 요구한다. 첫째는 얼굴 클로즈업 시트로, 중립과 좌우 회전, 상하 회전, 기울기의 최대치를 담는다. 둘째는 전신 시트로, 같은 축의 최대치를 담는다. 셋째는 접합부 시트다. 접합부란 머리카락 뿌리와 뒷머리, 턱과 목, 목과 옷깃과 어깨, 소매와 팔, 허리와 치마와 허벅지, 허벅지와 종아리를 가리킨다. 여기에 매니페스트를 나란히 저장한다. 매니페스트에는 원본 리비전과 해시, 패널 순서, 의도한 파라미터 극값, 프롬프트, 합격 기준을 적는다.

그런데 같은 문서가 곧바로 조건을 하나 더 단다. 트랜잭션 엔드포인트는 이 매니페스트를 자동으로 검사하지 않으며 이미지를 판정하지도 않는다. 엔드포인트가 성공을 돌려주었다고 해서 시각 게이트까지 통과했다고 볼 수는 없다. 게이트를 지키는 일은 운용자의 의무다.
MCP 서버에는 이미지 생성 도구도, 임의 파일 쓰기 도구도 없다. 필요한 참조 그림은 AI 클라이언트가 가진 별도의 파일과 이미지 도구로 준비하거나 사용자가 건네야 한다. AI_OPERATING_GUIDE.md는 standrig_render를 불렀다는 것만으로 참조 자료를 만들었다고 주장하지 말라고 도구 이름까지 적어 경고한다.
같은 종류의 경고가 문서 여기저기에서 되풀이된다. 클라이언트에 도구 목록이 떠 있어도 서비스와 연결됐다고 단정할 수 없다. connectedOutputs는 열린 SSE 연결의 수만 나타낸다. 프레임이 그려졌다는 뜻은 아니다. 골든 목록이 비어 있다면 비교할 기준선이 없다는 뜻이므로, 회귀 검사를 통과한 상태로 볼 수 없다. 숫자 QA는 필요조건일 뿐, 모델 프리즈의 충분조건은 아니다.
아예 구현하지 않은 범위도 따로 적어 두었다. cmo3와 moc3의 변환과 재생, 이미지 한 장에서 파츠를 자동으로 나누는 기능, 클라우드 호스팅, 다중 사용자 서비스는 없다. 얼굴 추론과 카메라 접근과 OBS 제어는 외부로 넘겼다. Live2D의 .motion3.json도 아직 읽지 못하고, 네이티브 StandRig 모션 JSON만 받는다.
그 밖의 구성
재생 상태는 메모리에만 있다. 슬라이더를 움직이거나 외부에서 수치를 넣어도 키폼이나 rig.json에 쓰이지 않는다. 여러 입력원이 같은 파라미터를 건드리면 파라미터별로 마지막에 받아들인 값이 이긴다. 섞거나 우선순위를 매기는 스케줄러는 아직 없다.
저장 위치의 기본값은 workspace/다. 현재 작업 모델은 workspace/public/rig.json, 복원점은 workspace/checkpoints/, 내보낸 번들은 workspace/exports/, 운용자가 만든 목표 시트는 workspace/references/에 들어간다. 데이터 폴더 하나는 서비스 프로세스 하나가 소유한다. 같은 폴더를 두 프로세스가 함께 쓰면 안 된다. npm start -- --data-dir로 다른 폴더를 지정하면 모델마다 별도의 작업 공간을 쓸 수 있다.
내보내기는 두 가지다. 일반 모델 JSON은 외부 이미지 참조가 남을 수 있어서, 다른 환경으로 옮길 때는 이미지를 포함한 형식을 쓴다. 9월 13일 커밋에서 이 형식의 확장자를 .srig로 정했다. 모델 JSON의 요청 크기는 64 MiB를 넘을 수 없고, 이미지를 함께 담으면 원본 PSD보다 커질 수 있다.
9월 12일에는 실험 단계의 WebGL 재생 경로가 추가됐다. ArtMesh 정점과 로컬 Warp 격자와 공유 Warp 격자를 GPU로 그리고, ArtPath와 클리핑과 블렌드 합성은 여전히 Canvas를 쓴다. docs/GPU_PLAYBACK.md는 이것을 하이브리드 렌더러라고 부르며, 완전한 GPU 씬 컴포지터나 GPU 물리 엔진으로 오해하지 말라고 덧붙인다.
개발 속도와 검증 기록
첫 커밋이 9월 9일, 마지막 커밋이 9월 13일이다. 닷새 동안 커밋 22개가 쌓였다. 앞쪽에서는 쓰기 경계 강화와 타입 구분 액션 레지스트리 생성, 브러시와 확장 블렌드 셰이프, Warp 키폼 출력이 들어갔다. 뒤쪽에서는 네이티브 모션 재생, Cubism Bridge 연결, 실험 GPU 재생, 이미지를 함께 담는 모델 내보내기가 이어졌다. 이 글을 쓰는 시점의 별은 50개, 포크는 8개다.
docs/VALIDATION.md는 변경마다 무엇을 어디까지 확인했는지를 날짜별로 남긴다. 검사 개수가 회차마다 늘어나는 것이 보인다. 초기의 스모크 검사 16개와 Node 테스트 13개에서 시작해, 브러시가 들어간 회차에서 33개, Warp 키폼에서 38개, 파츠 선택자 정리에서 40개가 됐다. 실제 브라우저 검사도 따로 기록한다. 한 장짜리 PSD를 실제 파일 선택 창에서 골라 거부되는 것을 확인했고, 두 장짜리 PSD에서는 파츠 3개와 에셋 2개가 잡히는 것을 확인했다.
README 화면을 만들 때 쓴 캐릭터 PSD는 게재 허가를 받은 것이고, 읽어들인 결과는 파츠 140개와 에셋 118개였다. 그러면서 같은 기록은 이 화면이 PSD를 자동으로 리깅했다는 주장도, 기존 제품 리그의 움직임을 재현했다는 주장도 아니라고 덧붙인다. 동봉되어 실행할 수 있는 샘플은 여전히 도형으로 만든 봇이다.
내가 곱씹은 대목
이 저장소를 읽으면서 오래 남은 것은 기능 목록보다 문서의 말투였다. 대부분의 기술 문서는 무엇을 할 수 있는지 설명하는 데 지면을 쓴다. 반면 StandRig 문서는 분량의 절반 가까이를 “이 성공이 무엇의 증거가 되지 못하는지"에 쓴다. HTTP 200 응답이 와도 실패일 수 있고, 도구 목록이 보여도 연결된 것이 아니며, 숫자 검사를 통과해도 그림이 완성된 것은 아니라는 식이다.

이 말투는 사람 독자를 향한 것이 아니다. 성공 판정을 서둘러 내리고 넘어가는 독자, 그러니까 AI 에이전트를 향한 것이다. 그래서 운용 계약서를 MCP 리소스로 노출해 연결 직후에 읽히도록 만들고, 첫 지시문 예시에 “아직 모델은 변경하지 마세요"를 넣어 두었다. 도구를 만드는 사람이 그 도구를 쓸 에이전트의 실패 방식을 먼저 헤아린 다음, 그 내용을 문서에 담아 함께 배포한 결과다.
MCP 서버를 제공하는 도구는 이미 많다. 그중에서 에이전트가 자기 결과를 과장하는 경향까지 설계 대상으로 삼은 예는 드물다. 캐릭터 리깅은 숫자 검사를 통과해도 그림이 어긋난 모습이 바로 눈에 띄는 분야다. 그래서 이 경계를 다른 분야보다 일찍 문서로 옮겨 적었을 것이다.
출처
이 글은 sayaka-aiart가 2026년 9월 9일에 공개한 StandRig 0.2.0을 읽고 정리했다. 라이선스는 Apache-2.0이다. 원문: https://github.com/sayaka-aiart/StandRig
함께 읽은 저장소 문서는 README.md, AGENTS.md, AI_OPERATING_GUIDE.md, docs/MCP.md, docs/ARCHITECTURE.md, docs/OPERATIONS.md, docs/DEFORM.md, docs/PSD.md, docs/MOTION.md, docs/GPU_PLAYBACK.md, docs/VALIDATION.md다.
저장소의 docs/images/character-preview.jpg에 실린 캐릭터 그림은 Apache-2.0 적용 대상이 아니어서 이 글에 옮기지 않았다. 대신 본문 삽화는 「느낌적인 느낌을 숫자로 옮기는 일」의 치비 서소영 라인아트를 참조해 gpt-image-2.5-flare의 image-to-image 방식으로 생성했다.
