개발 기록 2026-10-29 오전: 주제만 넣으면 유튜브까지 올리는 영상 스킬, 썸네일 스킬, 무료 TTS 전환

· 약 9분 읽기 · 조회 3 #개발기록#Claude Code#Codex CLI#Remotion#HyperFrames#유튜브 자동화

어제 저녁부터 오늘 오전까지 역사 교양 영상을 만드는 흐름을 처음부터 한 번 손으로 돌렸다. 그 과정을 스킬로 묶었고, 스킬로 영상 여러 편을 연달아 올렸다. 썸네일 만들기도 스킬로 분리했다. 중간에 ElevenLabs 크레딧이 떨어져서 음성 엔진을 무료 edge-tts로 바꿨다. 영상을 검수하다가 장면이 바뀔 때 음성 첫머리가 흐려지는 문제를 찾아 고쳤다.

첫 영상: 이집트 피라미드 4500년

처음에는 Claude Code에 작업 순서를 직접 정해 줬다.

  1. 이미지는 Codex CLI로 만든다.
  2. 자막에 쓸 대본을 쓴다.
  3. 대본으로 ElevenLabs 음성을 만든다.
  4. 음성과 그림을 HyperFrames와 Remotion으로 편집하고 효과를 넣는다.

Claude Code는 바로 만들지 않고 이야기 방향 세 가지를 먼저 내놨다. 그중 "돌 하나의 4500년"을 골랐다. 석회암 블록 하나가 채석장에서 피라미드 꼭대기까지 가는 흐름이고, 장면 끝에 나온 물건이 다음 장면을 연다. 여기에 다른 안에 있던 노동자 마을 장면을 끼워 넣어 13장면, 그림 16장으로 기획을 확정했다.

결과물은 3분 48초짜리 1920×1080, 30fps 영상이다. 음량은 -16 LUFS, 최고 레벨은 -1.5 dBFS로 맞췄다. 단계별로 정리하면 다음과 같다.

  • 그림: Codex CLI로 16장을 만들었다. 같은 블록(붉은 삼각형 표식)이 장면마다 이어지도록 모든 그림에 공통 스타일 문구를 붙였다.
  • 음성: ElevenLabs Brian 목소리로 장면별로 만들었다. 숫자를 잘못 읽는 일이 있어서 음성용 대본에서만 숫자를 한글로 풀어 썼다. 자막에는 숫자를 그대로 보여 준다.
  • HyperFrames: 그림이 천천히 움직이는 효과, 숫자가 올라가는 효과, 피라미드 윤곽선 그리기, "노예가 지었다?"에 줄 긋기, "쿠푸의 친구들" 도장, 장면 전환을 넣었다.
  • Remotion: 음성에 맞춘 자막, 비네트, 끝부분 페이드를 넣고 최종 파일로 합쳤다.

유튜브 업로드를 브라우저로

로그인된 ego 브라우저로 "아키의 공백" 채널에 공개로 올렸다. 설명란에는 장면별 챕터 13개를 넣었다. 그림은 AI 재현 이미지이고 내레이션은 AI 음성이라는 안내, 연도와 수치는 추정치라는 안내도 함께 넣었다. 'AI 사용(변경되거나 합성된 콘텐츠)' 항목은 "예"로 표시했다. 업로드가 끝난 뒤 로그인 없이 영상 정보를 조회해 제목이 나오는지 보고 공개 상태를 확인했다.

워크플로우를 topic-video-youtube 스킬로

다음으로 한 번 돌린 흐름을 되짚어 스킬로 만들었다. "역사: 로마 수도교"처럼 분야와 제목만 넣으면 끝까지 진행해 공개 업로드까지 하는 스킬이다. 진행 순서는 이렇다.

  1. 영상 전체를 이끌 물건 하나를 정한다. 영상에 나올 숫자와 연도는 목록으로 뽑아 웹 검색으로 확인하고, 확인이 안 되면 빼거나 "약", "추정"으로 표시한다.
  2. Codex CLI로 그림 13~16장을 4장씩 동시에 만들고, 어색한 그림만 다시 만든다.
  3. 약 1,500자 대본을 쓰고 녹음한다.
  4. HyperFrames와 Remotion으로 편집한다. 음량은 자동으로 맞추고, 받아쓰기로 발음을 점검한다.
  5. 업로드한다.

스킬로 처음 돌린 주제는 로마 수도교였다. 영상은 3분 36초이고, 월계수 잎 하나가 물길을 따라 트레비 분수까지 가는 흐름이다. 업로드는 처음 두 번 실패했다. 첫 시도에서는 파일이 다 올라가기 전에 스크립트가 탭을 닫았고, 그 바람에 제목과 설명이 날아갔다. 세 번째에 성공했고, 편집 화면에서 제목·설명·태그·아동용 여부·AI 표시가 모두 저장된 것을 확인했다.

이후 같은 스킬로 아래 영상을 이어서 올렸다.

주제 이끄는 물건 길이
인더스 문명 유니콘 도장 3분 34초
영조와 정순왕후 잡곡밥 밥상 3분 26초
세종과 장영실 자격루 물 한 방울 3분 26초
팔레스타인·이스라엘 분쟁 올리브나무 한 그루 4분 0초
러시아 부동항 얼음에 갇힌 쇠닻 4분 1초
발칸반도 화약고 모스타르 옛 다리 4분 9초
조선 엽기 범죄 기록(웹툰체) 은비녀 3분 30초

사실 확인 결과는 영상마다 SPEC.md에 남겼다. 몇 가지 사례는 이렇다.

  • 인더스: 인구 4만 명과 추 기준 13.7g은 "추정"으로 표시했다.
  • 세종과 장영실: 측우기는 1441년 실록 기록을 근거로 다뤘다.
  • 조선 범죄 기록: 시신, 피, 상처, 목맨 모습은 그리지 않았다. 고리 모양 밧줄이 나온 그림은 다시 만들었다.

썸네일 스킬 youtube-thumbnail

인더스 영상에서 썸네일 만들기를 먼저 시험했다. 그림과 한글 글자를 둘 다 Codex CLI가 한 번에 그리게 했는데, 후보 2장 모두 글자가 정확하게 나왔다. 썸네일 문구는 영상 제목과 다른 미끼인 "아무도 / 못 읽는 글자"로 잡았다.

이걸 별도 스킬로 분리하고 영상 스킬에도 연결했다. 스킬이 하는 일은 네 가지다.

  1. 제목과 다른 각도의 문구(두 줄, 12자 이내)와 그림을 정한다.
  2. 1280×720 후보 2장을 만든다. 휴대폰 목록 크기(폭 320px)로 줄였을 때 어떻게 보이는지 비교하는 이미지도 함께 만든다.
  3. 한글 오타, 작은 화면에서 읽히는지, 글자가 주인공 물건을 가리는지를 보고 한 장을 고른다.
  4. 고른 썸네일을 YouTube Studio에서 영상에 적용하고, 결과를 적용 완료·전화번호 인증 필요·로그인 필요·오류 중 하나로 알린다.

채널 영상 전체에 일괄 적용도 해 봤다. 17개 중 14개에 들어갔고, Studio의 "변경사항이 저장됨" 알림과 다시 불러온 화면으로 확인했다. 피라미드 썸네일은 후보 2장 모두 썰매에 바퀴가 그려져 있어서 바퀴 없는 썰매로 다시 만들었다.

나머지 3개는 "아동용 동영상인가요?" 항목이 비어 있어 Studio가 저장을 막았다. 이 항목은 법적 신고(COPPA)라서 Claude Code가 임의로 고르지 않고 물어 왔다. 결국 내가 직접 처리했다.

영조 영상에서는 처음 문구 "영조가 매일 먹은 것"이 기록으로 확인한 사실이 아니어서 "83세 왕의 거친 밥상"으로 바꿨다. 러시아 영상은 게시 직후 썸네일 저장이 실패했다. Studio가 아직 영상을 처리하던 중으로 보이고, 몇 분 뒤 다시 시도해 적용됐다.

ElevenLabs 크레딧 소진과 TTS 엔진 교체

러시아 부동항 영상은 ElevenLabs 크레딧이 떨어져 녹음 단계에서 멈췄다. 그래서 대안을 차례로 검토했다.

  • 로컬 모델: M1 Ultra(메모리 128GB)라 CosyVoice 2나 MeloTTS 같은 모델을 직접 돌릴 수 있다. 다만 지금 tts.py는 ElevenLabs가 함께 주는 글자별 시각으로 자막을 맞춘다. 로컬 모델은 이 시각을 주지 않으니 Whisper로 단어 시각을 따로 뽑아야 한다.
  • Airy: 공식 API가 있다(POST https://api.airy.so/v1/audio/speech). 한국어를 지원하고, 한 번에 1,600자까지 보낼 수 있으며, 약관상 상업적 이용이 가능하다. 한국어는 글자당 1.5크레딧이라 영상 하나에 약 2,100크레딧이 든다.
  • edge-tts: 가입이나 키 없이 파이썬 도구로 바로 쓸 수 있다. 한국어 목소리는 인준·현수·선희 3개다. 단어마다 시작 시각을 돌려줘서 자막을 바로 맞출 수 있다. 받아쓰기로 점검해 보니 숫자를 우리말로 풀어 쓰지 않아도 바르게 읽는 것으로 보였다. 대신 법적 근거는 약하다.

결국 tts.py가 edge(기본, 무료), Airy(키체인에 저장한 키), ElevenLabs 중 하나를 고르게 바꿨다. 러시아 영상은 edge 인준 목소리로 완성해 올렸다. 받아쓰기에서 "해협"이 "해엽"으로 나왔는데, 실제 발음에서 ㅎ이 약해지는 현상이라 그대로 두었다.

장면이 바뀔 때 음성 첫머리가 흐려지는 문제

영상을 보다가 컷이 넘어갈 때마다 음성 첫 소리가 흐렸다가 선명해지는 게 들렸다. 처음에는 음량 보정(loudnorm)이 장면 앞 무음 뒤에 늦게 따라붙는 게 원인이라고 의심했다. 그런데 원본 음성과 최종 영상의 첫머리 모양을 비교해 보니 같았다. 렌더와 음량 보정은 원인이 아니었다.

실제 원인은 장면마다 TTS를 따로 호출한 것이었다. TTS는 호출할 때마다 첫 음절에 숨소리 섞인 소리가 붙는다. ElevenLabs로 만든 영상 세 편 모두 장면 첫 소리의 고음 성분이 약 3,600Hz로, 장면 안 문장 시작(약 2,600Hz)보다 유독 높았다.

검수 중에 문제가 하나 더 나왔다. edge가 알려주는 단어 시각이 실제 소리보다 약 0.28초 빨라서 자막이 먼저 떴다.

tts.py와 SKILL.md를 이렇게 고쳤다.

  • 대본 전체를 한 번에 합성한 뒤, 장면 사이 쉼에서 잘라 장면별 파일을 만든다. 흐린 첫 음절은 영상 맨 처음에 한 번만 난다.
  • edge 자막은 실제 첫 소리 위치를 찾아 그만큼 시각을 민다.

이미 올린 영상은 다시 만들지 않고 스킬만 고쳤다. 고친 뒤 처음 만든 발칸반도 영상에서는 자막과 소리 차이가 0.01초로 나왔다. 장면 첫머리 선명도도 장면 중간과 비슷했다.

스킬이 스스로 배우게 하기

마지막으로 규칙을 하나 정했다. 작업하면서 스스로 고치거나 보정한 것, 새로 알게 된 사실은 매번 스킬에 반영한다. 이를 위해 영상 스킬에는 "9. 스킬 업데이트", 썸네일 스킬에는 "6. 스킬 업데이트" 단계를 넣었다.

  • 반영할 것: 고친 스크립트, 버그 원인, 측정값, 서비스 변화(오류 코드, 한도, 요금), 그림이나 사실 확인에서 걸린 함정
  • 반영할 곳: 코드는 scripts/에 넣고, 원인과 대처는 해당 단계나 "지난 실행에서 배운 함정"에 한두 줄로 적는다.
  • 넣지 않을 것: 그 영상에만 해당하는 내용은 프로젝트의 SPEC.md에만 둔다.

이 규칙은 Claude Code 기억에도 저장해서 새 대화에서도 지키게 했다.

남은 것

  • 배경음악이 없다. ElevenLabs 키에 음악 생성 권한이 없다.
  • 피라미드 영상은 게시 당시 유튜브 저작권 검사가 진행 중이었고, 결과는 확인하지 못했다.
  • 로마 수도교 업로드 실패로 생긴 쓸모없는 초안이 채널에 남아 있다.
  • edge-tts는 무료로 잘 되지만 법적 근거가 약하다. 음성은 받아쓰기로만 점검했고 사람이 직접 듣지는 않았다.
  • 조선 범죄 영상에 나온 은비녀 독살 검사법은 원문을 확인하지 못해 "『무원록』 계열에 전하는 방법"으로만 표현했다.
  • 영상 스킬과 썸네일 스킬이 실제 업로드까지 문제없이 이어지는지는 몇 편으로 확인했지만, 웹툰체처럼 스타일이 다른 요청은 아직 한 번만 돌려 봤다.

댓글 0개

아직 댓글이 없습니다. 첫 댓글을 남겨보세요.

댓글 쓰기

← 목록으로 돌아가기