Lesson Video Producer(수업 동영상 제작기)
하나의 수업 슬라이드 데크를 완성된 교육 동영상으로 변환합니다. 합성 음성이 내레이션을 읽고, 각 카드, 단계 또는 행이 음성이 해당 지점에 도달했을 때 정확히 나타나며, 전환 효과는 다양하게 적용되고, 부드러운 음향 효과가 각 표시를 알리며, 피아노 배경음이 음성 아래에서 잦아들고, 학습자가 일시 정지하는 부분에는 카운트다운이 실행되며, 주요 항목에는 손으로 그린 원이 표시되고, 자막은 별도 파일로 제공되며, 실습 수업에는 실제 화면 녹화가 포함됩니다. 한 번에 한 수업씩 실행하고, 확인한 다음 전달하세요.
lesson-slide-designer 스킬의 입력: slides/<course>/<lesson>/slides.json, <file_name>.pptx, _preview/slide-NN.png. 이 파일들이 없으면 먼저 데크를 빌드하세요. 베트남어 에디션(kieu, loi_doc, _kiem/)의 데크도 읽을 수 있습니다.
출력은 videos/<course>/<lesson>/에 생성됩니다(슬라이드 경로를 미러링하며, 그렇지 않으면 <slides folder>/video/):
| 파일 | 설명 |
|---|---|
<file_name>.mp4 | 동영상: 1920x1080, 30fps, H.264, AAC 48kHz, -16 LUFS |
<file_name>.<lang>.vtt / .srt | 별도 파일로 제공되는 자막(절대 영상에 하드코딩되지 않음, 슬라이드 텍스트를 가리지 않도록); 캡션으로 .vtt 업로드 |
<file_name>.narration.txt | 깔끔한 내레이션, 각 음성 비트가 한 줄로 표시됨; ` |
<file_name>.storyboard.json / .md | 발생 시점: pptx에서 측정된 영역, 각 영역이 나타나는 줄, 효과, 전환, 원, 확대, 카운트다운; .md는 눈으로 검토용 |
<file_name>.voice.mp3 + .timeline.json | 내레이션과 각 줄의 정확한 시작 및 종료 시간(줄은 .voice.mp3.cache/에 캐시됨) |
<file_name>.events.json, .audio.mp3 | 사운드 이벤트와 3-레이어 믹스 |
video.json (선택사항, 직접 작성) | 슬라이드별 재정의: 표시 줄, 전환, 유지, 원, 확대, 화면 녹화 |
_check/ | contact-NN.png (완성된 동영상의 프레임), <file_name>.report.md (측정치), voice-review.txt (Whisper), voice-exceptions.txt |
_segments/ | 슬라이드당 하나의 렌더링된 세그먼트, 해당 슬라이드가 변경되지 않으면 재사용 |
도구: Python 3.10+ (python-pptx, numpy, Pillow, 녹화 부드럽게 하기 위해 opencv-python, 음성 검토를 위해 faster-whisper); Node 18+ (assets/engine에서 puppeteer-core 필요, npm install) 및 Chrome/Chromium/Edge; ffmpeg/ffprobe. 음성: Kokoro (pip install kokoro soundfile) 또는 VieNeu-TTS, 둘 다 Apache 2.0 라이선스이며 로컬에서 실행됩니다. 엔진이 자체 가상 환경에 있는 경우 KOKORO_PYTHON 또는 VIENEU_PYTHON에 해당 Python 경로를 설정하세요. GPU가 있으면 도움이 되지만 필수는 아닙니다.
워크플로우
0단계. 데크 읽기 및 브리핑 확정
slides.json(내레이션, 제작 노트, 슬라이드 유형)을 읽고_preview/contact-sheet.png를 훑어보세요. 수업 소스가 존재하면, 학습자가 연습하고 질문하는 부분을 알기 위해 읽어보세요.references/video-standards.md(표준: 하나의 주제, 대본, 서론-본론-결론, 전환, 상호작용)와references/motion-and-sound.md(각 슬라이드 유형의 처리 방식, 동영상이 지나치지 않으면서 움직여야 하는 이유)를 읽으세요.- 다음을 확정하세요: 언어와 음성(
slides.json의language; 영어는 기본적으로 Kokoroam_michael, 여성 음성은af_heart, 기타 Kokoro 언어는 음성 접두사에 따름, 베트남어는 VieNeu); 수업에 실제 화면 녹화가 필요한지 여부(클릭, 타이핑, 소프트웨어를 가르치는 모든 수업: 예, 2단계 참조); 어떤 질문 슬라이드가 일시 정지하고 얼마나 오래 정지할지; 원 또는 확대할 항목. 내레이션은 슬라이드 단계에서 텍스트 음성 변환을 위해 작성되었습니다. 여기서 교육 콘텐츠를 다시 작성하지 마세요; 음성이 단어를 잘못 발음할 때만 발음 방식을 수정하세요.
1단계. 스토리보드 빌드 및 검토
python scripts/storyboard.py slides/<course>/<lesson>/slides.json
<file_name>.storyboard.md를 읽으세요: 슬라이드별 영역, 각 영역이 나타나는 줄, 전환, 유지, 원. motion-and-sound.md의 섹션 4와 대조하여 확인하세요: 세 번째 카드는 음성이 세 번째 아이디어에 도달할 때 나타납니다. 인접한 카드는 절대 동일한 전환을 공유하지 않습니다. 질문 슬라이드는 유지됩니다. "circle answer B"와 같은 노트는 원을 생성합니다. video.json으로 수정하고(templates/video.example.json 참조) 다시 실행하세요. "영역을 찾을 수 없음"은 슬라이드가 전체적으로 나타남을 의미합니다. image 유형에서는 괜찮지만, pptx에서 다른 유형을 확인하세요.
2단계. 실제 화면 녹화(실습, 핸즈온 및 소프트웨어 수업)
수업이 어떤 동작을 가르칠 때는 실제 동작을 보여주세요. 절대 스크린샷이나 모의 페이지로 대체하지 마세요. 규칙은 references/screen-recording.md에 있습니다. 요약:
- 창 준비: 개인 브라우저 창이나 깨끗한 계정, 알림 없음, 사이드바에 실제 이름 없음. Windows에서는
python scripts/record_screen.py --list로 창 제목을 확인하세요. - 녹화:
python scripts/record_screen.py videos/<course>/<lesson>/clips/S07-name.mp4 --window "<title>" --seconds 40 --size 1280x720 [--crop-top 90] [--scroll "6:200:4"](Windows; 다른 OS는 OBS나 ffmpeg 사용). 브라우저 도구를 통해 직접 클릭과 타이핑을 수행하거나 사용자에게 맡기세요.--scroll또는 부드러운 페이지 내 스크롤만 사용하여 스크롤하세요(window.scrollBy({top: 200, behavior: 'smooth'})를 0.60.8초 간격으로 실행), 한 단계씩 스크롤하지 마세요. 각 결과 후 35초간 멈추세요. 긴 결과는 학습자가 읽을 수 있도록 천천히(150~250px/s) 스크롤하세요. - 각 녹화 후
check_motion.py가 실행됩니다. 점프가 남아 있으면:python scripts/smooth_scroll.py <in> <out>을 실행하고 다시 측정하여 0이 될 때까지 반복하세요. 클립의 상단 밴드에서 계정 이름이나 잘못된 탭이 있는지 확인하세요. video.json에 선언하세요:"S07": {"clip": {"file": "clips/S07-name.mp4", "mode": "frame", "speed": "auto"}}. 슬라이드는 큰 프레임이 있는image또는two-column슬라이드여야 합니다. 클립의 첫 번째 프레임을 슬라이드에 넣고(composite_clips.py --first-frame clips/S07-name.mp4 slides/<course>/<lesson>/S07-first-frame.png) 데크를 다시 빌드하여 클립이 점프 없이 페이드 인되도록 하세요.make_video.py ... --extend를 실행하세요: 녹화 시간이 내레이션보다 길면 무음을 추가합니다. 절대 녹화 속도를 1.25배 이상으로 높이지 마세요.
3단계. 단일 명령으로 렌더링
python scripts/make_video.py slides/<course>/<lesson>/slides.json [--extend]
9단계: 스토리보드, 내레이션(gpu_lock.py 통해), Whisper 검토, 렌더링 계획, 3-레이어 믹스, 그림(Headless Chrome, 슬라이드별), 화면 녹화, 자막, 최종 확인. 3분 이상의 수업은 백그라운드에서 실행하세요(렌더링은 처음에 동영상 1분당 약 1~2분 소요, 슬라이드 수준 수정 시에는 몇 초). 중단되면:
- 음성 검토(
_check/voice-review.txt): Whisper가 전체 파일을 한 번 듣고, 의심스러운 줄만 최대 3회까지 재생성 및 재확인합니다. 짧은 단어, 음악 위에서 만들어낸 구절, 두 번째로 프라이밍된 청취에서 올바르게 들리는 것 등 Whisper의 자체 실수는 필터링합니다. 긴 단어, 용어, 이름 또는 여러 단어가 연속으로 나올 때만 중단합니다. 해당 위치를 들어보세요(ffmpeg -ss 1:23 -t 4 -i <voice.mp3> clip.wav). 음성이 잘못되었으면make_voice.py의PRONUNCIATION에 재철자를 추가하거나(자막은 실제 철자 유지)slides.json의 단어를 변경하세요. Whisper가 잘못 들었으면 해당 단어를_check/voice-exceptions.txt에 추가하세요. 그런 다음--from-step 2로 실행하세요(캐시된 줄은 재생성되지 않음). - 최종 확인 실패(
_check/<file_name>.report.md): 원인을 수정하고(음량은--music-db로, 점프는 녹화를 부드럽게 하여, 길이는 재렌더링하여) 해당 단계부터 다시 실행하세요.
4단계. 보고 전에 확인
_check/contact-NN.png를 확인하세요(슬라이드당 세 프레임: 도착, 정착, 떠나기 직전)references/quality-checks.md의 체크리스트와 함께: 텍스트 위에 남은 커버 패치, 확대/축소로 잘린 텍스트, 전환 중 동시에 보이는 두 슬라이드, 텍스트 위의 카운트다운, 프레임 밖의 녹화, 빈 첫 프레임. 특정 순간을 면밀히 검사하려면:node assets/engine/render.mjs sheet <storyboard.json> <timeline.json> _check/zoom --from 40 --to 46 --every 0.25.- 두 곳을 들어보세요: 처음 20초와 한 번의 전환(
ffmpeg -ss 0 -t 20 -i <mp4> -vn test.mp3). 효과는 음성 아래에서 명확하게 들리되, 음악은 낮게 유지되어야 합니다. video.json이나 스크립트로 수정하고, 다시 렌더링하고(변경된 슬라이드만 재렌더링), 최신 렌더의 연속 사진을 확인할 때까지 다시 확인하세요. 최신 렌더의 연속 사진을 확인하기 전에는 절대 동영상이 완료되었다고 보고하지 마세요.
5단계. 보고
사용자에게 다음을 제공하세요: mp4 및 vtt 경로; 실제 길이; 음성 및 속도(초당 단어 수); 슬라이드, 효과, 일시 정지; 검사 보고서(판정, LUFS, 점프); 합성된 녹화; 발음 테이블 또는 Whisper 예외에 추가된 단어; 남은 경고 및 그 이유. 연속 사진을 보여주세요.
여러 수업 연속 처리
코스 전체에서 음성, 음악 레벨 및 사운드를 동일하게 유지하세요. 수업 간 차이는 1.5 LU를 넘지 않아야 합니다(각 보고서의 LUFS 라인 비교). 발음 테이블과 Whisper 예외는 시간이 지남에 따라 커집니다. 재설정하지 마세요. 녹화는 videos/<course>/<lesson>/clips/에 보관하고, 테이크마다 새 파일 이름을 사용하세요. 주제별 동영상(V<k>-<name>/slides.json)으로 분할된 데크는 한 번에 하나의 하위 데크씩 렌더링됩니다.
원칙
- 표준은 고정됨(
video-standards.md): 하나의 동영상당 하나의 주제, 대본, 서론-본론-결론, 부분 간 음성 전환, 상호작용. 리듬, 화면 및 사운드에서 창의성을 발휘하세요. - 화면과 음성은 서로를 보완하며, 음성은 절대 슬라이드를 읽지 않습니다. 음성이 도달할 때 영역이 나타납니다. 읽히고 있는 텍스트는 움직이지 않습니다.
- 화면과 일치하는 일시 정지: "동영상을 일시 정지하세요"라고 말하는 내레이션은 3초 유지와 카운트다운 없음이 적용됩니다(학습자가 일시 정지를 누름; "60초" 레이블 옆에 실행 중인 타이머는 모순됨). 해당 문구가 없는 질문은 명시된 시간(최대 60초) 동안 유지되며 카운트다운이 표시됩니다.
- 주의 집중 원: "B에 동그라미"와 같은 답변 및 노트는 의도적인 원을 얻습니다. 강조 단어로 읽힌 아이디어는 자동으로 원이 나타나고 사라집니다. 카드에는 타원, 행에는 둥근 상자; 슬라이드당 최대 3개.
- 기본적으로 커서 끄기. 그려진 포인터는 대부분의 시청자에게 떠다니는 마우스로 읽힙니다. 데모 스타일 동영상의 경우
video.json에{"_all": {"cursor": true}}로 켜세요. 곡선으로 움직이고 텍스트 밖에 머물며 제목, 섹션, 핵심 메시지 또는 마무리 슬라이드에는 절대 표시되지 않습니다. - 생동감 있지만, 산만하지 않게: 5
10초마다 무언가 변경되고 25초 이상 정지하는 것은 없습니다. 그러나 프레임당 하나의 초점, 회전이나 뒤집기 없음, 분당 최대 16개의 음향 효과, 슬라이드 변경 시에만 전환 사운드, 음성 아래 1723dB의 음악. - 음성은 사람들이 가장 먼저 듣는 품질입니다. 늘렸을 때 나쁘게 들리는 모델(VieNeu)은 시간 스트레칭하지 말고 대신 더 긴 일시 정지로 속도를 늦추세요. Whisper 검토는 선택 사항이 아닙니다. 잘못 발음된 용어는 교육 오류입니다.
- 자막은 별도 파일이며, 절대 하드코딩되지 않습니다.
- 콘텐츠는 동영상 단계에서 변경되지 않습니다: 새로운 아이디어, 조작된 숫자 없음. 내레이션 문제는 수업 또는 슬라이드 단계로 돌아갑니다.
- 실행하고, 측정하고, 확인하세요 전달하기 전에: 음량, 점프, 길이, 연속 사진.
- 녹화는 녹화입니다: 동작을 대신하는 스크린샷 없음; 스크롤은 부드러움을 측정해야 합니다.
- 전환, 효과 또는 사운드를 추가하려면:
assets/engine/video.js,scripts/storyboard.py및references/motion-and-sound.md의 테이블을 확장하고, 테스트를 렌더링하고, 확인한 다음 사용하세요.
참조
references/video-standards.md: 오디오 및 비디오 학습 자료에 대한 교육 표준, 슬라이드 유형에 매핑, 플랫폼 사양(Udemy 및 유사) 포함.references/motion-and-sound.md: 영역 및 동작이 유추되는 방식, 슬라이드 유형 테이블, 모션 수치, 사운드트랙,video.json구문, 학습자를 깨어 있게 유지하는 방법.references/narration-voice.md: Kokoro 및 VieNeu, 속도, 발음 수정, Whisper 검토.references/screen-recording.md: 창 녹화, 부드러운 스크롤, 점프 측정 및 부드럽게 하기, 합성, 개인 정보 보호.references/quality-checks.md: 최종 확인 및 연속 사진 체크리스트의 임계값.templates/video.example.json: 슬라이드별 재정의.