remotion-interactivity について
remotion-interactivityは、Studioで編集できるようRemotionコードを構成するための開発者向けスキルです。個別に選択できるタイムライン要素、インスタンスごとのコントロール、スキーマ、編集可能なアニメーションパスを扱います。
主な機能
- 01個別に編集できるタイムライン項目の構成
- 02スキーマによるStudioコントロールの定義
- 03HTML・SVG要素のインタラクティブ化
- 04スタイル、エフェクト、メタデータの編集可能化
活用シーン
- 01Studio編集向けのコンポジション準備
- 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詳細
翻訳後に原文が更新されています。最新の内容は原文をご確認ください。
Remotion のマークアップを特定の方法で記述すると、Remotion Studio はコードの構造を認識し、インタラクティブに操作できるようになります。
- クリックして項目を選択できるようにする
- ドラッグ&ドロップ、サイズ変更、回転を可能にする
- CSS スタイルを編集する
- キーフレームとイージング値を編集可能にする
マークアップが複雑すぎて Studio でインタラクティブに操作できない場合、値はグレー表示になります。
独自のタイムラインを持つインタラクティブなコンポーネントを優先する
Track、接続されたコンポジション、Interactive.create() を使って、新しいコンポジションを構築します。
シーンには layout を明示的に 'absolute-fill' に設定し、範囲が定められた要素には 'none' を設定します。エクスポートされた同じシーンコンポーネントと再利用可能な要素コンポーネントを Composition に登録します。
まず、Track と接続されたコンポジションの完全な例を確認してください。 要素、シーン、親タイムライン、ルートの登録がすべて含まれています。
import {Track, useVideoConfig} from 'remotion';
import {Chapter} from './Chapter';
export const MyVideo = () => {
const {fps} = useVideoConfig();
return (
<Track name="Chapters">
<Chapter
name="Opening"
durationInFrames={3 * fps}
title="Introduction"
/>
<Chapter
name="Feature"
from={3 * fps}
durationInFrames={4 * fps}
title="New features"
/>
</Track>
);
};
完全な例のように、各シーンインスタンスに背景と配置のスタイルを設定します。レイアウト専用のコンテナーには通常の HTML を使用してください。
スキーマフィールドを選択する
スキーマの各キーは、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 が必要です。また、Studio がラベルとして表示する description も設定してください。
静的なコントロールを表示するには、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 を追加します。
子要素のコンテンツを操作するコントロールを提供し、今後より豊かなコンテンツに対応するために拡張される可能性があります。
現在は、デフォルト値が '' の「Text」というラベルの文字列フィールドを使用します。
コンポーネントの子要素に文字列のみが必要な場合は、代わりに type: 'string' を指定した明示的な children フィールドを宣言します。
Interactive.textSchema はタイポグラフィのスタイルを制御し、childrenSchema はコンテンツを制御します。
子要素のフラグメントは baseSchema には含まれず、カスタムコンポーネントに自動で追加されることもありません。
入れ子になったマークアップと計算された子要素は、現在読み取り専用です。
text-content は、フィールドタイプ string の非推奨の別名です。
すべてのオプションについては、InteractivitySchema をご覧ください。
再利用可能なコンポーネントを接続されたコンポジションとして登録する
シーンと再利用可能な要素を、スタンドアロンのコンポジションとして登録します。Studio ではこれらを接続されたコンポジションと呼びます。親ビデオと同じコンポーネント実装を共有しながら、それぞれ独自のタイムラインで開けます。
親に依存せず動作するよう、必要なスタイルを定義し、フォントをコンポーネント内で読み込みます。親からの独立性をご覧ください。
親がレンダリングするものと同じエクスポート済みコンポーネント参照を登録します。上記の例では、ChapterInner やインラインラッパーではなく、component={Chapter} を使用してください。接続に必要なシーケンスは Interactive.create() が提供するため、追加の <Sequence> は不要です。
import {Composition} from 'remotion';
import {Chapter} from './Chapter';
export const RemotionRoot = () => (
<Composition
id="Chapter"
component={Chapter}
width={1280}
height={720}
fps={30}
durationInFrames={90}
defaultProps={{
title: 'A new perspective',
style: {
backgroundColor: '#111111',
justifyContent: 'center',
alignItems: 'center',
},
}}
/>
);
プレビューに適した一意の ID、代表的なインラインのデフォルト値、幅、高さ、fps、再生時間を選択します。登録時のデフォルト値に、親インスタンスの props が自動的にコピーされることはありません。登録と抽出の詳細については、接続されたコンポジションをご覧ください。
タイミングはコンポーネントに直接指定する
タイミング用の props をすでに受け取るコンポーネントを、別の <Sequence> で囲むことは避けてください。組み込みのインタラクティブコンポーネントと Interactive.create() で作成したカスタムコンポーネントには、name、from、durationInFrames、trimBefore、playbackRate を直接指定できます。
<Chapter
name="Opening scene"
from={30}
durationInFrames={90}
style={{opacity: 0.9}}
title="A new perspective"
/>
シーンのタイミングを共有するには、コンテンツを Interactive.create() で作成したコンポーネントにまとめ、そのインスタンスにタイミングを指定します。管理対象のルートでは、useVideoConfig() 用の width と height も指定できます。
同じ Studio タイムラインの行にアイテムを配置するには、<Track> を使用します。
シーンを連続させる場合は、<TransitionSeries> を使用します。
独立して編集するアイテムごとに、専用の JSX ノードを用意する
Studio は、アイテムを作成した JSX ソースノードを編集します。複数の実行時アイテムが同じ JSX ノードから生成されると、同じソース編集対象を共有します。
それぞれ独立して編集できるようにするコンポジション登録、クリップ、シーン、レイヤー、シーケンスには、個別の JSX ノードを記述し、編集可能な props をそのノードに保持します。これは、<Composition>、<Still>、組み込みのメディアコンポーネント、<Sequence>、<TransitionSeries.Sequence>、カスタムコンポーネントに適用されます。
たとえば、次のように編集可能なタイムラインを作成します。
import { Track } from "remotion";
<Track name="Scenes">
<Introduction name="Introduction" durationInFrames={90} />
<Demo name="Demo" from={90} durationInFrames={150} />
</Track>
.map() などのプログラム上のループでは、1 つの JSX ソースノードから複数の実行時アイテムが作成されます。これは、視覚化バーやパーティクルなど、1 つのテンプレートとして意図的にまとめて制御する反復出力に適しています。一方、Studio でインスタンスごとに独立した ID、名前、props、メタデータ、タイミング、順序、削除、複製が必要な場合には適していません。
Interactive を使って HTML 要素をインタラクティブにする
<Img> はすでにインタラクティブなので例外ですが、<div> など、すべての HTML 要素と SVG 要素は 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>
テキストが動的な場合、または再利用する場合にのみ、プロパティや変数を使ってください。
インタラクティブ要素には内容がわかる名前を付ける
要素を簡単に識別できるよう、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 内の <path> の代わりに、remotion の <Interactive.Path> を使ってください。
パスの補間と Studio のパスキーフレームを使うには、@remotion/paths をインストールしてください。
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() でパスをモーフィングする
@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 のマークアップを構成するためのベストプラクティスについて、「ビデオ編集」を参照してください。