mcpField
R
remotion-interactivity

remotion-interactivity

github.com/remotion-dev创意与媒体5.8k217.7k 次安装2 天前更新
代码仓库

关于 remotion-interactivity

remotion-interactivity 指导开发者组织可在 Studio 中编辑的 Remotion 代码,重点包括可单独操作的时间线元素、实例级控件、字段架构和可编辑动画路径。

主要功能

  1. 01组织可独立编辑的时间线项目
  2. 02用字段架构定义 Studio 控件
  3. 03使 HTML 和 SVG 元素可交互
  4. 04保持样式、效果和元数据可编辑

适用场景

  1. 01为 Studio 编辑准备合成
  2. 02为元素提供文本和外观控件
  3. 03创建可编辑的 SVG 路径动画
  4. 04组织可在时间线编辑的片段与场景组件

安装

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

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

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

包含的文件

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

inline-effects.md
timeline-structure.md
agents/
openai.yaml
assets/
remotion-icon.svg

详细介绍

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 控制内容。 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 标记,以便在时间轴中交互式编辑剪辑。

评论

支持 Markdown