Themes
A written-down look that any deck can follow, plus the typed tokens the Design panel edits.
Two things in beem-slide go by the name "theme", and they solve different halves of the same problem.
A theme is a file under themes/ describing a look in prose and tables —
the thing an agent reads before it writes, so the deck comes out in your visual
language rather than a default one.
A deck's design export is a small typed object the runtime understands
and the Design panel edits live. It is how a look becomes adjustable after the
deck exists.
You generally want both: the theme decides what the deck should look like, the
design block makes the parts of it the panel can reach tunable.
The typed tokens
import type { DesignSystem, Page } from '@beem-slide/core';
export const design: DesignSystem = {
palette: { bg: '#0b0d10', text: '#f4ecdc', accent: '#d6a64b' },
fonts: {
display: 'Georgia, "Source Serif Pro", serif',
body: 'system-ui, -apple-system, sans-serif',
},
typeScale: { hero: 168, body: 36 },
radius: 4,
};Export it — not just const it — and the framework injects the values as CSS
variables at the canvas root:
--osd-bg, --osd-text, --osd-accent, --osd-font-display,
--osd-font-body, --osd-size-hero, --osd-size-body, --osd-radius.
Read them through var(--osd-…) for anything visual, because those update
while someone drags a slider in the Design panel, before any file is written.
Read design.typeScale.hero directly only when you need the number for
arithmetic — that path updates on the next HMR pass instead.
The shape is deliberately small: it covers exactly what the panel can edit. Everything else — heading sizes, spacing, extra palette entries, motion — stays as plain constants in the deck.
The theme file
A theme is a markdown file with a little frontmatter, and optionally a demo page beside it:
themes/
├── ink-and-rule.md # the look, written down
├── ink-and-rule.demo.tsx # a page rendering it, for the gallery
├── carbon-grid.md
└── carbon-grid.demo.tsxThe frontmatter carries the name, a one-line description and whether the theme is light or dark. The body is yours, but the sections an agent actually uses are palette, typography, layout and voice:
---
name: Ink & Rule
description: Light editorial deck — serif display, hairline rules, one oxblood accent.
mode: light
---
## Palette
| Role | Value | Notes |
| ------ | --------- | --------------------------- |
| bg | `#F7F4ED` | warm paper, never white |
| text | `#17140F` | primary copy |
| accent | `#8C2F26` | oxblood, once per page |
| rule | `#D8D0BE` | every hairline, one weight |
## Typography
- Display: `'Iowan Old Style', Georgia, serif`, weight 400.
- Body: `-apple-system, 'Inter', system-ui, sans-serif`, weight 400.
- Hero 176px / 0.98 / -0.03em · heading 92px serif · body 34px sans.
## Layout
- 130px side padding, left-aligned, body capped at 34ch.
- Every page opens with a folio rule: eyebrow left, page number right.Anything the theme does not mention falls back to the /slide-authoring
defaults, so a theme can be three lines long and still be useful.
The gallery
The dev server has a Themes section. Every themes/<id>.md appears there,
and the <id>.demo.tsx beside it is what gets rendered as the preview — which
is the difference between a theme you can judge and a theme you have to read.
The demo file is optional; a theme without one still works and still gets
picked up.
A deck that follows a theme should say so:
export const meta: SlideMeta = { title: 'Q3 board update', theme: 'ink-and-rule' };That is a plain string literal, read at build time by a regex rather than evaluated. It puts a chip on the deck's card and lists the deck under "used by" on the theme's page, so you can see what a change to the theme would affect.
Getting one
Ask for it by name when you draft:
/create-slide Q3 board update, use the ink-and-rule themeOr work backwards from something you already like — /create-theme will pull
the palette, type stack and layout habits out of an existing deck, a screenshot
or a brand's site, and write the .md and .demo.tsx pair for you.