Communitygithub.com

MBehtemam/montagent-skills

在 Montagent 中编辑真实视频:制作人物访谈、绿幕抠像、字幕与逐词高亮、下三分之一标题栏、画中画以及语音避让背景音乐。适用于以录播素材为基础的 Montagent 视频。

montagent-skills 是什么?

该技能提供了在 Montagent 中编辑录播视频的完整工作流,包括人物访谈、绿幕抠像、字幕与逐词高亮、下三分之一标题栏、画中画以及语音避让背景音乐等功能。它通过详细的食谱和 JSON 配置示例,指导用户如何基于录播素材构建视频。核心流程要求先对每个剪辑进行 `probe` 以获取其尺寸、帧率、长度和音频信息,然后根据语音时间戳规划整体节奏。技能支持复杂的视频处理,如冻结帧、速度斜坡、倒放、绿幕抠像参数微调、字幕自动生成与校验、动画化的标题栏和圆形的画中画效果。所有操作都包含具体的参数范围、视觉检查步骤和调试方法,确保最终输出质量。该技能适用于 Montagent 平台,并依赖于 `montagent-craft` 和 `montagent-motion` 等辅助工具。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/MBehtemam/montagent-skills/tree/HEAD/skills/montagent-footage

在你喜欢的 AI 中提问

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

文档

编辑录播视频

基于录播素材构建片段的食谱。它们嵌入在 montagent 循环的构建步骤中;如果尚未加载 montagent,请先加载。对于人物访谈、演示文稿片段或采访剪辑,请在规划前打开 人物访谈结构。

从素材开始

在编写元素之前,对每个剪辑执行 probe:获取其尺寸、帧率、长度以及是否包含音频。然后根据语音规划整个片段。语音的时间戳是每个字幕、提示和避让效果的时钟基准,因此需要首先检查时间戳(请参阅 字幕与逐词高亮)。

要从长剪辑中选择一个特定时刻(例如,在插播片段中展示屏幕录制的一部分),请将该剪辑单独放入一个临时项目中,并调用 frame --from 0 --to <其长度> --infill-ceiling <毫秒>,其中 ceiling 设置为长度的二十分之一。一次调用会每隔几秒生成一个带标签的图块;对任何你希望更仔细检查的图块使用 frame --at。

食谱

每个食谱提供起始范围,而非最终答案。每个食谱以 检查步骤 结束:加载 montagent-craft,然后在继续之前按照指示检查。

放置素材

{
  "frame": {"width": 1080, "height": 1920}, "fps": 30, "background": "#FF5A36", "duration": 6000, "output": "out/presenter.mp4",
  "tracks": [
    {"name": "presenter", "layer": 10, "elements": [
      {"id": "presenter", "type": "video", "start": 0, "end": 6000, "source": "media/clip.mp4", "source_start": 0, "source_end": 6000, "x": 540, "y": 2160, "origin": "bottom-center", "width": 3413, "height": 1920, "fit": "cover", "effects": [{"name": "chroma", "color": "#00FF00", "tolerance": 0.2, "softness": 0.08, "spill": 0.9}]}
    ]}
  ]
}
  • 宽素材在竖屏画框中: 使元素高度等于画框高度,宽度根据素材宽高比确定(对于 16:9 的素材,1920 高度对应 3413 宽度),然后水平移动元素以保持演讲者居中。
  • 眼睛位置: 位于画框从上往下的 25–35% 处。将元素的 bottom-center 移至画框底部边缘以下即可实现;腿部被裁剪是正常现象。
  • 头部空间: 头部上方保留画框高度的 4–8%。
  • 比片段短的镜头: "overrun": "hold" 会冻结最后一帧。保持冻结时间不超过半秒,或者提前结束片段。
  • 剪辑内的冻结帧、速度斜坡或倒放: 使用 source_time 替代 source_start 和 source_end:一个数值会冻结某一时刻,而将源毫秒时间与时间线 t 配对的键值对则可实现速度变化(平坦的一对冻结,下降的一对倒放)。对于慢动作 (speed < 1.0) 或速度斜坡 (source_time) 的剪辑,设置 "frame_blend": "mix" 以在连续源帧之间进行交叉溶解,而不是在最近帧之间跳转 ("none")。要对素材实现抽帧(定格动画)效果,请使用阶梯式的 source_time 关键帧,使每个目标源时间戳在多个时间线帧上保持。使用 source_time 的剪辑在 volume 为 0 时静音,因此请将其音频放在独立的 audio 元素上。
  • 镜头的自带音频: 语音音量保持 volume 1.0。其他所有声音都混合在它下面。
  • 检查: 在开始、中间和最后一帧处执行 frame,检查眼睛是否位于指定区间内,以及画框两侧没有重要内容被裁剪。

绿幕抠像

对素材元素应用 chroma 效果即可进行抠像。起始参数如下:

  • color: 屏幕的纯色,绿色屏幕为 #00FF00。稍微偏蓝或偏黄的照明屏幕在相同容差下也能正常抠像,因此无需取样。
  • tolerance: 0.2(范围 0.18–0.25)。高于约 0.3 时,抠像会吃掉黑色头发、白色衣领和深色衣物。
  • softness: 0.08(范围 0.05–0.1)。
  • spill: 0.9(范围 0.9–1.0)。

在叠加任何其他内容之前进行检查:

  1. 三次无损裁剪。 在头发、肩膀或袖口边缘、以及手部位置,对将用作背景的区域执行 frame --crop <x,y,w,h> --png。裁剪结果以真实比例返回,因此 200–400 像素的框就足够了。
  2. 已经完成了? 如果头发、衣领和手部区域实心,边缘最多有 1–2 像素的深色、橄榄色或棕褐色线条:抠像已完成,继续下一步。那条线是 边缘底线:从 0.12 到 0.3 的每个设置都会留下它,而 spill 已将其从绿色变为棕褐色,因此在其上读取的绿色像素计数为零。
  3. 否则,每个缺陷进行一次修复。 背景透过头发的缝隙显示出来、衣领或深色衣物边缘有绿色泄漏:将 tolerance 降低 0.05。出现比边缘底线更宽的苍白或绿色光晕:将 tolerance 提高 0.03,或将 softness 提高 0.03。再次裁剪并返回步骤 2。最多在同一个抠像元素上调整三次设置:按区域分割抠像副本会成倍增加渲染时间,并且仍然会留下接缝。
  4. 漂移。 对抠像元素执行 measure。其不透明部分在整段镜头中应保持在 1-2 个百分点内。出现阶梯变化意味着光照在此处发生了变化:在阶梯前后为 tolerance 添加关键帧,或者在该帧处切割元素并分别抠像每个部分。
  • 检查: 在演讲者运动幅度最大的两个时刻执行 frame 检查整体画面,确保轮廓保持清晰。

字幕与逐词高亮

字幕来自提供的词语时间戳,通过内置脚本自动生成,而非手动添加。python3 scripts/captions.py <project> <words> <spec>(使用 --help 查看 spec 参数)会检查时间戳,使用 measure 将词语分页为一行或两行,为每个口语词分配一个 highlight 窗口,并打印出添加了字幕的项目。它会将每项修复报告输出到 stderr。阅读该报告:这就是时间戳检查。

  • 检查内容: 在语音已经开始后才开始短语的词语(典型的例子是提供的 "Now" 晚了 110 毫秒且持续了 20 毫秒)、位于静音段内的词语、重叠的词语以及太短而无法看到的词语。短词语会被延长至 min_word (150 ms):首先占用其后的停顿,然后占用下一个词语的时间。报告中出现位于静音段内的词语意味着该文件在此处对齐错误:修复文件,然后重新运行。
  • 尺寸: 在 1080 宽的画框中为 56–72 px,粗体,使用一种浅色表示整行文字,使用品牌的强调色表示正在说的词。
  • 行数: 最多两行,width 约为画框宽度的 80%。在句子结束或停顿 400 毫秒或以上处分页。
  • 背景: 使用品牌最深色的 pill 样式,透明度为 80–85% (CC–D9),可在任何素材上清晰阅读。pad 横向 28–36 px,纵向 14–20 px,radius 20–28。
  • 放置位置: 下巴下方,并避开竖屏画框底部 15–20% 的区域(这是播放器控件区域)。在 1080×1920 画框中,中心大约在 y 1350–1450 处。在宽屏画框中,将其居中放置在距离底部 10–14% 的位置。
  • 页面 保持显示直到下一页开始,或者在较长的停顿后,在最后一个词语结束后再保持 1 秒。

它会生成真实的字幕,因此请根据 validate 对字幕提出的发现意见采取行动。

  • 检查: 在一页内容上执行 frame --from --to:每个高亮的词语都会生成一个单独的图块。检查每个图块是否按说话顺序恰好高亮一个词语,并且框体保持远离面部。然后,在最长的停顿后的第一帧执行 frame --at,检查新页面是否已显示且没有词语被提前高亮。

素材上的名称条

一个从边缘划入划出的下三分之一标题栏。由于素材不是纯色,所以来自 montagent-motion 的遮盖划变无法直接用来揭示标题栏本身。相反,标题栏 从边缘生长出来,其文本由一层 与标题栏颜色相同(纯色)的遮盖层来揭示。

{
  "frame": {"width": 1080, "height": 1920}, "fps": 30, "background": "#6E7B8B", "duration": 7000, "output": "out/namebar.mp4",
  "fonts": {"bold": [{"file": "fonts/Inter-Bold.ttf"}]},
  "fontVendor": {"fonts/Inter-Bold.ttf": {"licence": "OFL-1.1", "source": "https://github.com/rsms/inter", "sha256": "288316099b1e0a47a4716d159098005eef7c0066921f34e3200393dbdb01947f"}},
  "tracks": [
    {"name": "bar", "layer": 20, "elements": [
      {"id": "bar", "type": "rect", "start": 1000, "end": 6534, "x": 64, "y": 1160, "origin": "center-left", "width": 760, "height": 160, "fill": "#101418", "radius": 8, "scale": [{"t": 1000, "v": [0.0, 1.0]}, {"t": 1300, "v": [1.0, 1.0], "ease": [0.65, 0, 0.35, 1]}, {"t": 6266, "v": [1.0, 1.0], "ease": "linear"}, {"t": 6533, "v": [0.0, 1.0], "ease": [0.65, 0, 0.35, 1]}]}
    ]},
    {"name": "bar-edge", "layer": 21, "elements": [
      {"id": "bar-edge", "type": "rect", "start": 1000, "end": 6534, "x": 64, "y": 1160, "origin": "center-left", "width": 12, "height": 160, "fill": "#FF5A36"}
    ]},
    {"name": "bar-name", "layer": 22, "elements": [
      {"id": "bar-name", "type": "text", "start": 1300, "end": 6266, "x": 108, "y": 1128, "origin": "center-left", "width": 400, "height": 70, "font": "bold", "size": 58, "color": "#F5F0E6", "runs": [{"text": "Montagent"}], "caption": false}
    ]},
    {"name": "bar-line", "layer": 22, "elements": [
      {"id": "bar-line", "type": "text", "start": 1300, "end": 6266, "x": 108, "y": 1196, "origin": "center-left", "width": 560, "height": 44, "font": "bold", "size": 34, "color": "#F5F0E6", "runs": [{"text": "Video your agent can read"}], "caption": false}
    ]},
    {"name": "bar-cover", "layer": 23, "elements": [
      {"id": "bar-cover-on", "type": "rect", "start": 1300, "end": 1700, "x": 800, "y": 1160, "origin": "center-right", "width": 716, "height": 140, "fill": "#101418", "scale": [{"t": 1300, "v": [1.0, 1.0]}, {"t": 1666, "v": [0.0, 1.0], "ease": [0.65, 0, 0.35, 1]}]},
      {"id": "bar-cover-off", "type": "rect", "start": 6000, "end": 6266, "x": 84, "y": 1160, "origin": "center-left", "width": 716, "height": 140, "fill": "#101418", "scale": [{"t": 6000, "v": [0.0, 1.0]}, {"t": 6233, "v": [1.0, 1.0], "ease": [0.65, 0, 0.35, 1]}]}
    ]}
  ]
}
  • 进入: 标题栏在 250–350 毫秒内从其左边缘生长出来,缓动曲线 [0.65, 0, 0.35, 1]。文本及其遮盖层在标题栏完全展开的同一帧开始(绝不能更早,否则遮盖层会显示在素材上)。遮盖层在其远边缘处收缩,持续 300–400 毫秒,按阅读顺序揭示文本。
  • 退出, 从提示点开始:遮盖层在 200–300 毫秒内重新覆盖文本,然后标题栏在 250–300 毫秒内收缩回其边缘。整个标题栏在提示点后 450–600 毫秒内完全消失。
  • 尺寸: 在 1080 宽的画框中,标题栏高度 130–180 px,名称字号 52–64 px,第二行字号 30–38 px。前缘有一条 8–16 px 宽的强调色条纹。
  • 遮盖层: 颜色必须与标题栏的 fill 完全一致,边缘距离标题栏两端 20 px、上下 10 px,位于文本上方。
  • 放置: 距离画框侧边 48–80 px,与字幕框和演讲者面部保持距离,通常在竖屏画框高度的 55–65% 处。
  • 检查: 从每个提示点开始,在 1 秒内执行 frame --from --to --keyframes,检查在任何图块上遮盖层都没有超出标题栏边界。在标题栏静止时执行 frame --at,检查其左边缘是否与字幕框的边距对齐。

圆形画中画

在一个圆形中显示第二个剪辑:一个带有圆形 mask 的视频元素、一个背景环以及一个带有过冲贝塞尔曲线的弹出动画。

{
  "frame": {"width": 1080, "height": 1920}, "fps": 30, "background": "#6E7B8B", "duration": 6000, "output": "out/pip.mp4",
  "tracks": [
    {"name": "pip-ring", "layer": 30, "elements": [
      {"id": "pip-ring", "type": "ellipse", "start": 1000, "end": 5500, "x": 800, "y": 900, "origin": "center", "width": 384, "height": 384, "fill": "#F5F0E6", "scale": [{"t": 1000, "v": [0.0, 0.0]}, {"t": 1400, "v": [1.0, 1.0], "ease": [0.34, 1.56, 0.64, 1]}, {"t": 5233, "v": [1.0, 1.0], "ease": "linear"}, {"t": 5466, "v": [0.0, 0.0], "ease": "ease-in"}], "effects": [{"name": "shadow", "dx": 0, "dy": 16, "radius": 40, "color": "#101418", "opacity": 0.35}]}
    ]},
    {"name": "pip", "layer": 31, "elements": [
      {"id": "pip", "type": "video", "start": 1000, "end": 5500, "source": "media/clip.mp4", "source_start": 10000, "source_end": 14500, "volume": 0, "x": 800, "y": 900, "origin": "center", "width": 640, "height": 360, "fit": "contain", "scale": [{"t": 1000, "v": [0.0, 0.0]}, {"t": 1400, "v": [1.0, 1.0], "ease": [0.34, 1.56, 0.64, 1]}, {"t": 5233, "v": [1.0, 1.0], "ease": "linear"}, {"t": 5466, "v": [0.0, 0.0], "ease": "ease-in"}], "effects": [{"name": "mask", "shape": "circle", "x": 140, "y": 0, "width": 360, "height": 360}]}
    ]}
  ]
}
  • 圆形的矩形包裹盒: 一个与元素高度相等的正方形。其 x 值决定显示画面的哪一部分。居中位置是 (width - height) / 2,并且应该使用这个值:弹出动画围绕元素的 origin 进行缩放,因此偏离中心的圆形会在放大时产生侧向漂移。要显示画面的其他部分,请选择一个使该部分位于中间位置的 source_start,或者增大元素的尺寸并设置其 x 值,使该部分落在圆形内,然后按照弹出曲线为 x 设置关键帧,以使圆心保持静止。
  • 尺寸: 宽度约为画框宽度的 30–40%。背景环比圆形宽 12–24 px,使用背景中最浅的颜色,并应用柔和的 shadow。
  • 弹出动画: 两者都在 350–450 毫秒内使用缓动曲线 [0.34, 1.56, 0.64, 1],从 scale 0 开始,在相同的关键帧上完成。退出动画在 200–300 毫秒内,使用 ease-in,回到 scale 0。
  • 时机: 在演讲者首次提到所展示内容时进入,在结束前一个节拍处退出,以确保关闭干净利落。
  • 放置: 放在演讲者旁边,胸部高度,远离面部和字幕框,距离画框边缘 40 像素或更多。
  • 音频: volume 设置为 0,除非剪辑自身的声音是重点。
  • 检查: 在弹出动画峰值时(开始后加上其长度的 40%)执行 frame,检查圆形是否远离面部和画框边缘。在静止时执行 frame,检查重要部分是否在圆形内部。

语音避让背景音乐

音乐在语音说话时自动降低音量,在停顿期间恢复。scripts/duck.py 脚本会根据语音的词语时间戳(--words,一个 JSON 文件)将普通的 volume 关键帧写入音乐元素。

  • 关键帧写入 之前 和 之后 的混合时间。在语音开始前 100–200 毫秒开始降低音量,在语音结束后 100–200 毫秒开始恢复。这样切换听起来很自然。

  • 语音进行中的音量:音乐音量保持在一个较低的水平(volume 0.15–0.25),以免分散注意力。

  • 如果音乐是节奏感强的类型,在语音间隙音量可以稍微恢复(0.4–0.6)。

  • 如何使用: python3 scripts/duck.py --project <project> --words <words.json> --music-volume 0.2 --pause-volume 0.4 --attack 100 --release 200。运行后检查生成的 volume 关键帧是否符合预期。

  • 检查: 播放片段,感受音乐的避让效果是否自然,音量变化是否平滑。确保音乐在最响亮的时刻也不会盖过语音。

检查步骤:最终审查

在所有效果都应用后,执行一个完整的审查:

  1. 从头到尾播放整个片段,注意字幕、标题栏和画中画的时机。
  2. 检查绿幕抠像是否有闪烁或边缘问题。
  3. 验证语音避让是否在所有需要的地方都起作用。
  4. 最后,输出最终版本。

提示:montagent 循环中的构建步骤会处理所有这些食谱。根据你的具体素材微调参数。

Individual skills in this repo

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

相关技能