Communitygithub.com

제품 데모 비디오

정적 스크린샷이나 디자인을 깔끔한 애니메이션 데모로 변환합니다. 기기/브라우저 프레임, 애니메이션 커서 및 클릭 리플, 확대/축소 및 패닝, 콜아웃 주석, 단계 간 전환, 기능 캡션을 포함합니다.

제품 데모 비디오란 무엇인가요?

이 스킬은 제품 데모 비디오, 앱 데모 비디오, 기능 발표 비디오, SaaS 데모, UI 워크스루 비디오를 만들거나, 제품 스크린샷을 데모로 애니메이션화하거나, 스크린샷에 애니메이션 커서/클릭을 추가하거나, UI의 일부를 확대/축소하라는 사용자 요청이 있을 때 사용됩니다. 정적 스크린샷이나 디자인(화면 녹화가 아님)을 깔끔한 애니메이션 데모로 변환하는 작업을 다룹니다: 기기/브라우저 프레임, 애니메이션 커서 + 클릭 리플, 초점 UI로의 확대/축소 및 패닝, 콜아웃 주석, 단계 속도 조절, 화면 간 전환, 기능 캡션 등이 포함됩니다. 이 스킬은 Remotion 프레임워크를 기반으로 구축되었으며, 모든 커서 움직임, 확대/축소 및 전환이 `useCurrentFrame()`의 순수 함수로 구동되어 결정론적이고 재현 가능한 출력을 보장합니다. 스크린샷을 화면 녹화 대신 사용하면 각 단계를 쉽게 교체하고 UI 변경 사항을 다시 렌더링할 수 있어, 전통적인 화면 녹화 방식의 일반적인 문제점(커서 지터, UI 드리프트)을 해결합니다. 지원되는 출력 형식은 MP4 비디오와 선택적 GIF이며, 렌더링 전에 개별 프레임을 검증할 수 있는 정적 이미지 검사 워크플로가 포함되어 있습니다.

지원 대상~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/2233admin/design-pipeline/tree/HEAD/skill/references/iart-motion-skills/upstream/ecommerce-video-skills/skills/product-demo-video

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

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

문서

제품 데모 비디오은(는) 무엇을 하나요?

정적 제품 스크린샷이나 디자인을 세련된 애니메이션 데모로 변환합니다 — 화면 녹화기, 떨리는 실제 커서, UI 버전 불일치가 필요 없습니다. 각 화면에 프레임을 씌우고, 합성 커서를 정확한 픽셀 위치로 부드럽게 이동시키며, 클릭 리플을 추가한 후, 중요한 부분으로 확대/축소하고 기능에 캡션을 추가합니다. 입력이 정적이고 움직임이 코드로 처리되기 때문에 모든 값이 결정론적이며 스크린샷이 변경될 때 동일하게 다시 렌더링됩니다.

사용 시기

  • 앱/SaaS 데모, 기능 발표, 온보딩 워크스루 (15~90초)
  • 스크린샷이나 디자인만 있는 UI의 클릭 경로를 보여줄 때
  • 복잡한 대시보드의 한 초점 영역을 강조할 때 (영역 확대 + 콜아웃)

화면 녹화보다 스크린샷이 더 나은 이유

화면 녹화스크린샷 기반 (이 스킬)
실제 커서가 흔들리고, 목표를 오버슛하며, 지터가 발생함커서가 부드러운 경로를 따라 정확한 대상으로 이동함
한 단계를 수정하려면 전체 테이크를 다시 녹화해야 함PNG 하나를 교체하고, 동일한 코드를 다시 렌더링하면 됨
촬영 중 UI가 변경되고, 마우스가 헤맴각 화면은 깔끔하고 최종 상태의 에셋임
픽셀화 없이 확대/축소하기 어려움스크린샷을 2배(DPR 2)로 내보내면 선명한 확대/축소 가능

표시 크기의 두 배(레티나 / deviceScaleFactor: 2)로 입력을 캡처하여 2배 확대/축소 시에도 선명도를 유지합니다. Playwright 캡처 스크립트는 references/screenshot-demo.md를 참조하세요.

데모 루프

모든 데모는 기능별로 동일한 비트를 반복합니다. 읽을 수 있을 만큼 충분히 유지하고, 의도적으로 움직이며, 클릭을 안착시키고, 결과를 드러냅니다.

비트시간역할
화면에 안착0.5~1초움직이기 전에 시청자가 방향을 잡도록 함
커서가 대상으로 이동0.4~0.8초부드러운 이동 (ease-in-out), 선형 아님
클릭 리플 + 상태 변경0.2~0.3초촉각적 피드백; 같은 프레임에서 화면 반응
초점 영역으로 확대/축소12초 동안 확대, 24초 유지2배가 적정선 — 충분한 디테일, 맥락 유지
기능 캡션확대와 함께 유지"원클릭 내보내기"와 같은 한 가지 혜택 문구

카메라 또는 커서를 움직이되, 거의 동시에 움직이지 마세요. 두 가지가 동시에 움직이면 주의가 분산됩니다.

스크린샷 프레이밍

원시 스크린샷은 버그 리포트처럼 보이지만, 프레임이 씌워진 스크린샷은 제품처럼 보입니다. 모든 화면을 브랜드 배경의 브라우저 또는 기기 크롬으로 감쌉니다.

// 브라우저 프레임 — 스크린샷을 넣으면 그럴듯한 창이 됨
const BrowserFrame = ({ url, children }) => (
  <div style={{ borderRadius: 12, overflow: "hidden", background: "#1e1e22",
                boxShadow: "0 40px 80px rgba(0,0,0,.35)" }}>
    <div style={{ height: 40, display: "flex", alignItems: "center", gap: 8, padding: "0 14px" }}>
      {["#ff5f57", "#febc2e", "#28c840"].map((c) => (
        <span key={c} style={{ width: 12, height: 12, borderRadius: "50%", background: c }} />
      ))}
      <div style={{ marginLeft: 12, flex: 1, height: 24, borderRadius: 6, background: "#2b2b30",
                    color: "#9aa", fontSize: 13, display: "flex", alignItems: "center", padding: "0 10px" }}>
        {url}
      </div>
    </div>
    <div style={{ background: "#fff" }}>{children}</div>
  </div>
);

주소 표시줄에 실제 URL을 넣고(진정성), 부드러운 그림자와 그라데이션 배경을 추가합니다. 모바일의 경우, 노치와 둥근 모서리가 있는 전화 프레임으로 바꿉니다. 프레임 스타일을 하나의 테마 객체에 유지하여 모든 화면이 일관되게 보이도록 합니다.

애니메이션 커서 + 클릭 리플 (핵심 동작)

위치를 CSS 전환이나 벽시계가 아닌 현재 프레임에서 구동합니다. 비디오 렌더러는 모든 프레임이 프레임 번호의 순수 함수여야 합니다. 그렇지 않으면 커서가 동기화되지 않고 깜박입니다.

import { useCurrentFrame, interpolate, spring, useVideoConfig } from "remotion";

// `from`에서 `to`로 `startFrame`과 `startFrame+dur` 사이에서 부드럽게 이동
const useCursor = (from, to, startFrame, dur) => {
  const frame = useCurrentFrame();
  const t = interpolate(frame, [startFrame, startFrame + dur], [0, 1],
    { extrapolateLeft: "clamp", extrapolateRight: "clamp", easing: (x) => x * x * (3 - 2 * x) }); // smoothstep
  return { x: from.x + (to.x - from.x) * t, y: from.y + (to.y - from.y) * t };
};

export const Cursor = ({ from, to, startFrame, dur, clickAt }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const { x, y } = useCursor(from, to, startFrame, dur);

  // 리플은 클릭 프레임에 한 번 확장됨
  const since = frame - clickAt;
  const showRipple = since >= 0 && since < 18;
  const r = spring({ frame: since, fps, config: { damping: 18 }, durationInFrames: 18 });

  return (
    <>
      {showRipple && (
        <div style={{ position: "absolute", left: x, top: y, transform: "translate(-50%,-50%)",
          width: 12 + r * 60, height: 12 + r * 60, borderRadius: "50%",
          border: "2px solid rgba(80,140,255,.9)", opacity: 1 - r }} />
      )}
      <svg width="28" height="28" viewBox="0 0 28 28"
           style={{ position: "absolute", left: x, top: y, filter: "drop-shadow(0 2px 3px rgba(0,0,0,.4))" }}>
        <path d="M3 2 L3 21 L9 15 L13 24 L16 23 L12 14 L20 14 Z" fill="#fff" stroke="#222" strokeWidth="1.4" />
      </svg>
    </>
  );
};

커서는 smoothstep을 사용하여 정지 상태에서 가속하고 대상으로 감속합니다(선형 커서는 로봇처럼 보입니다). 원인과 결과가 일치하도록 동일한 clickAt 프레임에서 리플 그리고 화면의 상태 변경을 트리거합니다. 여러 화면에 걸쳐 여러 클릭을 연결하는 전체 구성은 references/screenshot-demo.md를 참조하세요.

영역 확대/축소 (UI용 Ken Burns 효과)

초점 요소로 확대/축소하려면 화면의 배율을 조정하고 transform-origin을 해당 요소의 중심으로 설정하여 확대/축소가 프레임 중앙 대신 그 요소를 향해 수렴하도록 합니다.

const ZoomToRegion = ({ target, scale = 2, startFrame, dur, children }) => {
  const frame = useCurrentFrame();
  const s = interpolate(frame, [startFrame, startFrame + dur], [1, scale],
    { extrapolateLeft: "clamp", extrapolateRight: "clamp", easing: (x) => 1 - Math.pow(1 - x, 3) }); // easeOutCubic
  return (
    <div style={{ transform: `scale(${s})`, transformOrigin: `${target.x}px ${target.y}px`,
                  willChange: "transform" }}>
      {children}
    </div>
  );
};

확대/축소는 약 2배로 제한합니다(3배를 넘으면 맥락을 잃고 방향 감각을 잃게 합니다). 확대된 상태를 2~4초 동안 유지하여 세부 정보를 읽을 수 있을 만큼 충분히 길게 한 후, 다음 화면으로 이동하기 전에 부드럽게 축소합니다. 확대/축소를 콜아웃과 함께 사용하고, 단독으로 사용하지 마세요.

콜아웃 주석 및 기능 캡션

중요한 지점에 주석을 달고, 그런 다음 지웁니다. 콜아웃은 레이블과 초점 요소를 가리키는 연결선(화살표, 원, 밑줄)으로 구성됩니다.

  • 부드러운 링이나 주변을 어둡게 처리하여 요소를 강조합니다 (box-shadow: 0 0 0 9999px rgba(0,0,0,.45)는 스포트라이트 구멍을 만듭니다).
  • 비트당 하나의 혜택을 캡션으로 표시합니다. 짧은 명사구("실시간 분석")여야 하며, 문장이 아니어야 합니다. 확대/축소와 함께 나타나고, 다음 단계 전에 사라집니다.
  • 캡션을 하단 1/3 지점과 타이틀 안전 영역 안에 유지하여 9:16으로 자를 때도 잘리지 않도록 합니다.

스포트라이트 마스크, 화살표 연결선 및 유형별 기능 캡션 트랙은 references/annotation-and-transitions.md를 참조하세요.

화면 간 전환

단계 사이에 일관된 언어로 화면을 이동합니다. 하나를 선택하고 유지하세요.

전환느낌사용
밀기 / 슬라이드"다음 단계" 전진 동작선형 워크스루
교차 확대/축소운동량, 앱과 유사세부 보기로 점프
교차 페이드차분함, 중립적컨텍스트 전환 (설정 → 대시보드)
공유 요소의 매치 컷매끄러움동일한 카드가 화면 간에 유지됨

클릭이 해결될 때까지 나가는 화면을 유지한 후 전환합니다. 절대 움직임 중간에 자르지 마세요. references/annotation-and-transitions.md를 참조하세요.

출력 체크리스트

  • 입력을 2배(DPR 2)로 캡처; 2배 확대/축소에서도 선명도 유지.
  • 모든 커서/확대/축소 값은 useCurrentFrame()의 순수 함수 — 애니메이션 상태에 CSS 전환을 사용하지 않음.
  • 커서는 부드러운 경로(smoothstep)로 이동; 리플과 상태 변경은 동일한 클릭 프레임에서 실행.
  • 각 화면에 프레임이 씌워져 있음(브라우저/기기): 실제 URL과 일관된 테마 사용.
  • 한 번에 하나의 움직임(카메라 또는 커서); 확대/축소 ≤ 2배, 2~4초 유지.
  • 비트당 하나의 혜택 캡션, 타이틀 안전 하단 1/3 지점에 위치; 전환은 하나의 일관된 언어 사용.

전달 및 검증 (렌더링된 스틸 → MP4)

패키지 도우미 (scripts/): scripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.png로 스틸을 바둑판식으로 배열한 후, scripts/probe-mp4.sh out.mp4 [WxH] [fps]로 인코딩을 확인하세요. scripts/README.md 참조.

이것은 무거운 작업입니다: 결과물은 MP4이며, 라이브 페이지가 아닙니다. 데모는 사용자 에셋(스크린샷/디자인, 선택적 로고)을 가져오므로 검증은 주로 올바른 이미지가 실제로 로드되어 프레임 내에 배치되었는지 확인하는 것입니다.

출력 계약:

  • 구성이 등록된 Remotion 프로젝트 (<Composition> + zod schema + defaultProps); 모든 커서/확대/축소/전환 값은 useCurrentFrame()의 순수 함수 (CSS 전환, 타이머, Date.now() 없음).
  • staticFile()을 통해 로드되는 스크린샷, delayRender/continueRender로 게이트 처리되어 2배 PNG(및 모든 웹 폰트)가 프레임 렌더링 전에 존재하도록 함. 그렇지 않으면 데모 중간에 화면이 빈 상태로 나타남.
  • 결과물 = 렌더링된 out/*.mp4 + 프로젝트 (스크린샷이 변경되면 다시 렌더링).

검증 루프 — 스틸 렌더링 → 검사 → 인코딩. 먼저 저렴한 PNG를 만들고, 올바른 경우에만 비디오를 만듭니다.

# 기본값이 아닌 실제 props(실제 스크린샷 경로)를 사용하여 프레임 정확한 스틸 생성
npx remotion still ProductDemo out/f-settle.png --frame=15  --props=demo.json   # 화면 프레임 씌워짐, 이동 전
npx remotion still ProductDemo out/f-click.png  --frame=90  --props=demo.json   # 커서가 대상에 있고 리플 표시됨
npx remotion still ProductDemo out/f-zoom.png   --frame=150 --props=demo.json   # 초점 영역으로 확대 + 캡션
# 종료 프레임 = durationInFrames - 1 (npx remotion compositions가 읽어옴)

각 PNG를 충실도(올바른 스크린샷 로드됨; 커서가 정확한 픽셀에 있음; 클릭 리플과 상태 변경이 같은 프레임에 있음; 캡션 텍스트가 올바름) AND 아티팩트(이미지가 비어 있거나 로드되지 않음, 화면이 캔버스 밖에 있음, 확대/축소가 픽셀화되거나 프레임을 벗어남, 캡션이 타이틀 안전 하단 1/3 지점 밖에 있음, 잘못된 종횡비/레터박싱)에 대해 검사합니다.

# 스틸이 깨끗한 경우에만:
npx remotion render ProductDemo out/demo.mp4 --props=demo.json
npx remotion render ProductDemo out/demo.gif --props=demo.json --codec=gif   # README 첫 화면 증명

일괄 처리 (하나의 템플릿, 여러 제품): 제품별로 데모를 다시 스킨하는 경우, 카탈로그를 일괄 렌더링하기 전에 대표 제품 하나의 props를 스틸로 검증하세요. 빈 이미지나 캔버스 밖 버그를 N번이 아닌 한 번에 잡을 수 있습니다.

마치기 전에:

  1. 스틸이 settle / click / end 프레임에서 오류 없이 깨끗하게 렌더링되고, 스크린샷이 실제로 로드되었는지(비어 있지 않은지) 확인.
  2. 커서가 정확한 대상에 도달; 리플 + 상태 변경이 같은 프레임에 발생; 캡션 텍스트가 올바르고 타이틀 안전 하단 1/3 지점에 위치.
  3. 모든 모션이 프레임 기반 — CSS 전환 / 타이머 / Date.now() / Math.random() 없음.
  4. 실제로 전달된 props(실제 스크린샷 경로)가 올바르게 렌더링되는지 확인 (defaultProps만 확인하지 않음).
  5. 전체 MP4가 인코딩되어 재생됨; (선택 사항) README용 GIF 렌더링 완료.

참조 파일

  • references/screenshot-demo.md — 완전히 실행 가능한 Remotion 데모: Playwright로 2배 스크린샷 캡처, 브라우저/전화 프레임 컴포넌트, 여러 화면에 걸쳐 커서를 클릭 리플과 함께 이동시키는 다단계 구성, 렌더링 명령어 포함.
  • references/annotation-and-transitions.md — 스포트라이트 마스크, 화살표/원 콜아웃 연결선, 유형별 기능 캡션 트랙, 네 가지 화면 간 전환(프레임 기반 구현 및 다중 종횡비(16:9 / 9:16) 안전 영역 참고 사항 포함).

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

관련 스킬