Communitygithub.com

devlucasalm/motion-promo-video-skill

고급 모션 디자인 프로모션 비디오(9:16 / 16:9, 60fps, SFX/음악 포함)를 HTML + Playwright + ffmpeg로 제작합니다. 모션 요청, 광고 영상, 릴스, 애니메이션 프로모션에 사용하세요.

motion-promo-video-skill란 무엇인가요?

이 스킬은 HTML, Playwright 및 ffmpeg를 사용하여 고품질 모션 디자인 프로모션 비디오를 생성하는 전문 도구입니다. SaaS 제품, 시계, 보석 등 다양한 제품에 맞춰 9:16(1080×1920) 또는 16:9(1920×1080) 형식, 60fps, H.264 + AAC 코덱으로 MP4를 출력합니다. 핵심은 `video.html` 내 `window.seek(T)` 함수를 통해 모든 애니메이션을 시간 T에 따라 완전히 결정론적으로 제어하는 엔진입니다. 사용자는 최소한의 브리핑(포맷, 대상 청중, 브랜드 자산)만 제공하면 되며, 스킬은 자동으로 배경 제거(`rembg`), 저해상도 이미지 업스케일, 타임라인 기반 장면 및 SFX 합성, 최종 렌더링 및 마스터링까지 처리합니다. 특히 장면 전환, 텍스트 리빌, 제품 3D 효과, 입자/필름 그레인 등 다양한 시각 효과가 내장되어 있으며, 2개의 병렬 청크 렌더링으로 효율적인 재렌더링이 가능합니다. 오디오는 numpy/scipy로 합성되어 청중 프로필에 맞는 SFX(젊은 층/SaaS용 밝은 사운드, 프리미엄용 차분한 사운드)를 제공하며, Loudnorm으로 마스터링하여 깨끗한 음질을 보장합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add devlucasalm/motion-promo-video-skill

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

모션 프로모션 비디오 (HTML → MP4)

결과물: 준비된 MP4 (H.264, yuv420p, AAC)를 SendUserFile로 전송합니다. 응답은 pt-BR로 짧게 작성하세요.

1. 최소 브리핑 (너무 많이 묻지 마세요)

기본값을 설정하고 결과를 바꾸는 것만 물어보세요:

  • 형식: 9:16 (1080×1920) 기본값; 16:9 (1920×1080) 요청 시. 지속 시간: Insta 광고 20–35초; 페이싱 느림 (각 단계 ~1.5–4초) — 사용자가 이미 "2배속 같다"고 불평했습니다.
  • 대상: 젊은 층/SaaS → 밝은 SFX (종소리, 팝, 클릭). 나이 든/프리미엄 대상 (시계, 보석) → 차분한: 패드, 부드러운 임팩트, 우쉬, 샤이머; 어린이용 팝 금지.
  • 브랜드: 팔레트, 폰트, 로고, CTA (WhatsApp/URL), 스크린샷/사진. 음악: 사용자가 트랙(Spotify 등)을 언급하면 오디오에 접근하지 말고 알린 후, 오리지널 트랙을 사용하고 사용자가 mp3를 보내면 동기화하겠다고 제안하세요 (라이선스 확인).

2. 에셋 준비

  • 제품 사진: rembg (isnet-general-use 모델)로 배경 제거 → 알파가 있는 PNG로 "3D" 효과 (떠다님, rotateY/rotateX + perspective, PNG 알파로 마스킹된 sheen 광택 via -webkit-mask-image).
  • 저해상도 스크린샷: Lanczos 3배 업스케일 + UnsharpMask. 사용자가 "광고 없이" 요청하면 원본 사진에서 광고 텍스트 제거.
  • 폰트: Inter / Inter Display ExtraBold (SaaS, 플랫 스타일), Lora serif + 골드 이탤릭 (프리미엄), Poppins.

3. 사용자가 승인한 스타일

  • 단색 블록, 큰 카드, 마스킹된 단어별 리빌이 있는 거대한 타이포그래피, 지속적인 움직임 (느린 패럴랙스, 느린 줌 1→1.15, 별/입자), 비트에 동기화된 3개의 컬러 패널 와이프 컷.
  • 카메라 흔들림 없음 (사용자가 shake 거부): 최대 shake ×0.12, 카메라 회전 없음, drift ≤3 px.
  • 내러티브 구조: 갈고리/문제 → 해결책 → 2–3 기능/통합 → 증거/혜택 → CTA. 각 씬 3–5초, 씬 사이에 와이프. SaaS에서는 해결책 전에 구체적인 문제(답장 없는 메시지, 손실된 매출 -R$)를 보여주세요.
  • 짧은 텍스트, 줄당 2–4단어, pt-BR, 한 단어 강조 (색/이탤릭). Instagram safe zone 준수 (9:16에서 상단 약 250px, 하단 약 400px 피해서 CTA/캡션).

4. 엔진 (결정론적 HTML)

video.html 파일 하나에 window.seek(T) 함수가 있어 시간 T에 따라 모든 것을 배치합니다 (requestAnimationFrame/CSS 애니메이션 없음). 핵심:

const cl=(x,a=0,b=1)=>Math.min(b,Math.max(a,x)),lerp=(a,b,p)=>a+(b-a)*p;
const E={outBack:(p,c=1.8)=>1+(c+1)*Math.pow(p-1,3)+c*Math.pow(p-1,2),outExpo:p=>p>=1?1:1-Math.pow(2,-10*p),outQuart:p=>1-Math.pow(1-p,4),inOutQuart:p=>p<.5?8*p**4:1-Math.pow(-2*p+2,4)/2,inOutCubic:p=>p<.5?4*p**3:1-Math.pow(-2*p+2,3)/2,lin:p=>p,inCubic:p=>p**3,inOutSine:p=>-(Math.cos(Math.PI*p)-1)/2};
const ez=(T,a,d,f=E.outExpo)=>f(cl((T-a)/d));
function mk(parent,html,cls='',style=''){const d=document.createElement('div');d.className='abs '+cls;d.style.cssText=style;d.innerHTML=html;parent.appendChild(d);return d} // .abs{position:absolute;left:50%;top:50%}
function P(el,o){const x=o.x||0,y=o.y||0,s=o.s==null?1:o.s,op=o.o==null?1:o.o,r=o.r||0,rx=o.rx||0,ry=o.ry||0;el.style.transform=`perspective(2400px) translate(-50%,-50%) translate(${x}px,${y}px) rotateX(${rx}deg) rotateY(${ry}deg) rotate(${r}deg) scale(${s})`;el.style.opacity=op;el.style.visibility=op<=.003?'hidden':'visible'}
function words(el,arr){el.innerHTML=arr.map(w=>`<span class="mk"><span class="wd ${w[1]||''}">${w[0]}</span></span>`).join(' ')} // .mk{display:inline-block;overflow:hidden;padding:.14em .05em .24em;margin:-.14em -.05em -.24em}
function lineIO(el,T,tin,tout,step=.1,d=1.0){[...el.querySelectorAll('.wd')].forEach((w,i)=>{const a=ez(T,tin+i*step,d,E.outQuart),b=tout?ez(T,tout+i*step*.5,.5,E.inCubic):0;w.style.transform=`translateY(${(1-a)*118-b*118}%)`;w.style.opacity=cl(a*2.2,0,1)*(1-b)})}
function addScene(a,b,bg,build,upd,cam){/* .sc div 생성, bg, inner; scenes.push({a,b,root,inner,obj:build(inner),upd,cam}) */}
function runScenes(T){/* T가 [a-.02,b+.02] 범위에 있을 때만 표시; inner.style.transform = cam(t,T)의 translate/scale; s.upd(t,obj,T) */}
// 와이프: 3개 패널 [어두운 색, 골드/액센트, 다음 씬 배경색], 각각 ez(T,t0+i*.09,.38,E.inOutQuart)로 들어오고 나감 (t0=wipe-.55); 방향 x / xr 교대
function seek(T){runScenes(T);drawWipes(T);drawFX(T);drawGrain(T);/* 마지막 페이드 블랙 */}

세계 위의 고정 레이어: 먼지/입자 캔버스, 와이프, 필름 그레인 (알파 .07), 비네트, fade-in/out용 검은 베일. 제품 3D 효과: P(hero,{ry:Math.sin(T*.7)*8, rx:Math.sin(T*.5)*3, y:Math.sin(T*1.1)*14, s}) + sweep() (PNG로 마스킹된 mix-blend-mode:soft-light 광택 스트립) + 뒤에 방사형 골드 글로우 + drop-shadow 그림자. 시계형 오프닝 (v1 시계에서 사용자 승인): SVG 760px, 60개 틱 (5개마다 더 굵고 골드), 그려지는 골드 아크 (stroke-dashoffset), 0.5초마다 6°씩 전진하는 바늘 (E.outBack), 지나간 틱은 켜짐; 텍스트 "O tempo passa pra todo mundo. / Poucos deixam marca."; 회전하는 별표 ✦. 제품이 허용할 때 이 유형의 테마 오프닝을 재사용하세요. 가변 속도 타임라인: SEG=[[ini,fim,fator],…]를 seek와 오디오의 M(t) 함수에 적용하여 SFX가 컷을 따르도록 함.

5. 렌더링 (결정론적, 재개 가능)

  • Playwright Chromium 뷰포트 1080×1920 (또는 1920×1080), page.evaluate('seek(t)') + screenshot(type='jpeg',quality=92).
  • 60fps + 모션 블러: 프레임당 2 서브프레임 (t=(f+(s+.5)/2-.5)/60), numpy float32 평균 → JPEG q95 → ffmpeg -f image2pipe -c:v mjpeg -i - -c:v libx264 -preset fast -crf 18 -pix_fmt yuv420p seg/NNNNN.mp4.
  • seg/에 120프레임 청크, 2개 병렬 프로세스 (짝수/홀수 청크), 기존 청크 건너뜀 (컨테이너 재시작 가능). setsid nohup ./go.sh &로 실행하고, until-loop로 파일 완료를 모니터링하는 Monitor 사용 (foreground sleep은 차단됨; 30분 후 만료 시 Monitor 재활성화). ~0.38초/스크린샷, 2 CPU: 24초 ≈ 1440프레임 ≈ 25–30분.
  • 시작 부분만 변경? 영향을 받는 청크만 삭제하고 재렌더링; 오디오만 변경되면 -c:v copy로 리먹스.
  • 연결: ffmpeg -f concat -safe 0 -i list.txt -i audio.wav -c:v libx264 -crf 21 -pix_fmt yuv420p -c:a aac -b:a 192k -shortest -movflags +faststart out.mp4.
  • 전체 렌더링 전에 핵심 시간대에 seek() 스크린샷 2–4장 찍어 두 형식 모두에서 텍스트 잘림/오버플로우 (이전에 큰 폰트에서 발생) 및 JS 오류 (page.on('pageerror')) 확인.

6. 오디오 (numpy/scipy, 합성)

헬퍼: lp/hp/bp (butter), add(buf,t,x,g), tt(d); 사운드: thump (사인 46–96 Hz 감쇠), impact (thump + lp 700 노이즈), riser (상승 대역 노이즈), swish (bp 1.8–5.5 kHz 노이즈, sin² 윈도우), shimmer (감쇠 비조화 부분), tick (사인 ~900 Hz, decay 90), pad (3개 디튠 사인 lp 1.4 kHz + 페이드), pluck; 리버브는 감쇠 노이즈와의 컨볼루션.

  • SaaS/젊은 층: 밝은 종소리, 팝, 클릭, 우쉬 — 무거운 저음 사용 금지 (사용자가 "모든 게 저음"이라고 싫어함).
  • 프리미엄/나이 든 층: 와이프에 riser+impact, 텍스트 리빌에 swish, 제품 등장에 shimmer, 목록에 틱, 시계 오프닝에 0.5초마다 시계 틱, 느린 코드 진행 패드 (Dm–Bb–F–C), 부드러운 비트 ~90 bpm. 비트 80–90 bpm은 4초 컷과 잘 어울림.
  • 마스터링 ("터짐" 방지): 핫 믹스에 tanh 절대 금지. x=x/np.abs(x).max()*.85 적용, wav 저장 후 ffmpeg -af loudnorm=I=-16:TP=-2:LRA=11 -ar 44100 실행. 피크 < -1 dBFS, 크레스트 팩터 > 10 dB 확인.

7. 전달 및 반복

MP4를 한 줄 캡션과 함께 전송하고, 변경 사항과 확인되지 않은 사항을 언급하세요 (예: "프레임과 메트릭 확인했지만 오디오는 듣지 못했습니다"). 일반적인 피드백 및 응답: "너무 빠름" → 타임라인 ×1.5 스케일; "떨림" → shake 감소; "소리 나쁨" → SFX 프로필 변경 (밝음 vs. 차분함); "터짐" → 오디오만 리마스터 후 리먹스; "v1 애니메이션 X가 좋았음" → 씬 X 다시 가져오고 영향받은 청크만 재렌더링. 사용자가 재사용 가능한 프롬프트/문서를 요청하면 이 흐름으로 문서를 생성하세요.

관련 스킬