Skip to content
Deckard
Esc
navigateopen⌘Jpreview
On this page

The canvas

Every slide is authored in one fixed 1920x1080 coordinate space. What that buys, what it costs, and how to handle content that does not fit.

Every slide is authored in one fixed coordinate space, 1920x1080 by default. SlideViewport measures the browser window, scales the canvas to fit, and centers it. SlideCanvas holds the header, footer, background, and slide body inside that space.

A slide looks the same on a laptop, a projector, a phone, and in the PDF. Only the scale changes.

Why fixed

A presentation is shown once, at one size, to a room. Responsive layout inside a slide makes every venue a layout you did not rehearse.

The fit is measured in the browser and published as --deckard-scale. Slide content stays server rendered, and the canvas stays hidden until the first measurement lands, so it never flashes at the wrong size.

Configuring it

canvas: {
  mode: "fixed",
  width: 1920,
  height: 1080,
  fit: "contain",
  margin: 0,
}

margin is the gap in browser pixels between the canvas and the window edge. At the default 0, a window with the canvas aspect ratio shows the canvas edge to edge. Raise it if a deck wants the canvas to float inside the window.

Content spacing is a slide concern, not a canvas one: the default frame keeps slide bodies off the canvas edges, and layout: "fullscreen" hands the whole canvas to the slide so media can bleed to every edge.

resolveCanvas throws when width or height is not a positive number, or when margin is negative.

No viewport units, no breakpoints

Size slide content against the canvas, with h-full, percentages, and fixed values.

The same goes for colors and type sizes. Style with semantic tokens (bg-card, text-muted-foreground, border-border) or slide tokens (--slide-title-size, --slide-code-size, --slide-surface), never a hardcoded color and never a raw font size where a token exists. Changing how something looks is a theme.css edit, not a component edit. See the token contract.

Outside the canvas the rules invert: the deck controls, command center, presenter console, and dialogs keep the app tokens from app/globals.css, so they stay readable whatever the deck looks like.

Overflow

A slide loses content three ways, and only one of them reaches the canvas edge. Content can run past the canvas, it can sit inside the canvas and run under the header or the footer, and it can be cut off inside a box that hides its own overflow. All three are silent, and all three are measured:

Development

next dev draws an amber outline around the slide and logs a warning naming the part, what it ran into, and by how many canvas pixels.

The overflow check

deckard check-overflow builds the deck, opens every slide, and exits non-zero with the same findings. It runs the same measurement the amber ring does, so the gate and the browser cannot disagree.

The contact sheet

deckard screenshots then deckard contact-sheet puts the whole deck in one grid. It catches the slide that fits but looks unfinished.

Two things are exempt, because in both the content is meant to leave its box: anything inside a SlideScrollArea, and a slide whose layout is "fullscreen", which is handed the whole canvas with the chrome out of the way.

The usual fix is deleting a sentence.

SlideScrollArea

When content genuinely has to scroll, wrap it. SlideScrollArea keeps wheel, touch, and key scrolling inside itself, so scrolling never steps the deck:

import { SlideScrollArea } from "@thebuilder/deckard-core/components"

<SlideScrollArea label="Full config" maxHeight={360}>
  <ConfigTable />
</SlideScrollArea>
Prop Type Notes
label string Required. Names the scrollable region for assistive tech.
maxHeight number Height cap in canvas pixels.
className string Applied to the scroll container.
children ReactNode Required.

CodeBlock takes its own optional maxHeight and uses it for long samples.

Where the chrome lives

Chrome splits in two.

Inside the canvas sit the deck header and footer. They scale with the deck, print into the PDF export, show up in a presenter preview, and belong to the theme.

Outside the canvas sit the deck controls: the command center trigger, the presenter popout, the color mode toggle, and compact previous and next buttons. They keep their own size and hit targets at any scale, down to a phone.

--slide-header-space and --slide-footer-space decide how much of the canvas the chrome gets; the token reference carries their defaults. The frame reserves them as padding, and a fullscreen slide republishes them as --slide-chrome-top and --slide-chrome-bottom, the inset a bleeding layout has to clear. A theme that redesigns the chrome to a different height sets those two and the slide content moves with it. phosphor does exactly that for its thinner status bar.

Was this page helpful?