Remotion에서 넘어오기
This content is for v0.4. Switch to the latest version for up-to-date documentation.
Remotion을 알고 있다면, 이 페이지에서 Remotion의 개념을 alpha2의 개념에 대응시키고, 같은 영상을 두 방식으로 작성해 보고, 둘이 어디서 다른지 확인할 수 있습니다.
가장 큰 차이
섹션 제목: “가장 큰 차이”Remotion에서 영상은 React 컴포넌트입니다. Remotion은 그것을 브라우저에서 프레임마다 렌더링하므로, 브라우저가 그릴 수 있는 것(HTML, CSS, SVG, canvas, WebGL)은 무엇이든 그림에 넣을 수 있고, 여러분의 코드가 프레임마다 실행됩니다.
alpha2에서 영상은 JSON 문서입니다. 소스, 트랙, 클립에 이펙트, 트랜지션, 텍스트·도형·flexbox/grid 레이아웃을 그리는 제너레이터, 자막, 오디오 믹서가 더해집니다. 이 문서를 GPU 엔진이 렌더링합니다. 프레임마다 실행되는 사용자 코드는 없고, 움직임은 문서 안의 키프레임으로 씁니다. 그래서 문서를 저장하고, diff하고, 검증하고, 생성할 수 있으며, 브라우저, Node.js, Python, Rust, CLI에서 같은 프레임이 나옵니다.
개념 대응표
섹션 제목: “개념 대응표”| Remotion | alpha2 | 참고 |
|---|---|---|
<Composition>(width, height, fps, durationInFrames) |
프로젝트와 그 settings(width, height, frame_rate) |
길이는 타임라인이 끝나는 지점입니다. frame_rate는 유리수이며, 29.97은 { "num": 30000, "den": 1001 }입니다. |
| 프레임 번호 | 틱(tick) 단위 시간, 1초에 120,000 | 틱은 흔히 쓰는 프레임 레이트에서 모두 정확하므로, 프로젝트의 시간이 프레임 레이트에 묶이지 않습니다. |
<AbsoluteFill> |
트랙 위의 클립, 또는 레이아웃 제너레이터의 root |
클립의 그림은 캔버스 전체입니다. 레이아웃의 루트 상자가 곧 캔버스이며, justify_content, align_items, padding으로 배치합니다. |
<Sequence from durationInFrames> |
클립의 timeline_range |
source_range는 소스의 어느 부분을 재생할지 정합니다. |
<Series> |
한 트랙에 차례로 놓인 클립 | |
| JSX 순서에 따른 겹침 | 트랙 순서 | 뒤 트랙이 위에 그려집니다. 한 트랙은 한 번에 클립 하나만 보여 줍니다. |
useCurrentFrame() + interpolate() |
키프레임: { "mode": "keyframes", "keyframes": [...] } |
키프레임의 interpolation(linear, hold, cubic_bezier)이 그 뒤 구간의 모양을 정합니다. |
Easing.bezier(...) |
{ "type": "cubic_bezier", "x1", "y1", "x2", "y2" } |
CSS cubic-bezier()와 같은 곡선입니다. |
<Img>, <Video>, <OffthreadVideo> |
image, video 소스 |
앱이나 호스트가 디코딩합니다. |
<Audio> |
오디오 트랙과 클립 | 게인, 팬, 페이드, 이펙트, 더킹, 마스터 버스. |
CSS transform, opacity |
클립의 visual(position, anchor, scale, rotation_degrees, opacity) |
레이아웃 상자의 translate, scale, rotation_degrees, opacity도 있습니다. |
| CSS 필터, 커스텀 셰이더 | 이펙트(내장 62개) 또는 런타임 WGSL 이펙트 | |
@remotion/transitions |
트랙 위 두 클립 사이의 트랜지션(내장 122개) | |
<Player> |
브라우저 플레이어, 또는 @alpha2-sh/react의 캔버스 |
|
renderMedia() |
@alpha2-sh/node의 exportProject(), 또는 alpha2-host export |
|
renderStill() |
@alpha2-sh/node의 still(), 또는 Python의 alpha2.still |
|
| Input props | 직접 작성한 코드로 JSON 생성 | 템플릿은 문서를 돌려주는 함수입니다. |
같은 영상, 두 가지 방식
섹션 제목: “같은 영상, 두 가지 방식”어두운 배경에 흰 제목이 0.5초부터 1.5초까지 서서히 나타나며 떠오르는 3초짜리 1080p 영상입니다.
import { AbsoluteFill, Composition, Easing, interpolate, Sequence, useCurrentFrame } from "remotion";
const Title = () => { const frame = useCurrentFrame(); const opacity = interpolate(frame, [0, 30], [0, 1], { extrapolateRight: "clamp" }); const rise = interpolate(frame, [0, 30], [54, 0], { easing: Easing.bezier(0.2, 0, 0, 1), extrapolateRight: "clamp", }); return ( <AbsoluteFill style={{ justifyContent: "center", alignItems: "center" }}> <h1 style={{ color: "white", opacity, transform: `translateY(${rise}px)` }}>Hello from alpha2</h1> </AbsoluteFill> );};
export const Root = () => ( <Composition id="Title" width={1920} height={1080} fps={30} durationInFrames={90} component={() => ( <AbsoluteFill style={{ backgroundColor: "#0d0d14" }}> <Sequence from={15}> <Title /> </Sequence> </AbsoluteFill> )} />);{ "schema_version": 1, "id": "remotion-title", "name": "Title", "settings": { "width": 1920, "height": 1080, "frame_rate": { "num": 30, "den": 1 }, "sample_rate": 48000 }, "sources": [ { "id": "bg", "kind": "generated", "generator": { "type": "fill", "paint": { "type": "solid", "color": { "red": 0.05, "green": 0.05, "blue": 0.08, "alpha": 1 } } } }, { "id": "title", "kind": "generated", "generator": { "type": "text", "text": "Hello from alpha2", "style": { "font_family": "Hanken Grotesk", "font_size": 0.12, "position": { "x": 0.5, "y": 0.5 }, "anchor": { "x": 0.5, "y": 0.5 } } } } ], "timeline": { "tracks": [ { "id": "background", "name": "Background", "kind": "video", "clips": [ { "id": "bg-clip", "source_id": "bg", "timeline_range": { "start": 0, "end": 360000 }, "source_range": { "start": 0, "end": 360000 } } ], "transitions": [] }, { "id": "title", "name": "Title", "kind": "video", "clips": [ { "id": "title-clip", "source_id": "title", "timeline_range": { "start": 60000, "end": 360000 }, "source_range": { "start": 0, "end": 300000 }, "visual": { "opacity": { "mode": "keyframes", "keyframes": [ { "time": 60000, "value": 0, "interpolation": { "type": "linear" } }, { "time": 180000, "value": 1, "interpolation": { "type": "hold" } } ] }, "position": { "mode": "keyframes", "keyframes": [ { "time": 60000, "value": { "x": 0.5, "y": 0.55 }, "interpolation": { "type": "cubic_bezier", "x1": 0.2, "y1": 0, "x2": 0, "y2": 1 } }, { "time": 180000, "value": { "x": 0.5, "y": 0.5 }, "interpolation": { "type": "hold" } } ] } } } ], "transitions": [] } ] }}alpha2 버전에서 제목은 단색 fill 위, 자기 트랙에 놓인 text 제너레이터입니다. 클립은 <Sequence from={15}>처럼 0.5초(60000틱)에 시작합니다. opacity와 position 키프레임이 두 interpolate 호출과 같은 일을 합니다. 클립의 visual 키프레임은 타임라인 시간 기준이므로 클립 시작인 0.5초에서 시작합니다. 첫 키프레임 전과 마지막 키프레임 뒤에는 가장 가까운 키의 값이 유지되며, extrapolateRight: "clamp"와 같습니다. y의 0.55에서 0.5까지는 캔버스 높이의 5%로, Remotion 버전의 54픽셀에 해당합니다.
렌더링
섹션 제목: “렌더링”import { exportProject } from "@alpha2-sh/node";
await exportProject({ project, // 위의 문서 assets: {}, // 파일 없음: 모든 소스가 생성 소스 fonts: ["HankenGrotesk.ttf"], startTicks: 0, endTicks: 360_000, frameRate: { num: 30, den: 1 }, output: "title.mp4",});alpha2-host export --project title.json --font HankenGrotesk.ttf --out title.mp4Remotion이 헤드리스 브라우저를 구동하는 자리에, alpha2-host는 GPU(Vulkan, Metal, Direct3D 12)로, GPU가 없으면 CPU로 렌더링하고 FFmpeg로 인코딩하는 네이티브 프로그램입니다. 서버에서 렌더링하기를 참고하십시오.
alpha2가 하지 않는 일
섹션 제목: “alpha2가 하지 않는 일”- React나 DOM을 렌더링하지 않습니다. 그림 안에 HTML, CSS 캐스케이드, SVG DOM, canvas API가 없습니다. 레이아웃 제너레이터가 텍스트와 도형을 담은 flexbox·grid 상자를 지원하고 SVG와 Lottie 파일을 소스로 쓸 수 있지만, 임의의 웹 콘텐츠는 그릴 수 없습니다.
- 프레임마다 코드를 실행하지 않습니다. 렌더링 중에 프레임 번호로 값을 계산할 수 없습니다. 미리 계산해 키프레임으로 쓰거나(레이아웃
text는 문자열 키프레임을 받으므로 카운터는 hold 키 목록이 됩니다), 픽셀 단위 작업은 런타임 WGSL 이펙트로 작성하십시오. - 렌더링 중에 데이터를 가져오지 않습니다. 렌더링에 필요한 것은 모두 문서에 있거나 함께 넘겨집니다(에셋 파일, 폰트, 이펙트 리소스).
- 폰트는 넘겨준 파일만 씁니다. 엔진은 시스템 폰트를 읽지 않습니다. 넘겨준 폰트 중 어느 것에도 없는 패밀리를 지정한 텍스트는 넘겨준 폰트의 대체 순서대로 그려집니다.
그 대신 얻는 것은 어디서나 똑같이 로드되는 스키마 검사 문서, 브라우저 프리뷰와 서버 export에서 같은 프레임, 그리고 서버에서 브라우저 없이 하는 GPU 렌더링입니다.
함께 보기
섹션 제목: “함께 보기”- 프로젝트 모델: 소스, 트랙, 클립.
- 애니메이션: 키프레임과 시간 기준.
- 레이아웃: JSX 레이아웃을 대신하는 flexbox·grid 상자.
- FFmpeg에서 넘어오기
