透過以特定方式撰寫 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) |
color | CSS 顏色字串 | 是 |
enum | 在 variants 之間選擇,每個 variant 都有自己的巢狀 schema | 選用 (hold) |
array | 數字、顏色、列舉等清單 | 否 |
asset | 媒體來源,可選 assetType | 否 |
font-family | CSS 字型家族 | 否 |
font-weight | 字型粗細 | 是 |
translate、scale、rotation-css、rotation-degrees、transform-origin | 變換 (Transform) | 是 |
uv-coordinate | 元素上標準化的 [x, y] 點 | 是 |
svg-path | SVG 路徑資料 | 是 |
remotion-captions | Caption[] 資料 | 否 |
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>
使用內聯方式變形路徑
…
[為翻譯而截斷]
