Communitygithub.com

AlexGit92s/Remotion2.0

Remotionのマークアップを構造化し、インタラクティブにするスキルです。

Remotion2.0 とは?

このスキルは、Remotion Studioでコードの構造を認識可能にし、クリックでの選択、ドラッグ&ドロップ、リサイズ、回転、CSSスタイルの編集、キーフレームやイージング値の編集といったインタラクティブな操作を実現するためのガイドラインを提供します。主にRemotionプラットフォームを対象としており、`Interactive.withSchema({wrapInSequence: true})`を使用してカスタムシーンやコンポーネントを作成する際のベストプラクティスを詳細に説明しています。スキーマフィールドの選択方法、インラインCSSスタイルの維持、`interpolate()`を用いたアニメーション、各編集可能要素に個別のJSXノードを割り当てる重要性など、具体的なコード例と共に解説します。また、接続されたコンポジションとしてコンポーネントを登録する方法や、タイミングプロパティを直接コンポーネントに設定する方法についても触れており、開発者がStudio上で効率的に動作するRemotionプロジェクトを構築するための包括的なリファレンスとなっています。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/AlexGit92s/Remotion2.0/tree/HEAD/.claude/skills/remotion-interactivity

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

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

プレビュー

スキル README より

Remotion2.0 preview

ドキュメント

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オン/オフスイッチはい (ホールド)
colorCSSカラー文字列はい
enumvariants間の選択。各バリアントは独自のネストスキーマを持つオプトイン (ホールド)
array数値、色、enumなどのリストいいえ
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のフィールドは追加しないでください。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
  }}

Individual skills in this repo

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

関連スキル