remotion-interactivity について
remotion-interactivityは、Studioでタイムライン要素やプロパティを編集できるよう、Remotionコンポジションを構成するためのスキルです。スキーマに基づくコントロール、インタラクティブ要素、キーフレーム、編集可能な動画タイムラインを説明します。
主な機能
- 01スキーマベースの編集可能なコントロール
- 02テキストやグラフィックのインタラクティブ化
- 03プロパティとキーフレームの編集
- 04動画タイムラインの構成ガイド
活用シーン
- 01コンポジションのテキストをStudioで編集可能にする
- 02インスタンスごとのスタイル設定を追加
- 03クリップを個別編集できるタイムラインの構築
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ remotion-dev/ remotion --skill remotion-interactivityインストール後、Claude Code で/remotion-interactivityを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
timeline-structure.mdinline-effects.mdagents/openai.yaml詳細
翻訳後に原文が更新されています。最新の内容は原文をご確認ください。
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, type InteractivitySchema} from 'remotion';
type SceneProps = {
readonly title: string;
};
const SceneInner: React.FC<SceneProps> = ({title}) => {
return (
<>
<Video
name="Background footage"
src="https://remotion.media/video.mp4"
objectFit="cover"
style={{width: '100%', height: '100%'}}
/>
<Interactive.Div
name="Scene title"
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: 'Title'},
} 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 | オン/オフの切り替え | はい(保持) |
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のフィールドは追加しないでください。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を追加します。
これは子要素のコンテンツを操作するコントロールを提供し、今後、より豊かなコンテンツに対応するよう拡張される可能性があります。
現在は、デフォルト値が''で、ラベルが「Text」の文字列フィールドを使用します。
コンポーネントの子要素を文字列のみにする必要がある場合は、代わりにtype: 'string'を指定したchildrenフィールドを明示的に宣言します。
Interactive.textSchemaはタイポグラフィのスタイルを制御し、childrenSchemaはコンテンツを制御します。
子要素のフラグメントはbaseSchemaに含まれておらず、カスタムコンポーネントに自動で追加されることもありません。
ネストされたマークアップと計算された子要素は、現在読み取り専用です。
text-contentは、フィールド型stringの非推奨の別名です。
すべてのオプションについては、InteractivitySchemaを参照してください。
再利用可能なコンポーネントを接続済みコンポジションとして登録する
独自のレイヤーやアニメーションを持つ大規模なシーンや再利用可能なコンポーネントは、独立したコンポジションとして登録します。Studioではこれらを接続済みコンポジションと呼びます。親動画と同じコンポーネント実装を共有しながら、独自のタイムラインで開くことができます。
コンポーネントが親なしでも動作するように、必要なスタイルを定義し、フォントを読み込みます。詳しくは 親からの独立性を参照してください。
親がレンダリングするものと同じエクスポート済みコンポーネント参照を登録します。上記の例では、SceneInnerやインラインラッパーではなく、component={Scene}を使用します。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: 'A new perspective',
}}
/>
);
一意のID、代表的なインラインのデフォルト値、プレビューに適した幅、高さ、fps、再生時間を選びます。登録時のデフォルト値によって、親インスタンスのpropsが自動的にコピーされることはありません。登録と抽出の詳細については、接続済みコンポジションを参照してください。
タイミングをコンポーネントに直接指定する
すでにタイミング用のpropsを受け付けるコンポーネントの周囲に、別の<Sequence>を配置するのは避けてください。組み込みのインタラクティブコンポーネントと、wrapInSequence: trueで作成したカスタムコンポーネントには、name、from、durationInFrames、trimBefore、playbackRateを直接渡せます。
<Scene
name="Opening scene"
from={30}
durationInFrames={90}
style={{opacity: 0.9}}
title="A new perspective"
/>
冗長なシーケンスを削除するときは、そのタイミングと名前を子コンポーネントに移します。既存の子要素のタイミングは保持し、上書きしたり、オフセットを二重に適用したりしないでください。コンポーネント内のuseCurrentFrame()呼び出しはローカルフレームを読み取りますが、呼び出し位置にあるスタイル式は引き続き呼び出し元のフレームを使用します。アニメーションのスタイルを移動するときは、この違いを保ってください。
複数の兄弟要素に共通のタイミングを設定する場合、タイミングを処理しないコンポーネントをラップする場合、または子要素に直接指定できない寸法を設定する場合は、<Sequence>を維持してください。管理対象のルートでは、useVideoConfig()用のwidthとheightも受け付けます。トランジションの有無にかかわらず、連続するレイアウトには<TransitionSeries.Sequence>を維持してください。fromを直接指定しても、これらの動作は置き換えられません。
独立して編集できる各項目に、専用の JSX ノードを割り当てる
Studio では、項目を作成した JSX ソースノードを編集します。複数の実行時項目が同じ JSX ノードから生成された場合、それらは同じソース編集対象を共有します。
独立して編集できるようにする各コンポジション登録、クリップ、シーン、レイヤー、シーケンスについて、個別の JSX ノードを記述し、編集可能な props はそのノードに保持してください。これは、<Composition>、<Still>、組み込みメディアコンポーネント、<Sequence>、<TransitionSeries.Sequence>、カスタムコンポーネントに適用されます。
たとえば、編集可能なタイムラインは次のように記述します。
import { TransitionSeries } from "@remotion/transitions";
<TransitionSeries>
<TransitionSeries.Sequence name="Introduction" durationInFrames={90}>
<Introduction />
</TransitionSeries.Sequence>
<TransitionSeries.Sequence name="Demo" durationInFrames={150}>
<Demo />
</TransitionSeries.Sequence>
</TransitionSeries>
.map() などのプログラムによるループでは、1 つの JSX ソースノードから複数の実行時項目が作成されます。ビジュアライゼーションのバーやパーティクルなど、意図的に 1 つのテンプレートとして制御する繰り返し出力には適しています。一方、Studio で各インスタンスに個別の ID や名前、props、メタデータ、タイミング、順序を設定したり、削除や複製を行ったりする必要がある場合には適していません。
Interactive を使って HTML 要素をインタラクティブにする
<div> などのすべての HTML 要素と SVG 要素は(すでにインタラクティブな <Img> を除き)、Interactive を使ってインタラクティブにできます。
<Interactive.Div
name="Greeting card"
style={{fontSize: 80, padding: 24}}
>
Hello
</Interactive.Div>
これにより、Studio でスタイルやキーフレームを設定できます。コンポーネントに要素が多い場合は、タイムラインが煩雑になることがあるため、適切に判断してください。
テキストはできるだけインラインで記述する
テキストが固定で、一度だけ使われる場合は、定数に切り出すのではなく、インタラクティブ要素の中に直接記述してください。
// 👍 Fixed copy stays editable
<Interactive.Div name="Title">
Remotion Best Practices
</Interactive.Div>
テキストが動的な場合や再利用される場合にのみ、props または変数を使用してください。
インタラクティブ要素には説明的な名前を付ける
要素を簡単に識別できるように、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 // ❌ 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 内の <path> の代わりに remotion の <Interactive.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>
インラインの interpolatePaths() でパスをモーフィングする
@remotion/paths の interpolatePaths() を d 内で直接使用してください。
フレーム、入力範囲、同じ長さのパス文字列配列、およびイージング、外挿、ポスタライズのオプションを受け取ります。
出力パス、範囲、オプションは、上記の 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 マークアップを構成するためのベストプラクティスについて、動画編集を参照してください。