A master is a YAML file. It defines the whole look as data. So one theme serves many decks, and an AI can both use it and write it. Reference it from a deck with master: ./your-theme.slaide.yaml. Omit it to use the bundled aurora theme.
Top-level shape
schema: slaide/1
name: my-theme
canvas: { aspect: "16:9", width: 1920, height: 1080 } # fixed design space, scaled to fit
fonts: { … } # named font roles, auto-imported from Google
typeScale: { … } # named size steps
colors: { palette, roles }
gradients: { … } # named CSS gradients for .grad text and slot fills
tokens: { … } # raw CSS variable overrides for spacing, code, and charts
backgrounds:{ … } # named background layers
variants: { … } # named scoped overrides
transitions:{ default, duration }
chrome: { header, footer, logo, logoPos }
ui: { progress } # web position bar, default on
layouts: { … } # grid templates with typed slots
Sizes are in canvas px. The runtime scales the whole slide with one transform to fit any screen. Match your source design, like 1920x1080, so px equals design pt.
Fonts and type scale
Use real Google Fonts only, with provider: google. Pick families that actually exist on Google Fonts. A display role for headings plus a sans role for body is usually enough. Add a mono role only if the deck shows code.
A font that is not a common system font and is not on Google Fonts will warn (non-embeddable-font). It will not embed in the .pptx, so PowerPoint substitutes it off the viewer’s machine.
fonts:
sans: { family: "Inter", provider: google, weights: [400, 600, 700] }
display: { family: "Fraunces", provider: google, weights: [600, 900] }
typeScale:
base: "26px"
ratio: 1.2
steps: { stat: "104px", hero: "82px", h1: "66px", h2: "44px", h3: "34px",
h4: "28px", body: "26px", caption: "21px", small: "18px" }
A step is an explicit size string like "72px", which is recommended. Or it is an integer exponent on the scale (base x ratio^step). The names body, caption, small, and h1…h4 also size Markdown text and headings.
Colors and gradients
There are two tiers. palette holds raw named colors. roles are semantic aliases that point at the palette. Content and layouts reference roles, so a reskin is just a palette swap. Both palette keys and role names work as inline classes.
colors:
palette: { navy: "#0B1220", white: "#F8FAFC", blue: "#5B8CFF", muted: "#8B93A7" }
roles:
background: "{palette.navy}"
text: "{palette.white}"
heading: "{palette.white}"
accent: "{palette.blue}"
muted: "{palette.muted}"
gradients:
brand: "linear-gradient(100deg, #5B8CFF 0%, #A855F7 50%, #2DD4BF 100%)" # .grad uses this
purple: "linear-gradient(120deg, #A855F7, #EC4899)" # .grad-purple
Tokens
Tokens are raw CSS variable overrides for spacing, chrome metrics, code panels, and chart colors. The names are exact. A misspelling is ignored, not warned.
tokens:
"--slide-padding": "96px" # content inset
"--chart-colors": "#5B8CFF, #A855F7, #2DD4BF" # ordered series colors for echart
"--code-bg": "#0E0B07"
"--code-fg": "#FBF7F0"
"--code-inline-bg": "#F0E8D9"
"--code-pad": "1.1em 1.3em" # note: --code-pad, not --code-padding
"--code-radius": "12px"
The --code-* tokens are the only way to style code panels. Set them once and every pre and code block changes.
Backgrounds
Named layers, picked by a layout or a slide. There are three types: solid, gradient (linear only), and image. There is no radial type. For a dark hero glow, point an image background at a small SVG that has a radialGradient inside.
backgrounds:
cover: { type: gradient, stops: ["#0B0B12", "#191933"], angle: 130 }
hero: { type: image, src: "./assets/hero-glow.svg", fit: cover }
plain: { type: solid, color: "{palette.navy}" }
A two-tone split gradient breaks the contrast check. It makes one worst-case background per slide, so text can fail --strict. For a two-tone slide, give each side its own slot surface with box: or bg: instead.
Variants
Scoped overrides, turned on by one word from a slide (variant: light).
variants:
light: { roles: { background: "#EEEFF1", text: "#0B1220", heading: "#0B1220" } }
Chrome
A header band, a footer band, and a corner logo on every slide. Toggle them per layout or per slide. Band cells left, center, and right can hold {{placeholders}}. The logo is inline SVG and inherits the text color through currentColor. logoPos is one of top-left, top-right, bottom-left, bottom-right.
chrome:
header: { right: "{{date}} | © {{company}}" }
footer: { left: "{{footer}}", right: "{{pagePadded}} / {{totalPadded}}" }
logoPos: top-left
logo: '<svg viewBox="0 0 96 40" fill="none" stroke="currentColor" stroke-width="2.1">…</svg>'
Do not put a band corner cell and the logo in the same corner. They overlap with no warning. Use different corners.
Layouts
Grid templates. areas is a grid-template-areas map, one row of slot names per entry. slots are the typed regions content routes into. Options: align (top, center, end), rows, cols, gap, padding, background, variant. Keep areas rectangular, and every slot in slots must appear in areas.
layouts:
statement:
background: navy
variant: dark
align: center
areas: ["title title title", "s1 s2 s3"]
rows: "auto 1fr"
cols: "1fr 1fr 1fr"
gap: "3em"
slots:
title: { type: title, style: { size: h1, weight: "800" } }
s1: { type: body, style: { align: center, valign: center } }
s2: { type: body, style: { align: center, valign: center } }
s3: { type: body, style: { align: center, valign: center } }
Slot type (title, subtitle, body, image, media, quote, caption) gives sensible defaults. style keys fine-tune font, size, color, fill (gradient text), align, valign, weight, leading, transform, maxw, box, and anchor.
Dark sections, read this or you ship invisible text. A layout’s
backgroundand its slots’ text color resolve on their own. Roles default to the light look. So a dark background with default slots renders dark on dark. The fix: bindvariant: darkto the layout, which flips the roles. Or set an explicit lightcolor:on each slot. The compiler warns withlow-contrastwhen text is too close to its background, so--strictcatches it.
aligncenters the whole grid, title and all. To pin the title at the top and center only the body, leave layoutalignunset and putvalign: centeron the content slots in a tall1frrow.
Inline classes
Inline [text]{.class} resolves against the master. Color is any palette or roles name. Gradient is .grad (the brand gradient) or .grad-<name>. Size is .xs .sm .md .lg .xl .xxl .huge, which map to small…stat. Utilities are .bold, .muted, and image classes .round, .cover, .shadow.
Bundled aurora layouts
cover, title-content, section, two-cols, image-right, image-left, content-sidebar, quote, full-bleed, blank.
Tips
- Reference roles and scale steps, not raw hex and px. Then a reskin is one palette swap.
- Give the deck one repeated motif and vary the composition slide to slide.
- A
box:card with novalignstretches to its row and pins text to the top. Addvalign: centerso the card hugs its content. - Add a new layout by adding an
areasmap andslots. No code.