Remotion 마크업을 특정 방식으로 작성하면 Remotion 스튜디오가 코드의 구조를 인식하고 상호작용성을 부여할 수 있습니다:
- 항목을 클릭하여 선택 가능
- 드래그 앤 드롭, 크기 조절, 회전 가능
- CSS 스타일 편집 가능
- 키프레임 및 이징 값 편집 가능
마크업이 스튜디오에서 상호작용 가능하게 만들기에 너무 복잡하면 값이 회색으로 표시됩니다.
고유한 타임라인을 가진 상호작용 컴포넌트 선호
Track, 연결된 컴포지션, Interactive.create()를 사용하여 새 컴포지션을 구축하세요.
레이아웃은 장면(scene)의 경우 명시적으로 '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로 유지하세요.
스키마 필드 선택
스키마의 각 키는 스튜디오가 호출 지점에서 읽고 편집할 수 있는 prop입니다. 스키마에 없는 prop도 작동하지만 스튜디오에서 편집할 수 없습니다. 키는 style.color와 같은 점 표기법을 사용할 수 있습니다.
| 유형 | 용도 | 키프레임 가능 |
|---|---|---|
string | 제목, 프롬프트, 코드 스니펫과 같은 문자열 | 아니요 |
number | 숫자 (선택적 min, max, step, integer 포함) | 예 |
boolean | 켜기/끄기 스위치 | 예 (hold) |
color | CSS 색상 문자열 | 예 |
enum | variants 중 하나를 선택 (각각 고유한 중첩 스키마 가짐) | 선택적 (hold) |
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이 있어야 합니다. 스튜디오에서 이 설명을 레이블로 표시합니다.
keyframable: false로 설정하면 정적 컨트롤이 표시됩니다.
콘텐츠와 인스턴스별 모양(예: 텍스트 및 강조 색상)을 노출하세요.
style.translate, style.scale, style.rotate, style.transformOrigin, style.opacity에 대한 필드는 추가하지 마세요. Interactive.create()가 자동으로 추가합니다.
루트의 CSS 속성을 인스턴스별로 편집 가능하게 만들려면 내장 스키마 프래그먼트를 펼치세요:
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는 콘텐츠를 제어합니다.
자식 프래그먼트는 baseSchema에 포함되지 않으며 사용자 정의 컴포넌트에 자동으로 추가되지 않습니다.
중첩된 마크업과 계산된 자식은 현재 읽기 전용입니다.
text-content는 string 필드 유형의 더 이상 사용되지 않는 별칭입니다.
모든 옵션은 InteractivitySchema를 참조하세요.
재사용 가능한 컴포넌트를 연결된 컴포지션으로 등록
장면 및 재사용 가능한 요소를 독립 실행형 컴포지션으로 등록하세요. 스튜디오에서는 이를 연결된 컴포지션(connected compositions) 이라고 합니다. 부모 비디오와 동일한 컴포넌트 구현을 공유하면서 자체 타임라인에서 열 수 있습니다.
부모 없이도 작동하도록 컴포넌트 내에 필요한 스타일을 정의하고 글꼴을 로드하세요. 부모 독립성을 참조하세요.
부모가 렌더링하는 동일한 내보내진 컴포넌트 참조를 등록하세요. 위 예제의 경우 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 및 지속 시간을 선택하세요. 등록 기본값은 부모 인스턴스에서 자동으로 prop을 복사하지 않습니다. 연결된 컴포지션의 등록 및 추출 세부 정보를 참조하세요.
타이밍을 컴포넌트에 직접 지정
이미 타이밍 prop을 허용하는 하나의 컴포넌트 주위에 별도의 <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()로 만든 컴포넌트에 콘텐츠를 그룹화하고 해당 인스턴스의 시간을 지정하세요. 관리되는 루트는 useVideoConfig()를 위한 width 및 height도 허용합니다.
<Track>을 사용하여 항목을 동일한 스튜디오 타임라인 행에 배치하세요.
<TransitionSeries>는 장면이 순차적일 때 사용하세요.
독립적으로 편집 가능한 모든 항목에 고유한 JSX 노드 사용
스튜디오는 항목을 생성한 JSX 소스 노드를 편집합니다. 여러 런타임 항목이 동일한 JSX 노드에서 오면 하나의 소스 편집 대상을 공유합니다.
편집 가능해야 하는 각 컴포지션 등록, 클립, 장면, 레이어 또는 시퀀스에 대해 별도의 JSX 노드를 작성하고 해당 노드에 편집 가능한 prop을 유지하세요. 이는 <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 소스 노드에서 여러 런타임 항목을 생성합니다. 이는 시각화 막대나 입자와 같이 의도적으로 하나의 템플릿으로 제어되는 반복 출력에 적합합니다. 인스턴스에 독립적인 ID나 이름, props, 메타데이터, 타이밍, 순서, 스튜디오에서의 삭제 또는 복제가 필요한 경우에는 적합하지 않습니다.
Interactive를 사용하여 HTML 요소를 상호작용적으로 만들기
<Img>(이미 상호작용적임)를 제외한 모든 HTML 및 SVG 요소(예: <div>)는 Interactive를 사용하여 상호작용적으로 만들 수 있습니다:
<Interactive.Div
name="Greeting card"
style={{fontSize: 80, padding: 24}}
>
Hello
</Interactive.Div>
이를 통해 스튜디오에서 스타일과 키프레임을 설정할 수 있습니다. 합리적으로 사용하세요. 컴포넌트에 요소가 많으면 타임라인이 지저분해질 수 있습니다.
인라인 텍스트 선호
텍스트가 고정되어 있고 한 번만 사용되는 경우 상수로 추출하지 말고 상호작용 요소 내부에 직접 작성하세요.
// 👍 고정된 복사본은 편집 가능한 상태로 유지됩니다.
<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 속성은 하드코딩된 값을 사용해야 합니다.
입력 범위는 추가적으로 durationInFrames, fps, width, height를 useVideoConfig()에서 직접 구조 분해하여 사용할 수 있습니다. 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 내부의 <path> 대신 remotion의 <Interactive.Path>를 사용하여 경로를 시각적으로 편집 가능하게 만드세요.
경로 보간 및 스튜디오 경로 키프레임을 위해 @remotion/paths를 설치하세요:
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>
인라인을 사용한 모핑 경로
…
(번역을 위해 잘렸습니다.)
