透過以特定方式編寫 Remotion 標記,Remotion Studio 能夠辨識程式碼結構並使其具備互動性:
- 允許點擊選取項目
- 允許拖放、調整大小和旋轉
- 編輯 CSS 樣式
- 使關鍵影格和緩動曲線可編輯
如果標記對 Studio 來說過於複雜而無法使其互動,則相關數值會變成灰色顯示。
偏好使用具有自己時間軸的互動式元件
對那些填滿其父容器的元件,使用 Interactive.withSchema({wrapInSequence: true, layout: 'absolute-fill'})。這個包裝器提供了它們的視覺根目錄和時間軸項目,並預設裁切溢出內容,因此內部元件可以返回一個片段 (fragment)。將計時、預掛載、尺寸和每個實例的樣式放在導出的元件上。
將屬於一起的視覺元素放在同一個元件中,這樣它們可以一起移動和修剪。內部佈局容器仍然可以提供對齊、在較小區域內裁切或動畫群組;只填充場景的容器通常是不必要的。卡片、文字框和具有自身邊界的 SVG 可以保留預設的 layout: 'none',並將 style 轉發給它們的視覺根元素。
import {Video} from '@remotion/media';
import type React from 'react';
import {Interactive, useVideoConfig, type InteractivitySchema} from 'remotion';
type SceneProps = {
readonly title: string;
};
const SceneInner: React.FC<SceneProps> = ({title}) => {
const {fps} = useVideoConfig();
return (
<>
<Video
name="背景素材"
src="https://remotion.media/video.mp4"
premountFor={fps}
objectFit="cover"
style={{width: '100%', height: '100%'}}
/>
<Interactive.Div
name="場景標題"
style={{
position: 'absolute',
left: 80,
bottom: 80,
color: 'white',
fontFamily: 'Helvetica, Arial, sans-serif',
fontSize: 80,
}}
>
{title}
</Interactive.Div>
</>
);
};
const sceneSchema = {
title: {type: 'string', default: '', description: '標題'},
} as const satisfies InteractivitySchema;
export const Scene = Interactive.withSchema({
Component: SceneInner,
componentName: 'Scene',
schema: sceneSchema,
wrapInSequence: true,
layout: 'absolute-fill',
});
選擇 Schema 欄位
Schema 中的每個鍵都是一個屬性 (prop),Studio 可以在調用點讀取和編輯它。
不在 schema 中的屬性仍然可以運作,但在 Studio 中無法編輯。
鍵可以使用點記法,例如 style.color。
| 類型 | 用途 | 可關鍵影格化 |
|---|---|---|
string | 字串,例如標題、提示或程式碼片段 | 否 |
number | 數字,可選 min、max、step、integer | 是 |
boolean | 開/關開關 | 是 (保持) |
color | CSS 顏色字串 | 是 |
enum | 在 variants 之間選擇,每個都有其自己的巢狀 schema | 可選 (保持) |
array | 數字、顏色、列舉等列表 | 否 |
asset | 媒體來源,可選 assetType | 否 |
font-family | CSS 字型家族 | 否 |
font-weight | 字重 | 是 |
translate、scale、rotation-css、rotation-degrees、transform-origin | 變換 | 是 |
uv-coordinate | 元素上一個標準化的 [x, y] 點 | 是 |
svg-path | SVG 路徑資料 | 是 |
remotion-captions | Caption[] 資料 | 否 |
hidden | 一個保持在控制項之外的值 | — |
每個欄位都需要一個 default 值,並且應該有一個 description,Studio 會將其顯示為標籤。
設置 keyframable: false 可顯示靜態控制項。
公開內容和每個實例的外觀,例如文字和強調色。
不要添加 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。
對於接受 React.ReactNode children 的元件,添加 ...Interactive.childrenSchema。
它為 children 內容提供控制項,並且未來可能發展為支援更豐富的內容。
目前,它使用一個標籤為「文字」的字串欄位,預設值為 ''。
如果一個元件只需要字串類型的 children,請改用 type: 'string' 宣告一個明確的 children 欄位。
Interactive.textSchema 控制排版樣式;childrenSchema 控制內容。
children 片段不包含在 baseSchema 中,也不會自動添加到自訂元件中。
巢狀標記和計算後的 children 目前是唯讀的。
text-content 是 string 欄位類型的已棄用別名。
請參閱 InteractivitySchema 了解所有選項。
將可復用元件註冊為連接的組合 (Connected Compositions)
將具有自己圖層或動畫的重要場景和可復用元件註冊為獨立的組合 (Compositions)。Studio 將這些稱為連接的組合 (connected compositions):它們可以在自己的時間軸中被打開,同時與父級影片共享相同的元件實作。
在元件內部定義所需的樣式並載入字型,使其無需依賴父級即可運作。請參閱 父級獨立性 (parent independence)。
註冊父級渲染的相同匯出元件參考。對於上面的範例,使用 component={Scene},而不是 SceneInner 或內聯包裝器。
使用 wrapInSequence: true,則無需額外的 <Sequence> 來建立連接。
import {Composition} from 'remotion';
import {Scene} from './Scene';
export const RemotionRoot = () => (
<Composition
id="Scene"
component={Scene}
width={1280}
height={720}
fps={30}
durationInFrames={30}
defaultProps={{
title: '一個新視角',
}}
/>
);
選擇一個唯一的 ID、有代表性的內聯預設值,以及適合預覽元件的尺寸、fps 和 持續時間。註冊預設值不會自動從父級實例複製屬性。請參閱 連接的組合 (connected compositions) 以了解註冊和提取的詳細資訊。
將計時直接放在元件上
避免在一個已經接受計時屬性的元件周圍使用單獨的 <Sequence>。
內建的互動式元件以及使用 wrapInSequence: true 製作的元件可以直接接收 name、from、durationInFrames、trimBefore、playbackRate 和 premountFor。
<Scene
name="開場場景"
from={30}
durationInFrames={90}
premountFor={fps}
style={{opacity: 0.9}}
title="一個新視角"
/>
移除冗餘的 sequence 時,將其計時和名稱移至子元件。
保留任何現有的子元件計時;不要覆蓋或重複偏移。
元件內部的 useCurrentFrame() 調用讀取其本地影格,而調用點的樣式表達式仍使用調用者的影格。在移入動畫樣式時保留這種區別。
在以下情況下保留 <Sequence>:它為多個兄弟元素提供共享計時,
包裝了一個不處理計時的元件,或者提供了子元件無法直接接受的尺寸。受管理的根節點也接受 useVideoConfig() 使用的 width 和 height。對於連續佈局(有或沒有過渡),保留 <TransitionSeries.Sequence>;直接的 from 屬性無法取代這些行為。
為每個可獨立編輯的項目賦予其自己的 JSX 節點
Studio 編輯建立項目的 JSX 源節點。如果多個執行時期項目來自同一個 JSX 節點,它們共享一個編輯源目標。
對於每個應該可以獨立編輯的組合註冊、片段、場景、圖層或 sequence,請編寫一個單獨的 JSX 節點,並將其可編輯屬性保留在該節點上。這適用於 <Composition>、<Still>、內建媒體元件、<Sequence>、<TransitionSeries.Sequence>
和自訂元件。
例如,像這樣編寫一個可編輯的時間軸:
import { TransitionSeries } from "@remotion/transitions";
<TransitionSeries>
<TransitionSeries.Sequence name="介紹" durationInFrames={90}>
<Introduction />
</TransitionSeries.Sequence>
<TransitionSeries.Sequence name="展示" durationInFrames={150}>
<Demo />
</TransitionSeries.Sequence>
</TransitionSeries>
一個 .map() 或其他程式化循環會從一個 JSX 源節點建立多個執行時期項目。這適用於有意作為一個模板控制的重複輸出,例如視覺化條或
粒子。當實例需要獨立的 ID 或
名稱、屬性、後設資料、計時、排序、刪除或在 Studio 中複製時,則不適用。
使用 Interactive 讓 HTML 元素變得可互動
每個 HTML 和 SVG 元素(除了 <Img>,它已經是互動式的)例如 <div> 都可以使用 Interactive 變成互動式:
<Interactive.Div
name="問候卡"
style={{fontSize: 80, padding: 24}}
>
哈囉
</Interactive.Div>
這允許在 Studio 中設定樣式和關鍵影格。要明智使用,如果一個元件有太多元素,時間軸可能會變得凌亂。
偏好內聯文字
如果文字是固定的且僅使用一次,請直接將其寫在互動元素內部,而不是將其提取到常數中。
// 👍 固定的副本保持可編輯
<Interactive.Div name="標題">
Remotion 最佳實踐
</Interactive.Div>
僅在文字是動態的或被重複使用時,才使用屬性或變數。
為互動元素賦予描述性名稱
為元素添加 name 屬性,使其易於識別。
避免使用計算名稱,請對其進行硬編碼。
<>
<Interactive.Div name="英雄標題" style={{fontSize: 80}}>
發布日
</Interactive.Div>
<Img name="頭像" src="https://remotion.media/image.jpeg" />
<Video name="背景" src="https://remotion.media/video.mp4" />
<Interactive.Div name="標題">
發布日
</Interactive.Div>
</>
將所有 CSS 樣式保持內聯
最好的方法是直接將一個純物件傳遞給 style——不要引用常數、不要展開物件、不要使用數學運算。
<Interactive.Div
style={{
fontSize: 80,
color: 'red',
}}
>
哈囉,世界!
</Interactive.Div>
const baseStyle = useMemo(() => {
return {
fontSize: 12 // ❌ 非內聯樣式不受支援
}
}, []);
<Interactive.Div
style={{
...baseStyle, // ❌ 展開不受支援
color: RED, // ❌ 引用常數不受支援
scale: frame * 10 // ❌ 數學運算不受支援
}}
>
哈囉,世界!
</Interactive.Div>
使用 interpolate() 製作動畫
將動畫編寫為對變化屬性進行的內聯 interpolate() 調用。
輸出範圍、緩動、外推和 output 屬性應使用硬編碼值。
輸入範圍還可以使用直接從 useVideoConfig() 解構的 durationInFrames、fps、width 和 height。支援僅標識符,例如 durationInFrames、乘以數字,例如 2 * fps 或 fps * 2,以及減去數字,例如 durationInFrames - 1。
const {fps, durationInFrames} = useVideoConfig();
// 👍 內聯值可以被標準化和關鍵影格化
<Interactive.Div
name="產品卡片"
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}),
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp'
}
)
}}
>
感謝您的觀看!
</Interactive.Div>
