Community코딩 & 개발github.com

ali-abassi/remotion-templates

선별된 Remotion 비디오 템플릿 모음 - 자막, 시각화, 효과, 전환 등 Claude Code 및 AI 코딩 에이전트용

remotion-templates란 무엇인가요?

이 스킬은 Claude Code 및 AI 코딩 에이전트가 Remotion을 사용하여 프로덕션 수준의 비디오를 제작할 수 있도록 포괄적인 컨텍스트를 제공합니다. 설계 원칙, 선별된 템플릿, 모범 사례를 포함하여 개발자가 React 기반으로 프로그래밍 방식으로 비디오 콘텐츠를 생성할 수 있게 해줍니다. 이 스킬은 다양한 유형의 비디오 제작을 지원합니다: 자막 및 TikTok 스타일 캡션, 오디오 시각화(파형 및 원형), Three.js를 활용한 3D 제품 목업, YouTube 구독 유도 및 Instagram 릴 인트로와 같은 소셜 미디어 템플릿을 포함합니다. 또한 글리치 효과, 입자 필드, 애니메이션 그라데이션과 같은 특수 효과 라이브러리도 제공합니다. 템플릿 외에도 비디오 디자인 원칙(템포, 시각적 위계, 텍스트 규칙, 애니메이션 타이밍), Remotion 프로젝트 구조 설정 방법, 핵심 패턴(애니메이션 기초, 시퀀싱, 텍스트 애니메이션, 오디오 동기화)을 학습할 수 있습니다. 모든 주요 소셜 플랫폼과 프레임 속도(24fps, 25fps, 30fps, 60fps) 및 종횡비를 지원합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add ali-abassi/remotion-templates

Installed? Explore more 코딩 & 개발 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

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

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

문서

목적

이 스킬은 Claude Code 및 AI 코딩 에이전트가 Remotion을 사용하여 프로덕션 수준의 비디오를 제작할 수 있도록 포괄적인 컨텍스트를 제공합니다. 설계 원칙, 선별된 템플릿 및 모범 사례를 포함합니다.

사용 시기

다음과 같은 경우 이 스킬을 사용하세요:

  • React로 프로그래밍 방식으로 비디오 콘텐츠 생성
  • 팟캐스트 오디오그램 또는 오디오 시각화 제작
  • 비디오에 애니메이션 자막 추가 (TikTok/Reels 스타일)
  • 3D 제품 쇼케이스 생성
  • 비디오 생성 SaaS 구축
  • 데이터 시각화 비디오 제작
  • 소셜 미디어 콘텐츠 대량 생성

비디오 설계 원칙

1. 템포 & 리듬

  • 빠른 컷: 1-2초 (에너지 전달, 소셜 미디어)
  • 중간 템포: 3-5초 (이해 위주, 튜토리얼)
  • 느린 템포: 5-10초 (강조, 시네마틱)
  • 오디오 매칭: 비트/음성에 맞춰 전환 동기화

2. 시각적 위계

  • 프레임당 하나의 초점
  • 모션을 사용하여 시선 유도
  • 중요한 요소 대비 강조
  • 일관된 간격 유지

3. 텍스트 규칙

  • 프레임당 최대 7단어
  • 고대비 (어두운 배경에 흰색, 또는 테두리 처리)
  • 텍스트를 두 번 읽을 수 있는 시간 동안 화면에 유지
  • 하단 1/3 또는 중앙에 배치
  • 가장자리 피하기 (안전 영역: 10% 여백)

4. 애니메이션 타이밍

요소지속 시간이징
텍스트 등장8-15 프레임easeOut
텍스트 퇴장6-10 프레임easeIn
장면 전환15-30 프레임easeInOut
로고 노출30-60 프레임spring
빠른 컷0-3 프레임linear

5. 프레임 속도

  • 30fps: 표준 비디오, 소셜 미디어
  • 60fps: 부드러운 모션, 게임 콘텐츠
  • 24fps: 시네마틱 느낌
  • 25fps: 유럽 방송

6. 종횡비

플랫폼비율해상도
YouTube16:91920x1080
TikTok/Reels9:161080x1920
Instagram 피드1:11080x1080
Instagram 스토리9:161080x1920
Twitter16:91280x720
LinkedIn16:91920x1080

빠른 시작

설치

# 템플릿 선택으로 새 프로젝트 생성
npx create-video@latest

# 수동 설정
mkdir my-video && cd my-video
npm init -y
npm install remotion @remotion/cli react react-dom
npm install -D typescript @types/react

프로젝트 구조

src/
├── index.ts           # registerRoot
├── Root.tsx           # Composition 정의
├── compositions/
│   ├── Main.tsx       # 메인 비디오
│   └── Intro.tsx      # 인트로 시퀀스
├── components/
│   ├── Text.tsx       # 애니메이션 텍스트
│   └── Logo.tsx       # 로고 노출
└── assets/
    ├── fonts/
    ├── images/
    └── audio/

Root.tsx 템플릿

import { Composition } from 'remotion';
import { Main } from './compositions/Main';

export const RemotionRoot = () => {
  return (
    <>
      <Composition
        id="Main"
        component={Main}
        durationInFrames={300}
        fps={30}
        width={1920}
        height={1080}
        defaultProps={{
          title: "My Video"
        }}
      />
    </>
  );
};

핵심 패턴

애니메이션 기초

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

const frame = useCurrentFrame();
const { fps, width, height, durationInFrames } = useVideoConfig();

// 선형 보간 (클램프)
const opacity = interpolate(frame, [0, 30], [0, 1], {
  extrapolateRight: 'clamp'
});

// 스프링 애니메이션 (바운스)
const scale = spring({
  frame,
  fps,
  config: { damping: 12, stiffness: 200 }
});

// 지연 스프링
const delayedScale = spring({
  frame: frame - 15, // 15프레임 지연
  fps,
  config: { damping: 10 }
});

시퀀싱

import { Sequence, AbsoluteFill } from 'remotion';

export const MyVideo = () => (
  <AbsoluteFill>
    <Sequence from={0} durationInFrames={60}>
      <Intro />
    </Sequence>
    <Sequence from={60} durationInFrames={120}>
      <MainContent />
    </Sequence>
    <Sequence from={180}>
      <Outro />
    </Sequence>
  </AbsoluteFill>
);

텍스트 애니메이션

const TextReveal = ({ text }: { text: string }) => {
  const frame = useCurrentFrame();
  const words = text.split(' ');

  return (
    <div style={{ display: 'flex', gap: 10, justifyContent: 'center' }}>
      {words.map((word, i) => {
        const delay = i * 5;
        const opacity = interpolate(frame - delay, [0, 10], [0, 1], {
          extrapolateLeft: 'clamp',
          extrapolateRight: 'clamp'
        });
        const y = interpolate(frame - delay, [0, 10], [20, 0], {
          extrapolateLeft: 'clamp',
          extrapolateRight: 'clamp'
        });

        return (
          <span key={i} style={{ opacity, transform: `translateY(${y}px)` }}>
            {word}
          </span>
        );
      })}
    </div>
  );
};

오디오 동기화

import { Audio, useCurrentFrame, interpolate } from 'remotion';
import { getAudioDurationInSeconds } from '@remotion/media-utils';

// 볼륨 엔벨로프
const frame = useCurrentFrame();
const volume = interpolate(frame, [0, 30, 270, 300], [0, 1, 1, 0]);

<Audio src={staticFile('music.mp3')} volume={volume} />

템플릿 카탈로그

자막 & 서브타이틀

remotion-subtitles (17가지 스타일)

npm install @ahgsql/remotion-subtitles
import { Subtitle } from '@ahgsql/remotion-subtitles';

// 사용 가능한 스타일: bounce, fire, glitch, neon, typewriter,
// 3d, lightning, glowing, explosive, wave, slide, fade,
// zoom, rotate, flip, shake, pulse

<Subtitle
  src={staticFile('captions.srt')}
  style="bounce"
  fontSize={48}
  color="#ffffff"
  strokeColor="#000000"
  strokeWidth={2}
/>

TikTok 스타일 자막

const Caption = ({ text, highlight }: { text: string; highlight: number }) => {
  const words = text.split(' ');

  return (
    <div style={{
      position: 'absolute',
      bottom: '20%',
      width: '100%',
      textAlign: 'center',
      fontSize: 64,
      fontWeight: 900,
      textTransform: 'uppercase'
    }}>
      {words.map((word, i) => (
        <span
          key={i}
          style={{
            color: i === highlight ? '#FFE135' : '#FFFFFF',
            textShadow: '4px 4px 0 #000, -4px -4px 0 #000, 4px -4px 0 #000, -4px 4px 0 #000'
          }}
        >
          {word}{' '}
        </span>
      ))}
    </div>
  );
};

오디오 시각화

파형 시각화

import { useAudioData, visualizeAudio } from '@remotion/media-utils';

const Waveform = ({ src }: { src: string }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const audioData = useAudioData(src);

  if (!audioData) return null;

  const visualization = visualizeAudio({
    fps,
    frame,
    audioData,
    numberOfSamples: 64
  });

  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
      {visualization.map((amplitude, i) => (
        <div
          key={i}
          style={{
            width: 8,
            height: amplitude * 200,
            backgroundColor: '#667eea',
            borderRadius: 4
          }}
        />
      ))}
    </div>
  );
};

원형 오디오 시각화

const CircularVisualizer = ({ audioData, frame, fps }) => {
  const visualization = visualizeAudio({ fps, frame, audioData, numberOfSamples: 32 });
  const radius = 150;

  return (
    <svg width={400} height={400} viewBox="0 0 400 400">
      {visualization.map((amp, i) => {
        const angle = (i / visualization.length) * Math.PI * 2;
        const x1 = 200 + Math.cos(angle) * radius;
        const y1 = 200 + Math.sin(angle) * radius;
        const x2 = 200 + Math.cos(angle) * (radius + amp * 100);
        const y2 = 200 + Math.sin(angle) * (radius + amp * 100);

        return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke="#667eea" strokeWidth={4} />;
      })}
    </svg>
  );
};

Three.js를 활용한 3D

설정

npm install @remotion/three three @react-three/fiber @react-three/drei

휴대폰 목업

import { ThreeCanvas } from '@remotion/three';
import { useFrame } from '@react-three/fiber';

const PhoneMockup = ({ videoSrc }: { videoSrc: string }) => {
  const frame = useCurrentFrame();
  const rotation = interpolate(frame, [0, 150], [0, Math.PI * 2]);

  return (
    <ThreeCanvas>
      <ambientLight intensity={0.5} />
      <pointLight position={[10, 10, 10]} />
      <mesh rotation={[0, rotation, 0]}>
        <boxGeometry args={[2, 4, 0.2]} />
        <meshStandardMaterial color="#1a1a2e" />
      </mesh>
    </ThreeCanvas>
  );
};

소셜 미디어 템플릿

Instagram 릴 인트로

const ReelIntro = ({ username, avatar }: Props) => {
  const frame = useCurrentFrame();
  const scale = spring({ frame, fps: 30, config: { damping: 12 } });

  return (
    <AbsoluteFill style={{ background: 'linear-gradient(135deg, #667eea, #764ba2)' }}>
      <div style={{
        transform: `scale(${scale})`,
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
        justifyContent: 'center',
        height: '100%'
      }}>
        <img
          src={avatar}
          style={{ width: 120, height: 120, borderRadius: '50%', border: '4px solid white' }}
        />
        <h1 style={{ color: 'white', fontSize: 48, marginTop: 20 }}>@{username}</h1>
      </div>
    </AbsoluteFill>
  );
};

YouTube 구독 유도

const SubscribeCTA = () => {
  const frame = useCurrentFrame();
  const slideIn = interpolate(frame, [0, 20], [100, 0], { extrapolateRight: 'clamp' });
  const bellWiggle = Math.sin(frame * 0.5) * 10;

  return (
    <div style={{
      position: 'absolute',
      bottom: 50,
      right: 50,
      transform: `translateX(${slideIn}%)`,
      display: 'flex',
      alignItems: 'center',
      gap: 20,
      background: 'rgba(0,0,0,0.8)',
      padding: '20px 30px',
      borderRadius: 50
    }}>
      <div style={{
        background: '#FF0000',
        padding: '12px 24px',
        borderRadius: 4,
        color: 'white',
        fontWeight: 'bold'
      }}>
        SUBSCRIBE
      </div>
      <div style={{ transform: `rotate(${bellWiggle}deg)`, fontSize: 32 }}>
        🔔
      </div>
    </div>
  );
};

효과 라이브러리

글리치 효과

const GlitchText = ({ text }: { text: string }) => {
  const frame = useCurrentFrame();
  const glitchOffset = Math.random() > 0.9 ? Math.random() * 10 - 5 : 0;

  return (
    <div style={{ position: 'relative' }}>
      <span style={{
        position: 'absolute',
        left: glitchOffset,
        color: 'cyan',
        clipPath: 'inset(0 0 50% 0)'
      }}>
        {text}
      </span>
      <span style={{
        position: 'absolute',
        left: -glitchOffset,
        color: 'magenta',
        clipPath: 'inset(50% 0 0 0)'
      }}>
        {text}
      </span>
      <span style={{ color: 'white' }}>{text}</span>
    </div>
  );
};

입자 필드

const Particles = ({ count = 50 }: { count?: number }) => {
  const frame = useCurrentFrame();
  const particles = useMemo(() =>
    Array.from({ length: count }, () => ({
      x: Math.random() * 100,
      y: Math.random() * 100,
      size: Math.random() * 4 + 2,
      speed: Math.random() * 0.5 + 0.2
    })),
    []
  );

  return (
    <AbsoluteFill style={{ overflow: 'hidden' }}>
      {particles.map((p, i) => (
        <div
          key={i}
          style={{
            position: 'absolute',
            left: `${p.x}%`,
            top: `${(p.y + frame * p.speed) % 100}%`,
            width: p.size,
            height: p.size,
            borderRadius: '50%',
            background: 'rgba(255,255,255,0.5)'
          }}
        />
      ))}
    </AbsoluteFill>
  );
};

그라데이션 배경

const AnimatedGradient = () => {
  const frame = useCurrentFrame();
  const hue1 = (frame * 2) % 360;
  const hue2 = (frame * 2 + 120) % 360;

  return (
    <AbsoluteFill
      style={{
        background: `linear-gradient(${frame * 0.5}deg, hsl(${hue1}, 70%, 50%), hsl(${hue2}, 70%, 50%))`
      }}
    />
  );
};

관련 스킬