Communitygithub.com

iamhuynq/video-remotion

以特定結構撰寫 Remotion 標記,讓 Remotion Studio 能夠辨識程式碼結構並實現互動功能。

video-remotion 是什麼?

這項技能提供一套完整的指南,教導開發者如何以結構化、互動友善的方式撰寫 Remotion 標記,從而充分利用 Remotion Studio 的互動編輯功能。它涵蓋了從建立互動式元件、註冊已連線的合成(connected compositions)、到在 Studio 中實現點選選取、拖放、調整大小、旋轉以及編輯 CSS 樣式和關鍵影格等核心互動操作。此技能支援 Remotion 框架,並詳細說明了如何透過 `Interactive.create()`、`Track` 和 `Interactive` 元件來建構可編輯的時間軸,並建議使用內聯樣式、`interpolate()` 動畫和明確的命名規則來最大化互動性。此外,它還提供了關於 schema 欄位類型選擇、互動式 SVG 路徑編輯以及如何避免因過於複雜的標記而導致編輯功能失效的具體實例與最佳實務。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/iamhuynq/video-remotion/tree/HEAD/.agents/skills/remotion-interactivity

在你喜歡的 AI 中提問

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

預覽

來自技能 README

video-remotion preview

說明文件

透過以特定方式撰寫 Remotion 標記,Remotion Studio 便能辨識程式碼的結構並使其具有互動性:

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

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

偏好使用具有獨立時間軸的互動式元件

使用 Track、已連線的合成 (connected compositions) 和 Interactive.create() 來建置新的合成。

明確將場景的 layout 設為 'absolute-fill',或將有邊界元素的 layout 設為 '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。

選擇 schema 欄位

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

類型用途可製作關鍵影格
string字串,例如標題、提示或程式碼片段否
number數字,可選 min、max、step、integer是
boolean開關是 (hold)
colorCSS 顏色字串是
enum在 variants 之間選擇,每個 variant 都有自己的巢狀 schema選用 (hold)
array數字、顏色、列舉等清單否
asset媒體來源,可選 assetType否
font-familyCSS 字型家族否
font-weight字型粗細是
translate、scale、rotation-css、rotation-degrees、transform-origin變換 (Transform)是
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 的欄位:Interactive.create() 會自動新增它們。

要使根元素的可編輯 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。 對於接受 React.ReactNode 子元件的元件,請新增 ...Interactive.childrenSchema。 它提供子內容的控制項,並且未來可能演進以支援更豐富的內容。 目前,它使用一個標籤為「Text」的字串欄位,預設值為 ''。 如果元件只需要純字串子元素,請改用 type: 'string' 宣告一個顯式的 children 欄位。 Interactive.textSchema 控制排版樣式;childrenSchema 控制內容。 children 片段不包含在 baseSchema 中,也不會自動新增到自訂元件。 巢狀標記和計算後的子元素目前是唯讀的。 text-content 是 string 欄位類型的已棄用別名。 有關所有選項,請參閱 InteractivitySchema。

將可重複使用的元件註冊為已連線的合成

將場景和可重複使用的元素註冊為獨立的合成。Studio 稱這些為已連線的合成 (connected compositions):它們可以在自己的時間軸中開啟,同時與父影片共享相同的元件實作。

在元件內定義必要的樣式和載入字型,使其在沒有父元件的情況下也能運作。請參閱父獨立性 (parent independence)。

註冊父元件渲染的相同匯出元件參考。對於上面的範例,使用 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 和持續時間。註冊預設值不會自動從父實例複製 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() 製作的元件中,並對該實例進行計時。受管理的根 (Managed roots) 也接受用於 useVideoConfig() 的 width 和 height。

使用 <Track> 將項目放在同一個 Studio 時間軸行上。 當場景是順序播放時,使用 <TransitionSeries>。

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

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

對於每個合成註冊、剪輯(clip)、場景、圖層或序列,如果需要獨立編輯,請撰寫一個單獨的 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() 或其他程式化迴圈會從一個 JSX 原始碼節點建立多個執行時期項目。這適用於需要作為一個模板進行控制的、有意義的重複輸出,例如視覺化長條圖或粒子。但當這些實例需要在 Studio 中擁有獨立的 ID 或名稱、props、元資料、時序、排序、刪除或複製功能時,這種做法就不合適了。

使用 Interactive 讓 HTML 元素變成互動式

每個 HTML 和 SVG 元素(除了 <Img>,它已經是互動的)如 <div> 都可以使用 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: interpolate(anyVariable, [0, 30], [0, 1]) // ❌ 只能解釋 `frame` 變數
  }}
/>

使用 Interactive.Path 保持 SVG 路徑可編輯

在 SVG 中使用來自 remotion 的 <Interactive.Path> 而不是 <path>,以使路徑在視覺上可編輯。

安裝 @remotion/paths 以進行路徑插值和 Studio 路徑關鍵影格:

bunx remotion add @remotion/paths

如果幾何形狀是靜態的,請直接將路徑字串放在 d prop 中。不要將其提取為常數。

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.

相關技能