오후 내내 topic-video-youtube 스킬을 손봤다. 핵심은 세 가지다. 영상을 vox 스타일로 바꿨고, 제작과 검수를 두 에이전트로 나눴고, 느려진 제작 속도를 측정해서 줄였다. 그 사이에 영상 4편을 「아키의 공백」 채널에 올렸다. 중간에 Open Notebook을 설치했다가 지웠다.
이미지 나열에서 vox 스타일로
기존 파이프라인은 이미지 → 타임라인 배치 → 음성 순서였다. 결국 정지 이미지를 시간만큼 늘어놓는 구조라 화면이 밋밋했다. 그래서 기획 순서를 바꾸는 문서를 첨부해서 "16세기 한양에 떨어진다면" 영상을 만들게 했다.
바뀐 방향은 이렇다.
- 이미지는 주인공이 아니라 배경 plate로 쓴다. 연출은 코드로 만든 도형, 타이포그래피, 키프레임 레이어가 맡는다.
- 타임라인의 기준은 음성이다. edge-tts의 WordBoundary 타이밍을 먼저 뽑고, 장면 길이와 키워드 강조를 그 타이밍에 맞춘다.
- 기획 순서는 스타일 바이블 → 음성 타이밍 → 씬별 레이어 스펙 → 에셋 생성 규격 → 모션 컴포넌트 → 렌더·QA다.
결과 영상은 3분 21초, -15.9 LUFS다. 구성은 아래와 같다.
- 배경판 12장: 왼쪽을 비워 글자 자리로 썼다.
- 투명 오브젝트 8개: 스마트폰, 호패, 순라군 등
- 코드 그래픽: 키워드 박스, 숫자 카운터, 화살표, 도장
- 장면 전환: 색면 와이프
모든 등장은 그 단어를 말하는 순간에 맞췄다. "28번"이라고 말할 때 28이 뜨는 식이다.
업로드는 한 번 실패했다. 로그인은 되어 있었는데 Studio 화면에 "동영상 업로드" 버튼이 2개 떠서 스크립트가 어느 것을 누를지 못 정했다. 보이는 첫 번째 버튼을 누르도록 고치고 스킬 문서에 적었다. 썸네일은 두 번 다 응답 없이 멈춰서 일단 중단했다.
제작과 검수를 두 에이전트로
스킬을 두 에이전트로 나눴다.
video-maker: 조사, 대본, 그림, 음성, 장면 구성, 렌더를 맡는다. 업로드는 하지 않는다. checker의 보고를 받으면 지적된 파일만 고친다.video-checker: 파일을 읽기만 한다. PASS 또는 FAIL을 내고, 문제를 장면 번호와 함께 적는다.
checker의 수치 검사는 새로 만든 qa_check.py가 한다.
- 장면별 음량 차이: 2 dB를 넘으면 경고, 4 dB를 넘으면 실패
- 장면 첫머리에서 소리가 작아지는지
- 자막과 소리의 싱크
- 영상과 음성의 길이
- 화면에 나온 숫자가 내레이션에 있는지
- 3초 넘게 멈춘 구간
사람처럼 판단하는 검사도 있다. 화면 글자와 그림, 음성이 같은 말을 하는지 본다. 받아쓰기로 발음을 확인하고, SPEC.md를 기준으로 이야기 맥락과 사실을 확인한다.
업로드 채널을 「아키의 공백」으로 고정하는 규칙도 스킬에 넣었다.
첫 maker/checker 영상: 조선 노비
"조선시대 노비의 실제 근무시간과 연봉"으로 첫 실행을 했다. 검수를 세 번 돌려 PASS를 받았다.
- 1회차 FAIL: 연도를 0부터 세어 올리는 효과 때문에 1초쯤 틀린 연도가 보였다(663년 → … → 1755년). 스킬 코드의 버그라 지난 영상에도 있던 문제였다. 이제 "년"이 붙은 숫자는 세어 올리지 않는다.
- 함께 고친 것: 노비가 돈을 받은 것처럼 읽히는 문구, 근거 없는 원인 설명, 1801년 장면의 궁궐 문(광화문형 → 돈화문형), 솔거·외거·공노비 발음
- 2회차 FAIL: 키워드가 단어 안의 글자에 걸려 10초 일찍 떴다. "노비는" 속의 "비는"에 걸린 경우다.
최종 영상은 3분 51초, 12장면이다. 제목은 "조선 노비의 연봉은 얼마였을까? | 받는 돈이 아니라 바치는 면포였다"다. 영상은 https://youtu.be/dL8u7rB7HaY 에 있다.
썸네일은 기본값
노비 영상에는 썸네일이 빠져 있었다. 한양 때 "썸네일 작업은 그만"이라고 한 말을 에이전트가 이후 영상까지 넓게 적용한 탓이다. "앞으로도 기본으로 넣는다"를 스킬 문서와 메모리에 저장했다. "그만"은 그 작업에만 적용된다.
그 뒤 노비 영상에 썸네일 B를 넣었다. 「아키의 공백」에 다시 올라간 한양 영상에도 썸네일 A("1590년 한양 / 하루도 못 버틴다")를 넣었고, 첫 시도에 바로 됐다.
고대 로마 브이로그
세 번째 영상은 "고대 로마 시민의 하루 브이로그"다. 3분 35초, 12장면이고 목소리는 edge 인준이다. 영상은 https://youtu.be/PEdbDvCoNZ8 에 있다.
- 검수 1회차 FAIL: "저녁 식사가 시작돼"처럼 근거 자료보다 세게 단정한 대사 때문이었다.
- 검수 2회차 PASS: 경고 2건이 남았다. 소파처럼 보이는 의자와, 장면 첫머리에 4개가 동시에 움직이는 부분이다. 둘 다 고쳤다.
느린 이유를 재 보니 검수 탓이 아니었다
영상 한 편이 너무 오래 걸려서 세션 기록의 타임스탬프로 원인을 쟀다. 노비 영상은 PASS까지 66분이 걸렸다.
| 단계 | 시간 |
|---|---|
| maker 1차 제작 | 32분 |
| checker 1회 | 5분 |
| maker 수정 1 | 11분 |
| checker 2회 | 4분 |
| maker 수정 2 | 7분 |
| checker 3회 | 2분 |
checker 자체는 세 번 합쳐 약 10분이다. 느려진 진짜 이유는 두 가지였다. 하나는 FAIL마다 반복된 재녹음 → 받아쓰기 → 전체 재렌더 → 재검수 왕복이고, 여기에 약 30분이 들었다. 다른 하나는 maker 혼자 오래 걸리는 시간이다.
1차로 반영한 것은 이렇다.
qa_check.py에--pre모드를 추가했다. 렌더 없이 화면 숫자와 정지 구간만 검사한다.- 검수를 렌더 전과 렌더 후로 나눴다. 렌더 전 검수(사실, 이야기, 화면 글자,
at_word, 발음)는 HyperFrames 스냅샷으로 보며, 12장면에 16초 걸렸다. - 받아쓰기는 maker가 남긴
assets/voice/transcript.json을 checker가 재사용한다. - 수정은 새 maker를 띄우지 않고 같은 maker에 이어서 보낸다.
로마 영상도 재 보니 원인이 더 보였다.
- maker 시간의 가장 큰 덩어리는 모델이 생각하고 글을 쓰는 시간이었다. 영상당 출력 토큰이 27만~31만이다.
- 받아쓰기를 maker가 11번, checker가 6번 더 호출했다.
- SKILL.md가 아침 28KB에서 34.6KB로 커져 있었다. 그중 "지난 실행에서 배운 함정"이 13KB(38%)였다. 실행할 때마다 스킬을 업데이트하라는 규칙 때문에 계속 불어났다.
결론은 규칙을 늘리면 오히려 느려진다는 것이다. 그래서 함정 목록을 스크립트 검사로 옮기고 문서를 줄였다. SKILL.md는 35KB에서 18KB가 됐다. 이미 코드로 막은 이력은 에이전트가 읽지 않는 CHANGELOG.md로 옮겼다. 시험 삼아 만든 발음 검사 스크립트(pronounce_check.py)는 빼기로 해서 지웠다.
영상 파일을 읽다가 메모리가 바닥났다
작업 중에 맥의 메모리가 꽉 차서 컴퓨터가 멈출 뻔했다. 스왑을 8.6GB 쓴 흔적이 있었다. 원인 후보는 세 가지인데, 어느 것이 결정적이었는지는 확인하지 못했다.
qa_check.py전체 모드가final.mp4의 소리를 풀어 읽은 것- whisper medium 받아쓰기 4개를 동시에 돌린 것
- 헤드리스 브라우저 스냅샷
"영상 파일은 절대 읽지 않는다"를 메모리 규칙으로 저장했다. 무거운 작업은 하나씩만 돌린다는 내용도 함께 넣었다.
스킬에서도 막았다.
qa_check.py는 이제final.mp4대신voice.wav로 측정한다. 노비 영상에 돌려 보니 값이 같았고(싱크 0.01초), 메모리는 약 81MB였다.render.sh에서 영상을 풀어 음량을 재던 부분을 지웠다.- 렌더 후 검수를 없애고 렌더 전 한 번으로 합쳤다.
공용 에셋 라이브러리
매번 에셋을 새로 만드는 게 느린 원인 같아서, 자주 쓰는 오브젝트를 미리 만들어 두고 배경만 그때그때 만드는 방식으로 바꿨다.
~/.claude/skills/topic-video-youtube/library/에 24개를 Codex로 만들었고 약 3분 걸렸다. 금화, 두루마리, 모래시계, 저울, 지구본, 노트북, 서버 같은 것들이다. INDEX.md에는 항목마다 시대(어느 시대나 / 옛 시대 / 현대)를 표시했다. 옛날 장면에 노트북이 들어가지 않게 하려는 것이다. 용량은 원본을 지워 48MB에서 18MB로 줄였다. 썸네일을 미리 만들어 두는 단계도 이때 함께 반영했다.
새 흐름으로 만든 첫 영상: 35분
"4060 세대에게는 향수를" 영상을 새 흐름으로 만들었다. 1975년생 아이가 51살이 되기까지를 따라가는 내용으로, 3분 56초에 13장면이다. 영상은 https://youtu.be/o5RIVAhb2oM 에 있다.
- 배경은 13장을 새로 만들었다.
- 오브젝트는 9개를 새로 만들고 4개를 공용 라이브러리에서 가져왔다.
- 음악은 생성 키 권한이 없어 넣지 못했다.
| 단계 | 시간 |
|---|---|
| maker | 17분 |
| checker | 3분 |
| WARN 7건 수정 | 3분 |
전체는 35분으로, 지난 로마 영상(61분)보다 크게 줄었다.
flow·globe 템플릿
다음 목표는 더 역동적인 화면이다. diagram-design의 HTML/SVG와 three.js를 영상 장면에 섞는다. HyperFrames가 원래 HTML + CSS + JS를 영상으로 찍는 도구라, 지금 구조에 레이어 하나만 얹으면 된다.
다만 조심할 점이 있었다. maker가 장면마다 three.js를 새로 짜면 생각하는 시간이 늘고, WebGL은 메모리를 더 쓴다. 그래서 장면마다 코드를 짜는 대신 템플릿 두 개를 먼저 만들었다.
flow: 상자가 대본 단어에 맞춰 하나씩 튀어나오고, 화살표가 그려진 뒤 빨간 점이 흐른다.scenes.json에 상자 이름, 위치, 연결만 적으면 된다.globe: three.js 지구본이다. 육지 모양은 Natural Earth 데이터를 한 번 그림으로 구워 넣어서, 렌더할 때 인터넷에서 지도를 받지 않는다. 단어에 맞춰 두 지점 사이에 호가 그려지고, 라벨이 지구 회전을 따라간다.
다음 영상부터 핵심 장면 1~3개에 쓰게 했다. 결과는 렌더된 화면을 사진으로 뽑아 확인했고, 영상 파일은 열지 않았다.
곁가지: Open Notebook 설치와 삭제
Open Notebook을 Docker로 설치했다. 컨테이너는 open_notebook과 surrealdb 두 개다. 문서상 8502·5055 포트가 비밀번호 없이 열리기 때문에 127.0.0.1에 묶었다.
막상 써 보니 맞지 않았다.
- 모델은 API 키나 로컬 서버로만 붙는다. Claude, ChatGPT 구독 세션을 바로 연결할 수 없다.
- Ollama는 LLM과 임베딩만 되고 음성 합성은 안 된다.
- 팟캐스트는 오디오만 나온다.
그래서 이 용도라면 NotebookLM이 낫다고 판단했다. 컨테이너, 이미지, ~/open-notebook 폴더까지 전부 지웠다. 이어서 Ollama로 할 수 있는 일, 요즘 쓸 만한 오픈 모델, 맥 스튜디오 여러 대를 썬더볼트 5 RDMA로 묶는 사례도 찾아봤다. 결론은 지금 장비 수준에서 작업하자는 것이었다.
남은 것
- yyk 채널에 예전 한양 영상(5fc2oWwFJvs)이 남아 있다. 지울지 아직 정하지 않았다.
- 노비 영상의 "갑오개혁" 발음을 직접 들어 확인해야 한다.
- 로마 영상 소리는 수치와 받아쓰기로만 확인했고 직접 듣지 않았다.
- 렌더 후 검수를 없애면서 배경음악을 섞은 최종 음량과 렌더 화면의 자막 위치는 확인하지 않게 됐다.
flow·globe템플릿은 실제 영상에 아직 쓰지 않았다.- 메모리 부족의 결정적 원인은 확인하지 못했다.
댓글 0개
아직 댓글이 없습니다. 첫 댓글을 남겨보세요.