[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6PHA39F197G4QECYKMCSEAQ":3,"skill-same:01M6PHA39F197G4QECYKMCSEAQ":68},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":20,"linkOnly":21,"markdownContent":22,"markdownBody":23,"frontMatter":24,"refName":25,"commitSha":26,"skillDirectory":27,"forksCount":28,"repositoryHtmlUrl":29,"repositoryHomepageUrl":6,"ownerHtmlUrl":30,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":31,"install":32,"resources":45},"01M6PHA39F197G4QECYKMCSEAQ","sprite-matting",null,"스프라이트·캐릭터 애니메이션 프레임에서 배경을 제거해 투명 PNG 시퀀스를 만드는 절차. 크로마 배경 생성 → WAN i2v → 색상 키잉이 정답 경로이며, 사후 매팅(RMBG\u002FSDMatte\u002FSAM3\u002FMatAnyone)은 소스를 바꿀 수 없을 때의 차선책이다. \"누끼\", \"배경 제거\", \"투명 PNG\", \"알파 채널\", \"매팅\", \"스프라이트 시트\", \"프레임 깜빡임\", \"크로마키\" 키워드에 트리거된다.","DevelopmentDummy\u002Fclaude-play","DevelopmentDummy","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F269318128?v=4","01M6PH7WG74ND790ED9698KRBP","01M6PH7WM7KC9N0V51ZCQ43P8B",3,"MIT","https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play\u002Fblob\u002Fmain\u002Fdata\u002Fskills\u002Fsprite-matting\u002FSKILL.md",[],[18,19],"sprite matting","png","2026-11-10 10:12:30",false,"---\nname: sprite-matting\ndescription: 스프라이트·캐릭터 애니메이션 프레임에서 배경을 제거해 투명 PNG 시퀀스를 만드는 절차. 크로마 배경 생성 → WAN i2v → 색상 키잉이 정답 경로이며, 사후 매팅(RMBG\u002FSDMatte\u002FSAM3\u002FMatAnyone)은 소스를 바꿀 수 없을 때의 차선책이다. \"누끼\", \"배경 제거\", \"투명 PNG\", \"알파 채널\", \"매팅\", \"스프라이트 시트\", \"프레임 깜빡임\", \"크로마키\" 키워드에 트리거된다.\n---\n\n# 스프라이트 매팅 스킬\n\n## 핵심 원칙 — 정보를 복원하지 말고, 처음부터 넣어라\n\n흰 배경 위의 흰 옷 캐릭터에서 \"팔과 몸 사이 좁은 틈\"의 흰 픽셀이 배경인지 옷자락인지는 **이미지 안에 정보가 없다**. 사람은 문맥으로 알지만 모델은 추측한다.\n\n2026-07-26 세션에서 RMBG-2.0 \u002F SDMatte \u002F SAM3 \u002F MatAnyone 네 가지를 모두 시도했고, **넷 다 같은 자리에서 실패**했다. 모델을 바꿔서 풀 수 있는 문제가 아니다.\n\n따라서 소스를 통제할 수 있으면 **반드시 크로마 배경에서 생성**하라. 그러면 키잉이 수학적으로 정확하고 연산은 거의 0이다.\n\n## 정답 경로 (소스 생성이 가능할 때)\n\n### 1단계 — 크로마 배경 시작 프레임 만들기\n\n**t2i 모델에게 직접 크로마 배경을 요구하지 마라.** SDXL(Illustrious 계열)에 `solid magenta background, chroma key background`를 넣으면 배경에 거대한 얼굴을 그리는 등 지시를 무시한다. 실측 확인됨.\n\n대신 **Qwen-Image-Edit 2511로 배경만 교체**한다. 이건 확실하게 작동한다.\n\n- 패키지: `qwen-edit`\n- steps 4, cfg 1 (Lightning), megapixels 1\n- 프롬프트 예시:\n  ```\n  Replace the background with a completely flat, uniform, solid pure magenta color (#FF00FF).\n  Keep the girl exactly as she is - same pose, same colors, same outfit, same lineart.\n  Do not tint the character. The background must be a single flat magenta with no gradient,\n  no shading, no shadow under her feet.\n  ```\n- 결과 배경은 지시한 순색과 다소 다를 수 있다(실측: #FF00FF 요청 → 약 `(235,23,157)`). **문제없다.** 키 컬러는 결과에서 샘플링해서 쓴다.\n\n**배경색 선택 규칙**: 캐릭터 팔레트에 없는 색으로. 민트 머리 캐릭터에 초록 배경은 금지. 흰옷·살구색 피부·갈색 부츠 조합에는 마젠타 계열이 안전하다.\n\n\n### 1-B단계 — 키 색은 hue가 아니라 **색차축 부호**로 고른다 (2026-07-29, 아이린 사례)\n\n`pick_key.py`는 **색상환 점유**만 본다. 그래서 캐릭터 팔레트와 hue가 안 겹치면 통과시키는데, **키잉이 실제로 쓰는 축**이 오염되는 경우를 놓친다.\n\n실측 사례 — 진홍 머리 + 살구 피부 + 흰 옷 캐릭터(아이린):\n\n| 키 색 | 축 | 피부 alpha | 머리 alpha | 판정 |\n|---|---|---|---|---|\n| 노랑 #FFDF00 (pick_key 추천, occupied 0px) | `min(R,G) - B` | 0.927 | 0.905 | ❌ 캐릭터가 7~10% 반투명 |\n| 마젠타 #FF00FF | `min(R,B) - G` | 1.000 | 1.000 | ✅ |\n\n노랑축은 **따뜻한 색 전체가 배경과 같은 부호**를 갖는다. 붉은 머리·살구 피부가 조금씩 배경 취급을 당해 알파가 1에서 깎인다. hue는 안 겹쳐도 축이 겹치면 소용없다.\n\n**절차**: pick_key 결과는 후보로 받고, 실제 캐릭터 색 몇 개를 축 식에 넣어 **전부 `s \u003C= 0`인지 검산**한 뒤 확정한다.\n\n```python\nkey = np.array([244., 0., 186.])              # 결과에서 샘플링한 실제 배경색\nS   = min(key[0], key[2]) - key[1]\nfor name, c in [('skin',[250,206,193]), ('hair',[208,52,33]), ('white',[254,249,245])]:\n    print(name, min(c[0],c[2]) - c[1])        # 전부 음수여야 통과\n```\n\n### 2단계 — WAN i2v로 시퀀스 생성\n\n- 패키지: `wan-i2v` (Wan2.2 lightning 2-stage)\n- 프롬프트에 `the flat solid magenta background stays completely uniform and unchanged` 명시\n- 네거티브에 `gradient background, color shift` 추가\n\n**검증된 사실**: WAN은 크로마 배경을 끝까지 유지한다. 33프레임 실측에서 모서리 색 편차가 RGB 5 이내였다(f00 `(233,21,160)` → f32 `(234,21,156)`). 키 임계를 넉넉히 잡아도 안전하다.\n\n### 3단계 — 색상 키잉\n\n거리 기반 소프트 알파 + 디스필. ComfyUI 노드로 짜도 되지만 Python 후처리가 더 통제하기 쉽다.\n\n두 가지를 반드시 지켜야 한다. **알파는 색차(color difference)로 구하고, 색은 언믹싱으로 되돌린다.**\n\n#### 알파 — 유클리드 거리 키를 쓰지 마라 (가장 중요)\n\n배경색과의 RGB 거리로 알파를 구하면 **검은 라인아트 외곽이 반드시 실패한다.**\n\n애니 스타일 캐릭터의 외곽은 검은 선이고, 안티에일리어싱 때문에 선과 배경 사이에 혼합 픽셀이 생긴다. 검정과 마젠타의 50% 혼합은 `(127, 20, 88)`인데, 이 색과 키 컬러의 거리는 **126.8**이다. 전경 임계(110)를 넘어버려 **alpha 1.0인 완전 불투명 전경으로 오판**되고, 어두운 마젠타가 그대로 외곽에 남는다. 언믹싱을 아무리 잘해도 손댈 기회조차 없다.\n\n대신 **색차 키**를 쓴다. 마젠타 배경은 R·B가 높고 G가 낮다는 성질을 이용한다.\n\n```python\nkey   = np.array([233.5, 21.0, 157.0])            # 결과에서 샘플링한 실제 배경색\nS_key = min(key[0], key[2]) - key[1]              # 키의 색차값 (여기선 136)\n\ns     = np.minimum(rgb[..., 0], rgb[..., 2]) - rgb[..., 1]\nalpha = np.clip(1.0 - s \u002F (S_key * 0.92), 0, 1)   # 0.92: 배경을 확실히 0으로 밀어냄\n```\n\n검증된 응답 특성:\n\n| 픽셀 | 색차값 | alpha |\n|---|---|---|\n| 배경 | 136 | 0.00 |\n| 검정 라인 50% 혼합 | 68 | **0.50** |\n| 검정 라인 | 0 | 1.00 |\n| 흰 옷 | -3 | 1.00 |\n| 피부 | -15 | 1.00 |\n| 갈색 벨트 | -20 | 1.00 |\n\n거리 키에서 오판되던 혼합 픽셀이 정확히 0.50으로 잡힌다. 초록 배경이면 `min(R,B) - G` 대신 `G - max(R,B)` 로 축만 바꾸면 된다.\n\n#### 색 — 언믹싱으로 역산\n\n경계 픽셀은 선형 합성 결과이므로 원래 색을 되돌릴 수 있다.\n\n```\nobserved = alpha·F + (1-alpha)·key   →   F = (observed - (1-alpha)·key) \u002F alpha\n```\n\n```python\nA = np.clip(alpha, 1e-3, 1)[..., None]\nF = np.clip((rgb - (1 - A) * key) \u002F A, 0, 255)\nF = np.where(alpha[..., None] >= 0.999, rgb, F)   # 완전 불투명 영역은 원본 보존\n```\n\n**실측 개선**: 경계 마젠타 지표 66.9(뺄셈 디스필) → -12.3(거리 키 + 언믹싱) → **-11.0에 경계 픽셀 1,410 → 7,614개**(색차 키 + 언믹싱). 지표 자체보다 **경계로 인식되는 픽셀 수가 5배 늘어난 것**이 핵심이다. 이전에는 외곽의 어두운 혼합 픽셀을 아예 전경으로 오판해 보정 대상에서 빼먹고 있었다.\n\n#### 하지 말 것\n\n**스필 억제 보정을 전체 픽셀에 걸지 마라.** R·B를 G 기준으로 누르는 연산이라, 밴드 제한 없이 걸면 **갈색 벨트가 회색으로 변한다.** 색차 키를 제대로 쓰면 이 보정 자체가 대개 불필요하다.\n\n`lo`\u002F임계 계수를 올리면 잔상이 줄지만 실루엣이 깎인다. 색차 키에서는 `0.92` 계수를 만진다.\n\n**실측 결과**: 팔-허리 틈이 전 프레임에서 일관되게 투명 처리됨. 팔이 순간적으로 뚫리는 결함 사라짐.\n\n## 차선책 (소스를 바꿀 수 없을 때)\n\n기존에 만들어 둔 흰 배경 소스를 재활용해야 한다면 아래 순서.\n\n1. **단일 이미지** → 패키지 `sprite-matte`\n   - `RMBG → ThresholdMask(0.5) → GrowMaskWithBlur → JoinImageWithAlpha`\n   - 얼룩 투명화의 원인은 RMBG의 **연속 신뢰도 값을 그대로 알파로 쓰는 것**. 이진화 하나로 해결된다\n2. **프레임 시퀀스** → 패키지 `sprite-matte-seq`\n   - 첫 프레임만 시드 마스크, 나머지는 MatAnyone이 시간축 전파\n   - 시드 프레임은 **관절이 벌어진 프레임**을 고를 것. 팔이 몸에 붙은 프레임을 시드로 쓰면 그 상태가 전파되어 틈이 계속 메워진다\n\n두 방법 모두 흰옷\u002F흰배경 조합에서는 완전하지 않다. 한계를 인지하고 쓸 것.\n\n## 절대 하지 말 것\n\n| 금지 | 이유 |\n|---|---|\n| `AILab_SDMatte` | 밝은 불투명 의상을 반투명으로 오인해 몸통에 구멍을 뚫는다(11,216px 실측). 유리·연기 등 진짜 반투명 피사체 전용 |\n| `Morphology` close로 구멍 메우기 | 위상을 구분하지 않는다. 커널 9면 9px 이하 간격은 전부 닫혀서 팔-허리 사이, 목 옆 같은 **진짜 빈 공간까지 메운다** |\n| `GrowMaskWithBlur`의 `fill_holes=true` | 현 빌드에서 고장. output0이 전면 빈 마스크, output1이 전면 충만으로 나온다. 이미지 패딩 여부와 무관 |\n| `blur_radius` 1.0 이상 | 실루엣 전체에 후광이 생겨 배경 위에 올렸을 때 티가 난다. 0.5 이하 권장 |\n| MatAnyone 파라미터로 결함 잡으려 시도 | `max_mem_frames` 5→15, `use_long_term` on\u002Foff 모두 유의미한 차이 없음(손실 163px→156px). 결함의 원인은 시드 마스크지 메모리가 아니다 |\n\n## 극성 함정 (전부 실측 확인)\n\n- **RMBG의 MASK 출력(index 1)은 극성 반전** → `invert_output=true` 필요. false면 전경이 77%로 나온다. IMAGE 출력(index 0)은 정상\n- **MatAnyone은 극성을 뒤집지 않는다.** 넣어 준 시드 마스크를 그대로 따라간다. 출력이 뒤집혀 보이면 시드가 뒤집힌 것\n- **`LoadImagesFromFolderKJ`는 `image_load_cap`과 `start_index`를 명시적으로 넘겨야 한다.** optional로 선언돼 있지만 생략하면 TypeError\n\n## 검증 지표\n\n누끼 품질은 눈대중 대신 아래 수치로 판정하라.\n\n```python\nfg   = (alpha > 0.98).mean()                       # 전경 비율\nhole = (char_pixels & (alpha \u003C 0.9)).sum()         # 캐릭터인데 투명해진 곳\nover = (bg_pixels   & (alpha > 0.9)).sum()         # 배경인데 불투명한 곳\nxor  = np.logical_xor(mask[i], mask[i+1]).sum()    # 프레임간 깜빡임\nsoft = ((alpha > 0.02) & (alpha \u003C 0.98)).sum()     # 경계 밴드 폭\n```\n\n- `hole`과 `over`가 동시에 0에 가까워야 정상. 한쪽만 0인 결과는 대개 극성 오류나 과도한 이진화\n- 바닥 그림자를 캐릭터 픽셀로 오판하지 않도록 주의(그림자는 빠지는 게 맞다)\n- 프레임간 XOR은 실루엣이 실제로 변하는 구간에서 자연히 커진다. 절대값보다 **같은 클립 안에서의 비교**로 쓸 것\n\n## 관련 패키지\n\n| 패키지 | 용도 |\n|---|---|\n| `qwen-edit` | 배경을 크로마 단색으로 교체 |\n| `wan-i2v` | 크로마 시작 프레임 → 프레임 시퀀스 |\n| `sprite-matte` | 단일 이미지 사후 누끼(차선책) |\n| `sprite-matte-seq` | 시퀀스 사후 누끼, MatAnyone 전파(차선책) |\n| `rembg` | 단순 RMBG 단독(레거시) |\n\n## 환경 메모\n\n- MatAnyone: `custom_nodes\u002FComfyUI-MatAnyone` + `checkpoint\u002Fmatanyone.pth`(141MB). 의존성 `omegaconf`\n- SDMatte: 첫 실행 시 5.19GB 자동 다운로드(`models\u002FRMBG\u002FSDMatte\u002F`). 브릿지가 타임아웃 날 수 있으니 직접 큐잉으로 확인\n- ComfyUI 실사용 venv는 `comfyui_submodule\u002Fvenv` (`comfyui\u002Fvenv`는 사문)\n\n## ComfyUI 패키지로 쓰기 — `sprite-chroma-key`\n\nPython 후처리 대신 ComfyUI 안에서 끝내려면 이 패키지를 쓴다. 위 알고리즘이 커스텀 노드로 구현돼 있다.\n\n```\nLoadImagesFromFolderKJ → ChromaKeyUnmix → InvertMask → JoinImageWithAlpha → SaveImage\n```\n\n- 노드: `custom_nodes\u002FComfyUI-ChromaKeyPro`의 **`Chroma Key + Unmix`**. 외부 의존성 없음(torch만)\n- 출력 3종: `rgba` \u002F `alpha`(MASK) \u002F `rgb_unmixed`\n- `key_color_hex`를 비우면 네 모서리에서 배경색을 자동 샘플링한다\n- `key_axis`로 magenta \u002F green \u002F blue \u002F cyan 전환\n\n**기본 노드로는 만들 수 없다.** ComfyUI 코어에는 `min(R,B) - G` 같은 픽셀 단위 산술 노드가 없고, `ImageColorToMask`·`ColorToMask`는 전부 거리 기반이라 위에서 폐기한 방식과 같다.\n\n### ⚠ JoinImageWithAlpha는 MASK를 내부에서 반전시킨다\n\n`ChromaKeyUnmix`의 alpha 출력을 그대로 물리면 **전경이 78%로 나오고 배경만 남는다.** 반드시 `InvertMask`를 한 단계 끼울 것.\n\nRMBG 계열 패키지가 `invert_output=true`를 쓰는 이유도 같은 규약 때문이다. \"마스크 극성이 뒤집혔다\" 싶으면 대부분 이 노드가 범인이다.\n\n### 검증 기록\n\n패키지 출력과 Python 레퍼런스 구현의 **알파 최대 오차 0, 평균 0.0000**. 33프레임 전경 비율 18.83 \u002F 18.84 \u002F 19.86%로 일치.\n\n## 픽셀화 (스프라이트 최종 단계)\n\n크로마 키잉으로 RGBA 시퀀스를 얻은 뒤, 게임 에셋으로 만드는 결정론적 후처리. 확산 모델을 다시 쓰지 않는 것이 핵심이다 — 같은 입력에 같은 출력이 나오므로 프레임 간 깜빡임이 발생할 수 없다.\n\n### 순서\n\n```\n언샤프 프리패스 → Weber 축소 → 라인 인식 합성 → selout 외곽선 → 팔레트 고정 양자화\n```\n\n검증된 설정 (480×704 → 160×234):\n\n| 항목 | 값 |\n|---|---|\n| 축소 배율 | 1\u002F3 |\n| 언샤프 | radius 1.5, amount 1.2 |\n| Weber σ | 0.12 |\n| 라인 threshold \u002F strength | 0.13 \u002F 1.0 |\n| selout | 0.35 (순수 검정 아님) |\n| 팔레트 | 시퀀스 전체 1회 추출, MedianCut 32색, 디더링 없음 |\n\n### 반드시 지킬 것\n\n- **팔레트는 시퀀스 전체에서 1회만 추출**한다. 프레임별로 뽑으면 색이 미세하게 춤춘다. 한 프레임에서만 뽑아도 안 된다 — 다른 프레임에만 등장하는 색을 놓친다\n- **알파가 1 미만인 픽셀은 팔레트 계산에서 제외**한다. 경계 혼합색이 팔레트 항목을 낭비한다\n- **디더링은 끈다.** 패턴이 프레임마다 달라져 지글거린다\n- **격자 원점을 고정**한다. 다운스케일 오프셋이 흔들리면 픽셀이 반짝인다\n\n### 해상도가 후처리보다 중요하다\n\n8등신 캐릭터를 80px로 줄이면 눈이 2px가 된다. 어떤 알고리즘도 없는 정보를 만들지 못한다.\n\n- **치비(3~4등신)로 전환**하면 같은 해상도에서 얼굴 정보량이 3배가 된다. 픽셀 스프라이트가 전통적으로 SD 비율인 이유가 이것이다\n- 그래도 부족하면 **해상도를 올린다.** 120~160px에서 눈동자·벨트·옷 끈이 모두 읽힌다\n- 판정은 **반드시 실제 표시 크기에서** 하라. 8배 확대해서 결함을 뜯어보면 실사용과 무관한 결론이 나온다\n\n### 기여도 (실측)\n\nselout 외곽선 > 라인 인식 합성 > 팔레트 고정. **팔레트 양자화 단독은 화질 개선이 아니다** — 오히려 계단이 생긴다. 게임 톤 통일과 용량 절감이 본래 목적이며, 시퀀스에서는 색 흔들림 차단 역할을 한다.\n\n### 하지 말 것\n\n- **최빈값(mode) 축소** — 큰 면적 경계는 살아나지만 앞머리·입·눈동자 하이라이트가 투표에서 져서 소실된다\n- **픽셀 아트 모델로 저해상도 재렌더** — denoise 0.45에서 얼굴이 재생성된다. 낮추면 무효과, 높이면 정체성 붕괴. 안전지대가 없다\n- **기성 고정 팔레트(DB32 등) 직접 매핑** — 캐릭터 색이 없으면 머리가 파랗게, 부츠가 주황으로 끌려간다. 팔레트 우선 설계라면 캐릭터를 먼저 재디자인할 것\n\n### 구현\n\n`research-repo\u002Fsrc\u002Fpipeline\u002F` 의 `pix.py`(팔레트·OKLab), `lines.py`(Weber 축소·라인 합성·selout) 참조.\n\n## 크로마 키 색은 캐릭터마다 다르게 골라라\n\n마젠타나 초록을 관습적으로 쓰면 안 된다. **캐릭터가 그 색을 조금이라도 갖고 있으면 그 부분이 뚫린다.** 실측 사례: 무지개 트림이 달린 치마에서 마젠타 조각 31픽셀 때문에 밑단이 통째로 투명해졌다.\n\n### 자동 선정 절차\n\n`research-repo\u002Fsrc\u002Fpipeline\u002Fpick_key.py` 참조.\n\n1. 레퍼런스에서 채도 있는 픽셀만 추출(흰 배경·무채색 제외)\n2. 색상환 72구간 히스토그램\n3. 원형으로 감아 **연속 5구간(25°) 합이 최소인 지점**을 찾음\n4. 그 구간 중앙을 최대 채도·명도로 → hex 반환\n\n출력 hex를 **Qwen 배경 교체 프롬프트와 `ChromaKeyUnmix`의 `key_color_hex`에 동일하게** 넣는다. 그러면 생성과 키잉이 어긋나지 않는다.\n\n실측 결과 예시:\n\n| 캐릭터 | 추천 | 색상각 | 해당 구간 점유 |\n|---|---|---|---|\n| 무지개 요소 캐릭터 | `#5FFF00` | 97.5° | 48 px |\n| 흰옷·민트머리 치비 | `#FFDF00` | 52.5° | 0 px |\n| 8등신 원본 | `#F4FF00` | 62.5° | 0 px |\n\n앞의 두 캐릭터는 **노랑 계열이 완전히 비어 있었다.** 마젠타를 기본값처럼 쓰던 습관이 오히려 손해였다.\n\n### 노드의 `auto` 축\n\n`ChromaKeyUnmix`의 고정 공식 4종(magenta\u002Fgreen\u002Fblue\u002Fcyan)은 임의 배경색에 대응하지 못한다. `auto (project onto key color)`를 쓰면\n\n- 회색 성분을 제거한 채도 벡터를 **키 컬러 방향에 투영** → 밝기 무관\n- 축에서 벗어난 성분(`perp`)을 `off_axis_penalty`만큼 감점 → **인접 색상이 살아남음**\n\n연두 배경 실측: 배경 alpha 0.00, 무지개 마젠타 트림 1.00, 파란 치마 1.00, 초록 리본 0.86. 리본이 아쉬우면 `off_axis_penalty`를 올린다.\n\n## 모션 진폭 — 프롬프트로는 안 늘어난다\n\nlightning 증류 모델은 속도를 얻는 대신 모션 진폭을 잃는다. 프롬프트를 아무리 상세하게 써도 한계가 있다.\n\n| 방식 | 상체 | 하체 | 전체 | 이음새 |\n|---|---|---|---|---|\n| 기본 프롬프트 | 3.82 | 0.86 | 2.34 | — |\n| 상세 프롬프트(신체 부위별 서술) | 3.67 | 1.14 | 2.41 | — |\n| `loop=true` 단일 클립 | 4.97 | 2.33 | 3.65 | 3.70 |\n| **FLF 왕복 2클립** | **11.19** | **4.48** | **7.84** | 8.49 |\n\n- **`loop=true`는 쓰지 마라.** 시작과 끝이 같은 프레임으로 고정되면 모델이 \"크게 벗어났다 정확히 돌아오는\" 경로 대신 **\"애초에 조금만 움직이는\" 경로**를 택한다. 동작이 절반 이하로 줄어든다\n- **FLF 왕복이 정답이다.** 포즈 A와 포즈 B를 만들고 A→B, B→A 두 클립을 뽑아 이어 붙인다. 모션이 프롬프트 해석이 아니라 **기하학적으로 강제**된다\n- 포즈 B는 Qwen-Image-Edit으로 만든다. \"자세만 바꾸고 나머지는 동일하게\" 지시하면 정체성이 유지된다\n- **시작 포즈는 중립(차렷)으로.** 팔이 이미 올라가 있거나 다리가 교차된 상태로 시작하면 움직일 공간이 없다\n- 이음새는 억지로 잘라내지 마라. 프레임을 제거할수록 오히려 나빠지는 경우가 많다(12.16 → 13.99 → 16.23)\n\n## 재생 속도\n\n프레임을 솎는 것과 fps를 올리는 것은 결과가 다르다. 같은 1.8초라도\n\n- **fps 상향(64장 36fps)** — 프레임이 촘촘해 부드럽게 빨라진다. 현대적 스프라이트\n- **프레임 솎기(32장 16fps)** — 툭툭 끊겨 도트 게임 특유의 질감이 난다. 엔진 메모리에도 유리\n\n용도에 맞춰 고르되, 기본은 **원본 프레임을 다 남기고 재생 duration만 조절**하는 쪽이 안전하다. 나중에 되돌릴 수 있다.\n\n## 스프라이트시트 조립 시 — 프레임별 트림 금지 (2026-07-29)\n\n매팅이 완벽해도 조립 단계에서 애니가 튈 수 있다. 흔한 구현 실수:\n\n> 프레임마다 자기 알파 bbox로 트림 → 셀 크기에 fit → 하단중앙 앵커\n\n이러면 **팔을 들면 몸이 축소되고, 발을 들면 하단 앵커가 올라간다.** 단일 컷을 흔드는 micro-tween에서는 bbox가 안 변해 안 드러나고, 진짜 모션 프레임을 넣는 순간 터진다.\n\n**올바른 방식**\n1. 한 상태(행)의 **모든 프레임 bbox 합집합**으로 사각형을 잡는다.\n2. 전 프레임을 같은 rect·같은 배율로 자른다 → 프레임 간 상대 움직임만 남는다.\n3. 합집합은 좌우 비대칭일 수 있다(머리카락이 한쪽으로만 흩날린 프레임). 사각형 중심을 셀 중앙에 맞추면 캐릭터가 반대로 쏠린다 → **프레임별 bbox 중심의 평균**을 앵커로 셀 중앙에 놓는다. 좌우반전 행은 앵커도 반전(`tw - anchorX`).\n\n**검산**: 완성 아틀라스에서 각 셀의 알파 bbox 중심을 재라. 셀 폭의 절반 ±1px이면 정상.\n","# 스프라이트 매팅 스킬\n\n## 핵심 원칙 — 정보를 복원하지 말고, 처음부터 넣어라\n\n흰 배경 위의 흰 옷 캐릭터에서 \"팔과 몸 사이 좁은 틈\"의 흰 픽셀이 배경인지 옷자락인지는 **이미지 안에 정보가 없다**. 사람은 문맥으로 알지만 모델은 추측한다.\n\n2026-07-26 세션에서 RMBG-2.0 \u002F SDMatte \u002F SAM3 \u002F MatAnyone 네 가지를 모두 시도했고, **넷 다 같은 자리에서 실패**했다. 모델을 바꿔서 풀 수 있는 문제가 아니다.\n\n따라서 소스를 통제할 수 있으면 **반드시 크로마 배경에서 생성**하라. 그러면 키잉이 수학적으로 정확하고 연산은 거의 0이다.\n\n## 정답 경로 (소스 생성이 가능할 때)\n\n### 1단계 — 크로마 배경 시작 프레임 만들기\n\n**t2i 모델에게 직접 크로마 배경을 요구하지 마라.** SDXL(Illustrious 계열)에 `solid magenta background, chroma key background`를 넣으면 배경에 거대한 얼굴을 그리는 등 지시를 무시한다. 실측 확인됨.\n\n대신 **Qwen-Image-Edit 2511로 배경만 교체**한다. 이건 확실하게 작동한다.\n\n- 패키지: `qwen-edit`\n- steps 4, cfg 1 (Lightning), megapixels 1\n- 프롬프트 예시:\n  ```\n  Replace the background with a completely flat, uniform, solid pure magenta color (#FF00FF).\n  Keep the girl exactly as she is - same pose, same colors, same outfit, same lineart.\n  Do not tint the character. The background must be a single flat magenta with no gradient,\n  no shading, no shadow under her feet.\n  ```\n- 결과 배경은 지시한 순색과 다소 다를 수 있다(실측: #FF00FF 요청 → 약 `(235,23,157)`). **문제없다.** 키 컬러는 결과에서 샘플링해서 쓴다.\n\n**배경색 선택 규칙**: 캐릭터 팔레트에 없는 색으로. 민트 머리 캐릭터에 초록 배경은 금지. 흰옷·살구색 피부·갈색 부츠 조합에는 마젠타 계열이 안전하다.\n\n\n### 1-B단계 — 키 색은 hue가 아니라 **색차축 부호**로 고른다 (2026-07-29, 아이린 사례)\n\n`pick_key.py`는 **색상환 점유**만 본다. 그래서 캐릭터 팔레트와 hue가 안 겹치면 통과시키는데, **키잉이 실제로 쓰는 축**이 오염되는 경우를 놓친다.\n\n실측 사례 — 진홍 머리 + 살구 피부 + 흰 옷 캐릭터(아이린):\n\n| 키 색 | 축 | 피부 alpha | 머리 alpha | 판정 |\n|---|---|---|---|---|\n| 노랑 #FFDF00 (pick_key 추천, occupied 0px) | `min(R,G) - B` | 0.927 | 0.905 | ❌ 캐릭터가 7~10% 반투명 |\n| 마젠타 #FF00FF | `min(R,B) - G` | 1.000 | 1.000 | ✅ |\n\n노랑축은 **따뜻한 색 전체가 배경과 같은 부호**를 갖는다. 붉은 머리·살구 피부가 조금씩 배경 취급을 당해 알파가 1에서 깎인다. hue는 안 겹쳐도 축이 겹치면 소용없다.\n\n**절차**: pick_key 결과는 후보로 받고, 실제 캐릭터 색 몇 개를 축 식에 넣어 **전부 `s \u003C= 0`인지 검산**한 뒤 확정한다.\n\n```python\nkey = np.array([244., 0., 186.])              # 결과에서 샘플링한 실제 배경색\nS   = min(key[0], key[2]) - key[1]\nfor name, c in [('skin',[250,206,193]), ('hair',[208,52,33]), ('white',[254,249,245])]:\n    print(name, min(c[0],c[2]) - c[1])        # 전부 음수여야 통과\n```\n\n### 2단계 — WAN i2v로 시퀀스 생성\n\n- 패키지: `wan-i2v` (Wan2.2 lightning 2-stage)\n- 프롬프트에 `the flat solid magenta background stays completely uniform and unchanged` 명시\n- 네거티브에 `gradient background, color shift` 추가\n\n**검증된 사실**: WAN은 크로마 배경을 끝까지 유지한다. 33프레임 실측에서 모서리 색 편차가 RGB 5 이내였다(f00 `(233,21,160)` → f32 `(234,21,156)`). 키 임계를 넉넉히 잡아도 안전하다.\n\n### 3단계 — 색상 키잉\n\n거리 기반 소프트 알파 + 디스필. ComfyUI 노드로 짜도 되지만 Python 후처리가 더 통제하기 쉽다.\n\n두 가지를 반드시 지켜야 한다. **알파는 색차(color difference)로 구하고, 색은 언믹싱으로 되돌린다.**\n\n#### 알파 — 유클리드 거리 키를 쓰지 마라 (가장 중요)\n\n배경색과의 RGB 거리로 알파를 구하면 **검은 라인아트 외곽이 반드시 실패한다.**\n\n애니 스타일 캐릭터의 외곽은 검은 선이고, 안티에일리어싱 때문에 선과 배경 사이에 혼합 픽셀이 생긴다. 검정과 마젠타의 50% 혼합은 `(127, 20, 88)`인데, 이 색과 키 컬러의 거리는 **126.8**이다. 전경 임계(110)를 넘어버려 **alpha 1.0인 완전 불투명 전경으로 오판**되고, 어두운 마젠타가 그대로 외곽에 남는다. 언믹싱을 아무리 잘해도 손댈 기회조차 없다.\n\n대신 **색차 키**를 쓴다. 마젠타 배경은 R·B가 높고 G가 낮다는 성질을 이용한다.\n\n```python\nkey   = np.array([233.5, 21.0, 157.0])            # 결과에서 샘플링한 실제 배경색\nS_key = min(key[0], key[2]) - key[1]              # 키의 색차값 (여기선 136)\n\ns     = np.minimum(rgb[..., 0], rgb[..., 2]) - rgb[..., 1]\nalpha = np.clip(1.0 - s \u002F (S_key * 0.92), 0, 1)   # 0.92: 배경을 확실히 0으로 밀어냄\n```\n\n검증된 응답 특성:\n\n| 픽셀 | 색차값 | alpha |\n|---|---|---|\n| 배경 | 136 | 0.00 |\n| 검정 라인 50% 혼합 | 68 | **0.50** |\n| 검정 라인 | 0 | 1.00 |\n| 흰 옷 | -3 | 1.00 |\n| 피부 | -15 | 1.00 |\n| 갈색 벨트 | -20 | 1.00 |\n\n거리 키에서 오판되던 혼합 픽셀이 정확히 0.50으로 잡힌다. 초록 배경이면 `min(R,B) - G` 대신 `G - max(R,B)` 로 축만 바꾸면 된다.\n\n#### 색 — 언믹싱으로 역산\n\n경계 픽셀은 선형 합성 결과이므로 원래 색을 되돌릴 수 있다.\n\n```\nobserved = alpha·F + (1-alpha)·key   →   F = (observed - (1-alpha)·key) \u002F alpha\n```\n\n```python\nA = np.clip(alpha, 1e-3, 1)[..., None]\nF = np.clip((rgb - (1 - A) * key) \u002F A, 0, 255)\nF = np.where(alpha[..., None] >= 0.999, rgb, F)   # 완전 불투명 영역은 원본 보존\n```\n\n**실측 개선**: 경계 마젠타 지표 66.9(뺄셈 디스필) → -12.3(거리 키 + 언믹싱) → **-11.0에 경계 픽셀 1,410 → 7,614개**(색차 키 + 언믹싱). 지표 자체보다 **경계로 인식되는 픽셀 수가 5배 늘어난 것**이 핵심이다. 이전에는 외곽의 어두운 혼합 픽셀을 아예 전경으로 오판해 보정 대상에서 빼먹고 있었다.\n\n#### 하지 말 것\n\n**스필 억제 보정을 전체 픽셀에 걸지 마라.** R·B를 G 기준으로 누르는 연산이라, 밴드 제한 없이 걸면 **갈색 벨트가 회색으로 변한다.** 색차 키를 제대로 쓰면 이 보정 자체가 대개 불필요하다.\n\n`lo`\u002F임계 계수를 올리면 잔상이 줄지만 실루엣이 깎인다. 색차 키에서는 `0.92` 계수를 만진다.\n\n**실측 결과**: 팔-허리 틈이 전 프레임에서 일관되게 투명 처리됨. 팔이 순간적으로 뚫리는 결함 사라짐.\n\n## 차선책 (소스를 바꿀 수 없을 때)\n\n기존에 만들어 둔 흰 배경 소스를 재활용해야 한다면 아래 순서.\n\n1. **단일 이미지** → 패키지 `sprite-matte`\n   - `RMBG → ThresholdMask(0.5) → GrowMaskWithBlur → JoinImageWithAlpha`\n   - 얼룩 투명화의 원인은 RMBG의 **연속 신뢰도 값을 그대로 알파로 쓰는 것**. 이진화 하나로 해결된다\n2. **프레임 시퀀스** → 패키지 `sprite-matte-seq`\n   - 첫 프레임만 시드 마스크, 나머지는 MatAnyone이 시간축 전파\n   - 시드 프레임은 **관절이 벌어진 프레임**을 고를 것. 팔이 몸에 붙은 프레임을 시드로 쓰면 그 상태가 전파되어 틈이 계속 메워진다\n\n두 방법 모두 흰옷\u002F흰배경 조합에서는 완전하지 않다. 한계를 인지하고 쓸 것.\n\n## 절대 하지 말 것\n\n| 금지 | 이유 |\n|---|---|\n| `AILab_SDMatte` | 밝은 불투명 의상을 반투명으로 오인해 몸통에 구멍을 뚫는다(11,216px 실측). 유리·연기 등 진짜 반투명 피사체 전용 |\n| `Morphology` close로 구멍 메우기 | 위상을 구분하지 않는다. 커널 9면 9px 이하 간격은 전부 닫혀서 팔-허리 사이, 목 옆 같은 **진짜 빈 공간까지 메운다** |\n| `GrowMaskWithBlur`의 `fill_holes=true` | 현 빌드에서 고장. output0이 전면 빈 마스크, output1이 전면 충만으로 나온다. 이미지 패딩 여부와 무관 |\n| `blur_radius` 1.0 이상 | 실루엣 전체에 후광이 생겨 배경 위에 올렸을 때 티가 난다. 0.5 이하 권장 |\n| MatAnyone 파라미터로 결함 잡으려 시도 | `max_mem_frames` 5→15, `use_long_term` on\u002Foff 모두 유의미한 차이 없음(손실 163px→156px). 결함의 원인은 시드 마스크지 메모리가 아니다 |\n\n## 극성 함정 (전부 실측 확인)\n\n- **RMBG의 MASK 출력(index 1)은 극성 반전** → `invert_output=true` 필요. false면 전경이 77%로 나온다. IMAGE 출력(index 0)은 정상\n- **MatAnyone은 극성을 뒤집지 않는다.** 넣어 준 시드 마스크를 그대로 따라간다. 출력이 뒤집혀 보이면 시드가 뒤집힌 것\n- **`LoadImagesFromFolderKJ`는 `image_load_cap`과 `start_index`를 명시적으로 넘겨야 한다.** optional로 선언돼 있지만 생략하면 TypeError\n\n## 검증 지표\n\n누끼 품질은 눈대중 대신 아래 수치로 판정하라.\n\n```python\nfg   = (alpha > 0.98).mean()                       # 전경 비율\nhole = (char_pixels & (alpha \u003C 0.9)).sum()         # 캐릭터인데 투명해진 곳\nover = (bg_pixels   & (alpha > 0.9)).sum()         # 배경인데 불투명한 곳\nxor  = np.logical_xor(mask[i], mask[i+1]).sum()    # 프레임간 깜빡임\nsoft = ((alpha > 0.02) & (alpha \u003C 0.98)).sum()     # 경계 밴드 폭\n```\n\n- `hole`과 `over`가 동시에 0에 가까워야 정상. 한쪽만 0인 결과는 대개 극성 오류나 과도한 이진화\n- 바닥 그림자를 캐릭터 픽셀로 오판하지 않도록 주의(그림자는 빠지는 게 맞다)\n- 프레임간 XOR은 실루엣이 실제로 변하는 구간에서 자연히 커진다. 절대값보다 **같은 클립 안에서의 비교**로 쓸 것\n\n## 관련 패키지\n\n| 패키지 | 용도 |\n|---|---|\n| `qwen-edit` | 배경을 크로마 단색으로 교체 |\n| `wan-i2v` | 크로마 시작 프레임 → 프레임 시퀀스 |\n| `sprite-matte` | 단일 이미지 사후 누끼(차선책) |\n| `sprite-matte-seq` | 시퀀스 사후 누끼, MatAnyone 전파(차선책) |\n| `rembg` | 단순 RMBG 단독(레거시) |\n\n## 환경 메모\n\n- MatAnyone: `custom_nodes\u002FComfyUI-MatAnyone` + `checkpoint\u002Fmatanyone.pth`(141MB). 의존성 `omegaconf`\n- SDMatte: 첫 실행 시 5.19GB 자동 다운로드(`models\u002FRMBG\u002FSDMatte\u002F`). 브릿지가 타임아웃 날 수 있으니 직접 큐잉으로 확인\n- ComfyUI 실사용 venv는 `comfyui_submodule\u002Fvenv` (`comfyui\u002Fvenv`는 사문)\n\n## ComfyUI 패키지로 쓰기 — `sprite-chroma-key`\n\nPython 후처리 대신 ComfyUI 안에서 끝내려면 이 패키지를 쓴다. 위 알고리즘이 커스텀 노드로 구현돼 있다.\n\n```\nLoadImagesFromFolderKJ → ChromaKeyUnmix → InvertMask → JoinImageWithAlpha → SaveImage\n```\n\n- 노드: `custom_nodes\u002FComfyUI-ChromaKeyPro`의 **`Chroma Key + Unmix`**. 외부 의존성 없음(torch만)\n- 출력 3종: `rgba` \u002F `alpha`(MASK) \u002F `rgb_unmixed`\n- `key_color_hex`를 비우면 네 모서리에서 배경색을 자동 샘플링한다\n- `key_axis`로 magenta \u002F green \u002F blue \u002F cyan 전환\n\n**기본 노드로는 만들 수 없다.** ComfyUI 코어에는 `min(R,B) - G` 같은 픽셀 단위 산술 노드가 없고, `ImageColorToMask`·`ColorToMask`는 전부 거리 기반이라 위에서 폐기한 방식과 같다.\n\n### ⚠ JoinImageWithAlpha는 MASK를 내부에서 반전시킨다\n\n`ChromaKeyUnmix`의 alpha 출력을 그대로 물리면 **전경이 78%로 나오고 배경만 남는다.** 반드시 `InvertMask`를 한 단계 끼울 것.\n\nRMBG 계열 패키지가 `invert_output=true`를 쓰는 이유도 같은 규약 때문이다. \"마스크 극성이 뒤집혔다\" 싶으면 대부분 이 노드가 범인이다.\n\n### 검증 기록\n\n패키지 출력과 Python 레퍼런스 구현의 **알파 최대 오차 0, 평균 0.0000**. 33프레임 전경 비율 18.83 \u002F 18.84 \u002F 19.86%로 일치.\n\n## 픽셀화 (스프라이트 최종 단계)\n\n크로마 키잉으로 RGBA 시퀀스를 얻은 뒤, 게임 에셋으로 만드는 결정론적 후처리. 확산 모델을 다시 쓰지 않는 것이 핵심이다 — 같은 입력에 같은 출력이 나오므로 프레임 간 깜빡임이 발생할 수 없다.\n\n### 순서\n\n```\n언샤프 프리패스 → Weber 축소 → 라인 인식 합성 → selout 외곽선 → 팔레트 고정 양자화\n```\n\n검증된 설정 (480×704 → 160×234):\n\n| 항목 | 값 |\n|---|---|\n| 축소 배율 | 1\u002F3 |\n| 언샤프 | radius 1.5, amount 1.2 |\n| Weber σ | 0.12 |\n| 라인 threshold \u002F strength | 0.13 \u002F 1.0 |\n| selout | 0.35 (순수 검정 아님) |\n| 팔레트 | 시퀀스 전체 1회 추출, MedianCut 32색, 디더링 없음 |\n\n### 반드시 지킬 것\n\n- **팔레트는 시퀀스 전체에서 1회만 추출**한다. 프레임별로 뽑으면 색이 미세하게 춤춘다. 한 프레임에서만 뽑아도 안 된다 — 다른 프레임에만 등장하는 색을 놓친다\n- **알파가 1 미만인 픽셀은 팔레트 계산에서 제외**한다. 경계 혼합색이 팔레트 항목을 낭비한다\n- **디더링은 끈다.** 패턴이 프레임마다 달라져 지글거린다\n- **격자 원점을 고정**한다. 다운스케일 오프셋이 흔들리면 픽셀이 반짝인다\n\n### 해상도가 후처리보다 중요하다\n\n8등신 캐릭터를 80px로 줄이면 눈이 2px가 된다. 어떤 알고리즘도 없는 정보를 만들지 못한다.\n\n- **치비(3~4등신)로 전환**하면 같은 해상도에서 얼굴 정보량이 3배가 된다. 픽셀 스프라이트가 전통적으로 SD 비율인 이유가 이것이다\n- 그래도 부족하면 **해상도를 올린다.** 120~160px에서 눈동자·벨트·옷 끈이 모두 읽힌다\n- 판정은 **반드시 실제 표시 크기에서** 하라. 8배 확대해서 결함을 뜯어보면 실사용과 무관한 결론이 나온다\n\n### 기여도 (실측)\n\nselout 외곽선 > 라인 인식 합성 > 팔레트 고정. **팔레트 양자화 단독은 화질 개선이 아니다** — 오히려 계단이 생긴다. 게임 톤 통일과 용량 절감이 본래 목적이며, 시퀀스에서는 색 흔들림 차단 역할을 한다.\n\n### 하지 말 것\n\n- **최빈값(mode) 축소** — 큰 면적 경계는 살아나지만 앞머리·입·눈동자 하이라이트가 투표에서 져서 소실된다\n- **픽셀 아트 모델로 저해상도 재렌더** — denoise 0.45에서 얼굴이 재생성된다. 낮추면 무효과, 높이면 정체성 붕괴. 안전지대가 없다\n- **기성 고정 팔레트(DB32 등) 직접 매핑** — 캐릭터 색이 없으면 머리가 파랗게, 부츠가 주황으로 끌려간다. 팔레트 우선 설계라면 캐릭터를 먼저 재디자인할 것\n\n### 구현\n\n`research-repo\u002Fsrc\u002Fpipeline\u002F` 의 `pix.py`(팔레트·OKLab), `lines.py`(Weber 축소·라인 합성·selout) 참조.\n\n## 크로마 키 색은 캐릭터마다 다르게 골라라\n\n마젠타나 초록을 관습적으로 쓰면 안 된다. **캐릭터가 그 색을 조금이라도 갖고 있으면 그 부분이 뚫린다.** 실측 사례: 무지개 트림이 달린 치마에서 마젠타 조각 31픽셀 때문에 밑단이 통째로 투명해졌다.\n\n### 자동 선정 절차\n\n`research-repo\u002Fsrc\u002Fpipeline\u002Fpick_key.py` 참조.\n\n1. 레퍼런스에서 채도 있는 픽셀만 추출(흰 배경·무채색 제외)\n2. 색상환 72구간 히스토그램\n3. 원형으로 감아 **연속 5구간(25°) 합이 최소인 지점**을 찾음\n4. 그 구간 중앙을 최대 채도·명도로 → hex 반환\n\n출력 hex를 **Qwen 배경 교체 프롬프트와 `ChromaKeyUnmix`의 `key_color_hex`에 동일하게** 넣는다. 그러면 생성과 키잉이 어긋나지 않는다.\n\n실측 결과 예시:\n\n| 캐릭터 | 추천 | 색상각 | 해당 구간 점유 |\n|---|---|---|---|\n| 무지개 요소 캐릭터 | `#5FFF00` | 97.5° | 48 px |\n| 흰옷·민트머리 치비 | `#FFDF00` | 52.5° | 0 px |\n| 8등신 원본 | `#F4FF00` | 62.5° | 0 px |\n\n앞의 두 캐릭터는 **노랑 계열이 완전히 비어 있었다.** 마젠타를 기본값처럼 쓰던 습관이 오히려 손해였다.\n\n### 노드의 `auto` 축\n\n`ChromaKeyUnmix`의 고정 공식 4종(magenta\u002Fgreen\u002Fblue\u002Fcyan)은 임의 배경색에 대응하지 못한다. `auto (project onto key color)`를 쓰면\n\n- 회색 성분을 제거한 채도 벡터를 **키 컬러 방향에 투영** → 밝기 무관\n- 축에서 벗어난 성분(`perp`)을 `off_axis_penalty`만큼 감점 → **인접 색상이 살아남음**\n\n연두 배경 실측: 배경 alpha 0.00, 무지개 마젠타 트림 1.00, 파란 치마 1.00, 초록 리본 0.86. 리본이 아쉬우면 `off_axis_penalty`를 올린다.\n\n## 모션 진폭 — 프롬프트로는 안 늘어난다\n\nlightning 증류 모델은 속도를 얻는 대신 모션 진폭을 잃는다. 프롬프트를 아무리 상세하게 써도 한계가 있다.\n\n| 방식 | 상체 | 하체 | 전체 | 이음새 |\n|---|---|---|---|---|\n| 기본 프롬프트 | 3.82 | 0.86 | 2.34 | — |\n| 상세 프롬프트(신체 부위별 서술) | 3.67 | 1.14 | 2.41 | — |\n| `loop=true` 단일 클립 | 4.97 | 2.33 | 3.65 | 3.70 |\n| **FLF 왕복 2클립** | **11.19** | **4.48** | **7.84** | 8.49 |\n\n- **`loop=true`는 쓰지 마라.** 시작과 끝이 같은 프레임으로 고정되면 모델이 \"크게 벗어났다 정확히 돌아오는\" 경로 대신 **\"애초에 조금만 움직이는\" 경로**를 택한다. 동작이 절반 이하로 줄어든다\n- **FLF 왕복이 정답이다.** 포즈 A와 포즈 B를 만들고 A→B, B→A 두 클립을 뽑아 이어 붙인다. 모션이 프롬프트 해석이 아니라 **기하학적으로 강제**된다\n- 포즈 B는 Qwen-Image-Edit으로 만든다. \"자세만 바꾸고 나머지는 동일하게\" 지시하면 정체성이 유지된다\n- **시작 포즈는 중립(차렷)으로.** 팔이 이미 올라가 있거나 다리가 교차된 상태로 시작하면 움직일 공간이 없다\n- 이음새는 억지로 잘라내지 마라. 프레임을 제거할수록 오히려 나빠지는 경우가 많다(12.16 → 13.99 → 16.23)\n\n## 재생 속도\n\n프레임을 솎는 것과 fps를 올리는 것은 결과가 다르다. 같은 1.8초라도\n\n- **fps 상향(64장 36fps)** — 프레임이 촘촘해 부드럽게 빨라진다. 현대적 스프라이트\n- **프레임 솎기(32장 16fps)** — 툭툭 끊겨 도트 게임 특유의 질감이 난다. 엔진 메모리에도 유리\n\n용도에 맞춰 고르되, 기본은 **원본 프레임을 다 남기고 재생 duration만 조절**하는 쪽이 안전하다. 나중에 되돌릴 수 있다.\n\n## 스프라이트시트 조립 시 — 프레임별 트림 금지 (2026-07-29)\n\n매팅이 완벽해도 조립 단계에서 애니가 튈 수 있다. 흔한 구현 실수:\n\n> 프레임마다 자기 알파 bbox로 트림 → 셀 크기에 fit → 하단중앙 앵커\n\n이러면 **팔을 들면 몸이 축소되고, 발을 들면 하단 앵커가 올라간다.** 단일 컷을 흔드는 micro-tween에서는 bbox가 안 변해 안 드러나고, 진짜 모션 프레임을 넣는 순간 터진다.\n\n**올바른 방식**\n1. 한 상태(행)의 **모든 프레임 bbox 합집합**으로 사각형을 잡는다.\n2. 전 프레임을 같은 rect·같은 배율로 자른다 → 프레임 간 상대 움직임만 남는다.\n3. 합집합은 좌우 비대칭일 수 있다(머리카락이 한쪽으로만 흩날린 프레임). 사각형 중심을 셀 중앙에 맞추면 캐릭터가 반대로 쏠린다 → **프레임별 bbox 중심의 평균**을 앵커로 셀 중앙에 놓는다. 좌우반전 행은 앵커도 반전(`tw - anchorX`).\n\n**검산**: 완성 아틀라스에서 각 셀의 알파 bbox 중심을 재라. 셀 폭의 절반 ±1px이면 정상.\n",{"name":5,"description":7},"main","87c4e526fb2dfb2c6bfeeb9f901d6320fcb457ec","data\u002Fskills\u002Fsprite-matting",0,"https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play","https:\u002F\u002Fgithub.com\u002FDevelopmentDummy","2026-10-07 22:33:19",{"source":8,"skillName":5,"commands":33,"prompt":43,"zipAvailable":44},[34,37,40],{"tool":35,"command":36},"npx","npx skills add DevelopmentDummy\u002Fclaude-play --skill sprite-matting",{"tool":38,"command":39},"bunx","bunx skills add DevelopmentDummy\u002Fclaude-play --skill sprite-matting",{"tool":41,"command":42},"pnpm","pnpm dlx skills add DevelopmentDummy\u002Fclaude-play --skill sprite-matting","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play\u002Fblob\u002Fmain\u002Fdata\u002Fskills\u002Fsprite-matting\u002FSKILL.md",true,[46,52,56,60,64],{"path":47,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":50,"sourceHtmlUrl":51},"scripts\u002Fchroma_key_pro.py","SCRIPT","脚本",6708,"https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play\u002Fblob\u002Fmain\u002Fdata\u002Fskills\u002Fsprite-matting\u002Fscripts\u002Fchroma_key_pro.py",{"path":53,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":54,"sourceHtmlUrl":55},"scripts\u002Flines.py",2330,"https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play\u002Fblob\u002Fmain\u002Fdata\u002Fskills\u002Fsprite-matting\u002Fscripts\u002Flines.py",{"path":57,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":58,"sourceHtmlUrl":59},"scripts\u002Fpick_key.py",2202,"https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play\u002Fblob\u002Fmain\u002Fdata\u002Fskills\u002Fsprite-matting\u002Fscripts\u002Fpick_key.py",{"path":61,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":62,"sourceHtmlUrl":63},"scripts\u002Fpix.py",2705,"https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play\u002Fblob\u002Fmain\u002Fdata\u002Fskills\u002Fsprite-matting\u002Fscripts\u002Fpix.py",{"path":65,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":66,"sourceHtmlUrl":67},"scripts\u002FREADME.md",1265,"https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play\u002Fblob\u002Fmain\u002Fdata\u002Fskills\u002Fsprite-matting\u002Fscripts\u002FREADME.md",[69,94,108,127,137,146],{"skillNo":70,"name":71,"nameZh":6,"description":72,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":73,"categories":74,"keywords":83,"publishedAt":20},"01M6PHD8Y8CNRBG3FR2ZAHWX5J","generate-video","claude-play-bridge MCP 서버로 영상을 생성한다. 로컬 ComfyUI의 영상 워크플로 패키지(MiniMax H3 = 영상+오디오 동시 생성, WAN 2.2 i2v, Z-Image→영상)를 호출한다. 렌더가 수 분~수십 분 걸리므로 async 큐잉 + 파일 폴링이 기본 절차다. \"영상\", \"동영상\", \"비디오\", \"video\", \"i2v\", \"t2v\", \"클립 만들어\", \"움직이는\", \"애니메이션 영상\" 요청에 트리거된다.","https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play\u002Fblob\u002Fmain\u002Fscripts\u002Fexternal-package\u002Fskills\u002Fgenerate-video\u002FSKILL.md",[75,80],{"categoryNo":76,"categoryName":77,"taxonomyType":78,"taxonomyTypeDesc":79},"01JBSEEDCAT000000000000016","图像与多媒体","SCENARIO","使用场景",{"categoryNo":81,"categoryName":82,"taxonomyType":78,"taxonomyTypeDesc":79},"01JBSEEDCAT000000000000023","Skill与智能体开发",[84,85,86,87,88,89,90,91,92,93],"Video","generate","generate video","MCP","image","play","bridge","minimax","async","minimax h3",{"skillNo":95,"name":96,"nameZh":6,"description":97,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":102,"publishedAt":20},"01M6PHD3MAQ9QYQQFG50WBP5JZ","generate-image","claude-play-bridge MCP 서버로 이미지를 생성한다. 기본 백엔드는 ComfyUI(로컬 GPU, 워크플로 패키지 기반)이고, 사용자가 명시적으로 요청할 때만 GPT\u002FGemini 백엔드를 사용한다.","https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play\u002Fblob\u002Fmain\u002Fscripts\u002Fexternal-package\u002Fskills\u002Fgenerate-image\u002FSKILL.md",[100,101],{"categoryNo":76,"categoryName":77,"taxonomyType":78,"taxonomyTypeDesc":79},{"categoryNo":81,"categoryName":82,"taxonomyType":78,"taxonomyTypeDesc":79},[103,85,88,90,87,104,89,105,106,107],"generate image","gemini","gpu","gpt","comfyui",{"skillNo":109,"name":110,"nameZh":6,"description":111,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":115,"publishedAt":20},"01M6PHD0134XK1NQNK4YMZB2E1","generate-image-openai","OpenAI\u002FGPT 이미지 생성(GPT Image 품질 \u002F 텍스트 렌더링·이미지 편집 강점). 기본 백엔드는 Codex CLI 구독(건당 과금 없음). ⚠️ 사용자가 이 백엔드를 명시적으로 지정했을 때만 사용한다(예 \"GPT로\u002FOpenAI로 그려줘\"). 기본 이미지 생성은 generate-image(ComfyUI)이며, 사용자가 콕 집어 요청하지 않았다면 절대 OpenAI를 자동으로 선택하지 마라.","https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play\u002Fblob\u002Fmain\u002Fdata\u002Ftools\u002Fopenai\u002Fskills\u002Fgenerate-image-openai\u002FSKILL.md",[114],{"categoryNo":76,"categoryName":77,"taxonomyType":78,"taxonomyTypeDesc":79},[116,103,117,85,88,118,119,120,121,122,106,123,124,125,107,126],"generate image openai","openai","렌더링","cli","이미지","codex","codex cli","Bash","read","write","텍스트",{"skillNo":128,"name":129,"nameZh":6,"description":130,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":131,"categories":132,"keywords":133,"publishedAt":20},"01M6PHCTMBPTG56KMK8VH5SCTE","generate-spritesheet","Gemini 이미지 생성으로 게임용 아이콘 스프라이트시트를 만들고 자동 슬라이스한다. 아이콘, UI 리소스, 뱃지, 마커 등 여러 개의 동일 카테고리 에셋이 필요할 때 사용한다.","https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play\u002Fblob\u002Fmain\u002Fdata\u002Ftools\u002Fgemini\u002Fskills\u002Fgenerate-spritesheet\u002FSKILL.md",[],[134,85,104,135,123,124,125,136,120],"generate spritesheet","ui","edit",{"skillNo":138,"name":139,"nameZh":6,"description":140,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":141,"categories":142,"keywords":144,"publishedAt":20},"01M6PHCPR07KYS2RPNZER9WS2S","generate-image-gemini","Gemini API로 이미지를 생성한다. 패널 배경, UI 리소스, 아이콘, 장면 삽화 등 디자인 리소스 제작에 사용한다. ComfyUI가 없을 때의 이미지 생성 대안이기도 하다.","https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play\u002Fblob\u002Fmain\u002Fdata\u002Ftools\u002Fgemini\u002Fskills\u002Fgenerate-image-gemini\u002FSKILL.md",[143],{"categoryNo":76,"categoryName":77,"taxonomyType":78,"taxonomyTypeDesc":79},[145,104,88,85,103,125,124,123,135,120],"generate image gemini",{"skillNo":147,"name":148,"nameZh":6,"description":149,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":150,"categories":151,"keywords":156,"publishedAt":20},"01M6PHCJD7S7KT64BB9F215TP6","workflow-research","새 ComfyUI 워크플로우를 설계하거나 신규 모델, 양자화 모델, LoRA 개발 전략을 비교할 때 분석 틀을 잡는다.","https:\u002F\u002Fgithub.com\u002FDevelopmentDummy\u002Fclaude-play\u002Fblob\u002Fmain\u002Fdata\u002Ftools\u002Fcomfyui\u002Fskills\u002Fworkflow-research\u002FSKILL.md",[152,155],{"categoryNo":153,"categoryName":154,"taxonomyType":78,"taxonomyTypeDesc":79},"01JBSEEDCAT000000000000021","资料检索与研究",{"categoryNo":81,"categoryName":82,"taxonomyType":78,"taxonomyTypeDesc":79},[157,158,159,107,124,160],"workflow","research","workflow research","LoRA"]