Install and embed
Install the package, host runtime assets and connect a controlled editor or standalone viewer.
reopt designUpdated
1. Install and prepare static assets
Use Node.js 20+ and React/React DOM 19.2.3+ within the supported major version. Next.js and a backend are not required. After installation, copy CanvasKit and bundled fonts into the app public directory.
Run the asset-copy command during builds after installing or upgrading the package. The default URL is /deck-assets; canvaskit.js, canvaskit.wasm and font files must all be accessible.
bun add @reopt-ai/opt-deck
bunx opt-deck-assets public/deck-assets2. Your first editor
Create a document in a React client component and connect value/onChange. In Next.js, mark the component with use client and import styles.css once from an appropriate application entry. This example edits in memory without server persistence. Editor controls use opt-ui-primitives with package-owned styles; Tailwind and an opt-ui stylesheet are not required.
"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 and uncontrolled state
With value/onChange the host retains the current document. Store the exact object emitted by the editor. Cloning value on every render can be interpreted as an external replacement and clear history.
defaultValue initializes the document once. To open another document, use controlled value or remount with a document-ID key. value expects v2; migrate v1 with migrateDeckDocument. defaultValue also accepts legacy input.
4. Embed a viewer
Use the /viewer entry for read-only pages. It accepts the same v2 document. Hide navigation with controls=false, or pair slideId with onSlideChange for host-controlled navigation.
"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. Configure runtime assets
Set assetBaseUrl when assets live at a different URL. runtime.fetch handles document assets and font requests. CanvasKit JavaScript is loaded through a script element, so this fetch does not intercept every engine request.
For a CDN, verify script, WASM and font responses, MIME types, CORS and application CSP. Supply a preloaded engine with runtime.canvasKit. Never put secret credentials in client runtime options.
"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. Verify the first run
Once the first slide appears, double-click text, edit, undo and open presentation mode. Export and reimport JSON or a portable file to check content and assets. AI and server persistence are optional at this stage.
If canvas preparation does not finish, inspect the Network responses for canvaskit.js, canvaskit.wasm and font files. For a 404, match the opt-deck-assets destination to runtime.assetBaseUrl. Missing styles usually mean a missing styles.css import; a blank area can mean a missing container height. Investigate document parsing errors through migrateDeckDocument or parseDeckDocument.