ElevenLabs 음성 해설 생성
ElevenLabs API를 사용하여 Remotion 비디오용 전문 AI 음성 해설을 생성합니다.
필수 조건
.env.local에ELEVENLABS_API_KEY설정
빠른 시작
# 텍스트로 음성 해설 생성
node .claude/skills/elevenlabs-remotion-skill/generate.js --text "여기에 텍스트를 입력" --output public/audio/voiceover.mp3
# 내레이터 스타일로 생성 (더 자연스럽게)
node .claude/skills/elevenlabs-remotion-skill/generate.js --text "당신의 텍스트" --character narrator --output voiceover.mp3
# 요청 스티칭으로 장면 생성
node .claude/skills/elevenlabs-remotion-skill/generate.js --scenes remotion/scenes.json --output-dir public/audio/project/
# 단일 장면 재생성
node .claude/skills/elevenlabs-remotion-skill/generate.js --scenes scenes.json --scene scene2 --new-text "업데이트된 텍스트"
# 사용 가능한 음성 및 캐릭터 프리셋 목록 확인
node .claude/skills/elevenlabs-remotion-skill/generate.js --list-voices
node .claude/skills/elevenlabs-remotion-skill/generate.js --list-characters
캐릭터 프리셋
화면 텍스트를 글자 그대로 읽는 대신 캐릭터 프리셋을 사용하여 더 자연스러운 음성 해설을 얻을 수 있습니다:
| 캐릭터 | 설명 | 최적 사용처 |
|---|---|---|
literal | 텍스트를 정확히 그대로 읽음 | 화면 텍스트, 인용문 |
narrator | 전문적인 스토리텔러, 부드럽고 매력적 | 설명, 다큐멘터리 |
salesperson | 열정적이고 설득력 있으며 활기참 | 마케팅, 광고 |
expert | 권위적이고 자신감 있으며 지식이 풍부함 | 법률 콘텐츠, 튜토리얼 |
conversational | 캐주얼하고 친근하며 자연스러움 | 소셜 미디어, 캐주얼 콘텐츠 |
dramatic | 강렬하고 감정적이며 강력한 영향력 | 후크, 문제 설명 |
calm | 부드럽고 안심시키며 온화함 | 신뢰 구축, 결론 |
# 전역적으로 내레이터 스타일 사용
node .claude/skills/elevenlabs-remotion-skill/generate.js --scenes scenes.json --character narrator --output-dir public/audio/
# 또는 scenes.json에서 장면별로 설정
{
"scenes": [
{ "id": "scene1", "text": "문제 설명", "character": "dramatic" },
{ "id": "scene2", "text": "해결책", "character": "calm" }
]
}
요청 스티칭을 통한 장면 기반 생성
ElevenLabs 요청 스티칭을 사용하여 일관된 운율로 여러 장면을 생성합니다:
scenes.json 형식
{
"name": "product-demo",
"voice": "George",
"character": "narrator",
"scenes": [
{
"id": "scene1",
"text": "일반 텍스트 음성 변환은 로봇처럼 들립니다. 당신의 브랜드는 더 나은 것을 원합니다.",
"duration": 4.5,
"character": "dramatic"
},
{
"id": "scene2",
"text": "음성 복제를 통해 자신의 목소리로 무제한 콘텐츠를 만들 수 있습니다.",
"duration": 5.5
},
{
"id": "scene3",
"text": "짧은 샘플을 녹음하고 복제하세요. 몇 분 만에 전문적인 음성 해설을 만드세요.",
"duration": 6,
"delay": 0.3
}
]
}
모든 장면 생성
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--scenes remotion/product-demo-scenes.json \
--output-dir public/audio/product-demo/
다음 파일이 생성됩니다:
product-demo-scene1.mp3~sceneN.mp3product-demo-combined.mp3(모든 장면이 연결된 파일)product-demo-info.json(길이 정보를 포함한 메타데이터)
단일 장면 재생성
장면이 너무 일찍 시작되거나, 타이밍이 잘못되었거나, 다른 텍스트가 필요한 경우:
# scene2를 새 텍스트로 재생성
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--scenes remotion/scenes.json \
--scene scene2 \
--new-text "업데이트된 장면 2 텍스트" \
--output-dir public/audio/project/
# scene3를 다른 캐릭터로 재생성
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--scenes remotion/scenes.json \
--scene scene3 \
--character salesperson \
--output-dir public/audio/project/
# 단순 재생성 (같은 텍스트, 같은 캐릭터)
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--scenes remotion/scenes.json \
--scene scene1 \
--output-dir public/audio/project/
# MP4 비디오에 썸네일 임베드
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--embed-thumbnail public/videos/my-video.mp4 \
--thumbnail public/videos/my-thumbnail.png \
--output public/videos/my-video-with-thumb.mp4
도구는 자동으로:
- 이전 장면의 요청 스티칭을 사용하여 일관된 운율 유지
- 새 메타데이터로 info.json 파일 업데이트
--new-text가 제공된 경우 scenes.json 업데이트
썸네일 임베딩
MP4 비디오에 썸네일 이미지를 임베드하여 Twitter, YouTube 및 비디오 플레이어가 첫 번째 프레임 대신 사용자 정의 썸네일을 표시하도록 합니다.
비디오에 썸네일 임베드
# 기본 사용법 - video-thumb.mp4로 출력
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--embed-thumbnail public/videos/promo.mp4 \
--thumbnail public/videos/thumbnail.png
# 사용자 정의 출력 경로
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--embed-thumbnail public/videos/promo.mp4 \
--thumbnail public/videos/thumbnail.png \
--output public/videos/promo-final.mp4
Remotion과 함께 사용하는 워크플로우
# 1. 비디오 렌더링
npx remotion render MyVideo public/videos/my-video.mp4
# 2. 썸네일 렌더링 (Still 컴포지션 사용)
npx remotion still MyVideoThumbnail public/videos/my-thumbnail.png
# 3. 썸네일 임베드
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--embed-thumbnail public/videos/my-video.mp4 \
--thumbnail public/videos/my-thumbnail.png \
--output public/videos/my-video-final.mp4
지원 형식
- 비디오: MP4 (H.264/H.265)
- 썸네일: PNG, JPG, JPEG
임베딩은 ffmpeg의 -disposition:v:1 attached_pic 플래그를 사용하여 썸네일을 첨부 이미지로 설정하며, 대부분의 비디오 플레이어와 플랫폼에서 이를 인식합니다.
타이밍 검증
스킬은 ffprobe를 사용하여 생성 후 자동으로 타이밍을 검증합니다:
검사 항목
| 검사 | 임계값 | 설명 |
|---|---|---|
| 길이 불일치 | >15% | 예상 길이와 실제 길이가 다를 경우 경고 |
| 앞쪽 묵음 | >200ms | 오디오가 늦게 시작됨 (음성 해설 지연) |
| 뒤쪽 묵음 | >500ms | 끝에 불필요한 묵음 |
| 말하기 속도 | 2-4.5 wps | 최적 약 3단어/초 |
기존 오디오 검증
# 프로젝트의 모든 장면 검증
node .claude/skills/elevenlabs-remotion-skill/generate.js --validate public/audio/product-demo/
출력 예시:
🔍 product-demo 검증 중 (6개 장면)
❌ scene1: 3.00초 (예상: 4.5초)
❌ 오디오가 예상보다 1.50초 짧음
👍 8단어 @ 3.1단어/초
⚠️ scene2: 6.35초 (예상: 5.5초)
⚠️ 앞쪽 묵음: 235ms (늦게 시작될 수 있음)
🐢 10단어 @ 1.8단어/초
✅ scene4: 4.36초 (예상: 4초)
👍 9단어 @ 2.3단어/초
📊 총 길이: 30.80초 (예상: 30.00초)
업데이트된 info.json
검증 후 info.json에 실제 측정값이 포함됩니다:
{
"scenes": [
{
"id": "scene1",
"duration": 4.5,
"actualDuration": 3.0,
"leadingSilence": 0.05,
"wordsPerSecond": 3.1
}
]
}
정밀한 동기화를 위해 Remotion 컴포지션에서 actualDuration을 사용하세요.
옵션
| 옵션 | 설명 | 기본값 |
|---|---|---|
--text, -t | 음성으로 변환할 텍스트 | 필수 (또는 --file/--scenes) |
--file, -f | 파일에서 텍스트 읽기 | - |
--output, -o | 출력 파일 경로 | output.mp3 |
--output-dir | 장면 출력 디렉토리 | public/audio |
--voice, -v | 음성 이름 또는 ID | George |
--model, -m | 모델 ID | eleven_multilingual_v2 |
--character, -c | 캐릭터 프리셋 | literal |
--scenes | 장면이 포함된 JSON 파일 | - |
--scene | 재생성할 단일 장면 ID | - |
--new-text | 장면 재생성을 위한 새 텍스트 | - |
--validate | 기존 오디오 디렉토리 검증 | - |
--skip-validation | 자동 검증 건너뛰기 | false |
--embed-thumbnail | 썸네일을 임베드할 비디오 파일 | - |
--thumbnail | 썸네일 이미지 파일 (PNG/JPG) | - |
--stability | 음성 안정성 (0-1) | 캐릭터에 따라 다름 |
--similarity | 음성 유사도 (0-1) | 캐릭터에 따라 다름 |
--style | 스타일 강조 (0-1) | 캐릭터에 따라 다름 |
--no-combined | 결합 파일 생성 안 함 | false |
추천 음성
| 음성 | 스타일 | 최적 사용처 |
|---|---|---|
George | 따뜻하고 매력적인 영국식 | 내레이션, 설명 |
Antoni | 전문적이고 따뜻함 | 법률 콘텐츠, 튜토리얼 |
Arnold | 권위적이고 깊이감 있음 | 기업, 진지한 주제 |
Josh | 친근하고 대화체 | 마케팅, 캐주얼 콘텐츠 |
Remotion과의 통합
장면 음성 해설을 생성한 후 컴포지션에서 사용하세요:
import { Audio, Sequence, staticFile } from "remotion";
// 정밀한 동기화를 위해 개별 장면 오디오 파일 사용
const SCENE_DURATIONS = {
scene1: 4.5, // info.json에서 확인
scene2: 5.5,
scene3: 8.0,
};
export const VideoWithVoiceover: React.FC = () => {
const { fps } = useVideoConfig();
const scene1Frames = Math.round(SCENE_DURATIONS.scene1 * fps);
const scene2Frames = Math.round(SCENE_DURATIONS.scene2 * fps);
return (
<>
<Sequence from={0} durationInFrames={scene1Frames}>
<Audio src={staticFile("audio/project/project-scene1.mp3")} />
<Scene1Visual />
</Sequence>
<Sequence from={scene1Frames} durationInFrames={scene2Frames}>
<Audio src={staticFile("audio/project/project-scene2.mp3")} />
<Scene2Visual />
</Sequence>
</>
);
};
최상의 결과를 위한 팁
- 캐릭터 프리셋 사용: 화면 텍스트를 글자 그대로 읽지 말고, 자연스러운 흐름을 위해
narrator또는expert를 사용하세요 - 구두점이 중요: 쉼표는 짧은 멈춤, 마침표는 긴 멈춤에 사용하세요
- 숫자: 자연스러운 발음을 위해 숫자를 풀어서 쓰세요("500" 대신 "오백")
- 약어: 전체 단어를 쓰세요("24h" 대신 "24시간")
- 장면별: 다른 장면에 다른 캐릭터를 사용할 수 있습니다(극적인 도입, 차분한 CTA)
- 세부 조정:
--scene을 사용하여 전체를 다시 생성하지 않고 개별 장면을 재생성하세요 - 요청 스티칭: 모든 장면에서 음성 일관성을 유지합니다
워크플로우 예시
# 1. 스크립트로 scenes.json 생성
# 2. 내레이터 스타일로 모든 장면 생성
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--scenes remotion/my-video-scenes.json \
--character narrator \
--output-dir public/audio/my-video/
# 3. Remotion에서 미리보기, scene2가 너무 일찍 시작됨을 확인
# 4. 업데이트된 텍스트로 scene2만 재생성
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--scenes remotion/my-video-scenes.json \
--scene scene2 \
--new-text "화면 타이밍에 맞춰 약간 더 긴 텍스트" \
--output-dir public/audio/my-video/
# 5. info.json의 새 길이로 비디오 컴포지션 업데이트
# 6. 타이밍이 완벽할 때까지 반복