설치와 첫 임베드
패키지 설치, 런타임 자산 호스팅, controlled 편집기와 독립 뷰어를 연결합니다.
reopt design업데이트
1. 설치와 정적 자산 준비
Node.js 20 이상, React와 React DOM은 19.2.3 이상의 19.x 버전을 사용합니다. Next.js와 백엔드는 필수 의존성이 아닙니다. 패키지를 설치한 뒤 앱의 public 디렉터리에 CanvasKit과 기본 글꼴을 복사합니다.
자산 복사 명령은 패키지 설치·업그레이드 후 빌드 과정에서도 실행하세요. 기본 경로는 /deck-assets이며 canvaskit.js·canvaskit.wasm·글꼴 파일이 모두 접근 가능해야 합니다.
bun add @reopt-ai/opt-deck
bunx opt-deck-assets public/deck-assets2. 첫 편집기
React 클라이언트 컴포넌트에서 문서를 만들고 value/onChange를 연결합니다. Next.js에서는 이 컴포넌트에 use client를 선언하고, 앱의 CSS 진입점이나 허용된 컴포넌트에서 styles.css를 한 번 가져옵니다. 아래 예제는 서버 저장 없이 메모리에서 동작합니다. 편집기 UI는 opt-ui-primitives를 사용하며 스타일을 패키지에 포함합니다. Tailwind나 별도의 opt-ui 스타일시트는 필요하지 않습니다.
"use client";
import { useState } from "react";
import { DeckEditor, createDeckDocument } from "@reopt-ai/opt-deck";
import "@reopt-ai/opt-deck/styles.css";
export function Presentation() {
const [document, setDocument] = useState(() =>
createDeckDocument({ design: "editorial", title: "Acme" }),
);
return (
<DeckEditor
value={document}
onChange={setDocument}
locale="ko"
style={{ height: "min(850px, 100dvh)" }}
/>
);
}3. Controlled와 uncontrolled 선택
value/onChange는 앱이 최신 문서를 보관하는 방식입니다. 편집기가 전달한 문서 객체를 그대로 state에 반영하세요. 매 렌더마다 복제한 value를 전달하면 외부 문서 교체로 인식되어 history가 초기화될 수 있습니다.
defaultValue는 최초 문서만 설정합니다. 이후 문서를 바꾸려면 controlled value를 사용하거나 문서 ID를 key로 주어 편집기를 다시 마운트합니다. value에는 v2 문서를 전달하고, v1 입력은 migrateDeckDocument로 변환하세요. defaultValue는 v1 입력도 변환합니다.
4. 읽기와 발표만 임베드
읽기 전용 화면은 /viewer 진입점을 사용합니다. document는 편집기와 같은 v2 문서입니다. controls=false로 탐색 UI를 감출 수 있고, slideId/onSlideChange를 함께 전달하면 앱이 현재 슬라이드를 제어합니다.
"use client";
import { DeckViewer } from "@reopt-ai/opt-deck/viewer";
import type { DeckDocument } from "@reopt-ai/opt-deck/server";
import "@reopt-ai/opt-deck/styles.css";
export function PresentationViewer({ document }: { document: DeckDocument }) {
return (
<DeckViewer
document={document}
locale="ko"
controls
showNotes={false}
autoPlay={false}
style={{ height: 720 }}
/>
);
}5. 런타임과 자산 경로 변경
다른 URL에 자산을 배포했다면 assetBaseUrl을 지정합니다. runtime.fetch는 문서 자산·글꼴을 읽는 요청에 사용됩니다. CanvasKit JavaScript는 script 태그로 로드되므로 해당 요청 전체를 이 fetch가 가로채는 것은 아닙니다.
CDN을 사용한다면 스크립트·WASM·글꼴의 실제 응답, MIME, CORS와 앱의 CSP를 확인하세요. 이미 준비한 CanvasKit 인스턴스는 runtime.canvasKit으로 주입할 수 있습니다. 비밀키를 클라이언트 runtime 옵션에 넣지 않습니다.
"use client";
import { DeckEditor } from "@reopt-ai/opt-deck";
import type { DeckRuntimeOptions } from "@reopt-ai/opt-deck";
const runtime: DeckRuntimeOptions = {
assetBaseUrl: "/presentation-assets",
fetch: (input, init) => fetch(input, { ...init, credentials: "same-origin" }),
};
export function CustomRuntimeEditor() {
return <DeckEditor runtime={runtime} locale="ko" />;
}6. 첫 실행 확인
첫 슬라이드가 보이면 텍스트를 더블클릭해 수정하고 undo한 뒤 발표 화면을 엽니다. JSON 또는 portable로 내보낸 파일을 다시 가져와 내용과 자산을 확인하세요. 이 단계에서는 AI와 서버 저장을 연결하지 않아도 됩니다.
캔버스 준비가 끝나지 않으면 Network에서 canvaskit.js·canvaskit.wasm·글꼴 파일의 응답을 확인하세요. 404이면 opt-deck-assets의 복사 위치와 runtime.assetBaseUrl을 맞춥니다. 스타일이 없으면 styles.css import를, 빈 공간만 보이면 컨테이너 높이를 확인하세요. 문서 파싱 오류는 migrateDeckDocument 또는 parseDeckDocument의 결과부터 확인합니다.