바로 아래에서 붓질을 하고 있는 로봇 팔, 저건 사실 지난 글에 썼던 피처 이미지입니다. 그때는 z-image로 뽑은 정지된 한 장이었는데, 이번엔 그 그림이 붓을 움직이고 카메라가 천천히 밀고 들어와요. 같은 사내 서버에서, 이번엔 Wan 2.2라는 영상 모델로 그 정지 이미지를 움직이게 만든 겁니다.

지난 글의 로봇 팔 이미지가 Wan 2.2 i2v로 움직이는 클립

지난 글의 피처 이미지였던 로봇 팔 페인팅 컷을, 이번엔 Wan 2.2 i2v로 움직이게 했다. 정지 이미지가 그대로 첫 프레임이 되고 붓질과 카메라 푸시인만 새로 생성된다. (웹 임베드용 GIF라 로딩이 잠깐 걸릴 수 있다.)

지난 글에서 “정지 이미지를 자동으로 만드는 파이프라인”을 소개했으니, 다음 질문은 자연스럽게 “그럼 움직이게도 되나?”였습니다. 미리 말해두면, 이건 이미지 쪽처럼 매일 굴리는 완성된 자동화가 아닙니다. 짬을 내서 처음 제대로 돌려본 첫 실험에 가까워요. 그래서 이 글의 숫자들도 “정상 운영값”이 아니라 “첫 측정값”입니다.

이미지 다음이 왜 영상이었나

지난 글(ComfyUI로 블로그 이미지를 자동 생성하는 파이프라인)의 요지는 단순했습니다. 글을 쓰면 이미지는 사내 ComfyUI 서버가 알아서 그리게 만들어, “이번 글 이미지 뭐 넣지”라는 고민을 없앤 것. 그게 어느 정도 자리를 잡으니 다음으로 손이 간 게 영상이었습니다.

이유는 두 가지였어요. 하나는 순수한 호기심 — 정지 이미지를 뽑는 그 서버에 영상 모델을 얹으면 그대로 움직이는 결과가 나올까? 다른 하나는 실용이었습니다. 이미 좋은 정지컷을 뽑는 파이프라인이 있으니, 그 컷을 첫 프레임으로 삼아 움직임만 입히면(i2v) 이미지 자산을 그대로 재활용할 수 있겠다는 계산이었죠.

다만 성숙도는 한참 다릅니다. 이미지는 매일 굴리는 파이프라인이지만, 영상은 아직 “돌려보고 결과를 눈으로 검수하는” 탐색 단계예요. 그래서 이 글은 완성된 영상 자동화 시스템을 자랑하는 글이 아니라, 첫 세션에서 뭘 봤고 뭐가 걸렸는지를 풀어놓는 경험담입니다.

왜 클라우드(Sora·Veo·Kling)가 아니라 로컬 Wan 2.2였나

영상이 필요하면 요즘 제일 쉬운 길은 클라우드입니다. OpenAI Sora 2, 구글 Veo, Kling, Runway 같은 서비스에 프롬프트를 넣으면 되니까요. 품질도 로컬 오픈모델보다 위고, 무엇보다 소리까지 만들어 줍니다.

가격을 보면 이렇습니다. 변동이 잦은 시장이라 전부 각 서비스 공개가 기준이고, 초당 단가는 해상도·티어에 따라 달라집니다.

서비스 대략 단가(공개 기준) 비고
OpenAI Sora 2 $0.10 / 초 720p, OpenAI 공식 문서
OpenAI Sora 2 Pro $0.30 / 초 720p, OpenAI 공식 문서
Google Veo 3.1 $0.05~0.40 / 초 티어별, 상위는 오디오 포함, 2차 출처
Kling 3.0 $0.10 / 초 안팎 구독 병행, 2차 출처
로컬 Wan 2.2 클립당 추가 과금 0 전력·하드웨어는 별도

Sora 2가 초당 $0.10, Pro가 $0.30인 건 OpenAI 공식 문서에 박혀 있는 숫자이고, 나머지는 2차 출처라 “~기준”으로만 받아들이시는 게 맞습니다. Runway처럼 클립·구독 단위로 과금하는 서비스까지 넣으면 대략 초당 $0.05~0.40 언저리예요. 5초짜리 한 클립이면 서비스·품질에 따라 몇십 센트에서 몇 달러까지죠. 로컬은 클립당 추가 과금이 0입니다. 물론 전기와 하드웨어는 이미 가진 자원이고, 정확한 손익분기 숫자는 (지난 글에서 이미지로 그랬듯) 여기서도 계산하지 않겠습니다. 전력·감가를 정확히 대지 않으면 그 숫자는 지어낸 게 되니까요.

제가 로컬을 고른 건 사실 단가 때문이 아니었습니다. 이유는 지난 글의 이미지 때와 똑같아요 — 마음껏 재생성, 프리셋·시드·프롬프트의 완전한 통제, 외부로 안 나가는 프라이버시, 그리고 내 스크립트가 API를 직접 때리는 자동화 친화성. 여기에 영상만의 이유가 하나 더 붙습니다. 클라우드 모델은 조용히 바뀌고 사라진다는 거예요. 실제로 Sora 2 API 문서를 보면 특정 스냅샷(sora-2-2025-12-08)이 이미 Deprecated로 표시돼 있습니다. 반면 Apache 2.0 오픈웨이트는 한 번 받아두면 계속 내 것이에요. 약관이 바뀌든 서비스가 종료되든 상관없이요.

대신 로컬의 약점도 분명합니다. 클립당 분 단위로 느리고, 소리를 못 만들고(무음 클립입니다), 품질·일관성은 Sora나 Veo 최상위엔 못 미칩니다. 이건 뒤에서 실측과 함께 더 짚겠습니다.

Wan 2.2를 사내 ComfyUI에 얹기

Wan 2.2는 알리바바가 2025년 7월 28일에 공개한 오픈소스 영상 생성 모델입니다. 라이선스가 Apache 2.0이라 상업적으로 자유롭게 쓸 수 있고 — 모델도, 만들어낸 영상도 — 이게 블로그처럼 결과물을 상업적으로 쓰는 입장에선 꽤 중요합니다. (물론 입력 이미지의 저작권이나 인물 초상권은 별개 책임이라는 건 이미지 글에서 짚은 그대로고요.)

구조에서 재미있는 건 MoE(전문가 혼합)를 영상 확산모델에 가져온 부분입니다. 우리가 쓴 14B(A14B) 모델은 전문가가 둘이에요. 확산 과정의 앞부분, 그러니까 형태를 잡는 시끄러운(high-noise) 단계를 맡는 전문가와, 뒷부분에서 디테일을 다듬는 조용한(low-noise) 단계를 맡는 전문가로 나뉩니다. 전체 파라미터는 약 27B이지만 한 스텝에서 실제로 도는 건 14B뿐이라, 품질은 키우면서 추론 비용은 14B급으로 눌렀다는 게 요지예요. 실제로 우리 워크플로우도 high-noise → low-noise 2단계로 샘플링합니다.

시점을 하나 짚고 갈게요. 지금이 2026년 7월인데도, 로컬에 받아서 돌릴 수 있는 최신 공식 오픈웨이트 Wan 영상 모델은 여전히 Wan 2.2입니다. 후속인 2.5, 2.6은 알리바바 클라우드 API로 넘어갔고 오픈웨이트는 공개되지 않았어요. 로컬 유저 입장에선 Wan 2.2가 사실상 현역 최신인 셈이죠. (일부 사이트가 “Wan 2.7 오픈웨이트”를 언급하지만 공식 배포처엔 없어서, 아직 확인되지 않은 이야기입니다.)

셋업은 새로 서버를 세운 게 아니라, 지난 글에서 이미지용으로 굴리던 그 사내 ComfyUI(0.18.1, RTX 5090)에 Wan 2.2 14B를 얹은 겁니다. 공식 VRAM 요구치는 14B 기준 80GB로 데이터센터급이지만, 커뮤니티가 쓰는 fp8 양자화를 얹으면 24GB급 소비자 카드에서도 실용적으로 돕니다. 우리는 32GB 5090에서 fp8로 별문제 없이 돌았어요. (VRAM을 얼마나 먹었는지 실측은 안 해서, “32GB 카드에서 문제없이 돌았다” 이상은 말하지 않겠습니다.) 클라이언트 흐름도 이미지 때와 판박이입니다. 워크플로우를 JSON으로 내보내 /prompt에 큐잉하고, /history를 폴링하다가 결과가 뜨면 mp4를 내려받는 식. i2v일 때만 입력 이미지를 /upload/image로 먼저 올리는 단계가 하나 추가됩니다.

t2v vs i2v: 직접 돌려본 차이

영상 생성엔 크게 두 갈래가 있습니다. t2v(text-to-video)는 텍스트 프롬프트만으로 처음부터 영상을 만드는 방식이고, i2v(image-to-video)는 정지 이미지 한 장을 첫 프레임으로 놓고 거기에 움직임만 입히는 방식이에요.

t2v부터 돌려봤습니다. 블로그 이름이 birdspring이니, 프롬프트도 거기 맞춰 “봄에 꽃가지에서 날아오르는 작은 파랑새, 슬로모션, 부드러운 아침 빛, 새를 따라가는 카메라”로 줬어요. 결과는 640×640·81프레임(16fps라 약 5초)짜리 클립이 47초 만에 나왔습니다.

벚꽃 가지에서 날아오르는 파랑새 — Wan 2.2 t2v로 생성한 클립

텍스트 프롬프트만으로 만든 t2v 데모. 블로그 이름(birdspring)에 맞춘 “봄 가지에서 날아오르는 파랑새”로, 640×640·81프레임(≈5초)이 47초 만에 나왔다.

t2v는 자유롭지만 복불복입니다. 텍스트만 주니 구도가 어떻게 나올지 뽑기 전엔 알 수 없어요. 반면 i2v는 이미 마음에 든 구도에서 출발하니 훨씬 통제가 쉽습니다. 바로 이 지점이 지난 글의 이미지 파이프라인과 예쁘게 이어져요 — 좋은 정지컷을 뽑는 능력이 이미 있으니, 그걸 첫 프레임으로 넘기면 되거든요. 그래서 이 글 맨 위의 로봇 팔 클립도 t2v가 아니라 i2v로 만든 겁니다. 지난 글의 피처 이미지를 그대로 첫 프레임으로 넣은 거죠.

세 번의 실험을 표로 정리하면 이렇습니다. 전부 오늘 하루에 연속으로 돌린, 이 글의 유일한 실측치예요.

실험 방식·프리셋 해상도 / 프레임 생성 시간 mp4 크기
A t2v 고속 (4-step) 640×640, 81f 47초 595KB
B i2v 고속 (4-step) 832×464, 81f 45초 320KB
C i2v 고품질 (20-step) 832×464, 81f 173초 319KB

A(t2v 고속)와 B(i2v 고속)가 둘 다 45~47초대로 비슷하게 나온 게 눈에 띕니다. 다만 이 둘은 프롬프트도 내용도 해상도도 다른 별개 데모라, “완전히 같은 조건”의 비교는 아니에요. “고속 프리셋이면 방식에 상관없이 클립당 1분 안쪽”이라는 감을 잡는 정도로 보시면 됩니다. 진짜 같은 조건 비교는 다음 장, B와 C입니다.

한 가지 더 — i2v 해상도(832×464)는 제가 정한 게 아니라 입력 이미지 비율에서 자동으로 잡힙니다. 지난 글의 1280×720 이미지를 넣으니 긴 변을 832로 맞춰 832×464로 축소되더군요.

고속(4-step) vs 고품질(20-step): 같은 씨앗, 다른 시간

이제 진짜 같은 조건 비교입니다. 표의 B와 C는 프롬프트도, 시드(42)도, 입력 이미지도 완전히 똑같습니다. 딱 하나, 프리셋만 다릅니다.

  • 고속 프리셋은 lightx2v라는 증류(distillation) LoRA를 얹어 4스텝만으로 뽑습니다. B가 이걸로 45초.
  • 고품질 프리셋은 증류 없이 20스텝을 그대로 다 밟습니다. C가 이걸로 173초, 약 2분 53초.

같은 로봇 팔 붓질 장면인데 시간은 약 3.8배 차이가 났습니다. 파일 크기는 320KB 대 319KB로 사실상 같았고요.

같은 시드로 뽑은 고품질 20-step 로봇 팔 클립

위 훅의 고속(4-step, 45초)과 정확히 같은 프롬프트·시드(42)로 뽑은 고품질(20-step, 173초) 버전. 같은 씨앗에서 출발해 스텝 수만 바꾼 비교다.

여기서 마케팅 숫자 하나를 짚고 갈 만합니다. lightx2v 같은 4스텝 증류를 두고 “x20 가속” 같은 표현이 자주 나오는데, 이건 거짓말은 아니지만 기준이 다릅니다. 벤더의 x20은 보통 “4스텝(가이던스 트릭 없이) vs 표준 40스텝(가이던스 포함)”을 비교한 이론적 함수평가 횟수 기준이에요. 제가 실제로 쓴 두 프리셋(4스텝 vs 20스텝) 사이의 벽시계 차이는 약 3.8배였고요. 그러니까 “몇 배 빠르냐”는 어떤 스텝 수를 기준으로 재느냐에 따라 달라집니다. 체감으로 말하면, 제 환경에서 고속은 고품질의 3~4배쯤 빨랐다 — 이게 맞는 표현이에요.

실무 감각은 지난 글의 “시드 고정하고 미세 수정” 워크플로우의 영상 버전입니다. 고속 4스텝으로 구도와 모션을 빠르게 확인하고, 마음에 들면 같은 시드로 20스텝을 밟아 최종본을 뽑는 식이죠. 다만 4스텝 증류는 공식 문서도 인정하듯 품질을 약간 낮추고, 특히 큰 움직임에서 손실이 있을 수 있습니다. 우리 로봇 팔처럼 움직임이 크지 않은 장면에선 고속으로도 충분히 쓸 만했어요.

실전에서 걸린 것들: 터진 건 모델이 아니라 ‘배달’이었다

경험담의 진짜 알맹이는 잘 된 것보다 걸린 것들이죠. 그런데 이번 세션에서 의외였던 건, 정작 애를 먹인 게 모델 자체는 아니었다는 점입니다. 프레임을 눈으로 넘겨본 한도에선 생성 품질이 크게 무너지진 않았어요. 속을 썩인 건 결과가 나올 때까지 ‘기다리는’ 단계와, 그 결과를 독자에게 ‘배달하는’ 단계였습니다. 여기에 애초에 감안해야 할 한계까지, 셋을 순서대로 풀어볼게요.

타임아웃 설계 — 지난 글 사고의 연장선

지난 글에서 폴링 타임아웃 이야기를 했었습니다. 서버가 콜드 스타트로 느려지면 짧은 타임아웃이 ‘실패’처럼 보인다는 거요. 영상에선 이게 더 커집니다. 이미지는 한 장에 12~19초였지만, 영상은 앞 표에서 봤듯 클립당 45초에서 3분이에요. 자릿수가 다르죠.

실제로 같은 날, 이미지용 스크립트(읽기 타임아웃 10초)는 서버 응답이 늘어지자 폴링이 죽었는데, 영상용 스크립트는 처음부터 넉넉하게(읽기 타임아웃 30초에 6초 간격 폴링) 잡아둔 덕에 무사히 완주했습니다. 교훈은 단순해요. 영상은 기본이 분 단위니, 타임아웃도 그 자릿수에 맞춰 처음부터 넉넉히 잡아야 한다는 것.

GIF의 저주

이게 이번에 제일 골치였습니다. Wan이 뽑아주는 원본은 mp4이고 크기도 320~595KB로 얌전합니다. 문제는 이걸 블로그에 넣을 때예요.

우리 CMS는 자작인데, 보안을 위해 bleach라는 새니타이저로 HTML을 거릅니다. 그런데 이게 <video> 태그를 허용하지 않아요. 즉 mp4를 그대로 임베드할 방법이 없습니다. 그래서 택한 폴백이 GIF 변환이었는데 — 여기서 저주가 시작됩니다. 얌전하던 mp4가 GIF로 바뀌자 6.4~8.7MB로 폭발했어요. 원본의 10배가 넘습니다. 이유를 찾아보니 당연한 결과였습니다. GIF는 1987년생 포맷이라 프레임 간 압축이라는 개념이 없고(매 프레임을 통째로 저장합니다), 색도 256색 팔레트가 한계예요. “바뀐 부분만 저장”하는 H.264 같은 영상 코덱과는 애초에 체급이 다른 거죠.

그대로는 도저히 못 쓰니 ffmpeg로 다시 쥐어짰습니다. 프레임레이트를 10fps로 낮추고 폭을 400~512px로 줄여 용량을 잡고, palettegen/paletteuse 2패스로 클립마다 최적 팔레트를 뽑아 그 조건에서 화질을 지키니 2.6~3.6MB까지 내려왔어요. 이 글 위쪽 클립들이 로딩에 잠깐 걸릴 수 있는 것도 이 때문입니다. 근본 해결은 아니고요. “CMS가 mp4(video 태그)를 받도록 고치기”를 다음 개선 항목으로 적어뒀습니다. 영상 글을 쓰면서 정작 영상을 제대로 못 넣는 아이러니라, 이건 좀 웃긴 상황이었죠.

소리도 없고, 5초고, 사람이 봐야 하고

마지막은 기대치 조정입니다. Wan 2.2 14B는 소리를 만들지 않아요. 완성된 무음 클립이 나옵니다. 배경음이나 대사·립싱크가 필요하면 여기선 답이 없고, 그건 클라우드(Veo나 Sora)의 영역이에요. 길이도 기본 81프레임, 약 5초입니다. 더 길게도 되지만 길수록 모션이 끊기고 아티팩트가 늘고 VRAM 부담도 커져서, 이번엔 전부 5초로 통일했어요. 그리고 이미지 때와 똑같이, 결과는 결국 사람이 프레임을 눈으로 넘겨보며 검수해야 합니다. 자동으로 “쓸 만한 클립”이 툭 나오는 단계는 아직 아니에요.

영상 프롬프트는 ‘무엇이 어떻게 움직이는지’를 쓴다

지난 글에서 이미지 프롬프트는 “장면 + 조명 + 색감 + 분위기 + 스타일”을 쌓는다고 했습니다. 영상, 특히 i2v는 여기서 축이 하나 바뀝니다.

i2v에선 장면을 묘사할 필요가 없어요. 장면은 이미 입력 이미지에 다 들어 있으니까요. 대신 써야 하는 건 무엇이 어떻게 움직이는지, 그리고 카메라가 어떻게 움직이는지입니다. 이걸 처음에 헷갈려서 장면을 다시 묘사했더니, 모델이 애먼 데 힘을 쓰더라고요.

예를 들어 로봇 팔 클립에 준 프롬프트는 장면 설명이 아니라 이런 동작·카메라 지시였습니다.

the robotic arm slowly moves the paintbrush across the canvas, bristles gently flexing as it paints, screens flickering softly in the background, subtle camera push-in, cinematic

“팔이 붓을 캔버스 위로 천천히 움직인다”, “붓털이 부드럽게 휜다”, “배경 스크린이 깜빡인다”, “카메라가 미세하게 밀고 들어온다”. 전부 동작과 카메라예요. 파랑새 클립도 마찬가지로 “날아오른다 / 슬로모션 / 새를 따라가는 팬”처럼 움직임 위주로 줬고요. 로봇 팔처럼 원래 정적인 피사체라도 움직임을 작고 그럴듯하게(붓질, 미세한 카메라 이동) 지정하면, 원본 장면의 정체성을 유지한 채 자연스럽게 살아납니다. 반대로 큰 움직임을 무리하게 요구하면 형태가 뭉개지기 쉬워요.

프리셋 자체는 지난 글과 같은 철학입니다 — 샘플러·스텝·해상도 같은 걸 매번 손으로 짜지 않고, 검증한 조합(고속 4스텝 / 고품질 20스텝)을 JSON으로 고정해 재사용합니다. 손대는 건 프롬프트와 시드, 그리고 고속이냐 고품질이냐의 선택 정도예요.

직접 굴려보고 내린 결론

첫 세션을 굴려본 소감을 정리하면 이렇습니다.

로컬 Wan이 맞는 경우는 생각보다 좁습니다. 영상을 대량으로 뽑아 클립당 과금이 부담될 때, 외부로 내보내기 곤란한 소재라 프라이버시가 중요할 때, 프롬프트·시드·프리셋을 완전히 통제하고 싶을 때, 배우는 것 자체가 목적일 때. 그리고 저처럼 이미 로컬 이미지 파이프라인이 있어서 그 위에 자연스럽게 얹을 수 있을 때. 이 조건들이 겹치면 로컬이 말이 됩니다.

반대로 클라우드가 나은 경우도 분명합니다. 소리나 립싱크가 필요할 때, 최상위 품질과 물리적 사실성이 필요할 때, 어쩌다 한 번만 쓸 때, 서버 관리 자체가 싫을 때. 그럴 땐 Sora나 Veo, Kling이 낫습니다. “로컬이 클라우드를 이겼다” 같은 결론을 내릴 생각은 없어요. Wan 14B는 여전히 느리고, 소리가 없고, 품질도 상용 최상위엔 못 미치니까요.

그래서 지금 로컬 영상은 완성된 자동화가 아니라 여전히 탐색 단계입니다. 이미지처럼 매끄럽게 굴러가려면 아직 멀었어요. 그럼에도 남는 게 하나 있습니다. 지난 글에서 파이프라인이 자동으로 그린 그 정지 이미지가, 이번 글에선 붓을 들고 움직이는 걸 직접 보는 경험이요. 이 글 맨 위의 로봇 팔이 바로 그겁니다. 정지된 한 장에서 시작해, 같은 서버에서 한 걸음 더 간 결과물.

참고로 이 글을 포함해 birdspring의 글들이 어떻게 만들어지는지 — 여러 AI 에이전트가 역할을 나눠 쓰는 방식은 에이전트 팀 이야기에 따로 정리해 뒀습니다.