Communitygithub.com

chandreshpv/remotion-프로모션-비디오-클로드-스킬

Remotion 프로모션 비디오 제작 스킬입니다. 캔버스 크기 조정, 장면 구조, 목업 3D 진입, 커서 애니메이션, 마이크로 애니메이션, 전환, 오디오 및 제작 모범 사례를 다룹니다.

remotion-프로모션-비디오-클로드-스킬란 무엇인가요?

이 스킬은 AI 에이전트(예: Claude Code, Cursor, Codex)가 Remotion을 사용하여 전문가 수준의 프로모션 비디오를 제작할 수 있도록 설계된 포괄적인 가이드입니다. 실제 SureCart 4.2 런칭 비디오 제작 경험에서 비롯된 이 스킬은, AI가 흔히 저지르는 실수(예: 웹사이트와 동일한 폰트 크기를 사용하거나, 부적절한 레이아웃 선택)를 방지하는 '하드 규칙'에 중점을 둡니다. 핵심 기능으로는 캔버스 필링(1920×1080, 내용이 화면의 최소 75%를 채우도록 하는 것), `useCurrentFrame()`을 통한 결정론적 애니메이션, 사전 레이아웃 게이트(내용 양에 따른 올바른 레이아웃 선택을 위한 의사 결정 테이블 포함), 그리고 효과적인 이징 레시피 모음이 포함됩니다. 또한 브랜드 정보 없이 작업할 때 대체 설정부터 시작하여, 사용자가 제공한 실제 자산(스크린샷, 웹사이트 URL)을 기반으로 색상 및 스타일을 추출할 수 있는 '2가지 질문' 사전 점검 프로세스를 안내합니다.

지원 대상✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/chandreshpv/remotion-product-videos-claude-skill/tree/main

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

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

문서

Remotion 시각 제작 스킬

실제 SureCart 4.2 런칭 비디오 제작 경험에서 비롯되었습니다. 작성자: Chandresh Vaghanani


시작 전 — 2가지 질문(필수)

코드를 작성하기 전에 2가지 질문을 물어보세요. 간편하게 한 메시지, 두 질문으로 작성하세요. 사용자가 "그냥 시작해" 또는 "지금 시작해"라고 말해도 절대 건너뛰지 마세요. 이 10초가 몇 시간의 재작업을 방지합니다.

시작하기 전에 — 두 가지만 여쭤볼게요:
1. 배경은 밝은색 또는 어두운색인가요? (또는 웹사이트/스크린샷을 공유해주시면 제가 거기서 추출하겠습니다)
2. 제품 스크린샷이나 목업이 있으신가요? (전적으로 선택사항입니다 — 없어도 제작 가능합니다)

이것으로 끝입니다. 사용자가 더 자세한 정보를 제공하지 않는 한 추가 질문은 하지 마세요.

답변 처리 방법:

  • 목업/스크린샷을 공유한 경우 — 배경색, 강조색, 폰트 스타일, UI 카피를 추출하세요. 이를 사용하세요.
  • 웹사이트 URL을 공유한 경우 — 해당 사이트를 가져와서 동일하게 추출하세요. 추측하지 마세요.
  • 밝음/어두움만 답한 경우 — 아래의 '정보 없음 대체 설정(No-Info Fallback Defaults)'을 진행하세요.
  • 두 질문을 모두 건너뛴 경우 — 아래의 '정보 없음 대체 설정'을 진행하세요. 다시 묻지 마세요.

로고, 음악, 추가 색상 등 다른 자산은 제공되면 수락하되, 절대 진행을 막지 마세요.


정보 없음 대체 설정 (No-Info Fallback Defaults)

브랜드 정보를 사용할 수 없을 때, AI의 본능은 폰트 크기를 줄이고 패딩을 추가하는 것입니다. 비디오에서는 그 본능이 잘못되었습니다. 대신 다음을 적용하세요:

이 설정은 목업, 스크린샷 또는 웹사이트가 제공되지 않을 때 자동으로 적용됩니다. 브랜드 정보가 전혀 없어도 전문적인 결과를 보장합니다.

레이아웃

  • 모든 장면의 AbsoluteFill에 justifyContent: "center" + alignItems: "center" — 예외 없음
  • 콘텐츠를 실제 중앙보다 약간 위로 당기기 위해 marginTop: -50
  • 목업/카드 너비: 1200px (상한선 사용 — 프레임을 채우세요)
  • 컨테이너 패딩: 최대 40px — 그 이상 사용하지 마세요
  • 콘텐츠는 1080px 높이의 최소 75% 를 차지해야 합니다. 그렇지 않으면 폰트 크기를 늘리거나 간격을 줄이세요.

폰트 크기(대체 — 상한선 기준)

요소대체 크기
메인 헤드라인140px
서브 헤드라인56px
본문 / 설명36px
라벨 / 필22px
카드 콘텐츠 텍스트28px

색상(대체 팔레트 — 안전하고 전문적)

  • 배경: #0a0a0f (거의 검정, 중립)
  • 강조: #6366f1 (인디고 — 읽기 쉽고 현대적이며 제품 특정적이지 않음)
  • 텍스트: #ffffff
  • 흐린 텍스트: rgba(255,255,255,0.55)
  • 카드 배경: rgba(255,255,255,0.06)

이것들은 시작점일 뿐입니다. 사용자가 브랜드 색상을 공유하는 즉시 완전히 교체하세요.

브랜드 정보 없을 때 하지 말아야 할 것

  • 네온/사이버 색상을 사용하지 마세요 — 개인 미적 감각일 뿐, 브랜드와 일치하지 않습니다
  • paddingTop: 120을 사용하고 "중앙 정렬됨"이라고 하지 마세요 — 상단 정렬에 데드 스페이스가 있습니다
  • "깔끔해 보인다"고 헤드라인에 fontSize: 32를 선택하지 마세요 — 비디오에서 읽을 수 없습니다

규칙 #1 — 캔버스는 웹사이트가 아닙니다

AI가 생성한 Remotion 비디오에서 가장 흔한 실수입니다.

Remotion 캔버스는 1920×1080px입니다. 웹페이지처럼 디자인하지 말고 캔버스를 채우도록 디자인하세요.

⚠️ 이것들은 최소값입니다. 본문 텍스트에 fontSize: 18을 쓰는 것은 버그이며, 스타일 선택이 아닙니다. 최소값 열 아래의 값은 텍스트가 1080p 화면에서 읽을 수 없음을 의미합니다. 이 숫자들을 타입 오류처럼 취급하세요 — 진행하기 전에 반드시 수정해야 합니다.

요소최소값(엄격한 하한선)권장 범위
메인 헤드라인80px100–160px
서브 헤드라인40px48–72px
본문 / 설명28px32–40px
라벨 / 필 / 배지18px20–24px
카드 콘텐츠 텍스트22px24–32px

규칙:

  • 콘텐츠가 화면을 가득 채우는 느낌이 들어야 함
  • 목업 카드: width: 1100–1200px, 가운데 정렬
  • 컨테이너 패딩: 최대 48px — 웹페이지처럼 80–120px가 아님
  • 텍스트가 "편안함을 넘어서는 크기"로 느껴지면 — 비디오에는 적합할 가능성이 높음

규칙 #2 — 모든 애니메이션은 useCurrentFrame()을 사용해야 합니다

// 올바른 예
const frame = useCurrentFrame();
const opacity = interpolate(frame, [0, 20], [0, 1], {
  extrapolateLeft: "clamp",
  extrapolateRight: "clamp",
});

// 금지 — 올바르게 렌더링되지 않음
// CSS: transition: opacity 1s ease
// Tailwind: animate-fade-in
// CSS @keyframes

명시적으로 경계 없는 값이 필요한 경우가 아니라면 모든 interpolate() 호출에 항상 extrapolateLeft: "clamp" 와 extrapolateRight: "clamp"를 포함하세요. 이것을 잊으면 값이 범위를 벗어나 미묘한 버그를 일으킵니다.


규칙 #3 — 결정론

// 금지 — 렌더링 패스마다 다른 값
const x = Math.random() * 100;

// 올바른 예 — 항상 동일한 값, 모든 프레임에서 동일
import { random } from "remotion";
const x = random("particle-x-1") * 100; // 문자열 시드 = 결정론적

규칙 #4 — 자산

import { staticFile } from "remotion";
import { Img } from "remotion";        // 네이티브 <img>가 아님
import { Audio } from "@remotion/media";

// public/ 폴더의 모든 항목에는 항상 staticFile() 사용
<Audio src={staticFile("bg-music.mp3")} />
<Img src={staticFile("logo.png")} />   // <Img>는 프레임 렌더링 전에 자산 로드를 보장

// 원격 URL은 staticFile()이 필요 없지만 CORS는 필요함

규칙 #5 — 부드러운 미리보기 재생

무거운 컴포넌트가 시작 시간 30프레임 전에 미리 로드되도록 <Sequence> 컴포넌트에 premountFor={30}을 추가하세요:

<Sequence from={90} durationInFrames={120} premountFor={30}>
  <HeavyScene />
</Sequence>

이징 레시피

import { Easing } from "remotion";

// 선명한 UI 진입 (강한 ease-out, 오버슈트 없음) — 대부분의 진입 애니메이션
Easing.bezier(0.16, 1, 0.3, 1)

// 느린 에디토리얼 페이드 (균형 잡힌 ease-in-out) — 분위기 전환
Easing.bezier(0.45, 0, 0.55, 1)

// 장난기 있는 오버슈트 — 탱글탱글/재미있는 요소
Easing.bezier(0.34, 1.56, 0.64, 1)

// 스프링 — 바운스 없음 (목업 진입, 카드, UI)
spring({ frame, fps, config: { damping: 200 } })

// 스프링 — 약간의 바운스가 있는 스냅 (펀치감 있는 요소)
spring({ frame, fps, config: { damping: 20, stiffness: 200 } })

// 스프링 — 바운시/장난기
spring({ frame, fps, config: { damping: 8 } })

사전 레이아웃 게이트 — 장면 레이아웃을 작성하기 전에 실행

이것들은 제안이 아닙니다. 어떤 장면의 첫 번째 <div>를 작성하기 전에 세 가지 게이트를 모두 실행하세요. 게이트 중 하나라도 실패하면 레이아웃을 변경하세요 — 고정된 치수나 추가 콘텐츠로 패치하지 마세요.


게이트 1 — 캔버스 채우기 (양축, 필수)

너비 축:
  dead_side = (1920 − content_width) / 2
  ≤ 300px이어야 함. > 300px인 경우 → 콘텐츠가 너무 좁습니다. 넓히거나 레이아웃을 변경하세요.

높이 축:
  fill_h = content_height / 1080
  ≥ 0.80이어야 함. < 0.80인 경우 → 콘텐츠가 너무 짧습니다. 레이아웃 형태를 변경하세요.

⚠️ 높이가 실패할 경우, 카드나 컨테이너에 고정 높이를 설정하여 수정하지 마세요. 고정 높이는 카드 내부에 빈 공간을 생성합니다 — 데드 스페이스가 제거되지 않고 요소 내부로 이동합니다. 유일한 실제 해결책은 레이아웃 형태를 변경하는 것입니다(게이트 2).

실패 사례 — 3개의 짧은 기능 카드:

버전content_widthdead_sidecontent_heightfill_h결과
v1: 3열 카드 (365px)1151px384px416px38%❌ 두 축 모두 실패
v2: 강제 height: 720px1542px189px864px80%✅ 너비, ❌ 시각적(카드 내 빈 공간)
v3: 가로 행 (1400px)1400px260px916px85%✅ 두 축 모두 통과

게이트 2 — 레이아웃 선택 결정 테이블

콘텐츠 양이 레이아웃 형태를 결정합니다. 코드를 작성하기 전에 이 테이블에서 레이아웃을 선택하세요.

항목 수항목당 콘텐츠올바른 레이아웃이유
3–5개 항목아이콘 + 이름 + 1줄가로 행 (1400px 너비)짧은 콘텐츠가 세로로 쌓임 → 높이를 자연스럽게 채움
3개 항목아이콘 + 이름 + 2–3줄3열 카드 (최소 1100px 너비)카드 높이를 채울 충분한 콘텐츠
2개 항목중요나란히 큰 카드 또는 분할 화면
1개 항목무엇이든전체 화면 히어로

콘텐츠에 대한 자연스러운 레이아웃이 게이트 1 후에 어느 축이든 임계값 미만으로 남으면 — 그 레이아웃은 잘못된 것입니다. 이 테이블에서 다른 행을 선택하세요.

미적 감각이나 기본 본능으로 레이아웃을 선택하지 마세요. 콘텐츠 적합성이 먼저입니다. 미적 감각은 그 다음입니다.


게이트 3 — 콘텐츠 밀도 제한

항목당 최대: 아이콘 + 이름 + 짧은 1줄. 엄격한 중단. 글머리 기호, 하위 섹션, 단락, 추가 설명 줄은 금지됩니다.

시청자는 장면당 약 5초를 봅니다. 그들은 1줄을 읽습니다. 4개의 글머리 기호를 읽지 않습니다.

콘텐츠가 부족하게 느껴지고 공간을 채우기 위해 더 추가하고 싶다면 — 이는 게이트 2가 레이아웃 형태가 잘못되었음을 알리는 것이지, 콘텐츠가 부족하다는 것이 아닙니다.

빈 공간은 크기(더 큰 폰트, 더 큰 아이콘, 항목 간 더 큰 간격)로 채우세요 — 절대 더 많은 콘텐츠로 채우지 마세요.


범용 장면 규칙

  1. 수직 정렬 — justifyContent: "center" + marginTop: -40 ~ -60 (실제 중앙보다 약간 위 = 현대적이고 프리미엄 느낌. 패딩으로 상단 정렬하지 않음)

    ❌ 잘못된 예 — 상단 정렬, 하단에 빈 공간 발생:

    <AbsoluteFill style={{ display: "flex", flexDirection: "column", paddingTop: 110 }}>
      <h1>헤드라인</h1>
      <p>서브텍스트</p>
      {/* 하단에 큰 빈 공간 */}
    </AbsoluteFill>
    

    ✅ 올바른 예 — 수직 중앙 정렬, 중간점보다 약간 위:

    <AbsoluteFill style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", marginTop: -50 }}>
      <h1>헤드라인</h1>
      <p>서브텍스트</p>
      {/* 콘텐츠가 프레임을 채움 — 데드 스페이스 없음 */}
    </AbsoluteFill>
    
  2. 캔버스 채우기 — 이 장면을 작성하기 전에 사전 레이아웃 게이트를 실행하세요. 게이트 1은 너비(dead_side ≤ 300px)와 높이(fill_h ≥ 0.80)를 함께 확인합니다. 게이트 2는 결정 테이블에서 레이아웃 형태를 선택합니다. 게이트 3은 항목당 콘텐츠를 제한합니다. 세 게이트 모두 위의 사전 레이아웃 게이트 섹션에 있습니다 — 이전에 있던 너비 전용 검사를 대체합니다.

  3. 헤드라인 z-index — 헤드라인 컨테이너에 항상 zIndex: 20을 설정하여 목업이 텍스트와 겹치지 않도록 함

  4. 헤드라인 오버플로우 — 헤드라인 텍스트에 항상 whiteSpace: "nowrap" 설정 (목업 뒤에서 줄 바꿈 방지)

  5. AbsoluteFill에 overflow: hidden 금지 — 커서 및 SVG 요소를 자릅니다. 제거하거나 커서를 외부에 배치하세요.

  6. 15프레임 유지 — 모든 장면은 전환이 시작되기 전에 완전히 보이는 유지 프레임을 최소 15개 가져야 합니다. 나가는 장면에서 애니메이션이 재생 중일 때 전환을 시작하지 마세요.

  7. 폰트 — 전체적으로 일관된 하나의 폰트를 사용하세요. 권장: @remotion/google-fonts를 통한 Plus Jakarta Sans. 최대 사용 가능 두께: 800 (fontWeight: 900을 쓰면 800으로 렌더링됨).

  8. 색상 — 최대 2–3개의 브랜드 색상. 하나의 어두운 배경, 하나의 기본 강조색, 텍스트용 흰색/흐린 흰색. 모든 장면에서 일관되게 사용.

타이포그래피 계층 구조

// 슈퍼타이틀 / 라벨 필
{ fontSize: 20, letterSpacing: "4px", textTransform: "uppercase", fontWeight: 600 }

// 메인 헤드라인
{ fontSize: 112, fontWeight: 800 }  // 범위: 100–160px

// 서브텍스트 / 설명
{ fontSize: 36, opacity: 0.7 }  // 범위: 32–40px

// 신뢰 라인 / 작은 배지
{ fontSize: 26, opacity: 0.5 }  // 범위: 24–28px

폰트 설정

import { loadFont } from "@remotion/google-fonts/PlusJakartaSans";

// 최상위 레벨에서 호출 — 렌더링 전에 로드되어야 함
const { fontFamily } = loadFont("normal", {
  weights: ["400", "600", "800"],
  subsets: ["latin"],
});

다른 폰트의 경우: @remotion/google-fonts/FontName을 통해 설치하거나 .woff2 파일을 public/에 넣고 @remotion/fonts에서 loadFont를 사용하세요.


장면 구조 템플릿

모든 장면은 다음의 고정된 레이어 순서를 따릅니다(아래 → 위):

<AbsoluteFill style={{ background: brandBg }}>
  {/* 배경 요소 (그라데이션, 패턴, 입자) */}
  {/* 콘텐츠 영역 (헤드라인, 본문) — zIndex: 20 */}
  {/* 목업 / 스크린샷 */}
  {/* 오버레이 (커서, 장식용 SVG) */}
</AbsoluteFill>

주석 처리된 장면 예제

다음은 useCurrentFrame(), 캔버스 채우기, 적절한 간격 및 결정론적 애니메이션을 보여주는 완전한 주석 처리된 Remotion 장면입니다.

import { AbsoluteFill, useCurrentFrame, interpolate, Easing, spring, Img, staticFile } from "remotion";
import { loadFont } from "@remotion/google-fonts/PlusJakartaSans";

const { fontFamily } = loadFont("normal", { weights: ["400", "600", "800"], subsets: ["latin"] });

// 브랜드 색상 (사용자 입력에서 추출하거나 대체 사용)
const brandBg = "#0a0a0f";
const brandAccent = "#6366f1";
const brandText = "#ffffff";

export const HeroScene: React.FC = () => {
  const frame = useCurrentFrame();

  // 결정론적 페이드 인 (규칙 #2 및 #3)
  const opacity = interpolate(frame, [0, 20], [0, 1], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
  });

  // 아래에서 위로 슬라이드 (약간의 스프링 오버슈트)
  const slideUp = spring({
    frame,
    fps: 30,
    config: { damping: 20, stiffness: 200 },
  });

  return (
    <AbsoluteFill
      style={{
        backgroundColor: brandBg,
        justifyContent: "center",
        alignItems: "center",
        marginTop: -50, // 시각적 중앙보다 약간 위
        opacity,
      }}
    >
      {/* 헤드라인 컨텐츠 — zIndex: 20 */}
      <div style={{ zIndex: 20, textAlign: "center" }}>
        <h1
          style={{
            fontFamily,
            fontSize: 140, // 캔버스 채우기 — 규칙 #1
            fontWeight: 800,
            color: brandText,
            whiteSpace: "nowrap",
            margin: 0,
            transform: `translateY(${(1 - slideUp) * 50}px)`,
          }}
        >
          제품 출시
        </h1>
        <p
          style={{
            fontFamily,
            fontSize: 40,
            color: "rgba(255,255,255,0.7)",
            margin: "10px 0 0 0",
          }}
        >
          더 빠르게, 더 스마트하게
        </p>
      </div>

      {/* 목업 이미지 */}
      <Img
        src={staticFile("product-mockup.png")}
        style={{
          width: 1200,
          marginTop: 40,
        }}
      />
    </AbsoluteFill>
  );
};

빠른 참조

  • 캔버스: 1920×1080, 항상 채우기
  • 헤드라인 최소값: 80px, 권장 100–160px
  • 목업 너비: 1100–1200px
  • 수직 정렬: 가운데 + marginTop -50
  • 게이트 1: dead_side ≤ 300px, fill_h ≥ 0.80
  • 게이트 2: 콘텐츠 양에 따라 결정 테이블에서 레이아웃 선택
  • 게이트 3: 항목당 아이콘 + 이름 + 1줄, 그 이상 금지
  • 애니메이션: useCurrentFrame() + interpolate() + clamp
  • 결정론: Math.random() 금지, random("seed") 사용
  • 자산: public/의 경우 staticFile(), 원격 URL은 CORS 필요
  • 이징: UI 진입용 Crisp bezier(0.16,1,0.3,1)
  • end 유지: 전환 전 15프레임 유지

관련 스킬