Communitygithub.com

bigzaqui/videolabs

使用 Remotion + ElevenLabs 构建一个约30分钟的叙述式技术视频课程,采用 Omarchy / Tokyo Night 终端风格(Waybar、平铺窗口、oh-my-zsh 提示符、markdown 标题),屏幕上每个元素在叙述者说出时精确出现,包含句子停顿、纯字幕、快速远程渲染以及带章节的Web播放器。对于实战主题,它首先构建一个真实的实验室(qemu/KVM虚拟机),并使用实验室的真实命令输出显示在屏幕上和叙述中。发布到 videolabs 网站(Cloudflare)由 videolabs_publish 技能完成。当用户想要一个关于技术主题的解说/课程/培训/实验视频,或者想要编辑、重新配音、重新渲染或重新发布以此方式制作的视频时使用。

videolabs 是什么?

videolabs 是一个功能强大的 AI 技能,旨在使用 Remotion 和 ElevenLabs 等现代工具,从零开始创建高度专业化、叙述式的技术视频课程。它独特的卖点在于,对于实践性主题,它会先在 QEMU/KVM 虚拟机中构建一个真实的实验室环境,然后捕获并显示真实的命令输出,确保教学内容的绝对准确性,而不是使用模拟数据。该技能严格遵循一个以脚本为中心的工作流程,从大纲和脚本达成一致开始,然后自动执行配音、视觉同步审核、在远程 GPU 服务器上快速渲染以及生成章节化播放器等一系列步骤,无需用户逐一批准,从而节省大量时间。生成的视频具有高度可识别的 Omarchy/Tokyo Night 终端美学风格,并且每个屏幕元素都与叙述者的旁白精确同步,确保学习者不会错过任何细节。它被设计为在单个仓库 `/opt/opus/videolabs` 中工作,所有实验室、引擎逻辑和站点发布文件都组织良好且相互独立。它支持的能力包括:从**视频创建**、**编辑脚本**、**重新配音**(在不破坏时间线的情况下替换音频)、**重新渲染**以及**重新发布**到 Cloudflare 页面。

兼容平台✓Claude Code✓Codex CLI✓Cursor
npx skills add https://github.com/bigzaqui/videolabs/tree/HEAD/skills/videolabs_create-video

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

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 - 快速入门”(26课/18分钟)、“ceph - 入门步骤”(14课/11.6分钟)以及更早的“ceph 快速入门”(41课/30分钟;其脚本和视觉效果保存在 reference/ 中,作为卡片、对比、仪表盘、树图、事件、状态和站点的示例)。当前的两个实验室都是实战性的:每个命令都首先在真实实验室上运行(参见“真实实验室”)。

/opt/opus/videolabs/
  engine/                       通用工具集:engine/cli.mjs <lab> <command>,src/ (Remotion),scripts/
  labs/<slug>/
    lab.config.json             目录条目(标题、描述、标签)+ 外观(品牌、logo、状态栏、工具名称、示例剪辑)
    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 解析):
    ## 模块 1 — 核心架构
    ### S02 · RADOS
    **可视化:** 给设计师的备注
    **命令:** `ceph -s` `ceph osd tree`        (可选,仅屏幕显示)
    **旁白:**
    一个段落,用于口头讲述。按口语拼写命令(“ceph dash s”)。
    
    在模块最后一课结束时加上“模块要点:…”——单词 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 中,colors 来自 @engine/theme),每个场景 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:一个真实的 shell;每个 cmd 在被说出时逐字键入,然后打印其 out 行;保留最新的行。host 设置整行的提示符(默认为配置中的 session.prompt)。上方有一个可选的紧凑型 topology。对于会话场景,底部命令栏是隐藏的。 其他种类: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,销毁实验室虚拟机,并使用 videolabs_publish 技能发布整个站点。

用户已签字同意的设计规则

  • 外观:Omarchy/Hyprland 桌面,Tokyo Night 调色板(src/theme.ts;像 rados、mon、cephfs 这样的语义名称只是调色板槽位)。Waybar 条,模块作为工作区 0–7,一个状态(在故障排除模块上显示 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 个字符,无逐词卡拉 OK 高亮显示(“令人精疲力竭”)。
  • 呼吸/停顿:engine/scripts/pace.mjs 在原始 ElevenLabs 音频中,在 . ? ! 后插入 250 毫秒,在 : ; 后插入 120 毫秒,并移动单词时间戳。裁剪点来自 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(语音库;适用于 TTS,尽管 GET /v1/voices/{id} 返回 404),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(五行块状字母)、statusbar(ok/warn 文本、right 文本、warnModule = 显示警告的模块)、statusCmd 和 networkLabels(拓扑场景的默认值)、session.prompt/session.title(终端会话)、tools(自动提示命令行时跳过的命令词)、sample(示例剪辑的场景 ID),以及用于目录的 title、description、tags。具有不同外观的新实验室无需更改引擎;新的图表种类或状态则需要更改(engine/src/types.ts、组件、cues.ts),然后会使每个实验室受益。

应用的 Remotion 实践(来自 remotion-* 技能)

通过 @remotion/google-fonts 使用字体(绝不依赖系统字体);使用来自 @remotion/media 的 <Audio> 并带有 from 属性;TransitionSeries;calculateMetadata 根据音频持续时间调整合成大小;使用 interpolate/Easing.bezier 和 translate 进行动画处理(无 CSS 过渡)。有意未采用的实践:Interactive.create/连接的合成(仅对在 Studio 中手动编辑有用)、大型社交媒体视频文字最小值、模因音效。

渲染

  • VIDEOLABS_RENDER_HOST(渲染和实验室服务器的 SSH 目标,密钥已设置)来自仓库根目录下的 .env:在执行以下命令之前,运行 set -a; . /opt/opus/videolabs/.env; set +a,并在提交的任何内容中写入该变量,而不是字面地址。同一台主机运行实验室虚拟机。
  • TMPDIR=/var/tmp 由 CLI 设置:/tmp 在这些主机上是一个小的 RAM tmpfs,长时间的音频混合会在最后失败并显示“设备上没有剩余空间”。
  • 本地机器(4 vCPU)大约需要 45 分钟来处理 30 分钟的视频。远程渲染服务器 $VIDEOLABS_RENDER_HOST(Ubuntu 26.04,24 线程,31 GB RAM,RTX 3090 Ti,KVM;Node 22,ffmpeg,rsync 以及来自 apt 的 Chromium 库)以 12–16 的并发度在 3 分钟内渲染 11.6 分钟的 ceph 课程,在 5 分钟内渲染 18 分钟的 kafka 课程。仓库位于两台机器的 /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/   # 从 /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
    
    (为了保持与你审查的时序一致,rsync labs/<slug>/data 和 public/voiceover,而不是在服务器上运行 scenes/pace。)切勿将 .env 复制过去。在后台运行长时间渲染(使用 ssh -f -n 启动的 nohup bash script &),并使用 time 命令 real 行的监视器等待;不要 grep 日志中的“error”(命令行中已有 --log=error)。如果 Waybar/图表代码发生更改,请检查两个实验室(stills),因为它们共享这些代码。
  • 验证引擎更改:使用新旧代码渲染示例剪辑,并比较 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.

相关技能