3줄 요약
- PSD Motion Lab은 일본 개발자 shinshin86(신도 유키)이 2026년 9월 17일에 공개한 MIT 라이선스 실험 배포판이다. 출발점은 하코니와(852wa)의 Anime2.5DRig다. 레이어를 나눈 PSD 캐릭터의 얼굴과 목과 상반신을 9방향으로 돌리고, 그 경로와 타이밍을 JSON으로 편집하는 로컬 웹앱이다.
- 구조는 간단하다. 9장의 방향 원화를 미리 그려 두고, 그 사이를 65×65 격자로 채운 4,225장의 자세 이미지를 배포물에 함께 넣어 두었다. 재생할 때는 지정한 경로를 60fps 좌표열로 계산하고, 그 좌표를 둘러싼 격자 이미지들을 RIFE로 다시 보간해서 동영상으로 만든다.
- 개발자는 이 배포판이 하지 못하는 일을 문서 곳곳에서 되풀이해 밝힌다. PSD 파일을 넣기만 하면 9방향이 자동으로 나오는 도구는 아니다. 립싱크와 표정과 팔 동작도 들어 있지 않다. 생성되지 않은 경로는 수십 초에서 수 분을 기다려야 하므로 실시간 얼굴 추적에도 쓸 수 없다. 동작 확인은 macOS에서만 마쳤다.
무엇을 배포한 것인가
저장소는 2026년 9월 17일에 커밋 하나로 공개된 개인 실험 프로젝트다. 이 글을 쓰는 시점에는 별도 소개문도 스타도 붙어 있지 않다. 코드는 JavaScript와 Python과 HTML을 합쳐 60KB 남짓이고, 저장소 용량의 거의 전부는 함께 넣어 둔 이미지가 차지한다.
출발점인 Anime2.5DRig는 PSD를 읽어 들여 자동으로 리그를 만들고 2.5D 애니메이션을 재생하는 프로젝트다. PSD Motion Lab은 그 PSD 로더와 자동 리깅 런타임을 가져오지 않았다. 대신 미리 만들어 둔 소재를 전용 런타임으로 재생한다. 개발자가 문서에 정리해 둔 역할 분담은 이렇다.
| 구성 요소 | 역할 |
|---|---|
| Anime2.5DRig | 출발점. PSD 읽기, 자동 리깅, 2.5D 애니메이션 |
| 이 배포판이 더한 부분 | 방향별 소재와 얼굴, 목, 상반신을 덮는 메시. 9방향 조작. 경로와 타이밍 편집. 녹화 |
| RIFE | 요청한 경로를 따라갈 프레임을 만들기 위해 가까운 자세 이미지 사이를 보간 |
들어 있지 않은 것도 문서가 하나씩 밝혀 둔다. 원본 PSD, PSD 로더, 음성, 립싱크, 표정 편집기, 팔 동작이 모두 빠져 있다. 모션을 PSD 파일로 되돌려 저장할 수는 없다. 다른 서비스에서 같은 움직임을 재현하려면 소재와 이 데이터 형식을 처리하는 재생 코드가 함께 필요하다. 모션 JSON의 형식도 Anime2.5DRig 표준 설정 JSON과 호환되지 않는다.
9방향은 어떻게 만들어졌나
개발자가 문서에 적어 둔 준비 공정은 다음과 같다. 위쪽 절반은 이미 끝나 있고, 배포판에서 실행할 수 있는 것은 아래쪽 절반이다.
소재를 준비하는 공정 (이 배포판에서는 이미 완료)
파츠를 나눈 PSD에서 뽑은 정면 이미지
→ 방향별 작화와 이미지 생성으로 편집
→ 얼굴, 목, 어깨, 몸통의 대응점과 메시
→ 65 × 65 자세 이미지 격자
배포판에서 실행할 수 있는 공정
모션 JSON / 방향 조작
→ 시각마다 x, y 계산
→ 가까운 자세 이미지를 RIFE로 보간
→ 이미지와 재생용 동영상을 로컬에 저장
→ 브라우저에서 재생, 프레임 단위 이동, 녹화
배포물에 들어 있는 기본 원화 9장은 이렇게 생겼다. 정면과 상하좌우, 그리고 네 대각선이다.
배포물 assets/의 기본 원화 9장을 내가 3×3으로 배열하고 방향 이름을 붙였다. 미코 캐릭터 이미지는 MIT 라이선스 대상이 아니며 미코 캐릭터 이용 가이드라인을 따른다. © Yuki Shindo (AITuber OnAir)
이 9장을 직접 받아서 열어 보니, 소재를 만든 과정이 파일에 그대로 남아 있었다. 정면 이미지 front.png 한 장만 배경이 투명한 PNG다. 나머지 여덟 방향은 모두 진한 초록 배경 위에 그려져 있고, 왼쪽 방향 파일은 이름부터 left-green.png다. 문서의 설명도 파일 상태와 맞는다. 정면 한 장은 PSD에서 나온 원본이고, 나머지 여덟 장은 그 뒤에 방향별로 다시 그리거나 이미지 생성으로 만든 결과다.
이 9장 사이를 채운 것이 assets/interpolated-grid/의 4,225장이다. 65×65 격자이고 WebP 형식이며 용량은 약 222MB다. 개발자는 이 격자와 실행 중에 만들어지는 RIFE 캐시가 서로 다른 것이라고 분명히 밝혀 둔다. 격자는 배포물에 이미 들어 있고, 캐시는 내가 어떤 경로를 재생하느냐에 따라 그때그때 늘어난다.
그리기 방식이 세 가지다
이 앱은 상황에 따라 세 가지 방식으로 캐릭터를 그린다.
- 메시 변형: 상하 값이 0이고 좌우로만 움직일 때는
MorphRenderer가 WebGL 메시를 변형해 그린다. 이 실험을 위해 따로 만든 렌더러이고, Anime2.5DRig 본체의 자동 리그를 그대로 부르지는 않는다. - 즉시 프리뷰: 상하나 대각선 방향에서는 격자에서 가장 가까운 이미지를 그대로 보여 준다. 조작에 곧바로 반응하지만 이미지와 이미지 사이의 단차가 보일 수 있다.
- RIFE 보간: 지정한 자세 주변의 격자 이미지를 먼저 좌우로 보간하고, 그 결과를 다시 상하로 보간한다. 경로 전체를 준비한 다음 60fps 동영상으로 재생한다. 프레임 단위 이동은 이미 만들어진 동영상의 재생 위치를 1/60초 단위로 옮기는 방식이다.
세 방식을 화면에서 나란히 비교하는 기능도 들어 있다. 「描画方式を並べて比較」, 즉 그리기 방식을 나란히 비교한다는 체크박스다.
얼굴과 목과 상반신이 한 장의 자세 이미지에 함께 들어 있기 때문에, 목만 따로 크게 돌리는 방식과는 구조가 다르다. 대신 눈과 입 같은 부위를 따로 움직이는 기능은 이 배포판에 아직 통합되지 않았다.
모션 JSON의 문법
배포물에는 샘플 경로 두 개가 들어 있다. 9방향을 차례로 도는 경로와, 대각선과 전환을 섞은 경로다. 편집하는 값은 시간에 따라 변하는 좌우와 상하의 두 좌표다. JSON은 이런 모양이다.
{
"format": "miko-xy-motion",
"name": "위를 보고 정면으로 돌아오기",
"keys": [
{ "time": 0, "x": 0, "y": 0 },
{ "time": 0.5, "x": 0, "y": 0 },
{ "time": 1.4, "x": 0, "y": 0.6 },
{ "time": 2.0, "x": 0, "y": 0.6 },
{ "time": 3.0, "x": 0, "y": 0 }
]
}
각 필드의 의미와 제약은 다음과 같다.
| 필드 | 내용 |
|---|---|
format | miko-xy-motion 고정. 기존 데이터와의 호환을 위해 유지한다 |
name | 화면에 표시할 모션 이름 |
keys[].time | 초 단위. 첫 값은 0, 이후는 중복 없는 오름차순. 최대 120초 |
keys[].x | -1이 화면 왼쪽, 0이 정면, 1이 화면 오른쪽 |
keys[].y | -1이 아래, 0이 수평, 1이 위 |
keys[].easing | 해당 키에 도달하기까지의 보간 방법. 생략하면 smooth |
control1 / control2 | bezier 구간에서 쓰는 x, y 좌표 공간의 제어점 |
좌표는 모두 -1에서 1 사이이고, 키 개수는 2개에서 1,500개까지다. 개발자는 이 수치가 측정한 각도나 도수가 아닌, 준비해 둔 자세 이미지 사이의 위치라고 덧붙인다.
보간 방법은 세 가지다. smooth는 구간의 시작과 끝에서 감속한다. 모든 키에서 멈추는 느낌이 나기 쉬워, 키를 촘촘히 놓아도 저절로 부드러워지지는 않는다. linear는 구간을 일정 속도로 이동한다. 그 대신 구간이 이어지는 지점에서 속도와 진행 방향이 급변할 수 있다. bezier는 두 제어점으로 경로를 휘게 한다. 이때 제어점에는 CSS 이징 값 대신 자세 좌표를 넣는다.
편집 화면에서 JSON을 고쳐도 배포 파일이 자동으로 덮어써지지는 않는다. 「モーションJSONを書き出す」로 따로 저장해야 한다.
설치와 저장 공간
요구 사항이 까다로운 편이다.
- macOS와 uv 0.9.21에서 확인했다. Windows와 Linux용 실행 파일 선택과 잠금 처리는 맞춰 두지 않았다.
- Python 3.12는 uv가 직접 내려받아 관리한다. 시스템 Python 설치는 필요하지 않다.
- FFmpeg이
ffmpeg명령으로 실행되어야 한다. - 브라우저는 WebGL과 H.264 재생을 지원해야 하고, 녹화에는 MediaRecorder의 WebM 지원이 필요하다.
- 이미지 생성에 CPU를 쓴다. 캐시되지 않은 짧은 전환도 수십 초가 걸리고, 긴 경로는 수 분 이상 걸린다.
설치는 uv 명령 세 줄이다. Python 다운로드와 uv 캐시를 프로젝트 안으로 묶는 환경 변수를 먼저 지정한다.
export UV_PYTHON_INSTALL_DIR="$PWD/.cache/uv-python"
export UV_CACHE_DIR="$PWD/.cache/uv"
uv sync --locked
uv run --locked python -B scripts/setup_rife.py
uv run --locked python -B scripts/serve.py --port 8012
setup_rife.py는 공식 20221029 ZIP 약 416MiB를 내려받아 SHA-256을 검증한 뒤, 실행 파일과 v4.6 모델과 라이선스만 꺼낸다. 설치된 파일은 약 35MiB이고 임시 ZIP은 지운다. 이미 설치되어 있으면 해시만 확인하고 끝낸다.
저장 공간은 세 곳에서 늘어난다. 배포물 자체가 약 233.5MB이고 그중 보간 이미지가 약 222MB다. 여기에 uv가 내려받는 Python 환경과 RIFE 도구, 그리고 재생하면서 쌓이는 cache/rife/가 더해진다. 이 디스크 캐시에는 용량 상한도 자동 삭제도 없다.
| 위치 | 내용 | 배포물 포함 |
|---|---|---|
assets/interpolated-grid/ | 자세 이미지 4,225장, 약 222MB | 포함 |
assets/*.png, data/ | 기본 원화 9장, 메시, 모션 설정 | 포함 |
.venv/, .cache/ | 격리된 Python 환경, uv가 관리하는 Python, 다운로드 캐시 | 미포함 |
tools/ | 설치 과정에서 내려받는 RIFE 실행 파일과 모델 | 미포함 |
cache/rife/ | 사용 중에 생성되는 PNG, 동영상, 관리 데이터 | 미포함 |
evidence/ | 사용자가 녹화한 WebM 파일과 렌더링 로그 | 미포함 |
설치를 마친 뒤에는 캐릭터 이미지도 녹화물도 외부로 나가지 않는다. 서버는 로컬 주소 127.0.0.1에서만 접속을 받는다.
개발자가 밝혀 둔 한계
개발자가 문서에서 가장 많은 분량을 쓴 대목은 한계 설명이다. 옮겨 보면 이렇다.
임의의 입력에 대응하는 모든 이미지를 미리 만들어 두는 방식은 아니다. 아직 생성하지 않은 이동에는 대기 시간이 있으며, 실시간 얼굴 추적을 제한 없이 따라갈 수도 없다.
「60fps」라는 표현도 준비가 끝난 뒤의 재생 속도를 말하는 것이지, 초당 60장을 생성하는 추론 속도를 뜻하지 않는다고 따로 적어 두었다. 이 밖에 문서가 밝혀 둔 한계는 이렇다.
- 실험 빌드라서 윤곽의 흐림, 머리색 차이, 작은 형태 변화가 남아 있다.
- 3D 모델이 아니므로 준비된 범위를 넘는 옆얼굴이나 뒷모습은 만들 수 없다.
- 방향 이미지와 보간 격자는 완성된 상태로만 제공하고, PSD에서 소재를 자동으로 준비하거나 격자를 다시 만드는 도구는 넣지 않았다.
- PNG만 갈아 끼우면 현재 캐릭터용 대응점과 격자가 맞지 않는다.
품질 확인 방법도 함께 적어 두었다. JSON은 따로 검증하고 렌더링 결과도 따로 확인한다. 경로를 고친 뒤에는 실제 렌더링 결과를 녹화해 시작과 중간 자세, 전환, 끝, 루프 이음매를 한 프레임씩 넘기며 본다. 확인할 항목은 얼굴과 목과 어깨의 연결, 이중으로 보이는 윤곽선, 형태나 색의 급변, 가속과 감속이다. 배포판을 만들며 확인한 범위는 새 Python 환경에서의 기동, 짧은 경로의 생성, 녹화한 120프레임 점검, 같은 경로의 캐시 재사용까지였다. 모든 경로와 환경에서의 화질과 실시간 성능은 보증 대상에 넣지 않았다고 덧붙였다.
소프트웨어와 캐릭터의 라이선스가 다르다
소프트웨어와 문서는 MIT 라이선스다. 그런데 함께 들어 있는 미코 캐릭터 이미지는 MIT 대상에서 빠져 있고, AITuber OnAir와 같은 미코 캐릭터 이용 가이드라인을 따른다. 대상은 assets/ 바로 아래의 기본 PNG 9장과 assets/interpolated-grid/의 중간 WebP 4,225장이다.
가이드라인의 골자는 이렇다. 개인과 상업 이용, 수정, 앱과 게임과 영상과 웹사이트 같은 작품에 포함한 배포는 허용한다. 소재를 단독으로 재배포하거나 소재집으로 내거나, 소재 제공을 주목적으로 재배포하는 일은 금지한다. 공식과의 관계를 허위로 내세우거나 미코의 권리와 독점적 이용권을 주장할 수도 없다. 크레딧 표기는 임의이고 표기 예는 © Yuki Shindo (AITuber OnAir)다. 개변하거나 보간한 이미지, 생성 캐시, 녹화물에도 같은 조건이 적용된다.
배포용 아카이브를 만드는 스크립트도 들어 있는데, 명시적으로 고른 코드와 문서와 입력 이미지만 담고 설치된 도구와 Python 환경과 캐시와 녹화물은 뺀다. PACKAGE_CONTENTS.json에 파일 목록과 SHA-256 해시를 적는다.
4,225라는 숫자
4,225장은 설치 과정에서 만들어지지 않는다. 개발자는 9장의 원화 사이를 65×65 격자로 미리 채운 이미지 4,225장을 만들어 두고, 그 222MB를 배포물에 통째로 넣었다. README에서 굵은 글씨를 쓴 곳도 이 대목이다.
RIFE를 CPU로 돌리면 짧은 전환에도 수십 초가 든다. 미리 계산한 결과를 배포해 첫 실행의 대기 시간을 줄인 판단은 납득이 간다. 그 대신 캐릭터를 바꾸는 비용이 커진다. 캐릭터를 바꾸려면 원화 9장을 다시 그리고, 대응점을 다시 잡고, 4,225장짜리 격자를 다시 만들어야 한다. 격자를 만드는 도구는 배포판에 없다. 그래서 이 배포판은 미코를 9방향으로 돌려 보는 앱에 머문다. 임의의 PSD 캐릭터를 9방향으로 돌려 주는 도구로는 쓸 수 없다.
문서가 한계를 길게 설명한 이유도 이 구조에서 나온다. 화면에 보이는 결과물만 보면, PSD 파일을 넣으면 캐릭터가 돌아간다고 받아들이기 쉽다. 개발자는 그 오해를 README와 부속 문서 네 편에서 반복해 막는다. 첫 커밋에 이 정도 분량의 「하지 못하는 일」 목록을 함께 올려 둔 개인 프로젝트는 흔치 않다.
출처
shinshin86 (신도 유키), PSD Motion Lab, 2026년 9월 17일 공개, MIT 라이선스. 원문: https://github.com/shinshin86/psd-motion-lab 출발점이 된 프로젝트: https://github.com/852wa/Anime2.5DRig 미코 캐릭터 이용 가이드라인: https://miko.aituberonair.com/#terms
본문에 실은 이미지 두 장은 저장소의 README 스크린샷과 assets/의 기본 원화 9장을 내가 3×3으로 배열한 것이다. 미코 캐릭터 이미지의 이용에는 위 가이드라인이 적용된다. © Yuki Shindo (AITuber OnAir)
