React
@alpha2-sh/react는 브라우저 플레이어를 React 트리의 캔버스에 연결합니다. 이 페이지를 읽고 나면 React 상태에 따라 원하는 시간의 프로젝트를 표시하고, 플레이어를 다시 만들지 않고 GPU 손실에서 복구하고, React 없이도 같은 연결을 구성할 수 있습니다.
이 패키지는 직접 아무것도 그리지 않습니다. 여러분이 (alpha2/player의) Alpha2Player를 만들면, 컴포넌트가 여기에 캔버스를 주고 전달받은 시간을 표시합니다.
npm install @alpha2-sh/react alpha2pnpm add @alpha2-sh/react alpha2yarn add @alpha2-sh/react alpha2Alpha2Canvas로 프로젝트 표시하기
섹션 제목: “Alpha2Canvas로 프로젝트 표시하기”- 워커에서 프리뷰하기처럼 엔진을 실행하는 렌더 워커를 작성합니다.
WorkerRenderBackend위에Alpha2Player를 만드는createPlayer콜백을 작성하고, 컴포넌트가 넘겨주는replaceSurface인자를 플레이어에 전달합니다.- 프로젝트 크기와 표시할 시간(틱 단위)을 지정해
<Alpha2Canvas>를 렌더링합니다.
import { useCallback, useState } from "react";import { Alpha2Canvas } from "@alpha2-sh/react";import { Alpha2Player } from "alpha2/player";import { WorkerRenderBackend } from "alpha2/worker";
function Preview({ workerUrl, refill }) { const [time, setTime] = useState(0n);
// 함수가 새로 만들어지면 플레이어도 새로 만들어지므로, 안정적으로 유지합니다. const createPlayer = useCallback( (replaceSurface) => new Alpha2Player(new WorkerRenderBackend(new Worker(workerUrl, { type: "module" })), { onRefill: refill, replaceSurface, }), [workerUrl, refill], );
return ( <> <Alpha2Canvas createPlayer={createPlayer} timeTicks={time} width={1280} height={720} onError={(error) => console.error(error)} /> <input type="range" min={0} max={120_000 * 10} onChange={(event) => setTime(BigInt(event.target.value))} /> </> );}refill은 표시에 필요한 프레임이 없을 때 DecoderRefillRequest를 받습니다. 요청을 디코딩해 각각 player.uploadVideoFrame으로 업로드하세요. WebCodecs로 디코딩하기를 참고하세요.
Props
섹션 제목: “Props”| Prop | 타입 | |
|---|---|---|
createPlayer |
(replaceSurface) => player |
캔버스용 플레이어를 만듭니다. 컴포넌트가 캔버스를 만들 때마다 호출됩니다. useCallback으로 안정적으로 유지하세요. |
timeTicks |
bigint |
표시할 타임라인 시간(틱 단위). |
width, height |
number |
프로젝트 크기. 플레이어가 그리는 크기이자 요소의 종횡비입니다. |
className, style |
요소의 스타일을 지정합니다. | |
onReady |
() => void |
플레이어가 캔버스를 받은 뒤 한 번 호출됩니다. |
onPresented |
(frame) => void |
다른 표시로 대체되지 않은 표시마다 호출됩니다. |
onError |
(error) => void |
초기화나 표시가 실패하면 호출됩니다. 지정하지 않으면 오류는 페이지의 reportError로 전달됩니다. |
동작 방식
섹션 제목: “동작 방식”- 요소는 프로젝트의 종횡비를 유지하면서 컨테이너의 너비를 채웁니다.
timeTicks가 바뀔 때마다 그 시간을 표시합니다. 표시가 진행 중일 때 들어온 시간들은 하나로 합쳐져, 가장 최근 시간만 표시됩니다.- 페이지가 숨겨져 있는 동안에는 아무것도 표시하지 않습니다. 페이지가 다시 보이면 가장 최근 시간을 표시합니다.
- 플레이어는 캔버스 하나에 속합니다. 마운트할 때마다,
createPlayer가 바뀔 때마다, 크기가 바뀔 때마다 새 캔버스와 새 플레이어가 만들어지고, 이전 플레이어는 캔버스가 사라질 때 dispose됩니다. React는 컴포넌트를 여러 번 설정할 수 있는데(<StrictMode>,<Activity>), 그때마다 각각 별도의 캔버스와 플레이어를 갖습니다.
GPU 손실에서 복구하기
섹션 제목: “GPU 손실에서 복구하기”GPU를 잃으면 Alpha2Player는 다음 표시 때 복구합니다. 일부 복구에는 새 캔버스가 필요합니다. WebGL2 컨텍스트를 잃었을 때, 또는 브라우저가 GPU 접근을 회수한 뒤 CPU 렌더러로 전환할 때가 그렇습니다. 컴포넌트가 createPlayer에 넘겨주는 replaceSurface 함수가 이를 처리합니다. 이 함수는 이전 캔버스 요소를 새 캔버스 요소로 교체하고, 같은 플레이어가 새 캔버스에 그립니다.
React 없이: bindCanvas
섹션 제목: “React 없이: bindCanvas”bindCanvas(player, canvas, options?)는 어떤 프레임워크에서든 쓸 수 있는 같은 연결 방식입니다. 캔버스를 플레이어에 넘기고, 지정한 시간을 표시합니다. 플레이어를 만들거나 dispose하지는 않습니다.
import { bindCanvas } from "@alpha2-sh/react";import { Alpha2Player } from "alpha2/player";import { WorkerRenderBackend } from "alpha2/worker";
const canvas = document.querySelector("canvas");canvas.width = 1280; // 드로잉 버퍼 크기는 transfer 이후에 바꿀 수 없습니다canvas.height = 720;
let binding;let current = canvas;const player = new Alpha2Player(new WorkerRenderBackend(worker), { onRefill: refill, replaceSurface: () => binding.replaceSurface(),});binding = bindCanvas(player, canvas, { // 바인딩된 캔버스 자리에 같은 크기의 캔버스를 넣습니다. replaceCanvas: async () => { const fresh = document.createElement("canvas"); fresh.width = current.width; fresh.height = current.height; current.replaceWith(fresh); current = fresh; return fresh; }, onPresented: (frame) => console.log(frame.presentedTimeTicks), onError: (error) => console.error(error),});
await binding.ready;binding.show(60_000n);
// 나중에:binding.dispose();player.dispose();binding.ready는 플레이어가 캔버스를 받으면 resolve되고, 받을 수 없으면 reject됩니다.bindCanvas자체는 절대 예외를 던지지 않습니다.binding.show(ticks)는 시간을 표시합니다. 초기화가 끝났다면 바로, 아니면 초기화 후에, 페이지가 숨겨져 있다면 다음에 보일 때 표시합니다. 같은 시간을 다시 지정하면 다시 표시합니다.binding.replaceSurface()는replaceCanvas에서 받은 새 캔버스를 이미OffscreenCanvas로 transfer한 상태로 반환합니다. 플레이어의replaceSurface옵션에 필요한 것이 바로 이것입니다.replaceCanvas가 없으면 reject됩니다.options.visibility는 페이지 표시 여부의 출처로document대신 사용할 객체를 지정합니다.
