@taylordb/deck
v0.1.0
Published
React presentation runtime for TaylorDB apps: a fixed 1920x1080 canvas scaled to fit, click-steps derived from what is on screen, a themed primitive set, an overflow probe that reports broken slides as text, and a PDF exporter.
Readme
@taylordb/deck
A React presentation runtime on a fixed 1920×1080 canvas, scaled to fit whatever screen it plays on.
It is the runtime, the theme and the tooling — not your slides. Layouts are the
part of a deck that changes per deck, so they stay in your app and reach the
runtime through one renderSlide prop.
pnpm add @taylordb/deckimport '@taylordb/deck/styles.css'
import { Deck } from '@taylordb/deck'
;<Deck
deck={deck}
renderSlide={(slide) => <SlideRenderer data={slide} />}
warnOnOverflow={import.meta.env.DEV}
/>What it gives you
A canvas that cannot reflow. Author in absolute pixels; the stage is scaled and centred. There are no breakpoints, so a slide cannot look different on someone else's screen — it can only be too small to read, which is a decision, not a surprise.
Click-steps that count themselves. A step exists because a <Reveal at={n}>
is mounted. Nothing declares a count and nothing can fall out of sync with one,
so a CMS editor adding a bullet adds a click.
An overflow probe. A fixed canvas has no give: a headline three words too
long is a broken slide, and it still renders. The probe measures every element
against the slide's safe area and names the offenders — as text for
taylor-deck check in CI, and as a red border live while somebody types.
A theme, not a straitjacket. Warm paper, ink text, one accent, a serif for
display type. Every value is a CSS custom property in styles.css; redefine
what you like after importing it. The primitives are conveniences — a slide is
just a component, and raw JSX is always allowed.
API
| Export | |
| ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| Deck | The runtime. deck, renderSlide, and optionally tinaField, insetRight, warnOnOverflow, emptyLabel. |
| Reveal / Stagger | Click-driven reveals. <Reveal at={2}>; delay staggers siblings within one step. |
| useDeck / useStep / useTinaField | Runtime state inside a slide. |
| SlideFrame / SlideHeader / Title / Kicker / Subtitle / Body / Bullets / TwoCol / Grid / Card / Stat / Quote / Spacer | Themed primitives. |
| Rich | Renders *emphasis* as accented italic. Already applied inside the type primitives. |
| Rings / Ruled / Photo | Full-bleed slide backgrounds. |
| normalizeDeck / useEditorInset | In-page CMS glue. Neither imports a CMS. |
| measureOverflow / useOverflowProbe | The probe, if you want to drive it yourself. |
| present | Drops nulls from a CMS list. |
Two things to get right
warnOnOverflow must not reach a presented deck. Pass your bundler's dev
flag. The runtime deliberately does not sniff one: import.meta.env.DEV is
undefined outside Vite, which reads as not production and would paint a red
border across a slide in front of an audience.
Mark full-bleed decoration data-bleed. It tells the probe that leaving
the safe area is the point, and — just as important — excludes the subtree from
the probe's mutation watch. Anything animating every frame inside the measured
tree writes style continuously and postpones the measurement indefinitely.
taylor-deck
taylor-deck check render every slide headless and fail on overflow
taylor-deck export write export/slides.pdf plus per-slide PNGs at 2xBoth boot your deck through your own Vite config, so what they measure is
what vite build would ship — and both render ?export=1, which is your
app's signal to show the deck as committed, never whatever a CMS editor has
open. A check that measured unsaved content would pass or fail for reasons that
are not in the repository.
vite and playwright-chromium are optional peers, resolved from your project
rather than from beside the CLI. Install the browser once:
pnpm add -D playwright-chromium && pnpm exec playwright install chromiumDeveloping against a local checkout
If you link: this package, add its peers to your app's Vite resolve.dedupe
(react, react-dom, motion). A linked package resolves import 'react'
against its node_modules, your app ends up with two Reacts, and every hook
in the runtime throws.
