mcpField
R
remotion-interactivity

remotion-interactivity

github.com/remotion-dev创意与媒体69.1k103 次安装今天更新
代码仓库

关于 remotion-interactivity

remotion-interactivity 是一项技能,指导如何组织 Remotion 合成内容,使 Studio 能编辑时间线元素及其属性。它介绍基于架构的控件、交互元素、关键帧和可编辑视频时间线。

主要功能

  1. 01基于架构的可编辑控件
  2. 02可交互的文本与图形
  3. 03可编辑属性和关键帧
  4. 04视频时间线组织指南

适用场景

  1. 01让合成文本可在 Studio 中编辑
  2. 02添加按实例设置的样式控件
  3. 03构建片段可独立编辑的时间线

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/remotion-dev/remotion --skill remotion-interactivity

安装后在 Claude Code 中输入/remotion-interactivity确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

timeline-structure.md
inline-effects.md
agents/
openai.yaml

详细介绍

Studio 会编辑用于创建时间线项目的 JSX 节点。围绕用户应能独立选择、移动、裁剪或设置样式的内容来组织代码。将可编辑值内联放在每个实例上。

在编写场景或重构其图层之前,请阅读可编辑时间线结构。其中介绍了编辑单元、轨道、共享时间、普通布局容器,以及从组件到根节点的完整示例。对于由素材构建的时间线,还请阅读可编辑视频时间线。

当场景或可复用组需要拥有自己的时间线时,请使用连接的合成。请分别验证其独立视图和完整的父级时间线;仅建立连接并不能保证可见行数会减少。

选择架构字段

架构中的每个键都是 Studio 可在调用处读取和编辑的属性。不在架构中的属性仍然可用,但无法在 Studio 中编辑。键可以使用点表示法,例如 style.color。

类型用途可设关键帧
string字符串,例如标题、提示词或代码片段否
number数字,可选设置 min、max、step、integer是
boolean开/关切换项是(保持)
colorCSS 颜色字符串是
enum从多个 variants 中选择,每个选项都有自己的嵌套架构可选(保持)
array数字、颜色、枚举等列表否
asset媒体源,可选设置 assetType否
font-familyCSS 字体系列否
font-weight字重是
translate、scale、rotation-css、rotation-degrees、transform-origin变换是
uv-coordinate元素上的归一化 [x, y] 点是
svg-pathSVG 路径数据是
remotion-captionsCaption[] 数据否
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 控制内容。 子元素片段不会包含在 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 让路径逐渐显现。

使用 scale、translate、rotate CSS 属性

避免使用 transform CSS 属性。
如果可能,请改用 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 标记,以便在时间轴中交互式地编辑片段。

评论

支持 Markdown