关于 remotion-interactivity
remotion-interactivity 指导开发者组织可在 Studio 中编辑的 Remotion 代码,重点包括可单独操作的时间线元素、实例级控件、字段架构和可编辑动画路径。
主要功能
- 01组织可独立编辑的时间线项目
- 02用字段架构定义 Studio 控件
- 03使 HTML 和 SVG 元素可交互
- 04保持样式、效果和元数据可编辑
适用场景
- 01为 Studio 编辑准备合成
- 02为元素提供文本和外观控件
- 03创建可编辑的 SVG 路径动画
- 04组织可在时间线编辑的片段与场景组件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ remotion-dev/ skills --skill remotion-interactivity安装后在 Claude Code 中输入/remotion-interactivity确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
inline-effects.mdtimeline-structure.mdagents/openai.yamlassets/remotion-icon.svg详细介绍
Studio 会编辑用于创建时间线项目的 JSX 节点。围绕用户应能独立选择、移动、修剪或设置样式的内容来组织代码。将可编辑值内联放在每个实例上。
编写场景或重构其图层之前,请阅读 可编辑时间线结构。其中介绍了编辑单元、轨道、共享时间、普通布局容器,以及从组件到根节点的完整示例。对于基于素材构建的时间线,也请阅读 可编辑视频时间线。
当场景或可复用分组需要自己的时间线时,请使用连接组合。验证其独立视图和完整的父时间线;仅建立连接并不能保证可见行数会减少。
选择架构字段
架构中的每个键都是 Studio 可以在调用处读取和编辑的属性。
不在架构中的属性仍然有效,但无法在 Studio 中编辑。
键可以使用点号表示法,例如 style.color。
| 类型 | 用途 | 可设关键帧 |
|---|---|---|
string | 字符串,例如标题、提示词或代码片段 | 否 |
number | 数字,可选设置 min、max、step、integer | 是 |
boolean | 开关 | 是(保持) |
color | CSS 颜色字符串 | 是 |
enum | 在多个 variants 中选择,每个变体都有自己的嵌套架构 | 需启用(保持) |
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 可显示静态控件。
公开内容和每个实例的外观,例如文本和强调色。
不要为 style.translate、style.scale、style.rotate、style.transformOrigin 和 style.opacity 添加字段:Interactive.create() 会自动添加它们。
要让根节点的 CSS 属性可按实例编辑,请展开内置架构片段:
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。
它提供用于控制子元素内容的控件,未来可能会支持更丰富的内容。
目前,它使用一个标签为“文本”、默认值为 '' 的字符串字段。
如果组件要求子元素只能是字符串,请改为显式声明一个 children 字段,并将 type 设为 'string'。
Interactive.textSchema 控制排版样式;childrenSchema 控制内容。
children 片段不会包含在 baseSchema 中,也不会自动添加到自定义组件中。
嵌套标记和计算得出的子元素目前为只读。
text-content 是已弃用的 string 字段类型别名。
有关所有选项,请参阅 InteractivitySchema。
使用 Interactive 让 HTML 元素具有交互性
所有 HTML 和 SVG 元素(<Img> 除外,它本身已具有交互性),例如 <div>,都可以使用 Interactive 变成交互式元素:
<Interactive.Div
name="Greeting card"
style={{fontSize: 80, padding: 24}}
>
Hello
</Interactive.Div>
将它用于需要独立控件的文本或图形。仅用于布局的容器和装饰性内部元素 应保持为普通 HTML;交互式组件已为其根元素提供控件。
优先使用内联文本
如果文本是固定的,且只使用一次,请直接将其写在交互式元素内部,而不要提取为常量。
// 👍 Fixed copy stays editable
<Interactive.Div name="Title">
Remotion Best Practices
</Interactive.Div>
只有在文本是动态内容或需要重复使用时,才使用属性或变量。
为交互式元素指定描述性名称
为元素添加 name 属性,使其易于识别。
避免使用计算得出的名称,应将名称硬编码。
<>
<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 // ❌ Non-inline styles are not supported
}
}, []);
<Interactive.Div
style={{
...baseStyle, // ❌ Spreading is not supported
color: RED, // ❌ Referring to constants is not supported
scale: frame * 10 // ❌ Math is not supported
}}
>
Hello World!
</Interactive.Div>
使用 interpolate() 制作动画
在发生变化的属性上以内联方式调用 interpolate() 来编写动画。
输出范围、缓动、外推和 output 属性都应使用硬编码值。
输入范围还可以使用从 useVideoConfig() 中直接解构出来的 durationInFrames、fps、width 和 height。支持直接使用标识符(例如 durationInFrames)、与数字相乘(例如 2 * fps 或 fps * 2),以及减去数字(例如 durationInFrames - 1)。
const {fps, durationInFrames} = useVideoConfig();
// 👍 Inline values can be standardized and keyframed
<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]); // ❌ Math should be directly in the markup
<Interactive.Div
name="Product card"
style={{
translate: translateY, // ❌ Only inline interpolate() calls are supported,
rotate: interpolate(frame, [start, start + 10], [0, Math.PI]), // ❌ Cannot use math with arbitrary variables, cannot use constants
scale: interpolate(anyVariable, [0, 30], [0, 1]) // ❌ Can only interpret the `frame` variable.
}}
/>
使用 Interactive.Path 保持 SVG 路径可编辑
在 SVG 中使用来自 remotion 的 <Interactive.Path> 代替 <path>,使路径在视觉上可编辑。
安装 @remotion/paths,以便进行路径插值并在 Studio 中编辑路径关键帧:
bunx remotion add @remotion/paths
如果几何图形应保持静态,请将路径字符串直接写入 d 属性。不要将它提取为常量。
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>
使用内联 interpolatePaths() 变形路径
直接在 d 中使用来自 @remotion/paths 的 interpolatePaths()。
它接受一个帧、一个输入范围、一个长度相同的路径字符串数组,以及用于缓动、外推和海报化的选项。
与上面的 interpolate() 一样,输出路径、范围和选项应保持内联,并遵循相同的输入范围规则。
当路径关键帧需要在 Studio 中保持可编辑时,不要使用 interpolatePath() API,也不要将插值结果提取到变量中。
import {interpolatePaths} from '@remotion/paths';
import {Easing, Interactive, useCurrentFrame} from 'remotion';
export const MorphingPath = () => {
const frame = useCurrentFrame();
return (
<Interactive.Svg width={300} height={300} viewBox="0 0 300 300">
<Interactive.Path
name="Morphing triangle"
d={interpolatePaths(
frame,
[0, 30, 60],
[
'M 40 40 L 260 40 L 150 260 Z',
'M 40 150 L 150 40 L 260 150 Z',
'M 40 260 L 150 40 L 260 260 Z',
],
{
easing: Easing.bezier(0.42, 0, 0.58, 1),
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
},
)}
fill="#0b84f3"
/>
</Interactive.Svg>
);
};
Studio 可以编辑当前帧的路径、添加或移动关键帧,并调整其缓动。
使用 strokeDasharray 和 strokeDashoffset 来改变路径。
使用 CSS scale、translate 和 rotate 属性
避免使用 CSS transform 属性。
如果可以,请改用 scale、rotate 和 translate,因为只有这些属性可以交互式编辑。
将合成元数据内联
创建合成时,id 使用 JSX 字符串字面量,将 width、height、fps、durationInFrames 和 defaultProps 保持内联,且不要使用类型断言。
当 <Composition> 或 <Still> 上的 defaultProps 是内联对象字面量时,Props 编辑器可以将视觉编辑保存回代码。
// 👍 Static values are in <Composition>, dynamic values are in calculateMetadata()
const calculateMetadata = useMemo(async () => {
const dimensions = await getDimensions(); // just an example
return {width: dimensions.width, height: dimensions.height};
});
<Composition
id="my-video"
component={MyComponent}
durationInFrames={150}
fps={30}
calculateMetadata={calculateMetadata}
defaultProps={{title: 'Hello', color: '#0b84ff'}}
/>
const defaultProps = {title: 'Hello', color: '#0b84ff'}; // ❌ Don't extract defaultProps, must be inline
const calculateMetadata = useMemo(() => {
// ❌ Unnecessary because no calculation is being done,
return {durationInFrames: 150, fps: 30, width: 1920, height: 1080};
});
<Composition
id="my-video"
component={MyComponent}
calculateMetadata={calculateMetadata}
defaultProps={{
title: 'Hello',
} as Props} // ❌ Don't have type assertions, instead type MyComponent correctly
/>
仅对动态的元数据部分使用 calculateMetadata()。
效果也应内联
将效果数组和参数保持内联,以便其结构和关键帧仍可编辑。示例请参阅内联效果。
让自己的组件支持交互
如要让自定义的用户组件支持交互,请使用: 让组件支持交互
视频编辑
如果 Remotion 组件主要由视频和音频剪辑组成,请参阅“视频编辑”,了解如何组织 Remotion 标记,以便在时间轴中交互式编辑剪辑。