remotion-interactivity

構造化されたRemotionマークアップを通じて、Studio上でインタラクティブな編集を可能にするスキルです。

remotion-interactivity とは?

このスキルは、Remotionプロジェクトにおいて、コンポーネントのマークアップを特定の方法で記述することで、Remotion Studioがコードの構造を認識し、クリックによる選択、ドラッグ&ドロップ、リサイズ、回転、CSSスタイルの編集、キーフレームやイージング値の編集といったインタラクティブな操作を可能にします。主に、`Interactive.withSchema()`を使用したコンポーネントの作成、インタラクティブなHTML要素の定義、スキーマフィールドの設計、タイミングプロパティの直接設定、独立したJSXノードの管理など、Studioでの編集体験を最大化するための具体的なコーディングパターンをカバーしています。動画編集ツールやUIコンポーネントライブラリを開発する際に、ビジュアルエディタとの親和性を高めるためのベストプラクティスとして非常に有用です。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/remotion-dev/skills/tree/main/skills/remotion-interactivity

Installed? Explore more ビデオ&アニメーション skills: steipete/video-frames, steipete/summarize, openclaw/openclaw · View all 6 →

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

プレビュー

スキル README より

remotion-interactivity preview

ドキュメント

Remotionマークアップを特定の方法で記述することで、Remotion Studioがコードの構造を認識し、インタラクティブに操作できるようになります。

  • クリックによる要素の選択
  • ドラッグ&ドロップ、リサイズ、回転
  • CSSスタイルの編集
  • キーフレームとイージング値の編集

マークアップが複雑すぎてStudioがインタラクティブにできない場合、値はグレーアウトされます。

独自のタイムラインを持つインタラクティブコンポーネントを優先する

親要素を埋めるコンポーネントには、Interactive.withSchema({wrapInSequence: true, layout: 'absolute-fill'})を使用します。このラッパーは視覚的なルートとタイムラインアイテムを提供し、デフォルトでオーバーフローをクリップするため、内部コンポーネントはフラグメントを返すことができます。タイミング、プリマウント、ディメンション、インスタンスごとのスタイルは、エクスポートされたコンポーネントに指定します。

同じグループに属するビジュアルは、同じコンポーネント内にまとめて配置し、一緒に移動・トリミングできるようにします。内部のレイアウトコンテナは、アライメント、小さな領域内でのクリッピング、またはアニメーショングループを提供できます。シーンを埋めるだけのコンテナは通常は不要です。カード、テキストボックス、独自の境界を持つSVGは、デフォルトのlayout: 'none'を維持し、styleを視覚的なルートに転送できます。

import {Video} from '@remotion/media';
import type React from 'react';
import {Interactive, useVideoConfig, type InteractivitySchema} from 'remotion';

type SceneProps = {
  readonly title: string;
};

const SceneInner: React.FC<SceneProps> = ({title}) => {
  const {fps} = useVideoConfig();

  return (
    <>
      <Video
        name="背景映像"
        src="https://remotion.media/video.mp4"
        premountFor={fps}
        objectFit="cover"
        style={{width: '100%', height: '100%'}}
      />
      <Interactive.Div
        name="シーンのタイトル"
        style={{
          position: 'absolute',
          left: 80,
          bottom: 80,
          color: 'white',
          fontFamily: 'Helvetica, Arial, sans-serif',
          fontSize: 80,
        }}
      >
        {title}
      </Interactive.Div>
    </>
  );
};

const sceneSchema = {
  title: {type: 'string', default: '', description: 'タイトル'},
} as const satisfies InteractivitySchema;

export const Scene = Interactive.withSchema({
  Component: SceneInner,
  componentName: 'Scene',
  schema: sceneSchema,
  wrapInSequence: true,
  layout: 'absolute-fill',
});

スキーマフィールドを選択する

スキーマの各キーは、呼び出し元でStudioが読み取り・編集できるプロパティです。スキーマにないプロパティも機能しますが、Studioでは編集できません。キーにはドット記法(例:style.color)を使用できます。

型用途キーフレーム化可能
stringタイトル、プロンプト、コードスニペットなどの文字列いいえ
number数値(オプションでmin、max、step、integer)はい
booleanオン/オフの切り替えはい(ホールド)
colorCSSカラー文字列はい
enumvariantsから選択(それぞれが独自のネストスキーマを持つ)オプトイン(ホールド)
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が必要であり、Studioでラベルとして表示されるdescriptionを持つべきです。keyframable: falseを設定すると、静的なコントロールが表示されます。

コンテンツとインスタンスごとの外観(テキストとアクセントカラーなど)を公開します。 style.translate、style.scale、style.rotate、style.transformOrigin、style.opacityのフィールドは追加しないでください。wrapInSequence: trueによって既に追加されています。

ルートの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を追加します。これにより、子コンテンツのコントロールが提供され、将来的にはよりリッチなコンテンツをサポートする可能性があります。現在は、デフォルトが''の「テキスト」というラベルの付いた文字列フィールドを使用します。コンポーネントが文字列のみの子を必要とする場合は、代わりにtype: 'string'の明示的なchildrenフィールドを宣言してください。Interactive.textSchemaはタイポグラフィスタイルを制御し、childrenSchemaはコンテンツを制御します。childrenSchemaはbaseSchemaに含まれておらず、カスタムコンポーネントに自動的に追加されることもありません。ネストされたマークアップと計算された子は現在読み取り専用です。text-contentはstringフィールドタイプの非推奨のエイリアスです。

すべてのオプションについては、InteractivitySchemaを参照してください。

再利用可能なコンポーネントを接続コンポジションとして登録する

重要なシーンや再利用可能なコンポーネントで、独自のレイヤーやアニメーションを持つものは、スタンドアロンのコンポジションとして登録します。Studioはこれらを接続コンポジションと呼びます。親ビデオと同じコンポーネント実装を共有しながら、独自のタイムラインで開くことができます。

コンポーネント内で必要なスタイルを定義し、フォントをロードして、親がなくても動作するようにします。親独立性を参照してください。

親がレンダリングするのと同じエクスポートされたコンポーネント参照を登録します。上記の例では、component={Scene}を使用し、SceneInnerやインラインラッパーは使用しないでください。wrapInSequence: trueを使用すると、接続のために追加の<Sequence>は不要です。

import {Composition} from 'remotion';
import {Scene} from './Scene';

export const RemotionRoot = () => (
  <Composition
    id="Scene"
    component={Scene}
    width={1280}
    height={720}
    fps={30}
    durationInFrames={30}
    defaultProps={{
      title: '新しい視点',
    }}
  />
);

一意のID、代表的なインラインデフォルト値、およびコンポーネントのプレビューに適した幅、高さ、fps、durationを選択します。登録デフォルトは、親インスタンスから自動的にプロパティをコピーしません。登録と抽出の詳細については、接続コンポジションを参照してください。

コンポーネントに直接タイミングを設定する

すでにタイミングプロパティを受け入れているコンポーネントの周りに、個別の<Sequence>を配置することは避けてください。組み込みのインタラクティブコンポーネントやwrapInSequence: trueで作成されたカスタムコンポーネントは、name、from、durationInFrames、trimBefore、playbackRate、premountForを直接受け取ることができます。

<Scene
  name="オープニングシーン"
  from={30}
  durationInFrames={90}
  premountFor={fps}
  style={{opacity: 0.9}}
  title="新しい視点"
/>

冗長なシーケンスを削除する場合は、そのタイミングと名前を子に移動します。既存の子のタイミングは保持し、オフセットを上書きしたり二重適用したりしないでください。コンポーネント内のuseCurrentFrame()呼び出しはローカルフレームを読み取りますが、呼び出し元のスタイル式は呼び出し元のフレームを使用します。アニメーションスタイルを移動する際は、その違いを維持してください。

<Sequence>は、複数の兄弟に共有タイミングを提供する場合、タイミングを処理しないコンポーネントをラップする場合、または子が直接受け入れられないディメンションを提供する場合に保持します。管理されたルートもwidthとheightをuseVideoConfig()に対して受け入れます。連続するレイアウトには<TransitionSeries.Sequence>を保持します(トランジションの有無にかかわらず)。直接のfromプロパティはこれらの動作を置き換えません。

独立して編集可能なすべてのアイテムに独自のJSXノードを与える

Studioは、アイテムを作成したJSXソースノードを編集します。複数のランタイムアイテムが同じJSXノードから生成される場合、それらは1つのソース編集ターゲットを共有します。

各コンポジション登録、クリップ、シーン、レイヤー、またはシーケンスは、個別に編集可能である必要がある場合、個別のJSXノードを作成し、その編集可能なプロパティをそのノードに保持します。これは、<Composition>、<Still>、組み込みのメディアコンポーネント、<Sequence>、<TransitionSeries.Sequence>、およびカスタムコンポーネントに適用されます。

例えば、編集可能なタイムラインを次のように記述します:

import { TransitionSeries } from "@remotion/transitions";

<TransitionSeries>
  <TransitionSeries.Sequence name="イントロダクション" durationInFrames={90}>
    <Introduction />
  </TransitionSeries.Sequence>
  <TransitionSeries.Sequence name="デモ" durationInFrames={150}>
    <Demo />
  </TransitionSeries.Sequence>
</TransitionSeries>

.map()やその他のプログラムによるループは、1つのJSXソースノードから複数のランタイムアイテムを作成します。これは、可視化バーやパーティクルなど、意図的に1つのテンプレートとして制御される繰り返し出力に適しています。インスタンスがStudio内で独立したIDや名前、プロパティ、メタデータ、タイミング、順序、削除、複製を必要とする場合には適していません。

Interactiveを使用してHTML要素をインタラクティブにする

<Img>を除くすべてのHTMLおよびSVG要素(すでにインタラクティブです)は、Interactiveを使用してインタラクティブにできます:

<Interactive.Div
  name="グリーティングカード"
  style={{fontSize: 80, padding: 24}}
>
  こんにちは
</Interactive.Div>

これにより、Studioでスタイルとキーフレームを設定できます。ただし、コンポーネントに多くの要素がある場合、タイムラインが乱雑になる可能性があるため、適切に使用してください。

インラインテキストを優先する

テキストが固定されており、1回だけ使用される場合は、定数に抽出せずに、インタラクティブ要素内に直接記述します。

// 👍 固定コピーは編集可能なまま
<Interactive.Div name="タイトル">
  Remotion ベストプラクティス
</Interactive.Div>

テキストが動的であるか再利用される場合にのみ、プロパティまたは変数を使用します。

インタラクティブ要素に説明的な名前を付ける

要素にnameプロパティを追加して、簡単に識別できるようにします。 計算された名前は避け、ハードコードします。

<>
  <Interactive.Div name="ヒーロータイトル" style={{fontSize: 80}}>
    ローンチ日
  </Interactive.Div>
  <Img name="アバター" src="https://remotion.media/image.jpeg" />
  <Video name="背景" src="https://remotion.media/video.mp4" />
  <Interactive.Div name="タイトル">
    ローンチ日
  </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="商品カード"
  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}),
        extrapolateLeft: 'clamp',
        extrapolateRight: 'clamp'
      }
    ),
  }}
>
  Hello World!
</Interactive.Div>

Springアニメーションにはinterpolate()を使用してください。useAnimatedPropertiesはStudioでは認識されないため、読み取り専用になります。

interpolate()を使用する場合、またはStudioでキーフレーム編集を有効にするには、output: 'perceptual-scale'、output: 'perceptual-rotate'、output: 'perceptual-color'、output: 'degrees'、output: 'interpolate-x-y'のいずれかを追加します。Studioはこれらの出力プロパティを認識し、それに応じてキーフレームの編集を最適化します。

Studioのキーフレーム編集には、デフォルト外挿(extrapolateLeft: 'clamp'、extrapolateRight: 'clamp')を明示的に使用することをお勧めします。"

Individual skills in this repo

This repo contains 19 individual skills — each has its own dedicated page.

関連スキル