| name | vtuber-deploy |
| description | AUTORIG rig(자체 2D 모델)를 정적 웹앱으로 빌드해 Vercel에 배포하고 OBS로 방송까지 거는 전체 파이프라인. 트리거 — "버튜버 모델 배포", "모델 남에게 주기", "방송 링크 만들기", "OBS 방송 셋업", "지피쨩/위벨 배포", "rig 웹앱화", "사용자 산출물(PLAYER)". 2026-06-15 005 지피쨩으로 end-to-end 실증 완료. |
VTuber 배포·방송 (AUTORIG-PLAYER-001)
자체 rig(rig_v0_project: character.json + parts PNG + mini_rig.json)를 동적 백엔드 0의 정적 웹앱으로 만들어 정적 호스팅(Vercel 등)에 올리고, OBS green screen 방송까지 거는 검증된 경로.
핵심 사실(2026-06-15 PoC 입증):
- 모델 뷰어·웹캠 트래킹 모두 순수 정적 호스팅으로 작동. 동적 서버 불필요 (POST는 에디터 저장·검증용뿐, 방송엔 안 씀).
- MediaPipe는 CDN, 웹캠은 클라이언트
getUserMedia, parts 경로는 상대경로(/project/)라 포터블.
- OBS 브라우저 소스는 웹캠을 못 씀(공식 한계) → 트래킹은 일반 브라우저, OBS는 그 창을 화면 캡처.
0. 빌드 전 — 그린스크린 아티팩트 청소 (2026-06-18 007 나비 실증)
OBS green screen은 부품 틈·분해 고스팅마다 초록이 비쳐 흰 구름·세로 선이 된다(흰색이라 크로마키로 안 빠짐). 베이지 배경판(일반 프리뷰)엔 가려 안 보이다 초록서 드러나니 배포 전 합성 ground truth로 점검(아래 "검증은 반드시 합성"). 보이면 분해 단계(파트 겹침 여백)에서 surgical하게 잡는다.
⚠️ deghost_front_hair.py는 LEGACY (2026-06-22) — 기본 실행 금지. face-bbox 하단 컷 휴리스틱이 긴 앞머리를 통째 삭제한다(008 나비=이마 베이지 노출 · 010 루비=앞머리 45→42 소멸, 두 번 주인님 거부 [[deghost-removes-long-front-hair]]). 2048 See-through는 halo가 적어 대개 불요. 짧은 뱅 + 풀캔버스 halo가 합성 ground truth로 실측된 단발성 경우에만 수동 1회(긴 앞머리 캐릭터 금지):
검증은 반드시 합성 ground truth로 (헤드리스 swiftshader 렌더는 **옅은 알파를 거의 안 그려 거짓 "깨끗"**을 준다 — 2026-06-18 3회 헛돔):
근본: see-through 분해가 hair_front 등 레이어에 garbage/halo 할당 → 분해 단계 정비가 진짜 해결(후속). 현재는 위 후처리.
외곽 흰 프린지(어두운 배경서 흰 윤곽)는 P4에서 defringe_white_halo.py가 자동 감쇠(DEFRINGE-HALO-001, dedup 다음). 실루엣 파트(hair/headwear/ear/clothes)의 반투명 near-matte 가장자리를 파트 코어 밝기에 상대화해 감쇠(머리색 무관·하드코딩 아님). 밝은 배경 무회귀·검정서 halo 제거 실측(2026-07-04 유키). SHOWCASE는 애초에 베이지라 안 보이지만, OBS 투명 송출 등 어두운 합성 대비.
1. 정적 웹앱 빌드
python3 scripts/build_player_webapp.py \
--project experiments/<id>/rig_v0_project \
--out /tmp/<id>_webapp \
--public-url https://<프로젝트>.vercel.app
결과: index.html·vendor/pixi·src/(앱) + project/parts/*.webp + api/project(character+mini_rig+base_url 구운 JSON) + drive.html + og.png.
- OG = 로고 + 태그라인 + 캐릭터 master 합성 카드(2026-06-25 결정, 2026-07-09 로고·태그라인 개편):
build_player_webapp.py가 좌측에 SNACK 로고 워드마크(scripts/templates/snack_logo.png — 흰배경 키잉된 투명 PNG, .gitignore 예외로 커밋됨)+브랜드 태그라인("From a single image to a live VTuber.", 2줄 자동 줄바꿈), 우측에 <project>/../generated/master.png(투명여백 크롭→높이맞춤→바닥정렬)를 합성해 og.png(1200×630) 자동 생성. 모델 무관(어떤 캐릭터든 자기 자신). twitter:card=summary_large_image. 로고 자산 없으면 --og-title 텍스트 워드마크(기본 SNACK)로 폴백, 태그라인은 --og-subtitle로 override.
- parts는 WebP q90 자동 변환(PLAYER-SHARE-002): PNG 7.2MB→~1MB(87%↓, 모바일 로딩 가속). 차원 불변이라 런타임/캔버스/좌표 안전,
source_path도 .webp로 구워짐. bbox 크롭은 캔버스 백엔드(drawImage 2048²)를 깨므로 금지 — WebP가 정답.
- 빈 파트 자동 가지치기(EMPTY-PART-PRUNE): 알파 0px 파트(없는 부위 raw_* · deghost로 비워진 hair_front 등)는 webp 미생성+파트/메시 제외(로드/텍스처 낭비 제거, 007=49→42장). ⚠️ 소스 프로젝트엔 죽은 파트가 남으니(빌드만 정리) deghost/추출 단계 정비는 후속.
- drive.html 모드 (2026-07-04 개편):
- 기본(파라미터 없음) = SHOWCASE(데스크톱·모바일 공통 — 공유 링크가 예쁜 캐릭터 풀스크린, SHOWCASE-DEFAULT-001 2026-07-04 데스크톱까지 통일). 초록은
?obs=1 방송 opt-in.
- 같은 URL, 트래커만 플랫폼별 분기: 데스크톱·안드로이드=MediaPipe, iOS=Jeeliz(아래 iOS 항목).
?clean=1 = SHOWCASE: 캐릭터 풀스크린 단색 베이지 + 수치·웹캠 프리뷰 숨김(주인님 "캐릭터만 크게") + 하단 표정 스트립(📷얼굴인식·윙크·방긋·놀람·지토·하트·눈물, EXPR-STRIP-001). ⚠️**transparent=1 금지** — 투명 캔버스가 뒤 다크 컴포짓을 비쳐 "검정 배경+흰 프린지"가 뜬다(2026-07-04 실측). clean만 주면 앱이 베이지(#f4f0e8) 칠함.
?panel=1 = 웹캠 패널·중립보정·수치(드라이버 셋업/디버그). ?obs=1 = 초록 호환.
- 카메라 자동 시작 (CAM-AUTOSTART-001, 2026-07-06): drive.html 로드 시 desktop/Android는 웹캠 얼굴 인식을 자동 시작(📷 버튼 클릭 불필요, 주인님 요청). 브라우저 카메라 권한 팝업은 그대로(못 없앰) — 사용자 클릭 한 단계만 제거. iOS Safari는 getUserMedia에 제스처 필수 + Jeeliz init-once 위험이라 자동 제외 → 대신
📷 얼굴 인식 버튼이 펄스 힌트로 탭 유도(desktop 자동시작 실패·권한 거부 시에도 동일 폴백, 켜지면 힌트 해제). ?auto=0으로 옵트아웃(관전 전용). OBS(?obs=1)도 이 공통 경로로 자동 시작.
- IDLE 제거됨(2026-07-04): 자가 애니메이션(숨쉬기·둘러봄)이 iOS 트래킹과 충돌(캐릭터 혼자 움직임)해 전역 삭제. 웹캠 전엔 정지, 실패/거부 시에도 정지(중립 스냅 없음). 표정 스트립은 유지(최신 표정만·잔상 없음).
- iOS = Jeeliz Weboji 얼굴 트래킹(2026-07-04, MediaPipe는 iOS Safari 미지원 →
if(IS_IOS) return runJeeliz()). 순수 WebGL이라 iOS 구동, 11 morph+3축을 jeelizChannels()가 기존 convert() ch로 흡수(새 어댑터 무). 튜닝=방향 S_YAW=-1·S_ROLL=1·pitch 0.15·입 floor 0.2~0.62+EMA·is_detected() 폴링 FREEZE·합성 시선([[ios-jeeliz-tracker-branch]], SPEC IOS-JEELIZ-TRACKING-001). vendor=scripts/templates/vendor/jeeliz/(Apache-2.0, build가 out/vendor/jeeliz/로 복사). 카메라 거부/실패 시에만 정지 폴백. HTTPS 필수.
- 인앱브라우저(카톡 등) 자동 감지 배너 + http 비보안 origin
getUserMedia 크래시 가드(폰 LAN http는 카메라 불가 → 관전 안내).
로컬 확인:
cd /tmp/<id>_webapp && python3 -m http.server 8077
2. Vercel 배포
cd /tmp/<id>_webapp
vercel deploy --yes --prod --scope <팀slug>
⚠️ 빌드는 디렉토리를 rmtree — 기존 프로젝트(예: nabiwebapp)에 올리려면 배포 전 링크 필수(안 하면 새 랜덤 프로젝트 생성):
vercel link --yes --project <프로젝트명> --scope <팀slug>
⚠️ Deployment Protection은 재배포마다 다시 켜진다(PLAYER-SHARE 실측) — 매 prod 배포 후 ssoProtection null PATCH를 다시 때려야 401이 안 뜬다. CLI 토큰으로:
TOKEN=$(python3 -c "import json;print(json.load(open('$HOME/Library/Application Support/com.vercel.cli/auth.json'))['token'].strip())")
TEAM=$(curl -s "https://api.vercel.com/v2/teams" -H "Authorization: Bearer $TOKEN" | python3 -c "import sys,json;print(json.load(sys.stdin,strict=False)['teams'][0]['id'])")
curl -s -X PATCH "https://api.vercel.com/v9/projects/<프로젝트명>?teamId=$TEAM" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"ssoProtection": null}'
배포 후 공유 URL = https://<프로젝트>.vercel.app/drive.html (SHOWCASE 기본, 방송은 ?obs=1 초록). OG는 /drive.html에만(루트 / 없음). ⚠️Vercel 프로젝트명 정확히: 유키=yukiwebapp001(≠yuki_webapp — 엉뚱한 프로젝트로 배포하면 클린 URL이 옛 파일 서빙). 매 prod 배포 후 ssoProtection=null PATCH 필수(§ssoProtection).
⚠️ 카톡 OG는 캐시 — 미리보기 안 바뀌면 https://developers.kakao.com/tool/clear/og에서 초기화(카카오 로그인) 또는 URL에 ?v=2 부스트.
3. OBS 방송 (macOS)
OBS 설치 위치 주의: OBS를 응용 프로그램 폴더에 설치하고 거기서 실행할 것. DMG(/Volumes/...)에서 바로 실행하면 화면 기록 권한이 안 잡혀 캡처가 까만 화면이 된다.
- 시스템 설정 → 개인정보 보호 및 보안 → 화면 기록 → OBS 켜기 → OBS 재시작
- Chrome에서
https://<프로젝트>.vercel.app/drive.html?obs=1 열기 → 카메라 허용 → green 배경 + 얼굴 트래킹 확인
- OBS → 소스 + → "macOS 화면 캡처" → 방법: 윈도우 (안 잡히면 응용 프로그램 캡처 → Google Chrome)
- 주소창 크롭: 소스 선택 → Option(⌥)+위쪽 핸들 아래로 드래그 (또는 우클릭→변환 편집→자르기 Top)
- 배경 제거: 소스 우클릭 → 필터 → 크로마키 → 초록 제거
- 방송: 설정 → 방송 → 플랫폼+스트림 키 → 우측 하단 "방송 시작"
트러블슈팅 (실제 겪은 것)
| 증상 | 원인 | 해결 |
|---|
| OBS 브라우저 소스에 모델 안 뜸/트래킹 X | 브라우저 소스는 웹캠 원천 차단 | Chrome에서 트래킹 + OBS는 화면 캡처 |
| 화면 캡처가 까만 화면 | OBS를 DMG에서 실행 | 응용 프로그램에 설치 후 실행 + 화면 기록 권한 |
| 윈도우 목록에 Chrome 없음 | 창이 다른 스페이스/전체화면 | "응용 프로그램 캡처 → Chrome" |
| 공개 URL이 401 | Vercel Deployment Protection | ssoProtection null (2단계) |
| OBS 캡처에서 모델 정지 | Chrome 창이 가려져 백그라운드 throttle | Chrome 창 보이게 두기 / chrome://flags "window occlusion" Disabled |
| 모델 위 노란 박스 | 에디터 오버레이(#overlay-canvas) | ?obs=1이 자동 숨김 (없으면 URL에 obs=1) |
| 초록 위 좌우 흰 구름 기둥 | 앞머리 분해 halo | 2048 분해는 대개 없음. 있으면 분해 단계서 정비(⚠️deghost_front_hair.py는 LEGACY — 긴 앞머리 통째 삭제, §0) |
| 목/셔츠 초록 세로선 | 목 파트가 턱보다 좁아 측면 노치 | (목 grow 도구 폐기 — 분해 단계 파트 겹침 여백으로 해결) |
| 뒤에 캐릭터 겹침 | 바디 백킹을 캐릭터색으로 실루엣보다 크게 깖 | 백킹 끄기(--backing 기본 OFF) — 후광 부작용 |
| "고쳤는데 그대로 보임" | ① CDN/브라우저 캐시 ② swiftshader 렌더가 옅은 알파 누락 | ① 고유 배포 URL(매 배포 새 hostname=캐시無)로 확인 ② 합성 ground truth로 검증(§0) |
| 재배포했는데 다시 401 | ssoProtection이 재배포마다 재활성 | 매 배포 후 PATCH 재실행(2단계) |
| 재배포했는데 clean URL이 옛 버전(고유 배포 URL엔 새 코드·alias만 옛것·age 큰 cache HIT) | <프로젝트>.vercel.app이 수동 alias라 --prod가 안 옮김(promote는 "이미 production" 409) | vercel alias set <새-배포-URL> <프로젝트>.vercel.app --scope <팀> 후 라이브 grep으로 새 마커 확인(010 루비 실측 2026-06-28) |
| 캐릭터 작음(옛 패널) | 옛 패널 레이아웃 | 기본이 SHOWCASE(데스크톱·모바일 공통 풀스크린·수치/셀프뷰 숨김·표정 스트립, SHOWCASE-DEFAULT-001) |
| 검은 배경에 흰 윤곽/프린지 | ① SHOWCASE에 transparent=1 줘 투명 캔버스가 다크 컴포짓 노출 ② See-through 실루엣 프린지 | ① clean만(transparent 금지)=앱이 베이지 단색 칠함 ② defringe_white_halo.py(P4 자동, 머리색 상대화) |
| 아이폰서 얼굴 안 움직임 | (구) MediaPipe iOS 미지원 | 이제 Jeeliz Weboji로 iOS 트래킹 작동(2026-07-04). 안 움직이면 카메라 권한/HTTPS 확인. 얼굴 없을 때 스윙=is_detected() 폴링 0.6s FREEZE로 정지, 근접 입 깜빡=floor 0.2~0.62+EMA |
| 폰서 "getUserMedia undefined" 크래시 | http LAN=비보안 origin → navigator.mediaDevices undefined | 가드로 크래시 대신 안내(관전 유지). 실제 웹캠은 배포 https(안드로이드) 또는 PC |
| 로딩 느림(preview loading) | parts 49장 2048² 풀캔버스 PNG 7.2MB | WebP q90 자동 변환(빌드, 87%↓) — bbox 크롭 금지(캔버스 백엔드 깨짐) |
| 카톡서 움직임 정지 | 인앱브라우저 getUserMedia 차단 | 인앱 감지 배너 "기본 브라우저로 열기"(자동) — 크롬/사파리서 정상 |
| 방향 반대(좌↔우) | 프리뷰 셀카 거울 vs 원본 랜드마크 구동 | convert() 수평·롤축 M=-1 반전(MIRROR-OFF-001) |
| 카톡 OG 옛 미리보기 | 카카오 OG 캐시 | developers.kakao.com/tool/clear/og 초기화 / ?v=2 |
한계 / 다음
- 진짜 2D 표준은 Live2D+VTube Studio이고, 우리는 자체 포맷 + 자체 런타임 경로(비표준). 상세 비교·로드맵:
docs/ref/vision/PRODUCTION-VISION.md.
- 현재는 완성 rig를 "전달"하는 경로. "PNG 업로드 → 즉각 모델"은 분해/생성/게이트 자동화가 선결(PRODUCTION-VISION 로드맵).