通过以特定方式编写 Remotion 标记,Remotion Studio 能够识别代码结构并使其具有交互性:
- 允许通过点击选择项目
- 允许拖放、调整大小和旋转
- 编辑 CSS 样式
- 使关键帧和缓动值可编辑
如果标记过于复杂,Studio 无法使其交互,那么这些值将变为灰色。
优先使用具有自身时间线的交互式组件
使用 Track、连接组件和 Interactive.create() 构建新的合成。
对于场景,显式设置 layout 为 'absolute-fill';对于有界元素,设置为 'none'。使用 Composition 注册相同的导出场景和可重用元素组件。
从完整的 Track + 连接组件示例 开始。 它包含元素、场景、父时间线和根注册。
import {Track, useVideoConfig} from 'remotion';
import {Chapter} from './Chapter';
export const MyVideo = () => {
const {fps} = useVideoConfig();
return (
<Track name="Chapters">
<Chapter
name="Opening"
durationInFrames={3 * fps}
title="Introduction"
/>
<Chapter
name="Feature"
from={3 * fps}
durationInFrames={4 * fps}
title="New features"
/>
</Track>
);
};
将背景和对齐样式放在每个场景实例上,如完整示例所示。保持仅用于布局的容器为纯 HTML。
选择 Schema 字段
Schema 中的每个键都是一个 prop,Studio 可以在调用站点读取和编辑。
不在 Schema 中的 Props 仍然有效,但在 Studio 中不可编辑。
键可以使用点号表示法,例如 style.color。
| 类型 | 用途 | 可关键帧 |
|---|---|---|
string | 字符串,例如标题、提示或代码片段 | 否 |
number | 数字,可选 min、max、step、integer | 是 |
boolean | 开/关开关 | 是(按住) |
color | CSS 颜色字符串 | 是 |
enum | 在 variants 之间选择,每个变体都有自己的嵌套 schema | 可选加入(按住) |
array | 数字、颜色、枚举等的列表 | 否 |
asset | 媒体源,可选 assetType | 否 |
font-family | CSS 字体家族 | 否 |
font-weight | 字体粗细 | 是 |
translate、scale、rotation-css、rotation-degrees、transform-origin | 变换 | 是 |
uv-coordinate | 元素上的标准化 [x, y] 点 | 是 |
svg-path | SVG 路径数据 | 是 |
remotion-captions | Caption[] 数据 | 否 |
hidden | 保持在控件之外的值 | — |
每个字段都需要一个 default,并且应该有一个 description,Studio 会将其显示为标签。
设置 keyframable: false 以显示静态控件。
暴露内容和每个实例的外观,例如文本和强调色。\n不要为 style.translate、style.scale、style.rotate、style.transformOrigin 和 style.opacity 添加字段:Interactive.create() 会自动添加它们。
要使根元素的 CSS 属性在每个实例上可编辑,展开内置的 schema 片段:
const cardSchema = {
...Interactive.textSchema, // style.color、style.fontSize、style.fontWeight、...
...Interactive.backgroundSchema, // style.backgroundColor
...Interactive.borderRadiusSchema, // style.borderRadius、...
} as const satisfies InteractivitySchema;
其他可用项:Interactive.borderSchema,以及用于接受字幕的组件的 Interactive.captionsSchema。
对于接受 React.ReactNode 子元素的组件,添加 ...Interactive.childrenSchema。
它为子内容提供控件,并可能演变为支持更丰富的内容。
目前,它使用一个标签为 "Text" 的字符串字段,默认值为 ''。
如果组件只需要字符串子元素,请改用 type: 'string' 声明一个显式的 children 字段。
Interactive.textSchema 控制排版样式;childrenSchema 控制内容。
children 片段不包含在 baseSchema 中,也不会自动添加到自定义组件中。
嵌套标记和计算出的子元素目前是只读的。
text-content 是 string 字段类型的已弃用别名。
有关所有选项,请参阅 InteractivitySchema。
将可重用组件注册为连接组件
将场景和可重用元素注册为独立的合成。Studio 称这些为连接组件:它们可以在自己的时间线中打开,同时与父视频共享相同的组件实现。
在组件内部定义必需的样式和加载字体,以便它可以在没有父级的情况下工作。请参阅 父级独立性。
注册与父级渲染相同的导出组件引用。对于上面的示例,使用 component={Chapter},而不是 ChapterInner 或内联包装器。
Interactive.create() 提供序列,因此连接不需要额外的 <Sequence>。
import {Composition} from 'remotion';
import {Chapter} from './Chapter';
export const RemotionRoot = () => (
<Composition
id="Chapter"
component={Chapter}
width={1280}
height={720}
fps={30}
durationInFrames={90}
defaultProps={{
title: 'A new perspective',
style: {
backgroundColor: '#111111',
justifyContent: 'center',
alignItems: 'center',
},
}}
/>
);
选择一个唯一的 ID、有代表性的内联默认值,以及适合预览组件的尺寸、帧率和持续时间。注册默认值不会自动从父实例复制 props。请参阅 连接组件以了解 注册和提取细节。
将时序直接放在组件上
避免在已接受时序 props 的组件周围使用单独的 <Sequence>。内置的交互式组件和使用 Interactive.create() 创建的自定义组件可以直接接收 name、from、durationInFrames、trimBefore 和 playbackRate。
<Chapter
name="Opening scene"
from={30}
durationInFrames={90}
style={{opacity: 0.9}}
title="A new perspective"
/>
对于共享场景时序,将内容分组到一个使用 Interactive.create() 创建的组件中,并为该实例计时。托管根还接受 width 和 height 以用于 useVideoConfig()。
使用 <Track> 将项目放在同一个 Studio 时间线行上。
当场景是顺序的时候,使用 <TransitionSeries>。
为每个可独立编辑的项目提供自己的 JSX 节点
Studio 编辑创建项目的 JSX 源节点。如果多个运行时项目来自同一个 JSX 节点,它们共享一个源编辑目标。
对于每个应单独编辑的合成注册、剪辑、场景、层或序列,编写一个单独的 JSX 节点,并将其可编辑 props 保留在该节点上。这适用于 <Composition>、<Still>、内置媒体组件、<Sequence>、<TransitionSeries.Sequence>
和自定义组件。
例如,像这样编写一个可编辑的时间线:
import { Track } from "remotion";
<Track name="Scenes">
<Introduction name="Introduction" durationInFrames={90} />
<Demo name="Demo" from={90} durationInFrames={150} />
</Track>
.map() 或其他程序化循环会从一个 JSX 源节点创建多个运行时项目。这适用于需要有意识地作为单个模板控制的重复输出,例如可视化条形图或粒子。当实例在 Studio 中需要独立的 ID 或名称、props、元数据、时序、排序、删除或复制时,这不合适。
使用 Interactive 使 HTML 元素具有交互性
每个 HTML 和 SVG 元素(除了 <Img>,它已经是交互式的)例如 <div> 都可以使用 Interactive 变为交互式:
<Interactive.Div
name="Greeting card"
style={{fontSize: 80, padding: 24}}
>
Hello
</Interactive.Div>
这允许在 Studio 中设置样式和关键帧。请明智使用,如果组件有很多元素,时间线可能会变得混乱。
优先使用内联文本
如果文本是固定的且只使用一次,请直接将其写在交互式元素内部,而不是将其提取到常量中。
// 👍 固定副本保持可编辑
<Interactive.Div name="Title">
Remotion Best Practices
</Interactive.Div>
仅在文本是动态的或可重用时才使用 prop 或变量。
为交互式元素提供描述性名称
向元素添加 name prop 以使其易于识别。
避免使用计算出的名称,硬编码它们。
<>
<Interactive.Div name="Hero title" style={{fontSize: 80}}>
Launch day
</Interactive.Div>
<Img name="Avatar" src="https://remotion.media/image.jpeg" />
<Video name="Background" src="https://remotion.media/video.mp4" />
<Interactive.Div name="Title">
Launch day
</Interactive.Div>
</>
将所有 CSS 样式保持为内联
最好的方法是直接将一个普通对象传递给 style —— 不要引用常量,不要展开对象,不要进行数学运算。
<Interactive.Div
style={{
fontSize: 80,
color: 'red',
}}
>
Hello World!
</Interactive.Div>
const baseStyle = useMemo(() => {
return {
fontSize: 12 // ❌ 不支持非内联样式
}
}, []);
<Interactive.Div
style={{
...baseStyle, // ❌ 不支持展开
color: RED, // ❌ 不支持引用常量
scale: frame * 10 // ❌ 不支持数学运算
}}
>
Hello World!
</Interactive.Div>
使用 interpolate() 制作动画
在变化的属性上以内联 interpolate() 调用的形式编写动画。
输出范围、缓动、外推和 output 属性应使用硬编码值。
输入范围还可以额外使用从 useVideoConfig() 直接解构的 durationInFrames、fps、width 和 height。支持裸标识符(例如 durationInFrames)、与数字相乘(例如 2 * fps 或 fps * 2)以及减去一个数字(例如 durationInFrames - 1)。
const {fps, durationInFrames} = useVideoConfig();
// 👍 内联值可以标准化和关键帧化
<Interactive.Div
name="Product card"
style={{
color: 'white',
fontSize: 80,
scale: interpolate(frame, [0, fps], [0, 1], {
easing: Easing.spring({damping: 200}),
output: 'perceptual-scale',
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp'
}),
rotate: interpolate(frame, [0, 1 * fps], ['0deg', '20deg'], {
easing: Easing.spring({damping: 200}),
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp'
}),
translate: interpolate(
frame,
[durationInFrames - 30, durationInFrames],
['0px 0px', '0px 120px'],
{
easing: Easing.spring({damping: 200}),
output: 'perceptual-scale',
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp'
}
),
}}
/>
const translateY = interpolate(frame, [0, 30], [0, 120]); // ❌ 数学运算应直接在标记中
<Interactive.Div
name="Product card"
style={{
translate: translateY, // ❌ 仅支持内联 interpolate() 调用,
rotate: interpolate(frame, [start, start + 10], [0, Math.PI]), // ❌ 不能使用带有任意变量的数学运算,不能使用常量
scale: interpolate(anyVariable, [0, 30], [0, 1]) // ❌ 只能解释 `frame` 变量。
}}
/>
使用 Interactive.Path 保持 SVG 路径可编辑
在 SVG 内部使用来自 remotion 的 <Interactive.Path> 而不是 <path>,以使路径在视觉上可编辑。
为路径插值和 Studio 路径关键帧安装 @remotion/paths:
bunx remotion add @remotion/paths
如果几何图形是静态的,请将路径字符串直接放在 d prop 中。不要将其提取为常量。
import {Interactive} from 'remotion';
<Interactive.Svg width={300} height={300} viewBox="0 0 300 300">
<Interactive.Path
name="Triangle"
d="M 40 40 L 260 40 L 150 260 Z"
fill="#0b84f3"
/>
</Interactive.Svg>
使用内联路径对路径进行变形处理
…
[内容已截断]
