news 2026/10/23 12:10:56

Stagewise 与 Remotion:在开源 Agentic IDE 中使用 `<Video>` 组件导入、裁剪与合成视频的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Stagewise 与 Remotion:在开源 Agentic IDE 中使用 `<Video>` 组件导入、裁剪与合成视频的完整指南
  • 人工智能
  • AI Agent
  • 代码智能体
  • 开发工具

【免费下载链接】stagewise

The Open Source Agentic IDE. Create and orchestrate coding agents, show app previews and run git workflows. Use your favorite models across all providers.

项目地址:https://gitcode.com/gh_mirrors/st/stagewise
点击查看免费下载

导读

本文以 Stagewise 仓库内置的 Remotion 视频创作技能(SKILL.md)中的规则文档为核心,系统讲解在 Remotion 项目中如何通过@remotion/media的<Video>组件导入本地与远程视频,并完成裁剪(trim)、延迟(delay)、缩放定位(style)、音量(volume)、静音(muted)、变速(playbackRate)、循环(loop)与变调(toneFrequency)等全套控制。文章同时结合仓库中同目录的配套规则文档(assets、audio、trimming、sequencing、can-decode、get-video-dimensions、get-video-duration 等)与技能流程,给出可直接复制运行的代码示例与底层原理,帮助你无论作为 Agent 还是开发者,都能在 Stagewise 的"创建 Remotion 视频"工作流中精确地使用视频素材。

一、前置准备:把视频放进 Remotion 项目

在 Stagewise 的 Remotion 技能流程中,所有素材(图片、视频、音频、字体)都必须先复制进项目根目录的public/文件夹,再通过staticFile()引用(见 assets.md)。这条规则同样适用于视频:永远不要把视频文件散落在组件目录里,一律放入public/。

import { Video } from "@remotion/media"; import { staticFile } from "remotion"; export const MyComposition = () => { return <Video src={staticFile("video.mp4")} />; };
  • 若项目尚未安装@remotion/media,先通过npx remotion add @remotion/media(或pnpm exec remotion add @remotion/media,依据项目包管理器选择)安装。
  • staticFile()会返回经过编码的 URL,在子目录部署(subdirectory deploys)下依然可用,是引用public/内文件的推荐方式。
  • 文件名中的特殊字符(#、?、&)会被自动编码,无需手工处理。

远程 URL 同样可用

规则文档明确:远程 URL 可以直接作为src传入,不需要包staticFile():

<Video src="https://remotion.media/video.mp4" />

加载行为说明

<Video>(以及<Img>、<Audio>)这类 Remotion 组件会等待资源完全加载完成后才进入渲染,因此无须在组件内自行做加载状态判断,这是 assets.md 明确给出的行为约定。

二、裁剪视频:trimBefore与trimAfter

规则文档给出的裁剪方式与音频规则(audio.md)一致:通过trimBefore+trimAfter指定要保留的片段,数值单位是帧(frames),需要结合useVideoConfig()拿到的fps换算成秒。

import { useVideoConfig } from "remotion"; export const MyComposition = () => { const { fps } = useVideoConfig(); return ( <Video src={staticFile("video.mp4")} trimBefore={2 * fps} // 剪掉前 2 秒 trimAfter={10 * fps} // 保留到第 10 秒 /> ); };

要点:

  • 裁剪后,视频仍然从合成(composition)的第 0 帧开始播放,只是实际播放的内容是被选中区间的那一段;这与音频规则中"Still starts at composition start. Only selected slice plays."的行为一致。
  • 通过fps而不是写死帧数,可以保证不同帧率项目下的裁剪时间语义一致。

三、延迟出现:用<Sequence>包装

如果希望视频不是从第 0 帧就开始,而是在若干秒后出现,规则文档给出的做法是把它包进<Sequence>并设置from:

import { Sequence, staticFile, useVideoConfig } from "remotion"; import { Video } from "@remotion/media"; export const MyComposition = () => { const { fps } = useVideoConfig(); return ( <Sequence from={1 * fps}> <Video src={staticFile("video.mp4")} /> </Sequence> ); };

上面的例子中,from={1 * fps}表示视频在合成开始 1 秒后才出现。

配套的 sequencing.md 补充了更多时序控制细节,可作为深化参考:

  • <Sequence>默认会把子元素包裹进一个absolute fill(绝对定位填充)容器,若不需要这种包裹行为,可传layout="none"。
  • 建议给<Sequence>加premountFor,让组件在真正进入播放时间之前提前加载,避免出现卡顿:
<Sequence from={1 * fps} durationInFrames={2 * fps} premountFor={1 * fps}> <Title /> </Sequence>
  • 在<Sequence>内部使用useCurrentFrame()时,返回的是从 0 开始的局部帧号,而不是全局帧号,这一点在做内部动画时要注意。

四、缩放与定位:style

视频在合成中的尺寸和位置通过标准的style对象控制,规则文档给出的示例同时演示了固定宽高、绝对定位与裁剪适配三种能力:

<Video src={staticFile("video.mp4")} style={{ width: 500, height: 300, position: "absolute", top: 100, left: 50, objectFit: "cover", }} />
  • position: "absolute"+top/left用于把视频精确放到合成画布的任意位置。
  • objectFit: "cover"让视频按"封面"模式填满指定宽高、必要时裁掉溢出部分,常用于背景视频或需要统一比例的卡片场景。
  • 由于 Remotion 本身就是 React,style的语义与浏览器 CSS 一致,任何响应式布局思路(如基于useVideoConfig()计算百分比)都可以直接复用。

五、音量控制:静态volume与动态回调

规则文档给出了两条音量控制路径。

5.1 静态音量

volume取值范围为0 到 1,直接传入常量即可:

<Video src={staticFile("video.mp4")} volume={0.5} />

5.2 动态音量(回调)

把volume写成接收当前帧f的回调函数,再配合interpolate做随时间变化的音量曲线:

import { interpolate, useVideoConfig } from "remotion"; export const MyComposition = () => { const { fps } = useVideoConfig(); return ( <Video src={staticFile("video.mp4")} volume={(f) => interpolate(f, [0, 1 * fps], [0, 1], { extrapolateRight: "clamp" }) } /> ); };

上面的写法实现"前 1 秒从无声渐入到全音量"。extrapolateRight: "clamp"保证超过输入区间后音量维持在末端值,不再继续增长。需要注意:在<Audio>组件中,回调的f是从音频开始播放时算起(从 0 开始),而不是合成全局帧;视频组件的回调语义与其一致,设计音量曲线时应以此为基准。

六、静音:muted

传入muted即可静音整个视频的音轨,用法与音量为静态常量时相同:

<Video src={staticFile("video.mp4")} muted />

动态静音(例如"第 2~4 秒间静音")在 audio.md 中给出了模式:muted可以接受布尔表达式,如muted={frame >= 2 * fps && frame <= 4 * fps},视频组件同样适用这一模式。

七、变速播放:playbackRate

playbackRate控制播放速度,默认值为 1。大于 1 加速,小于 1 减速(但仍为正向播放):

<Video src={staticFile("video.mp4")} playbackRate={2} /> <Video src={staticFile("video.mp4")} playbackRate={0.5} />

⚠️ 规则文档明确声明:反向播放(reverse playback)不支持。请勿尝试使用负的playbackRate,Remotion 的媒体组件不支持逆向解码播放。

八、循环播放:loop与loopVolumeCurveBehavior

loop让视频无限循环:

<Video src={staticFile("video.mp4")} loop />

当loop与动态volume回调组合使用时,loopVolumeCurveBehavior决定循环时回调收到的帧号如何计算:

  • "repeat":每次循环,帧号重置(回到 0 重新计)。适合音量曲线希望"每圈重新来一遍"的场景。
  • "extend":帧号持续增长,不随循环重置。适合希望音量曲线在整段播放中一次性走完的场景。

官方示例("extend"模式,前 300 帧音量从 1 渐降到 0,之后保持静音般的低音量):

<Video src={staticFile("video.mp4")} loop loopVolumeCurveBehavior="extend" volume={(f) => interpolate(f, [0, 300], [1, 0])} />

结合 audio.md 可知,"repeat"是默认值,与音频组件的语义完全一致。

九、变调不改速:toneFrequency

toneFrequency用于改变音调(pitch),取值范围为0.01 到 2,它只改变音高、不改变播放速度:

<Video src={staticFile("video.mp4")} toneFrequency={1.5} /> {/* 音调升高 */} <Video src={staticFile("video.mp4")} toneFrequency={0.8} /> {/* 音调降低 */}

两个需要特别注意的限制(规则文档明确说明,且与 audio.md 一致):

  1. 变调只在服务端渲染(server render)时生效;
  2. Studio 预览中不生效;
  3. <Player />中不生效。

因此,如果依赖toneFrequency变调,务必用服务端渲染产出的成片来验收效果,不要用 Studio 或 Player 预览判断。

十、纵深实践:解码校验、尺寸与时长探测

规则文档只解决"把视频放进画面",而"这个视频能否被浏览器解码、分辨率是多少、时长多长"这类问题,仓库配套的规则文件给出了 Mediabunny 方案,可在渲染前做防御性校验。

10.1 渲染前检查可解码性(can-decode.md)

先安装 Mediabunny:

npx remotion add mediabunny

然后可复制以下canDecode工具函数(同时检查主视频轨与主音频轨):

import { Input, ALL_FORMATS, UrlSource } from "mediabunny"; export const canDecode = async (src: string) => { const input = new Input({ formats: ALL_FORMATS, source: new UrlSource(src, { getRetryDelay: () => null }), }); try { await input.getFormat(); } catch { return false; } const videoTrack = await input.getPrimaryVideoTrack(); if (videoTrack && !(await videoTrack.canDecode())) { return false; } const audioTrack = await input.getPrimaryAudioTrack(); if (audioTrack && !(await audioTrack.canDecode())) { return false; } return true; };

使用方式:

const src = "https://remotion.media/video.mp4"; const isDecodable = await canDecode(src); if (isDecodable) { console.log("Video can be decoded"); } else { console.log("Video cannot be decoded by this browser"); }

若视频来自上传或拖拽(Blob),把UrlSource换成BlobSource即可,校验逻辑不变。

10.2 获取分辨率(get-video-dimensions.md)

import { Input, ALL_FORMATS, UrlSource } from "mediabunny"; export const getVideoDimensions = async (src: string) => { const input = new Input({ formats: ALL_FORMATS, source: new UrlSource(src, { getRetryDelay: () => null }), }); const videoTrack = await input.getPrimaryVideoTrack(); if (!videoTrack) { throw new Error("No video track found"); } return { width: videoTrack.displayWidth, height: videoTrack.displayHeight, }; };

对public/内的文件,用staticFile()包装路径传入即可,例如getVideoDimensions(staticFile("video.mp4"))。该 API 在浏览器、Node.js、Bun 中均可用。

10.3 获取时长(get-video-duration.md)

import { Input, ALL_FORMATS, UrlSource } from "mediabunny"; export const getVideoDuration = async (src: string) => { const input = new Input({ formats: ALL_FORMATS, source: new UrlSource(src, { getRetryDelay: () => null }), }); const durationInSeconds = await input.computeDuration(); return durationInSeconds; };

在 Node.js / Bun 环境使用本地文件时,将UrlSource换成FileSource(file);浏览器拖拽上传场景同样使用FileSource。知道精确时长后,你就能基于getVideoDuration(staticFile("video.mp4"))的结果,为<Video>设置准确的trimAfter,或为整段合成(composition)计算durationInFrames。

十一、组合示例:一段"延迟出现、裁剪、渐入、循环"的视频

将上述规则组合成真实可用的成分(composition)示例:

import { Sequence, staticFile, interpolate, useVideoConfig } from "remotion"; import { Video } from "@remotion/media"; export const MyComposition = () => { const { fps } = useVideoConfig(); return ( <Sequence from={1 * fps}> <Video src={staticFile("video.mp4")} trimBefore={2 * fps} trimAfter={10 * fps} style={{ width: 1280, height: 720, position: "absolute", top: 100, left: 50, objectFit: "cover", }} volume={(f) => interpolate(f, [0, 1 * fps], [0, 1], { extrapolateRight: "clamp" })} loop loopVolumeCurveBehavior="extend" /> </Sequence> ); };

行为解读:

  • 第 1 秒后视频才出现(Sequence from={1 * fps});
  • 只播放源视频第 2~10 秒的片段(trimBefore/trimAfter);
  • 固定为 1280×720 并绝对定位,cover裁剪填充;
  • 音量在出现后的 1 秒内从 0 渐入到 1,并因loop+"extend"而在循环播放中保持同一条音量曲线持续延伸。

十二、在 Stagewise 的 Remotion 视频工作流中的位置

这段视频规则并非孤立存在,而是 Stagewise 内置 Remotion 技能(SKILL.md)的"规则库"之一。从技能流程看:

  • 技能要求把所有素材先放进public/,再统一通过staticFile()引用,与 assets.md 完全对应;
  • 技能默认30 fps("Default to 30fps"),因此本文所有X * fps的写法在默认项目里等价于"X 秒";
  • 视频相关需求(导入、裁剪、音量、速度、循环、变调)时,技能会引导读取 videos.md,本文即该文件的完整展开;
  • 涉及静音片段裁剪、字幕等场景时,技能还会交叉引用 ffmpeg.md、silence-detection.md、subtitles.md 等规则文件,形成完整的视频制作链路。

十三、快速自查清单

  • @remotion/media已安装(npx remotion add @remotion/media)
  • 视频文件已复制进项目根目录public/,并用staticFile()引用;远程 URL 直接传入
  • 裁剪使用帧单位:trimBefore/trimAfter均乘以fps
  • 延迟出现使用<Sequence from={N * fps}>,并建议加premountFor
  • 音量取值范围 0~1,动态曲线用回调 +interpolate
  • muted可传布尔表达式实现动态静音
  • playbackRate仅支持正向(默认 1,不支持反向)
  • 循环时按需选择loopVolumeCurveBehavior:"repeat"(默认)或"extend"
  • toneFrequency(0.01~2)只在服务端渲染生效,Studio 与<Player />无效
  • 渲染前用 Mediabunny 的canDecode/getVideoDimensions/getVideoDuration校验素材

遵循以上规则,你就能在 Stagewise 的 Remotion 视频创作工作流中,像使用专业剪辑软件一样精确控制每一段视频素材的引入、裁剪、时序、布局、音量和播放行为。

  • 人工智能
  • AI Agent
  • 代码智能体
  • 开发工具

【免费下载链接】stagewise

The Open Source Agentic IDE. Create and orchestrate coding agents, show app previews and run git workflows. Use your favorite models across all providers.

项目地址:https://gitcode.com/gh_mirrors/st/stagewise
点击查看免费下载

相关推荐

上一篇:SDR++完整使用指南:10分钟学会跨平台软件定义无线电操作
下一篇:如何通过100+免费插件集打造专业级RPG游戏:RPG Maker MV/MZ终极指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 12:02:51

BeagleY-AI 实战:Python 控制 GPIO 与本地 AI 推理入门

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 14:00:15

SSM+Vue红色旅游网站毕设开发全流程:从环境搭建到答辩攻略

1. 先说结论&#xff1a;这个题目到底要做什么如果你正打算把“基于 SSM Vue 的漯河市红色旅游网站”作为 2026 届毕业设计&#xff0c;我先把话说透&#xff1a;这个题目不是让你去做一个新闻门户&#xff0c;也不是一个简单静态页面集合。它本质上是一个旅游信息管理系统 内…

作者头像 李华
网站建设 2026/10/21 14:00:19

FAT32数据恢复实战:用WinHex手动还原误删与格式化文件

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 14:00:19

晶圆盒FOUP ID识别实战:一体式读码设备的光学、算法与调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 14:00:17

飞凌嵌入式系统安装Java环境

文章目录1.安装JDK2.mysql注意事项3.redis注意事项4.nginx注意事项5.开机自启1.安装JDK 使用tar -zxvf解压不支持↓ 用zip来解压↓ which gzip gzip -d jdk-15.0.2_linux-aarch64_bin.tar.gz tar -xvf jdk-15.0.2_linux-aarch64_bin.tar2.mysql注意事项 mysql安装也一样&…

作者头像 李华