Communitygithub.com

bigzaqui/videolabs

Remotion + ElevenLabs 기반의 내레이션이 포함된 약 30분 분량 기술 영상 강좌를 Omarchy/Tokyo Night 터미널 스타일로 제작합니다.

videolabs란 무엇인가요?

이 스킬은 Remotion(영상 렌더링)과 ElevenLabs(음성 합성)를 결합하여 Omarchy/Tokyo Night 터미널 스타일의 기술 영상 강좌를 자동으로 제작합니다. Waybar 상태 표시줄, 타일드 창, oh-my-zsh 프롬프트, 마크다운 제목 등 모든 화면 요소가 내레이터의 음성과 정확히 동기화되어 나타나며, 문장 간 자연스러운 일시 정지와 일반 자막, 빠른 원격 렌더링 및 챕터별 웹 플레이어를 제공합니다. 실습형 주제의 경우 먼저 실제 qemu/KVM 가상 머신 실습실을 구축하고, 그 실습실의 실제 명령 출력을 화면과 내레이션에 사용합니다. 제작된 영상은 videolabs_publish 스킬을 통해 Cloudflare 기반의 videolabs 사이트에 게시됩니다. 사용자가 기술 주제에 대한 설명/강좌/교육/실습 영상을 만들거나, 이미 제작된 영상을 수정, 재녹음, 재렌더링, 재게시하려 할 때 사용합니다.

지원 대상✓Claude Code✓Codex CLI✓Cursor
npx skills add https://github.com/bigzaqui/videolabs/tree/HEAD/skills/videolabs_create-video

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

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

문서

videolabs: 비디오 만들기 (터미널 강좌 스타일)

모든 파일은 단일 레포지토리 /opt/opus/videolabs (github.com/bigzaqui/videolabs, 공개: 자격 증명을 절대 커밋하지 말 것; 커밋 전에 scripts/check-secrets.sh 실행)에 위치합니다. 이 스킬의 소스는 해당 레포지토리의 skills/videolabs_create-video/ 디렉토리에 있으며, scripts/setup.sh에 의해 ~/.claude/skills로 심볼릭 링크됩니다. 설정값(ElevenLabs 및 Cloudflare 키, 렌더 호스트)은 git에서 무시되는 레포지토리 루트의 .env 파일에 있으며, .env.example 파일을 참조하세요.

레포지토리 구성: 일반 엔진 (Remotion + ElevenLabs 도구 모음, npm ci 실행)과 labs/ 디렉토리 아래 각 실습실별 폴더입니다. "kafka - in a nutshell" (26개 레슨 / 18분), "ceph - first steps" (14개 레슨 / 11.6분) 및 이전 "ceph in a nutshell" (41개 레슨 / 30분; 스크립트와 비주얼은 카드, 비교, 게이지, 트리, 인시던트, 상태 및 사이트 예시로 reference/에 보관)에 사용됩니다. 두 현재 실습실 모두 실습형입니다: 모든 명령은 실제 실습실에서 먼저 실행되었습니다 ("실제 실습실" 참조).

/opt/opus/videolabs/
  engine/                       일반 도구 모음: engine/cli.mjs <lab> <command>, src/ (Remotion), scripts/
  labs/<slug>/
    lab.config.json             카탈로그 항목 (제목, 설명, 태그) + 외형 (브랜드, 로고, 상태 표시줄, 도구 이름, 샘플 컷)
    script/script.md            내레이션, 장면은 ### 제목으로 구분
    visuals.ts                  각 장면이 보여줄 내용 + 큐 오버라이드
    lab/                        create-lab.sh, destroy-lab.sh, cap.sh, captures/, lab-meta.json
    audio/raw/                  ElevenLabs 출력 (유료; git에 커밋됨)
    out/ data/ public/voiceover/  생성됨, git에서 무시됨
  site/  scripts/publish-all.sh  state/    사이트 및 게시 (스킬 videolabs_publish)

script.md ──cli scenes──▶ data/scenes.json
   └─ cli tts (ElevenLabs 단어 타이밍) ─▶ audio/raw ──pace──▶ public/voiceover/* + data/{durations,captions}.json
visuals.ts + engine/src/cues.ts (reveal = 단어가 발화되는 시점) ─▶ Remotion ──cli render──▶ out/<slug>.mp4
cli player ─▶ out/player/{chapters.json,lab.json} ──videolabs_publish──▶ videolabs.pages.dev

모든 명령어: node engine/cli.mjs <lab> <scenes|tts|pace|cues|stills|typecheck|studio|sample|render|player>, 추가로 list와 new <slug> (레포지토리 README.md에 명령어 표가 있습니다). 실습실 폴더만 강좌마다 다릅니다. 엔진 코드를 실습실에 복사하지 마십시오.

워크플로우 (사용자와 개요 및 스크립트를 먼저 합의; 이후 모든 작업은 허가 없이 실행)

사용자의 사전 승인: 스크립트가 합의되면, 각 단계마다 허가를 구하지 않고 유료 ElevenLabs tts, 큐 감사, 렌더 호스트에서 렌더링, 플레이어/포스터 생성, 실습실 해체를 실행합니다. 이후 결과와 새 길이를 보고합니다. 이 워크플로우를 벗어나는 경우(예: 실습실이 생성하지 않은 항목에 대한 파괴적 작업, 사용자가 요청하지 않은 사이트 게시)에만 질문을 위해 멈춥니다.

  1. 실습형 주제? 먼저 실제 실습실을 구축하고 실행합니다 (아래 "실제 실습실" 참조). 명령 출력을 기억에서 절대 작성하지 마십시오: ceph-first-steps 스크립트의 첫 번째 초안은 실제 클러스터에서 실행한 후 열 군데에서 틀렸습니다. 그런 다음 실제 발생한 내용을 바탕으로 스크립트를 작성합니다.
  2. 스크립트 우선, 비디오는 나중에. 개요(모듈 → 레슨, 각 레슨의 도표 포함)를 제안하고 합의를 얻은 후 labs/<slug>/script/script.md를 작성합니다. 텍스트 변경은 오디오 재생성보다 훨씬 저렴합니다. 속도 1.0으로 표시하고 일시 정지 포함 약 160 wpm: 1,500 단어 ≈ 모듈 카드 포함 9.5분; 1.08 ≈ 168 wpm. tts 직후 Paced … total X min 줄로 실제 길이를 확인하고 렌더링 전에 조정합니다. 버전별 명령어의 경우 현재 릴리스를 확인합니다(문서 및 프로젝트의 다운로드/이미지 태그). 형식 (engine/scripts/build-scenes.mjs에서 구문 분석):
    ## Module 1 — Core Architecture
    ### S02 · RADOS
    **Visual:** 디자이너를 위한 참고 사항
    **Commands:** `ceph -s` `ceph osd tree`        (선택 사항, 화면에만 표시)
    **Narration:**
    한 단락, 말하기 위해 작성됨. 명령어는 발음대로 철자 ("ceph dash s").
    
    모듈의 마지막 레슨을 "Module takeaway: …"로 끝냅니다 – takeaway 단어는 요약 창을 트리거합니다.
  3. node engine/cli.mjs new <slug>는 labs/<slug>/ (설정, 세 개 장면 스크립트, visuals.ts)의 기본 구조를 생성합니다; lab.config.json(카탈로그용 제목, 설명, 태그; 외형용 brand, user, logo, statusbar, statusCmd, networkLabels, session, tools, sample)을 채우고 node engine/cli.mjs <slug> scenes를 실행합니다.
  4. 시각 자료 labs/<slug>/visuals.ts (engine/src/types.ts의 타입, @engine/theme의 colors), 장면 ID당 하나의 항목. 도표 종류 (engine/src/components/Diagrams.tsx):
    • topology: 하나 또는 두 개의 네트워크 라인에 호스트(이름, IP, 데몬 칩, 디스크/복제본), 선택적 상태 라인(statusCmd 레이블, 설정의 기본값) 및 flows (호스트 간 이동하는 블록, cue부터 until까지). 모든 호스트/데몬/디스크/상태는 cue(발화될 때 나타남) 및 changes: [{cue, state, label}] (디스크 empty|osd|leader|idle|down|destroyed|new, 호스트 ok|spare|down|maint)를 가질 수 있습니다. 큐가 없는 요소는 처음부터 표시됩니다. 헬퍼(host(n), built(n))를 사용하여 실습실 상태를 구축하여 도표가 레슨별로 성장합니다.
    • session: 사실적인 셸; 각 cmd는 발화될 때 자체 입력되고, out 줄이 출력됩니다; 가장 최근 행을 유지합니다. host는 줄의 전체 프롬프트를 설정합니다(설정의 session.prompt 기본값). 그 위에 선택적 compact topology가 있습니다. 하단 명령어 표시줄은 session 씬에서 숨겨집니다. 기타 종류: title (fastfetch 카드; user, 추가 rows), layers, cards, flow, tree, compare, gauge, terminal (콜아웃이 있는 명령 출력), incident (증상/확인/조치), checklist, states, sites; 장면당 선택적 takeaway 및 commandCues. 모든 out 및 symptom에 대해 lab/captures/의 실제 출력을 사용합니다.
  5. 오디오 비용 지불 전에 시각 자료 검토: node engine/cli.mjs <slug> stills (장면당 60%에서 한 프레임; 특정 순간은 S04,S11 --at=12.5) 및 ffmpeg xstack으로 2×2 연락처 시트로 타일링하여 확인합니다. 오버플로, 줄 바꿈, 빈 레이아웃을 확인합니다.
  6. 음성: 레포지토리 루트 .env에 ELEVENLABS_API_KEY / ELEVENLABS_VOICE_ID, 그런 다음 node engine/cli.mjs <slug> tts (직접 실행, 승인 필요 없음; 기존 것은 건너뜀; --only=S03,S04 --force로 내레이션이 변경된 장면만 재실행하여 크레딧 절약). 자동으로 pace를 실행합니다. 스크립트가 길어졌을 때 새 길이를 사용자에게 알립니다. labs/<slug>/audio/를 커밋합니다 (유료 출력).
  7. 동기화 감사: node engine/cli.mjs <slug> cues (명령어를 변경한 후에는 commandCues 항목도 변경: dmesg 칩이 여전히 "smartctl"에 큐되어 있으면 조용한 불일치) — 모든 요소와 모든 명령어 줄을 드러내는 단어를 나열합니다 (MISS = 이웃 간 분산). 잘못된 일치는 큐 오버라이드로 수정합니다 (아래 참조). 내레이션 또는 음성 변경 후에 다시 실행합니다.
  8. 미리보기: node engine/cli.mjs <slug> sample (렌더 서버에서 약 1분), ffmpeg -ss <t> -frames:v 1로 스팟 체크, volumedetect로 레벨 확인 (클리핑 없음: 최대 < -1 dB).
  9. 전체 강좌 렌더링 (원격, 아래 참조), 그런 다음 node engine/cli.mjs <slug> player, 포스터 labs/<slug>/out/spot.jpg 생성, 실습실 VM 파괴, videolabs_publish 스킬로 전체 사이트 게시.

사용자가 승인한 디자인 규칙

  • 외형: Omarchy/Hyprland 데스크탑, Tokyo Night 팔레트 (src/theme.ts; rados, mon, cephfs 같은 시맨틱 이름은 단지 팔레트 슬롯). 워크스페이스 0–7의 모듈이 있는 Waybar 스트립, 상태 (HEALTH_WARN 문제 해결 모듈에), 레슨 카운터 07/41. 하나의 타일드 창, 2px 정사각형 테두리, 반경/광택/그라데이션 없음. 각 레슨은 타이핑되는 robbyrussell 프롬프트 ➜ module-1-core-architecture git:(s03) cat the-daemons.md로 시작하고, 이어서 # Heading이 나타납니다. 참고 사항은 // comments로, 명령어는 ❯ cmd 줄로, 요약은 플로팅 창 cat sre-takeaway.md로, 모듈 구분선은 cd module-N-… + 큰 제목으로, 오프너는 fastfetch로 렌더링됩니다. 모든 텍스트는 JetBrains Mono; Inter는 자막에만 사용됩니다. 사용자가 싫어했던 "일반적인" 어두운 그라데이션 외형을 대체했습니다.
  • 동기화 공개: 시간별로 지연시키지 않습니다. 각 요소는 내레이터가 해당 이름을 처음 말할 때 나타납니다 (engine/src/cues.ts: 가장 긴 의미 있는 토큰, 접두사 형태소 분석, 이전 큐에서 앞으로 검색). 실습실의 visuals.ts에서 오버라이드:
    • cue: "=managers" 정확한 발화 단어 (하이픈/구두점 무시: "=write-ahead"), cue: null = 단어 없음, 보간.
    • pointCues (비교면), noteCue (트리), linkCue (사이트), cues (제목 배지), commandCues (명령어 줄, 장면별).
    • cueLabels()의 레이블 순서는 engine/src/components/Visuals.tsx의 렌더러가 사용하는 인덱스 순서와 일치해야 합니다 (topology/session은 topologyKeys/sessionKeys에서 키 기반 순회 사용).
    • 하나의 전방 커서가 장면의 모든 레이블을 순회하므로, 나중 레이블이 일반적인 단어("three", "recovery", "add")를 재사용하면 이후 발생에 위치할 수 있습니다. 해당 순간 근처에서 한 번 발생하는 단어를 선호하고("=repeat", "=begins"), 항상 cues 감사 결과를 읽습니다.
  • 자막: 평이한 구문, 문장/절 끝에서 분리, 한 줄 ≤ 64자, 단어별 가라오케 강조 없음 ("피곤함").
  • 호흡: engine/scripts/pace.mjs는 원시 ElevenLabs 오디오에 . ? ! 후 250ms, : ; 후 120ms를 삽입하고 단어 타이밍을 이동합니다. 컷 포인트는 ffmpeg silencedetect (엄격 -38 dB/40 ms, 그 다음 -30 dB/20 ms)에서 오거나, 가장 조용한 5 ms 창에서 오며, 8 ms 페이드 포함 — 절대 ElevenLabs 단어 경계만으로 결정하지 않습니다 (단어 내부에 위치). SENTENCE_PAUSE/CLAUSE_PAUSE를 조정하고, node engine/cli.mjs <slug> pace를 다시 실행합니다 (무료; 원시 오디오는 audio/raw/에 보관됨). 페이싱은 ffmpeg 버전에 따라 다릅니다 (동일한 Kafka 오디오에 대해 7.1.5 및 8.0.1이 각각 17.9분 및 17.8분 제공): 렌더링하는 곳에서 페이싱하거나 data/ 및 public/voiceover/를 렌더 호스트로 복사합니다.
  • 전환: @remotion/transitions TransitionSeries를 통한 15프레임 크로스페이드; 무음 리드인(0.4초)/테일(0.8초)만 겹칩니다. engine/src/timeline.ts는 오버랩을 뺍니다; engine/scripts/player.mjs 및 stills.mjs는 해당 상수를 미러링합니다 — 동기화 상태를 유지하세요.
  • 사용자가 선택한 음성: ElevenLabs "Mark" v3p1kjzUvro6S76qmYmH (음성 라이브러리; GET /v1/voices/{id}가 404를 반환하지만 TTS에는 작동), eleven_multilingual_v2, 속도 1.08, with-timestamps 엔드포인트, 연속성을 위한 previous_text/next_text. 전체 실행 전에 항상 한 문장 TTS 호출로 음성 ID를 확인하십시오 (이전 .env의 ID는 잘렸습니다).

강좌별 설정 (labs//lab.config.json)

Waybar의 워크스페이스와 fastfetch 모듈/레슨 카운트는 장면을 자동으로 따릅니다. 강좌별 다른 모든 것은 설정의 데이터이며 코드가 아닙니다: brand (Waybar 이름), user (제목 카드의 프롬프트), logo (블록 문자 5줄), statusbar (ok/warn 텍스트, right 텍스트, warnModule = 경고를 표시하는 모듈), statusCmd 및 networkLabels (topology 장면의 기본값), session.prompt/session.title (터미널 세션), tools (명령어 줄 자동 큐잉 시 건너뛸 명령어 단어), sample (Sample 컷의 장면 ID), 그리고 카탈로그용 title, description, tags. 다른 외형의 새 실습실은 엔진 변경이 필요 없습니다. 새 도표 종류 또는 상태는 엔진 변경(engine/src/types.ts, components, cues.ts)이 필요하며 모든 실습실에 혜택을 줍니다.

적용된 Remotion 관행 (remotion-* 스킬에서 가져옴)

@remotion/google-fonts를 통한 글꼴 (시스템 글꼴에 의존하지 마십시오); @remotion/media의 <Audio>는 from과 함께 사용; TransitionSeries; calculateMetadata는 오디오 지속 시간에서 컴포지션 크기를 조정; interpolate/Easing.bezier 및 translate로 애니메이션 (CSS 전환 없음). 의도적으로 채택하지 않음: Interactive.create/연결된 컴포지션 (Studio에서 수동 편집에만 유용), 큰 소셜 비디오 텍스트 최소값, 밈 SFX.

렌더링

  • VIDEOLABS_RENDER_HOST (렌더 및 실습실 서버의 ssh 대상, 키는 이미 설정됨)는 레포지토리 루트 .env에서 가져옵니다: 아래 명령어 전에 set -a; . /opt/opus/videolabs/.env; set +a를 실행하고, 해당 변수를 커밋하는 모든 항목에 리터럴 주소 대신 작성합니다. 동일한 호스트가 실습실 VM을 실행합니다.
  • TMPDIR=/var/tmp는 CLI에 의해 설정됩니다: 이 호스트에서 /tmp는 작은 RAM tmpfs이며 긴 오디오 믹스가 마지막에 "No space left on device" 오류로 실패합니다.
  • 로컬 박스 (4 vCPU) ≈ 30분 비디오당 약 45분. 원격 렌더 서버 $VIDEOLABS_RENDER_HOST (Ubuntu 26.04, 24 스레드, 31 GB RAM, RTX 3090 Ti, KVM; Node 22, ffmpeg, apt의 Chromium 라이브러리)는 11.6분 ceph 강좌를 3분, 18분 kafka 강좌를 5분에 동시성 12–16으로 렌더링합니다. 레포지토리는 두 머신 모두 /opt/opus/videolabs에 있습니다. 흐름:
    rsync -az --delete --exclude node_modules --exclude out --exclude .env --exclude .git --exclude site --exclude state ./ $VIDEOLABS_RENDER_HOST:/opt/opus/videolabs/   # from /opt/opus/videolabs
    ssh $VIDEOLABS_RENDER_HOST 'cd /opt/opus/videolabs/engine && npm ci && cd .. && node engine/cli.mjs <slug> scenes && node engine/cli.mjs <slug> pace && node engine/cli.mjs <slug> render --concurrency=12 --log=error'
    rsync -a $VIDEOLABS_RENDER_HOST:/opt/opus/videolabs/labs/<slug>/out/<slug>.mp4 labs/<slug>/out/ && node engine/cli.mjs <slug> player
    
    (검토한 것과 동일한 타이밍을 유지하려면 서버에서 scenes/pace를 실행하는 대신 labs/<slug>/data 및 public/voiceover를 rsync하십시오.) 절대 .env를 복사하지 마십시오. 긴 렌더는 분리 실행(ssh -f -n으로 시작한 nohup bash script &)하고 time의 real 라인에 Monitor로 대기하십시오; 로그에서 "error"를 grep하지 마십시오 (명령어 줄에 --log=error가 있습니다). Waybar/도표 코드가 변경되면 두 실습실 모두 확인하십시오 (stills), 둘이 공유하므로.
  • 엔진 변경 확인: 이전 코드와 새 코드로 Sample 컷을 렌더링하고 ffmpeg -i a.mp4 -i b.mp4 -lavfi ssim -f null -로 비교; scenes/durations/captions.json 및 cues 감사가 재생성되어야 합니다.

…

[번역을 위해 잘림]

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

관련 스킬