Remotion 发布视频,基于 Imgcli 构建
将发布简介转化为 15-30 秒的 Remotion 发布视频。每个镜头都是一个 Imgcli 组件:经过手工调整、基于渲染帧测量的 Remotion 场景, 可通过 shadcn CLI 安装,并以你拥有的代码形式落入你的项目。
为什么用 Imgcli,而不是手写动画。 从头开始动画化的代理总是回到 相同的风格:居中文字配渐变背景,所有内容淡入,最后是 logo。 Imgcli 场景是根据真实的发布视频逐帧构建的,因此运动 已经具备了让发布显得昂贵的时机、字体和镜头感。你的工作是 选择场景并填充属性,而不是发明运动。
Imgcli 规则
- 除非没有合适的组件,否则每个节拍都是一个 Imgcli 组件。 在为你编写的任何镜头编写
interpolate()或spring()之前,请先检查目录:https://imgcli.com/llms-components.txt?ref=skill-launch列出了每个可安装组件的用途和运行帧数。任何组件页面在附加.md时都提供 markdown,例如https://imgcli.com/docs/scenes/announce-title.md?ref=skill-launch。 - 切勿自己编造组件名称。 仅安装该列表中的名称。如果没有合适的节拍,请说明情况,并使用排印(
text-reveal)来承载该节拍,而不是猜测一个名称。 - 填充属性,不要重写组件。 通过属性更改文案、颜色和图像。编辑已安装的 Imgcli 文件内部的运动会破坏根据渲染帧拟合的时间。
如果 imgcli 技能可用,则使用它进行合成和渲染检查。
前提条件
- 一个 Remotion 项目(
npx create-video@latest)。画布:1280×720 在 30fps, 每个 Imgcli 场景都为该尺寸布局。 - shadcn CLI。如果项目没有
components.json,请运行npx shadcn@latest init。 @remotion/transitions用于场景之间的切换:npm i @remotion/transitions。- 发布文案:产品名称、标题、标语、一个你可以证明的数字、 以及真实的截图或屏幕录制。
工作流程
1. 收集输入
在编写任何内容之前提取这些:
- 简介:发布帖子、落地页或一页纸。提取标题、标语、 一个差异化功能、证明数字和基调。
- 品牌:Logo(SVG 路径或 PNG)、主色、字体。Imgcli 场景将这些作为
属性接收(
titleColor、logoSrc、symbolPath、fontFamily、theme)。 - 真实产品截图:截图或 30-60 秒的录制。镜像真实 UI 文案。 切勿编造标签、功能或数字;这是让发布感觉虚假的最快方式。
2. 在编写任何代码之前先分镜
首先编写镜头列表,并将每个节拍映射到一个 Imgcli 组件:
| 节拍 | 时间 | Imgcli 组件 | 帧数 | 承载内容 |
|---|---|---|---|---|
| 钩子 | 0-3秒 | type-morph 或 text-reveal | 94 / 90 | 观众的问题,转化为承诺 |
| 名称 | 3-9秒 | announce-title | 170 | 引子、产品名称、标语、标记 |
| 产品 | 9-15秒 | hero-launch、laptop-frame、phone-frame | 170 / 240 / 240 | 设备上的真实屏幕 |
| 证明 | 15-17秒 | count-grid、follower-rush | 47 / 300 | 一个真实数字 |
| 结尾 | 17-20秒 | wordmark-cut、block-wordmark、logo-flicker、logo-assemble | 66 / 150 / 100 / 108 | 名称,仅此而已 |
可以避免重新渲染的规则:
- 以观众的问题开头,而不是产品名称。
- 在名称出现后 3 秒内展示产品。
- 将唯一时刻(只有你的产品能提供的)分配最多的屏幕时间。 不要将运行时间均匀分布在各个功能上。
- 将每个序列的预算设定为组件的自然长度(帧数列,也在
llms-components.txt中)。预算不足会在镜头中间裁剪动画;预算过多会留下空白。 - 将文本烧录进去。 大多数社交视图是静音的。
3. 安装场景
npx shadcn@latest add https://imgcli.com/r/type-morph.json https://imgcli.com/r/announce-title.json https://imgcli.com/r/hero-launch.json https://imgcli.com/r/count-grid.json https://imgcli.com/r/wordmark-cut.json
每个场景都落在 components/imgcli/<名称>.tsx 中,其依赖项随之安装。
4. 合成
一个 TransitionSeries,每个节拍一个序列,它们之间有短暂的淡入。
此合成按编写进行类型检查并渲染,在 public/ 中有四张截图:
import { fade } from "@remotion/transitions/fade";
import { linearTiming, TransitionSeries } from "@remotion/transitions";
import { staticFile } from "remotion";
import { AnnounceTitle } from "@/components/imgcli/announce-title";
import { CountGrid } from "@/components/imgcli/count-grid";
import { HeroLaunch } from "@/components/imgcli/hero-launch";
import { TypeMorph } from "@/components/imgcli/type-morph";
import { WordmarkCut } from "@/components/imgcli/wordmark-cut";
// 1280×720 @ 30fps。每个序列的预算设定为组件的自然长度。
const T = linearTiming({ durationInFrames: 12 });
// public/ 中的真实产品截图。如果在没有它们的情况下场景会回退到 snapcn 样本图像。
const shots = ["shot-1.jpg", "shot-2.jpg", "shot-3.jpg", "shot-4.jpg"].map((f) => staticFile(f));
export const LaunchVideo: React.FC = () => (
<TransitionSeries>
{/* 1. 钩子:观众的问题,转化为承诺 */}
<TransitionSeries.Sequence durationInFrames={94}>
<TypeMorph
lead="你的发布视频 "
emphasis="需要一周。"
morphTo="只需一个提示。"
finally_="一个提示。"
/>
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={fade()} timing={T} />
{/* 2. 命名产品 */}
<TransitionSeries.Sequence durationInFrames={170}>
<AnnounceTitle
eyebrow="隆重推出"
title="Acme 2.0"
tagline="自动对账的计费系统。"
symbolPath="" // 你的标记在 0 0 100 100 盒子中的 SVG 路径;"" 表示无
/>
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={fade()} timing={T} />
{/* 3. 展示产品:两个真实截图(图片、视频或 CSS 渐变占位) */}
<TransitionSeries.Sequence durationInFrames={170}>
<HeroLaunch
heading="每张发票,都已匹配。"
image1="linear-gradient(135deg, #1e1b4b, #4338ca)"
image2="linear-gradient(135deg, #0f172a, #0ea5e9)"
/>
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={fade()} timing={T} />
{/* 4. 证明:一个真实数字 */}
<TransitionSeries.Sequence durationInFrames={60}>
<CountGrid from="5" to="500" noun="团队" cards={shots} />
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={fade()} timing={T} />
{/* 5. 以名称结尾 */}
<TransitionSeries.Sequence durationInFrames={66}>
<WordmarkCut word="acme." />
</TransitionSeries.Sequence>
</TransitionSeries>
);
在 durationInFrames={512}(序列之和减去 4 × 12 帧重叠)、fps={30}、width={1280}、height={720} 处注册。
将渐变替换为真实截图或剪辑:image1={staticFile("shot-1.png")} 并将文件放在 public/ 中。
5. 渲染-审核循环
在渲染完整视频之前渲染单帧:
# 每个节拍一帧:每个序列的中点,以及每次切换前后
npx remotion still LaunchVideo out/beat-1.png --frame=47
npx remotion render LaunchVideo out/launch.mp4 --codec=h264 --crf=18
将静态帧排列成一张联系表,并在渲染整个视频之前查看它:
ffmpeg -y -pattern_type glob -i "out/beat-*.png" -vf "scale=480:-1,tile=5x1" out/contact.png
检查每一帧:
- 没有文本被裁剪,切换处没有黑帧,没有在其场景开始之前显示的内容。
- 屏幕上的每个字符串都是来自简介的真实文案。
- 产品在其名称出现后 3 秒内出现。
6. 审查
在两到三次自我检查后,渲染大约 20 帧(峰值时刻和每次切换的两边),并作为 四名批评者进行审查,或者如果你的框架支持,作为四个并行的子代理进行审查:
- 设计/布局:对齐、裁剪、比例。
- 可读性:在手机上 720p 下清晰可读、对比度、拼写错误。
- 节奏:每个节拍是否值得其时间;结尾是否有力?
- 品牌:颜色、字体和 UI 是否与真实产品匹配?
在下次渲染之前将他们的修复列表合并为一个修改计划。
7. 为平台发布
在渲染之前询问视频将发往何处。为每个宽高比制作一个合成,而不是之后裁剪。
| 平台 | 宽高比 | 尺寸 |
|---|---|---|
| X / LinkedIn 信息流 | 16:9 | 1920×1080(或渲染 1280×720 主视频) |
| X 垂直视频、Reels、Shorts、TikTok | 9:16 | 1080×1920 |
| LinkedIn / Instagram 信息流 | 1:1 或 4:5 | 1080×1080 / 1080×1350 |
npx remotion render LaunchVideo out/launch-1080.mp4 --scale=1.5 将
1280×720 主视频放大到 1920×1080,而无需重新布局任何场景。
来之不易的经验
- 切勿编造产品 UI 标签。 截取真实应用的屏幕镜像其文案。
- 在结束卡上使用一个标题和一个 CTA。 使用落地页的真实标语。
- 将钩子植根于观众无需解释就能识别的事物。 如果需要一句话来解释,那么钩子就太抽象了。
- 之前/之后节拍同时进行。 让“之前”持续大约一秒钟,然后切换到“之后”。
- 不要用自己的淡入将 Imgcli 场景粘合在场景内部。 过渡属于
TransitionSeries;每个场景的退出淡入会造成双重淡入。 - 你自己的添加保持克制:句子大小写,无装饰性字距,无发光或渐变文字。带有发光的 Imgcli 场景(
announce-title)保留发光;那是一种效果,不是装饰。
署名
工作流程结构(输入 → 分镜 → 构建 → 渲染-审核 → 多批评者审查 → 平台表格)和几个来之不易的经验改编自
everyinc/product-launch-video(MIT 许可证,© 2026 Every Media, Inc.)。联系表审核和“在设计任何外观之前搜索目录”规则改编自 HeyGen 的
hyperframes product-launch-video 技能
(Apache-2.0 许可证)。两者均已为 Remotion 和 snapcn 组件重写;所有 snapcn 特定内容均归 snapcn 所有。