Communitygithub.com

3bkader-gpt/remotion-tiktok-gym-editor

Remotionマークアップを構造化してインタラクティブにします

remotion-tiktok-gym-editor とは?

このスキルは、Remotion Studioでコードをインタラクティブに編集できるようにするためのマークアップ構造化手法を提供します。具体的には、要素の選択、ドラッグ&ドロップ、リサイズ、回転、CSSスタイル編集、キーフレームやイージング値の編集などを可能にします。対応プラットフォームはRemotion Studioで、Claude CodeやCursorなどのAIエージェントと連携して利用できます。このスキルは、`Track`、`Interactive.create()`、接続されたコンポジションを使って、各要素に個別のJSXノードを与え、インラインスタイルと`interpolate()`によるアニメーションを推奨します。複雑なマークアップを避け、シンプルで構造化されたコードを書くことで、Studioが最大限のインタラクティブ性を発揮できるようになります。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/3bkader-gpt/remotion-tiktok-gym-editor/tree/HEAD/.agents/skills/remotion-interactivity

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

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

プレビュー

スキル README より

remotion-tiktok-gym-editor preview

ドキュメント

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

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

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

独自のタイムラインを持つインタラクティブコンポーネントを推奨

Track、接続されたコンポジション、Interactive.create()を使用して新しいコンポジションを構築します。

レイアウトは、シーンには明示的に'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オン/オフスイッチはい(ホールド)
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のフィールドは追加しないでください。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はこれらを接続されたコンポジションと呼びます。親ビデオと同じコンポーネント実装を共有しながら、独自のタイムラインで開くことができます。

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

親がレンダリングするのと同じエクスポートされたコンポーネント参照を登録します。上記の例では、component={Chapter}を使用し、ChapterInnerやインラインラッパーは使用しません。 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、durationを選択します。登録デフォルトは親インスタンスからプロパティを自動的にコピーしません。登録と抽出の詳細については、接続されたコンポジションを参照してください。

タイミングを直接コンポーネントに配置

すでにタイミングプロパティを受け入れる1つのコンポーネントの周囲に別の<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も受け入れます。

<Track>を使用して、同じStudioタイムライン行に項目を配置します。 シーンが連続している場合は<TransitionSeries>を使用します。

個別に編集可能なすべての項目に独自のJSXノードを与える

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

個別に編集可能であるべきすべてのコンポジション登録、クリップ、シーン、レイヤー、シーケンスについて、別々のJSXノードを記述し、そのノードに編集可能なプロパティを保持します。これは、<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や名前、プロパティ、メタデータ、タイミング、順序、削除、複製が必要な場合には適していません。

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

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

<Interactive.Div
  name="Greeting card"
  style={{fontSize: 80, padding: 24}}
>
  Hello
</Interactive.Div>

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

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

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

// 👍 固定のコピーは編集可能なまま
<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 // ❌ 非インラインスタイルはサポートされていません
  }
}, []);

<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="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]); // ❌ 計算はマークアップ内に直接記述する必要があります

<Interactive.Div
  name="Product card"
  style={{
    translate: translateY, // ❌ インラインのinterpolate()呼び出しのみがサポートされています
    rotate: interpolate(frame, [start, start + 10], [0, Math.PI]), // ❌ 任意の変数で計算を使用できません。定数は使用できません
    scale: interpolate(anyVariable, [0, 30], [0, 1]) // ❌ `frame`変数のみ解釈できます。
  }}
/>

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>

インラインを使用したモーフパス

…

Individual skills in this repo

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

関連スキル