Remotionのマークアップを特定の方法で記述することで、Remotion Studioはコードの構造を認識し、インタラクティブにします。
- アイテムをクリックして選択できるようにする
- ドラッグ&ドロップ、リサイズ、回転を可能にする
- CSSスタイルを編集する
- キーフレームとイージング値を編集可能にする
マークアップが複雑すぎてStudioがインタラクティブにできない場合、値はグレーアウトされます。
独自のタイムラインを持つインタラクティブコンポーネントを優先する
カスタムシーン、カード、タイトル、およびその他の視覚コンポーネントで、プロパティをインスタンスごとに編集可能にするには、Interactive.withSchema({wrapInSequence: true})を使用します。InteractivitySchema内で意味のあるコンテンツと外観のコントロールを公開します。装飾的な実装の詳細はコンポーネント内部に保持します。
コンポーネントはstyleを受け入れ、それを1つの視覚的なルート要素に転送する必要があります。トランスフォーム、クロッピング、または不透明度がすべてのレイヤーに影響を与える場合は、共有ルートを維持します。レイアウトやアニメーションを変更せずにスタイルを既存の要素に移動できる場合は、冗長な内部ラッパーをフラット化します。
import type React from 'react';
import {Interactive, type InteractivitySchema} from 'remotion';
type LowerThirdProps = {
readonly children: string;
readonly accentColor: string;
readonly style?: React.CSSProperties;
};
const LowerThirdInner: React.FC<LowerThirdProps> = ({
children,
accentColor,
style,
}) => {
return (
<Interactive.Div
style={{
position: 'absolute',
left: 80,
bottom: 80,
display: 'flex',
alignItems: 'center',
gap: 20,
backgroundColor: 'white',
borderRadius: 16,
padding: '20px 32px',
color: 'black',
fontFamily: 'Helvetica, Arial, sans-serif',
fontSize: 48,
fontWeight: 600,
...style,
}}
>
<div
style={{
width: 8,
alignSelf: 'stretch',
borderRadius: 4,
backgroundColor: accentColor,
}}
/>
{children}
</Interactive.Div>
);
};
const lowerThirdSchema = {
children: {type: 'text-content', default: '', description: 'テキスト'},
accentColor: {
type: 'color',
default: '#0b84f3',
description: 'アクセントカラー',
},
} as const satisfies InteractivitySchema;
export const LowerThird = Interactive.withSchema({
Component: LowerThirdInner,
componentName: '<LowerThird>',
schema: lowerThirdSchema,
wrapInSequence: true,
});
コンポーネント内部で注入されたstyleを転送することは必須です。編集可能なスタイルは、コンポーネントの呼び出しサイトでインラインに保ちます。
スキーマフィールドを選択する
スキーマの各キーは、Studioが呼び出しサイトで読み取りおよび編集できるプロパティです。スキーマにないプロパティも機能しますが、Studioでは編集できません。キーはドット表記(style.colorなど)を使用できます。
| タイプ | 用途 | キーフレーム可能 |
|---|---|---|
text-content | タイトルなどのテキスト | いいえ |
number | 数値。オプションでmin、max、step、integer | はい |
boolean | オン/オフスイッチ | はい (ホールド) |
color | CSSカラー文字列 | はい |
enum | variants間の選択。各バリアントは独自のネストスキーマを持つ | オプトイン (ホールド) |
array | 数値、色、enumなどのリスト | いいえ |
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も利用できます。すべてのオプションについてはInteractivitySchemaを参照してください。
再利用可能なコンポーネントを接続されたコンポジションとして登録する
独自のレイヤーやアニメーションを持つ実質的なシーンや再利用可能なコンポーネントは、スタンドアロンのコンポジションとして登録します。Studioはこれらを接続されたコンポジションと呼びます。親と同じコンポーネント実装を共有しながら、独自のタイムラインで開くことができます。
コンポーネント内で必要なスタイルを定義し、フォントをロードして、親なしでも動作するようにします。親からの独立性を参照してください。
親がレンダリングするのと同じエクスポートされたコンポーネント参照を登録します。上記の例では、component={LowerThird}を使用し、LowerThirdInnerやインラインラッパーは使用しません。wrapInSequence: trueの場合、接続のために追加の<Sequence>は必要ありません。
import {Composition} from 'remotion';
import {LowerThird} from './LowerThird';
export const RemotionRoot = () => (
<Composition
id="LowerThird"
component={LowerThird}
width={1280}
height={720}
fps={30}
durationInFrames={30}
defaultProps={{
children: 'Jane Doe, Product Designer',
accentColor: '#0b84f3',
}}
/>
);
一意のID、代表的なインラインデフォルト値、およびコンポーネントのプレビューに適した寸法、fps、durationを選択します。登録時のデフォルトは、親インスタンスからプロパティを自動的にコピーしません。登録と抽出の詳細については、接続されたコンポジションを参照してください。
タイミングをコンポーネントに直接設定する
すでにタイミングプロパティを受け入れている1つのコンポーネントの周りに、個別の<Sequence>を配置しないでください。組み込みのインタラクティブコンポーネントおよびwrapInSequence: trueで作成されたカスタムコンポーネントは、name、from、durationInFrames、trimBefore、playbackRate、premountForを直接受け取ることができます。
<LowerThird
name="Lower third"
from={30}
durationInFrames={90}
accentColor="#0b84f3"
>
Jane Doe, Product Designer
</LowerThird>
冗長なシーケンスを削除する場合は、そのタイミングと名前を子に移動します。既存の子のタイミングは保持し、オフセットを上書きしたり二重に適用したりしないでください。コンポーネント内部のuseCurrentFrame()呼び出しは自身のローカルフレームを読み取りますが、呼び出しサイトでのスタイル式は呼び出し元のフレームを使用します。アニメーションスタイルを移動する際は、その区別を維持してください。
<Sequence>は、複数の兄弟に共有タイミングを提供する場合、useVideoConfig()のディメンションをオーバーライドする場合、またはタイミングを処理しないコンポーネントをラップする場合に保持します。<Series.Sequence>は連続レイアウトに、<TransitionSeries.Sequence>はトランジションに使用します。直接のfromプロパティはこれらの動作を置き換えません。
編集可能なアイテムごとに個別のJSXノードを与える
Studioは、アイテムを作成したJSXソースノードを編集します。複数のランタイムアイテムが同じJSXノードから生成される場合、それらは1つのソース編集ターゲットを共有します。
独自に編集可能であるべきすべてのコンポジション登録、クリップ、シーン、レイヤー、シーケンスについて、個別のJSXノードを作成し、編集可能なプロパティをそのノードに保持します。これは<Composition>、<Still>、組み込みメディアコンポーネント、<Sequence>、<Series.Sequence>、<TransitionSeries.Sequence>、カスタムコンポーネントに適用されます。
例えば、編集可能なタイムラインを次のように記述します:
<Series>
<Series.Sequence name="はじめに" durationInFrames={90}>
<Introduction />
</Series.Sequence>
<Series.Sequence name="デモ" durationInFrames={150}>
<Demo />
</Series.Sequence>
</Series>
.map()やその他のプログラム的なループは、1つのJSXソースノードから複数のランタイムアイテムを作成します。これは、可視化バーやパーティクルなど、意図的に1つのテンプレートとして制御される繰り返し出力に適しています。インスタンスに独立したIDや名前、プロパティ、メタデータ、タイミング、順序付け、Studioでの削除や複製が必要な場合には適していません。
Interactiveを使用してHTML要素をインタラクティブにする
すべてのHTMLおよびSVG要素(<Img>を除く。すでにインタラクティブです)は、Interactiveを使用してインタラクティブにできます:
<Interactive.Div
name="グリーティングカード"
style={{fontSize: 80, padding: 24}}
>
Hello
</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}),
output: 'perceptual-scale',
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp'
}
),
}}
/>
const translateY = interpolate(frame, [0, 30], [0, 120]); // ❌ 計算はマークアップ内で直接行う必要があります
<Interactive.Div
name="プロダクトカード"
style={{
translate: translateY, // ❌ インラインのinterpolate()呼び出しのみサポートされています
rotate: interpolate(frame, [start, start + 10], [0, Math.PI]), // ❌ 任意の変数を使用した計算、定数の使用はできません
scale
}}
