Communitygithub.com

AlexGit92s/Remotion2.0

以特定方式編寫 Remotion 標記,使 Remotion Studio 能夠識別程式碼結構並實現互動性。

Remotion2.0 是什麼?

此技能提供了一套最佳實踐,用於編寫 Remotion 標記,從而在 Remotion Studio 中實現互動性。它指導開發者如何設計自訂元件,使其能夠在 Studio 中被選取、拖放、調整大小、旋轉以及編輯 CSS 樣式和關鍵影格。核心概念是使用 `Interactive.withSchema()` 建立具有專屬時間軸的可互動元件,並定義一個 `InteractivitySchema` 來公開每個實例的可編輯 props。技能詳細說明了多種 Schema 欄位類型(如 `text-content`、`number`、`color` 等)及其用途,並強調應將時間直接設定在元件上,而非使用多餘的 `<Sequence>`。此外,技能也涵蓋了如何為每個獨立可編輯的項目建立單獨的 JSX 節點、使用 `Interactive` 讓 HTML 元素互動、偏好內聯文字、為元素提供描述性名稱、將所有 CSS 樣式內聯化,以及使用內聯的 `interpolate()` 調用進行動畫處理。遵循這些規範能確保元件在 Remotion Studio 中獲得最佳的互動編輯體驗。

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

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

預覽

來自技能 README

Remotion2.0 preview

說明文件

以特定方式編寫 Remotion 標記,使 Remotion Studio 能夠識別程式碼結構並實現互動性:

  • 允許點擊選取項目
  • 允許拖放、調整大小和旋轉
  • 編輯 CSS 樣式
  • 使關鍵影格和緩動值可編輯

如果標記過於複雜以至於 Studio 無法使其互動,則這些值會變成灰色。

偏好具有專屬時間軸的可互動元件

對自訂場景、卡片、標題以及其他 props 應可依實例編輯的視覺元件,使用 Interactive.withSchema({wrapInSequence: true})。在 InteractivitySchema 中公開有意義的內容和外觀控制項。將裝飾性的實作細節保留在元件內部。

元件必須接受 style 並將其傳遞給一個視覺根元素。當變形、裁剪或不透明度應影響其所有圖層時,保留一個共享的根元素。在可以將樣式移動到現有元素而不改變佈局或動畫時,扁平化冗餘的內部包裝器。

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: 'Text'},
  accentColor: {
    type: 'color',
    default: '#0b84f3',
    description: 'Accent color',
  },
} as const satisfies InteractivitySchema;

export const LowerThird = Interactive.withSchema({
  Component: LowerThirdInner,
  componentName: '<LowerThird>',
  schema: lowerThirdSchema,
  wrapInSequence: true,
});

需要在元件內部傳遞注入的 style;將可編輯的樣式保留在元件的呼叫點處的內聯中。

選擇 Schema 欄位

Schema 中的每個鍵都是一個 prop,Studio 可以在呼叫點處讀取和編輯。不在 Schema 中的 props 仍然可以運作,但在 Studio 中不可編輯。鍵可以使用點記號,例如 style.color。

類型用途可關鍵影格化
text-content文字,例如標題否
number數字,可選 min、max、step、integer是
boolean開關是 (保留)
colorCSS 顏色字串是
enum在 variants 之間選擇,每個選擇都有自己的巢狀 schema選擇加入 (保留)
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,並且應該有一個 description,Studio 會將其顯示為標籤。 設定 keyframable: false 以顯示靜態控制項。

公開內容和每個實例的外觀,例如文字和強調色。\n不要為 style.translate、style.scale、style.rotate、style.transformOrigin 和 style.opacity 添加欄位:wrapInSequence: true 已經添加了它們。

要使根元素的 CSS 屬性可依實例編輯,展開內建的 schema 片段:

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 和持續時間。註冊預設值不會自動從父實例複製 props。 有關註冊和提取的詳細資訊,請參閱已連接的組合。

將時間直接設定在元件上

避免在一個已經接受時間 props 的元件周圍使用單獨的 <Sequence>。使用 wrapInSequence: true 建立的內建可互動元件和自訂元件可以直接接收 name、from、durationInFrames、trimBefore、playbackRate 和 premountFor。

<LowerThird
  name="Lower third"
  from={30}
  durationInFrames={90}
  accentColor="#0b84f3"
>
  Jane Doe, Product Designer
</LowerThird>

移除冗餘的 sequence 時,將其時間和名稱移到子元件。 保留任何現有的子元件時間;不要覆寫或重複套用偏移量。 元件內部的 useCurrentFrame() 呼叫讀取其本地影格,而呼叫點處的樣式表達式仍使用呼叫者的影格。在移動動畫樣式時保留此區別。

在以下情況保留 <Sequence>:它為多個兄弟元件提供共享時間、覆寫 useVideoConfig() 的尺寸、或包裝一個不處理時間的元件。對於連續佈局保留 <Series.Sequence>,對於過渡保留 <TransitionSeries.Sequence>;直接的 from props 不會取代這些行為。

為每個獨立可編輯的項目提供其自己的 JSX 節點

Studio 編輯的是建立項目的 JSX 原始碼節點。如果多個執行時期項目來自同一個 JSX 節點,它們共享一個來源編輯目標。

對於每個應可獨立編輯的組合註冊、剪輯、場景、圖層或序列,撰寫一個單獨的 JSX 節點,並將其可編輯的 props 保留在該節點上。這適用於 <Composition>、<Still>、內建媒體元件、<Sequence>、<Series.Sequence>、<TransitionSeries.Sequence> 和自訂元件。

例如,像這樣撰寫一個可編輯的時間軸:

<Series>
  <Series.Sequence name="Introduction" durationInFrames={90}>
    <Introduction />
  </Series.Sequence>
  <Series.Sequence name="Demo" durationInFrames={150}>
    <Demo />
  </Series.Sequence>
</Series>

.map() 或其他程式化迴圈會從一個 JSX 原始碼節點建立多個執行時期項目。這適用於有意作為一個模板控制的重複輸出,例如視覺化長條圖或粒子。當實例需要獨立的 ID 或名稱、props、元資料、時間、排序、刪除或在 Studio 中複製時,則不適用。

使用 Interactive 使 HTML 元素可互動

每個 HTML 和 SVG 元素(除了 <Img>,它已經是互動的)都可以使用 Interactive 變成可互動:

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

這允許在 Studio 中設定樣式和關鍵影格。要明智地使用,如果一個元件有許多元素,時間軸可能會變得雜亂。

偏好內聯文字

如果文字是固定的且僅使用一次,請直接將其寫在可互動元素內部,而不是提取到常數中。

// 👍 固定的副本保持可編輯
<Interactive.Div name="Title">
  Remotion Best Practices
</Interactive.Div>

僅在文字是動態或可重複使用時才使用 prop 或變數。

為可互動元素提供描述性名稱

為元素添加 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 // ❌ 不支援非內聯樣式
  }
}, []);

<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

Individual skills in this repo

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

相關技能