Beem Slide

Slide module exports

Everything the runtime reads from a slides/<id>/index.tsx.

slides/<id>/index.tsx
import type { DesignSystem, Page, SlideMeta, SlideTransition } from '@beem-slide/core';

const Cover: Page = () => <div>{/* … */}</div>;
const Agenda: Page = () => <div>{/* … */}</div>;

export const design: DesignSystem = {
  palette: { bg: '#101014', text: '#f4f2ee', accent: '#d56b48' },
  fonts: { display: 'Georgia, serif', body: 'system-ui, sans-serif' },
  typeScale: { hero: 168, body: 36 },
  radius: 6,
};

export const meta: SlideMeta = {
  title: 'Q2 launch',
  createdAt: '2026-08-20T09:00:00Z',
  theme: 'ink-and-rule',
};

export const notes = ['Open with the analyst quote.', undefined];

export const transition: SlideTransition = {
  duration: 480,
  enter: { keyframes: { opacity: [0, 1] } },
};

export default [Cover, Agenda] satisfies Page[];

default — required

An array of components in display order. Non-empty; anything else is not a deck.

type Page = ComponentType & { transition?: SlideTransition };

Components take no props. Each fills its container, and the runtime renders one at a time onto the 1920 × 1080 canvas.

meta

type SlideMeta = {
  /** Deck title, shown in the deck list and the header. Defaults to the directory name. */
  title?: string;
  /** Theme id — the file name under themes/ without its extension. */
  theme?: string;
  /** ISO 8601 timestamp, used to sort the deck list newest-first. */
  createdAt?: string;
};

theme is a theme id, not a light/dark switch: 'ink-and-rule' points at themes/ink-and-rule.md. Setting it puts a chip on the deck's card and lists the deck under "used by" on that theme's page.

theme and createdAt must be plain string literals. Both are read by a regex at build time rather than by evaluating the module, so a computed value — new Date().toISOString(), a constant imported from elsewhere — reads as absent.

design

Typed tokens the runtime turns into CSS variables at the canvas root, and the Design panel edits live. Must be a literal object — no spreads, no helper calls — because the panel writes back to it through the AST. See Themes.

notes

Speaker notes, as an array aligned index-for-index with the page array. Use undefined for a page with no note.

export const notes: (string | undefined)[] = [
  'Open with the analyst quote.',
  undefined,
  'Pause here for questions.',
];

The dev server reads notes from slides/<id>/notes.json instead, which is what the in-app notes editor writes. This export is what a static build falls back to. See Present mode.

transition

One transition for the whole deck. A single page can override it by assigning transition to the component itself, which takes precedence over the module's.

What you can import

import {
  CANVAS_WIDTH,        // 1920
  CANVAS_HEIGHT,       // 1080
  ImagePlaceholder,    // see /docs/reference/image-placeholder
  useSlidePageNumber,  // { current, total } — for a footer or folio
} from '@beem-slide/core';

import type {
  Page,
  SlideMeta,
  SlideModule,
  SlideTransition,
  DesignSystem,
  ImagePlaceholderProps,
} from '@beem-slide/core';

On this page