Communitygithub.com

geoqiao/short-video-skills

코드로 나레이션이 있는 짧은 비디오를 제작합니다. 비디오 생성 모델 없이 그래픽, 텍스트, 코드 및 데이터 차트에 적합합니다.

short-video-skills란 무엇인가요?

이 스킬은 코드와 Canvas API를 사용하여 나레이션이 포함된 짧은 수직 비디오를 생성합니다. 그래픽, 텍스트, 코드 블록 및 데이터 차트에 특화되어 있으며, 실제 장면 촬영이나 비디오 생성 모델이 필요하지 않습니다. 지식 설명, 소프트웨어 튜토리얼, 제품 기능 소개 및 데이터 해석에 적합합니다. 핵심은 `window.render(t)` 함수로 각 프레임을 시간순으로 그리고, edge-tts를 사용하여 나레이션을 합성하며, Playwright로 Chrome을 구동하여 프레임을 캡처하고, ffmpeg로 최종 비디오를 인코딩하는 것입니다. 이 스킬은 여러 플랫폼을 지원하며(Claude Code, Cursor, Codex 등), 정적 프레임 검사 기능을 제공하여 텍스트 넘침과 레이아웃 문제를 방지합니다. 또한 16:9, 4:3, 3:4 세 가지 커버와 연락처 시트를 생성합니다. 스크립트와 비주얼을 코드로 관리하여 반복 편집이 용이하지만, 렌더링 파이프라인을 다시 실행해야 합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/geoqiao/short-video-skills/tree/HEAD/skills/code-video

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

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

문서

코드로 짧은 비디오 만들기

화면은 시간에 의해서만 결정됩니다. 페이지가 window.render(t)를 노출하고, 시간(초)을 전달하면 해당 순간의 화면을 그립니다. 렌더링 스크립트는 헤드리스 Chrome을 사용하여 프레임별로 호출하고 스크린샷을 찍으며, ffmpeg가 스크린샷과 나레이션을 mp4로 합성합니다. 화면을 바꾸는 것은 코드를 바꾸는 것이며, 다시 렌더링하면 됩니다.

이 방법은 xilo의 X 게시글(2026-09-29, https://x.com/xilo2991/status/2104912748794589515)에서 비롯되었습니다. 이 스킬은 여기에 나레이션 정렬, 커버, 정적 프레임 검사 및 스크립트 및 화면 작성 규칙을 추가했습니다.

시작하기

Node 20+, uv, ffmpeg 및 로컬 Google Chrome이 필요합니다. 기본 글꼴은 macOS의 송체(Songti), 핑팡(PingFang) 및 SF Mono입니다. 다른 시스템의 경우 brand.json의 fonts에서 로컬 글꼴로 변경하세요.

  1. 이 스킬의 template/ 전체를 새 프로젝트 디렉터리로 복사합니다.
  2. 새 디렉터리에서 npm install을 실행합니다(playwright-core만 설치).
  3. brand.json을 수정합니다. series는 커버 왼쪽 상단의 시리즈 이름, handle은 커버 및 엔딩 크레딧의 이름, avatar는 아바타 이미지의 상대 경로(null 가능), colors 및 fonts는 색상 및 글꼴입니다.
  4. 예제를 실행합니다:
uv run tools/voice.py demo                # 나레이션, 배경 음악, 타임라인 -> episodes/01-demo/build/
node tools/render.mjs demo --stills auto  # 각 샷의 마지막 프레임에서 정적 프레임 출력
node tools/render.mjs demo                # 전체 렌더링 -> episodes/01-demo/out/video.mp4 및 cover.png
sh tools/covers.sh demo                   # 4:3 및 3:4 커버
sh tools/sheet.sh demo                    # 커버와 각 샷의 마지막 프레임을 결합하여 연락처 시트 build/sheet.png 생성

명령어에는 슬러그만 작성하면 스크립트가 자동으로 episodes/<시즌 번호>-<slug>/을 찾습니다. 나레이션은 나레이션 텍스트를 Microsoft의 온라인 TTS 서비스로 전송합니다.

프로젝트 구조

  • brand.json: 브랜드. 여기서 수정, 엔진 수정하지 않음.
  • src/lib.js: 그리기 도구, window.E에 연결.
  • src/run.js: 타임라인 스케줄링. 프레임 0은 커버, 0.3초 정지 후 첫 번째 샷으로 팬; 샷은 가로로 배열, 팬 전환으로 연결; 자막 및 진행률 표시줄도 여기서 그림.
  • src/stage.html: 렌더링 페이지.
  • tools/voice.py: 각 줄을 합성하여 나레이션 생성, 단어별 타임스탬프로 구문 시작점 결정, 배경 음악 및 효과음 합성, 음량을 -14 LUFS로 정규화. 합성이 불완전하면 재시도, 세 번 실패 시 오류 보고.
  • tools/render.mjs: 4개 페이지 병렬 프레임 캡처, ffmpeg 인코딩, 30fps.
  • tools/covers.sh, tools/cover-vertical.mjs: 4:3 가로 커버(16:9 커버에 상하 배경색 채움) 및 별도로 레이아웃된 3:4 세로 커버.
  • tools/sheet.sh: 완성된 비디오에서 커버와 각 샷의 마지막 프레임을 추출하여 연락처 시트 생성.
  • episodes/<시즌 번호>-<slug>/: 각 에피소드의 디렉터리, script.json, shots.js 및 생성된 build/ 및 out/ 포함.

에피소드 제작流程

순서대로 진행하며, 이전 단계를 통과하지 못하면 다음 단계로 넘어가지 않습니다.

콘텐츠와 사실은 직접 준비하며, 이 스킬은 스크립트 작성부터 시작합니다.

  1. 스크립트: episodes/<시즌 번호>-<slug>/ 생성, script.json 작성, 시즌 번호를 cover.no에도 기록.
  2. 화면: 동일 디렉터리에 shots.js 작성, 샷 수는 나레이션 줄 수와 동일.
  3. 나레이션: uv run tools/voice.py <slug>. 나레이션, 음색 또는 커버 문구를 변경한 경우 다시 실행.
  4. 정적 프레임 검사: 아래 "정적 프레임 검사" 참조.
  5. 완성 비디오: node tools/render.mjs <slug>, 그다음 covers.sh 및 sheet.sh 실행, 연락처 시트 확인.
  6. 전달: 이 문서의 마지막 섹션 참조.

시즌 번호를 조정할 때는 디렉터리 접두사와 cover.no를 함께 변경한 후 나레이션과 렌더링을 다시 실행합니다. 커버 텍스트만 변경하는 경우 나레이션을 다시 할 필요가 없습니다. script.json의 cover를 수정하고, build/timeline.js의 cover도 동일한 내용으로 바꾼 후 렌더링과 covers.sh를 다시 실행합니다.

script.json

{
 "title": "이 비디오는 코드로 그렸습니다",
 "cover": { "no": "01", "lines": ["이 비디오는", "코드로 그렸습니다"], "hot": 1, "tag": "편집 소프트웨어도, 비디오 모델도 없습니다" },
 "voice": "zh-CN-YunxiNeural",
 "rate": "+6%",
 "lines": [["당신이 보는 모든 프레임은", "코드로 그려졌습니다."], ["페이지는 하나의 함수만 노출합니다.", "시간을 주면", "그 순간의 화면을 그립니다."]]
}
  • 한 줄은 하나의 샷이며, 줄 내 각 구문은 하나의 화면 비트입니다. 구문은 [낭독 텍스트, 자막 텍스트]로 작성 가능: "75%"라고 말하면서 "75%"를 표시; 영어 용어 발음이 어려울 때도 이 방법을 사용하여 발음을 수정합니다.
  • 커버: lines는 두 줄 이내, hot은 주 색상을 사용하는 줄, tag는 구체적인 숫자나 결론이 있는 훅(hook) 문장, no는 두 자리 시즌 번호. 커버 제목, 플랫폼 제목 및 첫 번째 나레이션 문장은 동일한 내용을 말해야 합니다.

스크립트 작성 방법

  • 세로 화면으로 스크롤되는 짧은 비디오의 경우 75-90초, 8-9개 샷이 적절합니다. +6% 속도는 초당 약 4.8자(공백 포함)이며, 나레이션은 약 380-430자(중국어 단어 + 영어 단어)입니다. 초과 시 먼저 글자를 줄인 후 나레이션을 진행하세요.
  • 처음 2초 안에 이번 에피소드에서 가장 매력적인 것을 넣으세요. 스크립트를 작성하기 전에 먼저 답하세요: 이번 에피소드에서 정말 사람을 끄는 점은 무엇인가요? 보통 상식에 반하는 숫자, 구체적인 결과, 또는 시청자가 겪고 있는 문제입니다. 템플릿에서 나레이션은 0.5초 후에 시작하며(tools/voice.py의 HEAD), 2초까지는 8-9자만 말할 수 있으므로 0번째 구문은 짧아야 하고, 처음 몇 글자가 그 점이어야 합니다. 첫 번째 샷은 1.2초 전에 이를 큰 글자로 만들고, 커버의 tag도 이 점을 말해야 합니다. 이 점은 시청자 자신의 표현으로, 주제어를 포함해야 합니다(예: "추론 강도를 낮추지 마세요" → "High에서 Max로 올리면 비용은 2.9배, 점수는 0.6점만 증가"). 그런 다음 본문으로 들어갑니다. 서두를 꾸미지 말고, 자기소개를 하지 말며, "오늘은 ~에 대해 이야기해보겠습니다"라고 말하지 마세요. 빈 껍데기인 "X가 무엇인가요?" 또는 "같은 A, 같은 B"와 같은 정보 없는 서두를 사용하지 마세요. 이는 적은 수의 비디오에서 얻은 경험이며, 검증되지 않은 것으로 처리하세요.
  • 다음 순서를 시작점으로 사용하고 내용에 따라 조정하세요.
  • 튜토리얼 유형: 최종 결과 → 한 단계 한 샷 → 일반적인 함정 → 한 문장으로 마무리.
  • 제품 소개: 해결하는 문제 → 주요 기능 2-3개, 기능당 하나의 샷 → 시작 방법 → 한 문장으로 마무리.
  • 개념 설명: 결론 및 숫자 → 기존 방식 또는 일반적인 오해 → 문제점 → 새로운 방식 → 구체적인 메커니즘 → 실제 측정 또는 공식 데이터 → 한 문장으로 마무리.
  • 연구 발견: 결론 및 숫자 → 일반적인 오해 → 실험 방법 → 결과 → 후속 연구 → 원인 → 한 문장으로 마무리.
  • 마무리는 먼저 한 문장으로 결론을 명확히 하거나 방법을 제시한 다음, 시청자가 자신의 경험으로 답할 수 있는 질문(예: "평소에 어떤 옵션을 사용하시나요?")을 사용하여 댓글을 유도하세요. 질문은 고정 댓글과 일치해야 합니다. 이 또한 검증되지 않은 것으로 처리하며, 댓글 수 변화를 지켜봅니다. 제한 사항에 대한 별도의 샷을 만들지 말고, 데이터의 제한 조건은 데이터 샷의 출처 각주에 작성하세요.
  • "다음 에피소드에서 다룹니다", "지난 에피소드에서 다뤘습니다"라고 말하지 마세요. 게시 순서가 변경될 수 있습니다. 다른 에피소드를 언급하려면 "~를 다룬 에피소드"라고 말하세요.
  • 원문에 오차 범위가 주어진 경우, 오차 내의 차이는 "거의 변하지 않음"이라고 말하세요. 직접 추론한 숫자는 전달 시 약한 증거로 분류하세요.
  • 나레이션에 URL을 포함하지 말고, "~사이트에 가보세요", "~를 검색하세요"라고 말하지 마세요(플랫폼은 이러한 내용을 외부 사이트 유도로 간주합니다. video-publish 스킬 참조).

화면 그리는 방법

shots.js는 즉시 실행 함수이며, 마지막에 window.SHOTS = [...]를 작성합니다. 각 샷은 (c, k) => {}입니다:

  • c는 1920×1080 Canvas 2D 컨텍스트입니다.
  • k.at(i, delay, dur)는 i번째 구문이 delay초 후 시작되어 dur초 동안 0에서 1로 완화되는 진행률을 반환합니다. k.raw는 동일한 선형 진행률입니다. k.t는 샷 내 경과 시간(초), k.d는 이 줄의 나레이션 길이, k.segs는 각 구문의 샷 시작 기준 초 수입니다.
  • 그리기 도구는 window.E에 있습니다: title(샷 제목 + 브랜드 획), txt, measure, rise(페이드 인 + 변위), pop(팝업), rrect, path(진행률에 따라 꺾은선 그림), arrow, chip(태그 블록), code(타자기 코드 블록), stroke(브랜드 획), mark(아바타), sign(엔딩 크레딧), fmt, 색상 C, 글꼴 F. 먼저 src/lib.js의 함수 시그니처를 읽고 사용하세요. 부족한 도구는 해당 에피소드의 shots.js에 직접 작성하고, 단일 샷을 위해 lib.js 및 run.js를 수정하지 마세요.

규칙:

  • 각 구문은 화면에 새로운 요소와 일치해야 하며, 2-4초마다 변화가 있어야 합니다. 하나의 샷은 한 가지 주제만 다루고, 그림을 사용하여 설명하세요: 프로세스 화살표, 수량 도트 매트릭스, 비교 막대, 코드 블록, 표; 전체 화면 텍스트를 사용하지 마세요.
  • 왼쪽 정렬, 비대칭. 어두운 배경에 중앙 큰 글자를 사용하지 말고, 모든 요소가 함께 페이드 인되지 않도록 하며, 발광 효과를 추가하지 마세요.
  • 주 강조색은 "이 화면에서 봐야 할 숫자"를 표시하며, 좋고 나쁨을 나타내지 않습니다. 악센트 색상은 한 화면에 최대 한두 군데만 사용하세요.
  • 휴대폰을 세로로 들고 가로 화면을 볼 때의 글꼴 크기를 기준으로 합니다. txt는 56px 미만의 글꼴 크기를 올립니다(24 전달 시 34px로 그림, 30 전달 시 38px로 그림). 정보를 전달하는 글자의 전달 값은 30 이상이어야 하며, 출처 각주는 24를 전달할 수 있습니다. 너비 추정은 올림된 글꼴 크기를 기준으로 하며, 고정 폭 글꼴의 각 문자는 글꼴 크기의 약 0.6배입니다.
  • 레이아웃 경계: 자막 표시줄은 y 932 이하, 한 줄에 약 30개의 전각 문자; 커버 훅 문장은 약 14개의 전각 문자면 아바타에 닿을 수 있음; 샷은 1.025배의 느린 줌 인이 있으므로 가장자리 요소는 20px 이상의 여백을 유지; 24 전달 각주는 한 줄에 약 48개의 전각 문자.
  • 송체(Songti) Black에는 "÷"가 없고, "×"는 매우 큰 X로 그려집니다: 연산자는 핑팡(PingFang)으로 그리거나 "나누기", "배"로 작성하세요. 200px 제목에서 영어의 하강 획이 다음 줄을 칠 수 있습니다.
  • 0번째 구문이 매우 짧을 때 샷 시작 부분이 비어 보일 수 있습니다: 그림의 뼈대(축, 표 머리글, 윤곽선)를 0번째 구문과 함께 등장시키고, 데이터는 이후 구문과 함께 나타나게 하세요.
  • 실제 측정 데이터로 그린 아이콘만 "개략도"라고 표시하세요. 원문 차트에서 읽은 숫자는 각주에 "원문 차트에서 읽음"을 작성하세요. 데이터 샷 하단에 출처 각주를 작성하며, 이름만 기재(예: "출처: XX 공식 문서"), 도메인 및 URL은 기재하지 마세요.
  • 각 샷은 E.title로 제목을 출력합니다. 마지막 샷은 E.sign으로 크레딧을 표시합니다.

정적 프레임 검사

node tools/render.mjs <slug> --stills auto는 각 샷의 마지막 프레임을 출력합니다. --stills 0,t1,t2,...는 지정된 초의 프레임을 출력합니다(0은 커버). 중간 프레임은 각 줄 시작 후 약 0.4초 및 각 구문 후 약 1초를 취하며, 시간은 해당 에피소드의 build/timeline.js에서 읽습니다. --stills를 실행할 때마다 이전 배치를 지우므로, 배치별로 확인하거나 시간 지점을 동일한 명령에 병합하세요. 프레임이 많으면 ffmpeg로 연락처 시트를 만들고, 커버와 마지막 프레임은 원본 크기로 확인하세요.

프레임별로 확인:

  • 텍스트가 카드, 코드 블록, 표 열을 넘어가거나 자막 표시줄 및 진행률 표시줄에 가려지지 않는지 확인.
  • 오른쪽 정렬된 숫자와 왼쪽 레이블이 충돌하지 않는지; 축 레이블과 곡선 레이블이 겹치지 않는지 확인.
  • 샷의 마지막 프레임이 정보가 가장 완전한 프레임인지, 아직 등장하지 않은 요소가 없는지 확인.
  • 커버의 두 줄 제목이 너무 작게 축소되지 않았는지, 훅 문장이 너무 넓지 않은지 확인.
  • 2-3초 동안 새로운 내용이 없는 빈 화면이 없는지, 특히 샷 시작 부분 확인.

문제를 발견하면 수정하고, 알려진 넘침 문제를 안고 완성 비디오를 만들지 마세요. 화면만 변경한 경우에는 렌더링을 다시 실행하세요.

알려진 제한 사항

  • edge-tts는 Microsoft의 비공식 인터페이스를 사용합니다. 7.2.8 버전은 2026년 10월부터 403을 반환합니다(rany2/edge-tts #490). tools/voice.py는 수정 PR #491의 커밋에 고정되어 있습니다. 공식 버전이 출시되면 edge-tts==<새 버전>으로 변경하세요. 다시 403이 발생하면 상위 저장소의 이슈를 확인하세요.
  • agent는 나레이션을 들을 수 없습니다: 영어 용어의 발음과 속도는 사람이 한 번 들어야 합니다. 합성 중 연결 끊김은 voice.py의 길이 확인으로 처리합니다.
  • 모션 블러가 없으며, 음악 비트에 따른 편집도 지원하지 않습니다.

전달 시 설명해야 할 사항

  • 나레이션을 아무도 듣지 않았습니다.
  • 정적 프레임 검사 결과, 남아 있는 알려진 문제 포함.
  • 완성 비디오, 세 개의 커버 및 연락처 시트의 경로와 길이.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

관련 스킬