Skip to content
Content
Skill

/web-demo-video

화면 녹화 도구 없이 웹사이트/웹앱의 짧은 제품 데모·소개 영상(SNS용 1:1, 9:16, 16:9)을 만들 때 사용. 실제 사이트를 iframe에 띄워 진짜 마우스 이벤트로 조작하면서 프레임을 캡처하고 ffmpeg로 합성한다.

BOOST
From plugin
solo-skills
36539 skills
Install
$ npx -y skills add bam-bam-2/solo-skills --skill web-demo-video --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/web-demo-video

Context preview

The summary Claude sees to decide when to auto-load this skill.

화면 녹화 도구 없이 웹사이트/웹앱의 짧은 제품 데모·소개 영상(SNS용 1:1, 9:16, 16:9)을 만들 때 사용. 실제 사이트를 iframe에 띄워 진짜 마우스 이벤트로 조작하면서 프레임을 캡처하고 ffmpeg로 합성한다.

SKILL.md

web-demo-video.SKILL.md
name: web-demo-video
description: 화면 녹화 도구 없이 웹사이트/웹앱의 짧은 제품 데모·소개 영상(SNS용 1:1, 9:16, 16:9)을 만들 때 사용. 실제 사이트를 iframe에 띄워 진짜 마우스 이벤트로 조작하면서 프레임을 캡처하고 ffmpeg로 합성한다.

웹 데모 영상 만들기

밤밤의 웹 프로젝트(모자이크, 겟백앱, 카공메이트 등) 소개 영상을 만들 때 쓰는 절차. 목업 이미지를 이어붙이는 게 아니라 **실제 사이트를 실제로 조작한 화면**을 찍는 게 핵심이다.

먼저 물어볼 것

영상은 어디 쓰느냐로 비율·길이가 갈린다. **만들기 전에 반드시 확인한다.**

| 용도 | 비율 | 길이 | |---|---|---| | 스레드·릴스·쇼츠 | 9:16 (1080x1920) | 15~25초 | | 블로그·유튜브 임베드·랜딩 | 16:9 (1920x1080) | 30~40초 | | 인스타 피드·카톡 공유 | 1:1 (1080x1080) | ~20초 |

밤밤은 시각 산출물의 **형식**에 구체적인 기대가 있다. 레퍼런스가 있으면 먼저 달라고 한다.

절차

1. 로컬 서버로 대상 사이트를 띄운다

cd <프로젝트> && python3 -m http.server 8899

무대(stage) 페이지와 대상 사이트는 **반드시 같은 오리진**이어야 한다. 포트가 다르면 `iframe.contentDocument` 접근이 막혀서 조작이 불가능하다. → 무대 파일을 프로젝트 폴더 안에 임시로 두고, **작업이 끝나면 반드시 빼낸다**(안 그러면 다음 배포에 딸려 올라간다).

2. 무대 페이지를 만든다

`assets/stage-template.html`를 복사해서 고친다. 구조:

  • `#stage` — 출력 비율 그대로의 고정 크기 div (1:1이면 540x540, dpr 2로 캡처하면 1080x1080)
  • `#cap` / `#foot` — 큰 자막(상단) / 보조 문구(하단)
  • `#win` — 맥 브라우저 창 목업(신호등 3개 + URL) 안에 `<iframe>`을 `transform: scale()`로 축소해 넣음
  • `#cursor` — 가짜 마우스 커서 SVG. **이게 있어야 조작 영상처럼 보인다**
  • `#ring` — 클릭·브러시 크기를 보여주는 하이라이트 원
  • `#end` — 엔딩 카드(제품명 / 한줄 설명 / 셀링포인트 3개 / URL)
  • `window.__tick(frameIndex)` — 프레임 번호 하나를 받아 그 시점의 화면 상태를 만드는 **결정론적** 함수

3. 타임라인을 결정론적으로 짠다

`__tick(frame)` 안에서 `t = frame / FPS`로 시간을 계산하고, 모든 상태를 t로부터 다시 계산한다. 실시간 `setTimeout`을 쓰면 캡처 속도와 어긋나서 망가진다.

  • 1회성 동작(이미지 로드, 모드 전환)은 `once(key, fn)` 으로 중복 실행을 막는다
  • 드래그는 `drag(t, 시작초, 끝초, ptFn)` — 시작 프레임에 `mousedown`, 매 프레임 `mousemove`, 끝나면 `mouseup`
  • 이벤트는 iframe의 `W.MouseEvent`로 만들어 `clientX/clientY`(iframe 기준 좌표)로 dispatch한다.

`mousedown`은 대상 요소에, `mousemove`/`mouseup`은 보통 `window`에 붙어 있으니 확인하고 각각 맞는 타깃에 쏜다

  • 좌표는 하드코딩하지 말고 **요소의 `getBoundingClientRect()` 또는 그려넣은 목업의 rect 비율**로 계산한다. 창 크기를 바꿔도 안 깨진다
  • iframe 안에서 영상에 불필요한 요소(헤더, SEO 본문, 푸터, 광고 배너, 상태줄)는 `iframe` load 시점에 `<style>` 주입으로 숨긴다

4. 프레임을 캡처한다

for (let i = from; i <= to; i++) {
  await page.evaluate(f => __tick(f), i);
  const buf = await page.screenshot({ clip: { x:0, y:0, width:540, height:540 } });
  await fs.writeFile(`${DIR}/f${String(i).padStart(4,'0')}.png`, buf);
}
  • **`clip`은 CSS 픽셀 단위다.** devicePixelRatio를 곱하면 안 된다. dpr 2면 540 클립이 1080px 이미지로 나온다
  • 프레임 한 장에 약 0.09초. 400장이면 40초 → REPL 120초 제한 때문에 **100~150장씩 나눠 호출**한다
  • 캡처 시작 전에 페이지를 새로 로드해 상태를 초기화하고, `__tick(0)` 후 이미지 로드가 끝날 시간을 준다

5. ffmpeg로 합성한다

`ffmpeg`는 PATH에 없다. `export PATH="$PATH:/opt/homebrew/bin"` 를 붙인다.

ffmpeg -y -framerate 20 -i frames/f%04d.png \
  -vf "scale=1080:1080:flags=lanczos,fps=30" \
  -c:v libx264 -profile:v high -pix_fmt yuv420p -crf 20 -movflags +faststart out.mp4
  • `-pix_fmt yuv420p`는 SNS 호환 필수
  • 채팅에 붙여 보여줄 미리보기 GIF는 palettegen/paletteuse 2패스로:

`fps=10,scale=420:-1:flags=lanczos,palettegen=stats_mode=diff` → `paletteuse=dither=bayer:bayer_scale=3`

  • 콘티 확인용 컨택트시트: `select='eq(n\,20)+...',scale=340:340,tile=3x3`

6. 뒷정리

  • 무대 파일을 프로젝트 폴더 밖으로 옮긴다 (배포에 섞이면 안 됨)
  • 로컬 서버 종료: `lsof -ti:8899 | xargs kill -9`
  • 캡처 탭 닫기

주의

  • 영상에 쓰는 예시 데이터(대화 내용, 이름, 계좌번호, 전화번호, 주소)는 **전부 지어낸 가짜**로 만들고, 보고할 때 가짜라고 명시한다. 밤밤의 실제 개인정보(전세금 등)나 제3자 정보는 절대 넣지 않는다
  • 무음이 기본. 음악이 필요하면 밤밤에게 확인받는다
  • 완성본은 세션 artifacts에 두되, 다시 뽑을 수 있도록 **무대 파일을 영구 경로에 보관**한다

---

부록 · 블로그 본문용 GIF (브라우저 목업 없이)

SNS 영상과 목적이 다르다. 블로그 독자는 **"이 도구가 뭘 하는지"**를 3초 안에 봐야 하므로, 맥 브라우저 창 목업·엔딩 카드 없이 **작업 대상만 크게** 보여주는 편이 낫다. 무대(stage) 페이지도 로컬 서버도 필요 없다. 배포된 사이트를 직접 조작하고 캔버스를 그대로 뜬다.

절차

1. 배포 사이트를 열고 예시 이미지를 붙여넣기 이벤트로 주입한다(파일 선택 UI를 거치지 않아도 된다).

   await page.evaluate(async (b64) => {
     const blob = await (await fetch('data:image/png;base64,'+b64)).blob();
     const dt = new DataTransfer(); dt.items.add(new File([blob],'s.png',{type:'image/png'}));
     document.dispatchEvent(new ClipboardEvent('paste',{clipboardData:dt,bubbles:true}));
   }, b64);

2. 영상에 불필요한 요소는 캡처 전에 숨긴다 (`adInCanvas` 같은 광고 영역). 3. **좌표는 반드시 픽셀로 탐지한다. 눈대중 금지.** 이번에 눈대중으로 잡았다가 펜·채우기가 엉뚱한 데 찍혀서 세 번 다시 찍었다. 캔버스 픽셀을 직접 훑어 대상 글자의 bbox를 구한다.

   const bbox = (x0,x1,y0,y1) => { /* 어두운 픽셀(r,g,b<110)의 min/max */ };

노란 말풍선 같은 색 블록은 해당 색 범위로 같은 방식으로 찾는다. 4. 프레임은 **캔버스를 새 캔버스에 다시 그려서** 만든다. `page.screenshot({clip})`은 스크롤/DPR 때문에 좌표가 어긋나기 쉽다. 자막·커서·선택 박스·브러시 원도 이 합성 단계에서 그려 넣는다.

  • 상단에 라벨 띠(무슨 모드를 쓰는지)를 넣으면 GIF 하나로 기능 여러 개를 설명할 수 있다
  • 드래그 중에는 파란 점선 선택 박스를, 펜 모드에서는 브러시 크기 원을 그린다

5. 실제 마우스 이벤트로 조작하면서 매 스텝 프레임을 저장한다. 동작 전후로 **정지 프레임 6~8장**을 넣어야 눈이 따라간다. 6. ffmpeg 2패스로 GIF 합성 (본문용은 폭 620~640px, 12fps, 70KB 안팎이면 충분).

효과 선택 주의

  • **단색 영역에 블러를 걸면 화면상 아무 변화가 없다.** 평면 아바타를 블러 처리하는 컷을 넣었다가

차이가 안 보여서 뺐다. 블러는 디테일이 있는 대상에만 쓴다.

  • **펜은 모자이크보다 블러가 깔끔하다.** 펜+모자이크는 블록이 흩뿌려진 것처럼 지저분하게 나온다.
  • 가리기 결과를 보여줄 땐 **가린 영역 위로 원본이 삐져나오지 않았는지** 마지막 프레임에서 확인한다.

살짝 비치면 여백을 더 줘서 한 번 더 덮고 뒤쪽 정지 프레임만 다시 찍으면 된다.

어디에 쓰나

  • 네이버 블로그: 사진 업로드와 동일하게 `사진` 버튼 → 파일 선택으로 올린다 (GIF도 그대로 애니메이션된다)
  • 티스토리: `첨부 → 사진`. 업로드하면 `[##_Image|...|_##]` 문법이 본문에 들어가므로,

그걸 읽어서 전체 HTML을 조립한 뒤 `setContent()` 하면 이미지 위치를 원하는 곳에 둘 수 있다

  • 사이트 자체: `<figure>` + `loading="lazy"` + 캡션에 "예시 데이터는 전부 가짜"를 명시
Read more
Ships withsolo-skills

1인 사업가 생산성 키트 — 직원 없이 58개를 자동화했고, 그중 바로 쓸 수 있는 AI 에이전트 스킬 38개(+실행 스크립트 19개)를 공개합니다

Get the whole plugin

Other skills on solo-skills.

advisory-minutes
Skill

advisory-minutes

겟백 1:1 자문 세션(A 대표·B 원장)이 끝난 뒤 줌 녹화 전사록을 받아 노션 코칭 대시보드에 회의록을 올리고, 할 일 보드 등록·대시보드 문구 갱신·클라이언트 카톡 통보까지 처리할 때 읽을 것. "B 원장님 자문했어 노션에…

book-pdf
Skill

book-pdf

마크다운 원고를 실제 책처럼 보이는 PDF/EPUB 전자책으로 만들 때 사용. 표지, 타이틀 페이지, 판권(콜로폰) 페이지, 실제 쪽번호가 달린 목차, 장마다 러닝헤더가 붙는 본문까지 갖춘 '책스러운' 구성이 필요할 때 (단순…

community-launch
Skill

community-launch

온라인 유료 커뮤니티 개설 전체 프로세스를 지원하는 에이전트 조직 스킬. 커뮤니티 기획부터 모집 카피, 노션 DB 세팅, 운영 SOP까지 한번에 처리. 오케스트레이터가 인터뷰를 진행하고 4개 전문 에이전트가 결과물을 순서대로…

daangn-search
Skill

daangn-search

당근마켓 웹에서 넓은 지역을 훑어 매물을 찾을 때 사용. 당근 웹 검색은 "동 하나"로만 되기 때문에 구·시·전국 단위로 찾으려면 지역코드를 순회해야 한다. 대형가전·노트북처럼 매물이 드물어 한 동네에서는 안 나오는 물건을 찾을 때.