Requirements and compatibility
The Node, Next, React, and Tailwind versions a deck needs, which package managers work, what a presented deck asks of the browser, and which commands need Chromium.
A deck is a Next.js app with @thebuilder/deckard-core as a dependency. Everything below is what that app needs.
Versions
| What | Version | Where it comes from |
|---|---|---|
| Node | 20.9 or newer | engines on all three packages, and the floor deckard doctor checks |
| Next.js | 16 or newer | peerDependencies on @thebuilder/deckard-core |
| React | 19 or newer | peerDependencies on @thebuilder/deckard-core |
| React DOM | 19 or newer | peerDependencies on @thebuilder/deckard-core |
| Tailwind CSS | 4 | @thebuilder/deckard-core/styles.css uses @source, which is v4 only |
deckard init pins the versions the reference deck runs rather than the floors, so a deck generated today installs Next 16.3.3, React ^19.2.8, Tailwind ^4.3.3, and TypeScript ^7.0.2.
Tailwind is not a declared peer dependency of any Deckard package. The requirement arrives through the one stylesheet import:
@import "tailwindcss";
@import "@thebuilder/deckard-core/styles.css";
That second line carries the --slide-* tokens and registers the runtime’s own Tailwind source. Drop it and the deck renders unstyled. deckard doctor checks for it by name.
Package managers
bun, npm, pnpm, and yarn all work. Pass --package-manager <name> to deckard init, or let it use the one that invoked it.
A generated deck carries no packageManager field. Corepack reads that field as an enforcement lock, so writing it would refuse every other manager afterwards. Later deckard commands read the lockfile instead, walking up from the deck directory: pnpm-lock.yaml, bun.lock, bun.lockb, yarn.lock, package-lock.json.
That detection is what fills in the commands the CLI prints. A missing Chromium tells a pnpm deck to run pnpm exec playwright install chromium and an npm deck to run npm exec -- playwright install chromium.
init is covered by an automated smoke test on pnpm and npm. Yarn and bun are supported in the code and are not covered by that test.
Chromium
Four commands drive a real browser, so they need the Playwright Chromium binary on the machine:
Playwright and pdf-lib are dev dependencies of the deck, not of the CLI. deckard init writes both into the generated package.json, and the four commands above load them from the deck’s own node_modules. A deck built by hand adds them itself:
pnpm add -D playwright pdf-lib
The browser binary is a separate download on top of the package:
pnpm exec playwright install chromium
Without the package those four commands fail naming it and printing the install line; without the binary they fail with Failed to launch Chromium and the download line for your package manager. deckard doctor reports both packages under tooling. Nothing else in the CLI needs a browser: init, validate, doctor, add, and eject do not, and npx @thebuilder/deckard-cli init downloads neither.
check-overflow, screenshots, and export pdf also run next build and next start before they capture, so they need a machine that can build and serve the deck. contact-sheet needs the browser but neither the build nor the server, because it composes PNGs that screenshots already wrote.
Browsers for a presented deck
The runtime is tested on Chromium, Firefox, and WebKit. Those three are what pnpm test runs the browser suite against, and they are the closest thing to a support matrix the repository states.
There is no browserslist in the repository and no configured build target, so the shipped bundle takes Next 16’s defaults. That means there is no minimum browser version to quote here.
What the deck uses that a browser has to support:
oklch()colours andcolor-mix(), in the token contract and every theme- Tailwind v4 cascade layers
svhunits for the shell heightResizeObserver, for measuring the canvas fitBroadcastChannel, for presenter sync- The
inertattribute, on unrevealed step content
ResizeObserver is used without a fallback, so a browser without it will not scale the canvas. BroadcastChannel is checked before use: a browser without it runs the deck normally and the presenter window never syncs.
The canvas scale is measured in JavaScript and published as --deckard-scale rather than divided in CSS, because Firefox before 155 has no typed CSS arithmetic. That is the one engine difference the runtime works around by design.
Edge runtime
Not established, and nothing in the repository claims it either way. There is no export const runtime anywhere, no middleware, and no test that runs a deck on Edge.
What is true: the route adapters in @thebuilder/deckard-core/next import no Node APIs, and the slide route reads nothing from the request. @thebuilder/deckard-core/code-block is the part to check first if you try it, because shiki loads a WebAssembly regex engine there.
Treat Edge as untested rather than as supported or unsupported.
Static export
output: "export" works, with two changes to the app.
Force the sitemap static
Without this the build fails with export const dynamic = "force-static"/export const revalidate not configured on route "/sitemap.xml" with "output: export".
import { createDeckSitemap } from "@thebuilder/deckard-core/next"
import { deck } from "@/deck/deck"
export const dynamic = "force-static"
export default createDeckSitemap(deck)Turn off image optimization
The media blocks use next/image. Left alone, the export emits /_next/image?... URLs, which need the optimizer a static host does not run, so every image 404s.
const nextConfig: NextConfig = {
images: { unoptimized: true },
output: "export",
}Every slide, the presenter page, and the sitemap prerender. One thing changes: / becomes a page that redirects to the first slide once it loads in the browser, rather than a server 307.
The capture commands do not work against a static export. They run next start, which output: "export" disables. Build twice, or run the captures before you switch the config.
Deploying covers the rest of getting a built deck in front of an audience.