Communitygithub.com

zoih6/masafat-watan-video

以特定方式組織 Remotion 標記,讓 Studio 能夠識別程式碼結構並實現互動性

masafat-watan-video 是什麼?

此技能詳細說明如何撰寫 Remotion 標記,使其 Studio 介面具備互動編輯能力。使用者可以透過點擊選取元素,並支援拖放、調整大小與旋轉,也可直接編輯 CSS 樣式、關鍵影格和緩動函數。技能強調使用 `Interactive.create()` 建立可互動元件,並設定明確的 `layout` 屬性(如 `'absolute-fill'` 或 `'none'`)。文件也涵蓋如何透過 schema 定義可編輯屬性,每種資料型別(如 string、number、boolean、color 等)都對應不同的編輯控制項與關鍵影格支援。此外,建議將每個獨立可編輯的項目寫成個別的 JSX 節點,避免使用 `.map()` 迴圈,以確保 Studio 能正確識別與編輯。動畫應直接在 `style` 中使用 `interpolate()`,並將所有 CSS 樣式寫為內聯物件。最後,還包含 SVG 路徑的互動編輯方法,以及如何註冊「連結合成」讓子元件在獨立時間軸中運作。此技能主要適用於 Remotion 平台,幫助開發者打造高度可編輯的影片合成。

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

在你喜歡的 AI 中提問

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

預覽

來自技能 README

masafat-watan-video preview

說明文件

masafat-watan-video 是做什麼的?

以特定方式撰寫 Remotion 標記,Remotion Studio 就能夠識別程式碼的結構並使其具備互動性:

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

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

偏好使用具有自身時間軸的互動元件

使用 Track、連結合成與 Interactive.create() 來建立新的合成。

為場景明確設定 layout 為 '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。

選擇 Schema 欄位

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

類型用途可關鍵影格化
string字串,例如標題、提示或程式碼片段否
number數字,可選用 min、max、step、integer是
boolean開/關切換是 (hold)
colorCSS 顏色字串是
enum在 variants 之間選擇,每個都有其自己的巢狀 schema選擇性 (hold)
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 新增欄位: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,以及用於接受 captions 元件的 Interactive.captionsSchema。 對於接受 React.ReactNode 子元件的元件,請加入 ...Interactive.childrenSchema。 它為子內容提供控制項,並可能在未來支援更豐富的內容。 目前,它使用一個標籤為「Text」的字串欄位,預設值為 ''。 如果元件只需要字串子內容,請改用 type: 'string' 宣告一個明確的 children 欄位。 Interactive.textSchema 控制排版樣式;childrenSchema 控制內容。 children 片段不包含在 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 和持續時間。註冊預設值不會自動從父實例複製 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() 建立的元件中,並對該實例進行時間設定。受管理的根元素也接受 width 和 height 供 useVideoConfig() 使用。

使用 <Track> 將項目放在同一個 Studio 時間軸行上。 當場景是連續的時候,請使用 <TransitionSeries>。

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

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

對於每個合成註冊、剪輯、場景、圖層或序列(應該可以獨立編輯的),請撰寫一個單獨的 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> 除外,它本來就是互動的)都可以使用 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 路徑可編輯

使用 remotion 中的 <Interactive.Path> 而非 SVG 內的 <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.

相關技能