Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds
Powrót do kolekcji
Przewodnik12 min czytania

Remotion, wideo pisane w Reakcie

Remotion generuje pliki wideo z komponentów React. Jak działa oś czasu, renderowanie, licencja zależna od wielkości firmy i realne zastosowania.

Remotion, czyli plik wideo jako wynik działania kodu

Remotion pozwala napisać wideo w Reakcie i wyrenderować je do pliku. Komponenty, style, animacje i logika są dokładnie tym, czym w zwykłej aplikacji, tylko wynikiem nie jest strona, lecz nagranie.

Pomysł brzmi ekscentrycznie, dopóki nie zobaczysz zastosowania. Generowanie tysiąca spersonalizowanych filmów, w których każdy zawiera imię odbiorcy i jego dane, jest w klasycznym programie do montażu niewykonalne, a tutaj to pętla po liście.

Zanim przejdziemy dalej, jedno zastrzeżenie, bo bez niego cały tekst wprowadzałby w błąd: to nie jest projekt otwarty w zwykłym rozumieniu. Licencja zależy od wielkości Twojej firmy i opisuję ją niżej.

Licencja, czyli rzecz do sprawdzenia najpierw

Kod jest publiczny i można go czytać, natomiast prawo do użycia komercyjnego zależy od liczby osób w organizacji.

Użycie bezpłatne obejmuje osoby prywatne oraz firmy zatrudniające najwyżej trzy osoby. Powyżej tego progu potrzebna jest licencja firmowa, a ona ma dwa tory rozliczenia i to właśnie tutaj najczęściej myli się kwoty.

WariantStawkaDla kogo
Za renderowania0,01 USD za renderowanie, minimum 100 USD miesięcznieAplikacje generujące wideo automatycznie, gdzie programista nie potrzebuje miejsca
Za miejsca25 USD miesięcznie za miejsceTworzenie wideo ręcznie, jedno miejsce na osobę
Licencja rozszerzonaOd 500 USD miesięcznieWłasne warunki, wsparcie priorytetowe, dodatkowe produkty

Minimalne zobowiązanie stu dolarów miesięcznie producent przypisuje do toru rozliczanego renderowaniami, więc przy samych miejscach rachunek zaczyna się od dwudziestu pięciu dolarów za osobę.

Ten próg zaskakuje zespoły częściej, niż mogłoby się wydawać. Czteroosobowa firma korzystająca z narzędzia w projekcie dla klienta jest już po stronie płatnej, niezależnie od tego, ilu programistów faktycznie dotyka kodu wideo.

Warto też wiedzieć, co szykuje się w wersji piątej, bo dotyczy tego, co narzędzie wysyła na zewnątrz podczas pracy. Bieżąca linia to nadal 4.0, a wersja piąta nie została jeszcze wydana. W zapowiedzianych zmianach raportowanie użycia przez klucz licencyjny staje się obowiązkowe dla wszystkich posiadaczy licencji firmowej, niezależnie od toru rozliczenia, a osoby na licencji bezpłatnej podają w tym samym miejscu wartość oznaczającą użycie bezpłatne.

Praktyczna rada: sprawdź warunki na stronie producenta przed rozpoczęciem projektu, a nie po jego zakończeniu. Licencja tej klasy nie jest przeszkodą, natomiast bywa niemiłą niespodzianką, gdy odkrywa się ją przy rozliczeniu z klientem.

Jak to działa

Podstawowym pojęciem jest kompozycja: opis wideo obejmujący rozmiar, liczbę klatek na sekundę i długość wyrażoną w klatkach.

Code
TypeScript
import { Composition } from 'remotion'

export const RemotionRoot = () => (
  <Composition
    id="Powitanie"
    component={Powitanie}
    durationInFrames={150}
    fps={30}
    width={1920}
    height={1080}
    defaultProps={{ imie: 'Anna' }}
  />
)

Sto pięćdziesiąt klatek przy trzydziestu klatkach na sekundę daje pięć sekund. Ta arytmetyka jest tu obecna wszędzie i warto się do niej przyzwyczaić, bo animacje opisuje się klatkami, a nie sekundami.

Sam komponent wygląda jak zwykły komponent React, z jedną różnicą: wie, którą klatkę właśnie renderuje.

Code
TypeScript
import { useCurrentFrame, interpolate } from 'remotion'

export const Powitanie = ({ imie }: { imie: string }) => {
  const klatka = useCurrentFrame()

  const przezroczystosc = interpolate(klatka, [0, 30], [0, 1], {
    extrapolateRight: 'clamp',
  })

  return (
    <div style={{ opacity: przezroczystosc, fontSize: 80 }}>
      Cześć, {imie}
    </div>
  )
}

To jest cała idea. Animacja nie jest osobnym mechanizmem, tylko funkcją numeru klatki, więc każda klatka renderuje się niezależnie i deterministycznie. Ta sama klatka wyrenderowana dwa razy da identyczny wynik.

Konsekwencja jest praktyczna i przyjemna: renderowanie da się zrównoleglić, bo klatki nie zależą od siebie nawzajem. Można też podejrzeć dowolny moment nagrania bez odtwarzania wszystkiego od początku.

Renderowanie i wdrożenie

Podgląd działa w przeglądarce i przypomina zwykły serwer deweloperski, z dodatkową osią czasu do przewijania.

Code
Bash
npx remotion studio
npx remotion render Powitanie wyjscie.mp4 --props='{"imie":"Anna"}'

Renderowanie uruchamia przeglądarkę bez interfejsu, zrzuca kolejne klatki i składa je w plik. To znaczy, że wymaga sporo zasobów: procesora, pamięci i miejsca na dysku na klatki pośrednie.

Z tego wynika główna decyzja wdrożeniowa. Renderowanie na serwerze aplikacyjnym zablokuje go na czas pracy, więc sensowniejszy układ to osobna kolejka zadań albo funkcje bezserwerowe uruchamiane na żądanie, z których każda renderuje fragment nagrania.

Warto przy tym pamiętać o limitach czasu wykonania, bo przy funkcjach bezserwerowych są one twarde. Renderowanie podzielone na fragmenty po kilkanaście sekund materiału mieści się w typowych ograniczeniach, a fragment obejmujący całe nagranie zwykle nie. Przy wdrożeniu u dostawcy takiego jak Vercel warto sprawdzić maksymalny czas funkcji przed zaprojektowaniem podziału, bo to on wyznacza rozmiar fragmentu, a nie odwrotnie.

Czas renderowania warto zmierzyć wcześnie, bo intuicja myli. Minuta wideo w wysokiej rozdzielczości to tysiąc osiemset klatek, a każda wymaga wyrenderowania strony i zrzutu obrazu. Przy złożonych animacjach minuta materiału potrafi renderować się kilka minut, więc obietnica natychmiastowego wygenerowania filmu wymaga sprawdzenia na własnym przypadku.

Warto też wiedzieć, że przetwarzanie mediów przeszło na nowy silnik. Znaczniki dźwięku i wideo zalecane dla nowych projektów pochodzą dziś z osobnej paczki, a ich odpowiedniki z paczki głównej zostały przemianowane na warianty oparte o mechanizmy przeglądarki i zostają jako droga zapasowa. Przy aktualizacji między głównymi wersjami warto przeczytać listę zmian, bo dotyczy właśnie nazw pakietów i komponentów.

Do czego to naprawdę służy

Warto rozdzielić zastosowania, w których narzędzie wygrywa, od tych, w których przegrywa z programem do montażu.

Wygrywa przy generowaniu masowym z danych. Tysiąc filmów podsumowujących rok dla tysiąca użytkowników, każdy z innymi liczbami i wykresami. Setka klipów produktowych generowanych z katalogu przy każdej zmianie cennika. Automatyczne nagrania z wynikami, raportami albo statystykami.

Wygrywa przy powtarzalnych formatach. Wideo z cytatem na tle, klip z fragmentem podcastu i napisami, animowana karta z nagłówkiem wiadomości. Wszędzie tam, gdzie układ jest stały, a zmienia się treść.

Wygrywa też przy wideo powiązanym z aplikacją. Podgląd generowany na podstawie tego, co użytkownik ustawił, karta do udostępnienia z jego wynikiem, animacja z jego danymi.

Przegrywa przy pojedynczym filmie o dowolnej formie. Nagranie z kamery, wywiad, film reklamowy z ujęciami i muzyką zmontuje się szybciej w zwykłym programie, bo tam pracujesz na osi czasu, a nie na numerach klatek.

Przegrywa też wtedy, gdy nad materiałem ma pracować osoba nietechniczna. Zmiana koloru napisu wymaga tu edycji kodu i uruchomienia renderowania, co dla montażysty jest krokiem wstecz.

Dźwięk, wideo i synchronizacja

Nagranie bez dźwięku rzadko wystarcza, a to obszar, w którym praca na klatkach wymaga zmiany przyzwyczajeń.

Ścieżkę dźwiękową dokładasz jako komponent, podając moment startu w klatkach. Biblioteka synchronizuje ją z obrazem przy renderowaniu, więc nie ma dryfu, który zdarza się przy ręcznym składaniu.

Code
TypeScript
import { Sequence, staticFile, useVideoConfig } from 'remotion'
import { Audio } from '@remotion/media'

export function Nagranie() {
  const { fps } = useVideoConfig()

  return (
    <>
      <Audio src={staticFile('lektor.mp3')} />
      <Sequence from={2 * fps} durationInFrames={5 * fps}>
        <Napis tekst="Zamowienie przyjete" />
      </Sequence>
    </>
  )
}

Liczenie momentów przez liczbę klatek na sekundę zamiast wpisywania liczb wprost jest tu nawykiem wartym wyrobienia od pierwszego projektu. Zmiana kompozycji z trzydziestu na sześćdziesiąt klatek przesuwa wtedy wszystko poprawnie, a wartości wpisane na sztywno rozjeżdżają się z dźwiękiem.

Wstawianie gotowego materiału wideo działa podobnie, przy czym warto znać jedno ograniczenie. Podgląd w przeglądarce odtwarza materiał w czasie rzeczywistym, a renderowanie pobiera z niego pojedyncze klatki, więc te dwa tryby mogą się nieznacznie różnić przy materiale o innej liczbie klatek na sekundę niż kompozycja. Wyrównanie liczby klatek na sekundę usuwa ten problem u źródła.

Napisy zsynchronizowane z mową to jedno z najczęstszych zastosowań i warto podejść do nich metodycznie. Transkrypcja ze znacznikami czasu zamienia się na listę fragmentów z numerami klatek, a komponent wyświetla ten, który przypada na bieżącą klatkę. Wynik jest dokładniejszy niż ręczne ustawianie w programie do montażu i powtarzalny przy każdej zmianie tekstu.

Warto pamiętać, że dźwięk wydłuża renderowanie mniej niż obraz, ale komplikuje wdrożenie równoległe. Fragmenty renderowane osobno trzeba złożyć razem ze ścieżką dźwiękową, więc krok scalający musi wiedzieć o obu.

Praca z danymi

Skoro największą przewagą jest generowanie z danych, warto opisać, jak przekazać je do nagrania.

Najprostsza droga to właściwości kompozycji podawane przy renderowaniu. Wystarcza przy prostych przypadkach i przestaje wystarczać, gdy dane są duże albo pochodzą z bazy.

Wtedy sensowniejszy układ polega na pobraniu danych przed renderowaniem i przekazaniu gotowego zestawu.

Code
TypeScript
const dane = await baza.podsumowanieRoku(uzytkownikId)

await renderMedia({
  composition,
  serveUrl,
  codec: 'h264',
  outputLocation: `out/${uzytkownikId}.mp4`,
  inputProps: dane
})

Renderowanie ma być deterministyczne, więc pobieranie danych w trakcie tworzenia klatek jest ryzykowne: dwa przebiegi mogą dać różny wynik, a przy renderowaniu równoległym każdy fragment odpytałby źródło osobno. Kształt przekazywanych danych warto opisać schematem, bo błąd w nich wychodzi dopiero na gotowym nagraniu.

Obrazy i czcionki warto wczytywać przez mechanizmy przewidziane w bibliotece, a nie zwykłymi znacznikami.

Code
TypeScript
import { Img, staticFile, delayRender, continueRender } from 'remotion'

const [uchwyt] = useState(() => delayRender('ladowanie czcionki'))

useEffect(() => {
  document.fonts.load('700 48px Inter').then(() => continueRender(uchwyt))
}, [uchwyt])

<Img src={staticFile('logo.png')} />

Renderowanie zrzuca klatkę, gdy strona jest gotowa, więc zasób wczytany o ułamek sekundy za późno po prostu nie pojawi się w kadrze. Para wywołań wstrzymujących i wznawiających mówi wprost, że klatka nie jest jeszcze gotowa, i to jest właściwe rozwiązanie wszędzie tam, gdzie coś wczytuje się asynchronicznie. To najczęstsza przyczyna nagrań, w których pierwsze klatki są puste.

Przy generowaniu masowym zaplanuj też obsługę niepowodzeń. Renderowanie tysiąca filmów zawsze kończy się kilkoma błędami, a proces powinien zapisać, które pozycje się nie udały, zamiast przerywać całość na pięćsetnej.

Code
TypeScript
const nieudane: Array<{ id: string; powod: string }> = []

for (const uzytkownik of uzytkownicy) {
  try {
    await wyrenderuj(uzytkownik)
  } catch (blad) {
    nieudane.push({ id: uzytkownik.id, powod: String(blad) })
  }
}

await fs.writeFile('nieudane.json', JSON.stringify(nieudane, null, 2))
console.log(`gotowe: ${uzytkownicy.length - nieudane.length}, bledy: ${nieudane.length}`)

Zapis listy niepowodzeń do pliku zamiast do dziennika ma tu praktyczne znaczenie: ponowienie sprowadza się do wczytania tego pliku i przejścia wyłącznie po nim, zamiast szukania w dzienniku, które z tysiąca pozycji trzeba powtórzyć.

Remotion kontra alternatywy

RozwiązanieMocna stronaSłabośćKiedy wybrać
RemotionWideo z danych, znany język, powtarzalnośćLicencja zależna od wielkości firmy, koszt renderowaniaGenerowanie masowe z danych
Program do montażuPełna swoboda, praca wizualnaBrak automatyzacji, praca ręcznaPojedynczy film o dowolnej formie
MotionAnimacje w przeglądarce, lekkieNie daje pliku wideoAnimacja na stronie, nie nagranie
Narzędzia wiersza poleceń do wideoBardzo szybkie, bez przeglądarkiTrudne przy złożonym układzieProste cięcie, łączenie, konwersja

Trzeci wiersz bywa mylony z pierwszym, a to zupełnie inne rzeczy. Animacja w przeglądarce jest interaktywna i żyje na stronie, a wideo to plik, który da się wysłać, wstawić do serwisu społecznościowego albo odtworzyć bez internetu.

Czwarty wiersz warto rozważyć, zanim sięgniesz po pierwszy. Jeśli zadanie sprowadza się do dołożenia napisu do gotowego nagrania albo połączenia dwóch plików, narzędzie wiersza poleceń zrobi to w sekundy, bez uruchamiania przeglądarki i bez licencji.

Jak zacząć rozsądnie

Kolejność, która oszczędza najwięcej czasu przy pierwszym projekcie, wygląda inaczej niż podpowiada dokumentacja.

Zacznij od jednego, najprostszego formatu i doprowadź go do końca, łącznie z renderowaniem i wysłaniem pliku tam, gdzie ma trafić. Dopiero ten pełny przebieg pokazuje, gdzie leżą prawdziwe problemy, a te zwykle nie dotyczą animacji, tylko czasu renderowania i miejsca, w którym proces ma działać.

Nie zaczynaj od skomplikowanej animacji. Praca na klatkach wymaga innego myślenia niż praca na osi czasu, więc pierwszy projekt lepiej poświęcić na przyswojenie tej różnicy przy prostym układzie.

Zbuduj podgląd dla osób nietechnicznych możliwie wcześnie. Studio uruchamiane lokalnie wystarcza programiście, natomiast osoba zamawiająca materiał potrzebuje zobaczyć wynik bez instalowania czegokolwiek. Wygenerowanie kilku wariantów i wysłanie ich jako plików rozwiązuje to prościej niż budowanie interfejsu.

Zmierz koszt i czas przy realnej skali, zanim obiecasz cokolwiek. Dziesięć filmów wyrenderowanych lokalnie mówi niewiele o tysiącu filmów renderowanych równolegle, bo tam dochodzą limity, kolejkowanie i obsługa niepowodzeń.

Wreszcie sprawdź licencję i policz koszt miejsc dla programistów, jeśli firma przekracza próg bezpłatny. To decyzja biznesowa, którą lepiej podjąć na początku niż po zbudowaniu całego procesu.

Typowe błędy

Pierwszy to rozpoczęcie projektu bez sprawdzenia licencji. Próg trzech osób w firmie zaskakuje zespoły regularnie, a odkrycie tego przy rozliczeniu z klientem jest kłopotliwe.

Drugi to renderowanie na serwerze obsługującym ruch. Praca zajmuje procesor i pamięć na minuty, więc należy do osobnej kolejki zadań albo do funkcji uruchamianych na żądanie.

Trzeci to opisywanie animacji w sekundach zamiast w klatkach. Cała biblioteka operuje na numerach klatek, a mieszanie jednostek daje animacje rozjeżdżające się przy zmianie liczby klatek na sekundę.

Czwarty to obietnica natychmiastowego generowania bez pomiaru. Minuta materiału potrafi renderować się kilka minut, więc czas warto sprawdzić na realnym przypadku przed obiecaniem czegokolwiek.

Piąty to używanie tego do pojedynczych filmów o dowolnej formie. Program do montażu zrobi to szybciej i bez pisania kodu.

Szósty to oddanie narzędzia osobie nietechnicznej. Każda zmiana wymaga edycji kodu i renderowania, więc bez programisty proces staje.

FAQ

Czy Remotion jest darmowy?

Dla osób prywatnych i firm zatrudniających najwyżej trzy osoby tak, również do zastosowań komercyjnych. Powyżej tego progu wymagana jest licencja firmowa: 25 USD miesięcznie za miejsce przy pracy ręcznej albo 0,01 USD za renderowanie przy generowaniu automatycznym, gdzie obowiązuje minimum stu dolarów miesięcznie. Warunki warto sprawdzić na stronie producenta przed rozpoczęciem projektu.

Czy to jest projekt otwarty?

Kod jest publiczny i można go czytać, natomiast licencja nie jest swobodna: prawo do użycia komercyjnego zależy od wielkości organizacji. To rozróżnienie warto rozumieć, bo publiczne repozytorium bywa mylone z licencją pozwalającą na dowolne użycie.

Ile trwa renderowanie?

Zależy od złożoności i rozdzielczości. Minuta materiału w wysokiej rozdzielczości to tysiąc osiemset klatek, z których każda wymaga wyrenderowania strony, więc przy złożonych animacjach czas potrafi wielokrotnie przekroczyć długość nagrania. Zmierz to na własnym przypadku przed obiecaniem terminów.

Czy zastąpi program do montażu?

Nie przy pojedynczym filmie o dowolnej formie, bo tam praca wizualna jest szybsza. Zastąpi go przy generowaniu masowym z danych i przy powtarzalnych formatach, gdzie układ jest stały, a zmienia się wyłącznie treść.

Gdzie renderować w produkcji?

Poza serwerem obsługującym ruch użytkowników. Sensowne układy to osobna kolejka zadań na maszynie przeznaczonej do tego albo funkcje bezserwerowe renderujące fragmenty równolegle, co przy dłuższych nagraniach skraca czas oczekiwania kilkukrotnie.

Dokumentacja stoi na stronie projektu, a warunki licencyjne opisuje osobna strona.