Presentation as Code: Why I Built Slaide
Presentation as code means a slide deck is a plain-text file an AI can write correctly. Here's what breaks in other formats, and what .slaide does about it.
Presentation as code means writing a slide deck the same way you write software: a plain-text file that lives in version control, that a diff can show you, and that a program, including an AI model, can generate and edit directly, instead of a binary file only a GUI can open.
I did not set out to coin a phrase. I set out to stop watching a model fail at the same three things every time I asked it to write a deck.
What breaks when an AI writes slides in something that is not really text
“Markdown-based” is not the same claim as “safe for a model to write blind.” A .pptx file is OOXML wrapped in a zip, and no model should be patching that unsupervised. But even a Markdown slide format can fail an agent quietly, because Markdown alone does not tell you where content is allowed to go or what happens when it goes somewhere it shouldn’t. Two failure modes show up constantly, and they are worth naming exactly because they are so easy to miss until the deck is on screen.
Invisible text. A slide’s background and its text color are set independently. If a layout’s background is dark and nothing tells the text to flip light, you get dark text on a dark background: technically valid, completely unreadable, and a model has no way to notice by reading its own source. This is not hypothetical - it is the single most common way a generated deck looks fine in the diff and broken on screen.
Content that silently collapses. Put a chart in a row sized auto instead of one sized to actually take space, and the chart shrinks to nothing with no error. The Markdown was correct. The chart tag was correct. The row height was one YAML value away from wrong, and there was no signal anywhere in the text that would tell a model, or a person skimming a diff, that it had happened.
Ambiguous structure. A slide format built on plain Markdown still has to decide, line by line, what counts as configuration and what counts as content the audience sees. Get that wrong and a model either eats a line of body text as if it were a setting, or writes a setting that renders on screen as a literal string. It is a small thing until it happens on the one slide you didn’t proofread.
Neither of these is a Slaide-specific problem. They are what happens whenever a format lets you describe layout and content in the same breath without a way to check the result. A model that has never seen your rendered slide will make all three mistakes with total confidence, because nothing in the source told it not to.
What the .slaide format does about it
A .slaide file separates concerns on purpose. Content is Markdown, routed into named regions with a plain marker:
layout: two-cols
---
:: title ::
## Input vs. output
:: left ::
**You write this**
:: right ::
**Your audience sees**
The layout, the fonts, the colors, and the contrast rules live in a separate YAML file called a master, referenced once from the deck’s headmatter. The model never touches raw CSS or absolute pixel positions. It picks a named layout and a named slot, and the master decides what that actually looks like. That alone removes an entire category of mistakes, because there is no coordinate for a model to get wrong.
The structure question gets a fixed rule instead of a guess. A block after a slide separator is that slide’s frontmatter only if every line in it is key: value and it ends with another --- before the body starts. Anything else, including a body line that happens to contain a colon, like “We offer: Tooling,” is just body text. When a line is genuinely ambiguous, an empty frontmatter block (--- then ---) forces what follows to be read as body, so there is always a way to be explicit instead of hoping the parser guesses right. A model does not need to infer the rule from examples, it is one paragraph in the language reference.
Then there is slaide validate --strict, which exists specifically to catch the failure modes above before a human ever sees them. Unknown layout, slot, class, or gradient names get flagged with line numbers. The dark-background problem is caught by name: the compiler warns low-contrast when resolved text color is too close to its background, which is exactly what an unvalidated model-written deck produces when it forgets to bind a light variant to a dark layout.
Validation alone still is not enough, because a deck can pass every structural check and still look wrong: text that overflows its box, an image that crops badly, a slide that is technically valid and visually cramped. That is what the render-and-look-back step is for. slaide shoot --montage renders every slide to one small image, and the agent reads that image back the same way you would glance at a printed deck before a meeting. It is the difference between a spell-checker and someone actually looking at the page. This is what the Slaide Agent Skill automates end to end: write the source, validate it, render a montage, read the montage, fix what’s wrong, repeat until it holds together, then export.
The honest limit
None of this makes a heavily art-directed deck immune to drift. If you hand-place decorative elements or build custom animation, that does not survive a .pptx round trip intact - the export flattens what it cannot faithfully reproduce as real PowerPoint shapes. Presentation as code is strongest when the deck is mostly structured content: a talk, a report, an investor pitch, a status update. It is not aimed at someone building a bespoke, pixel-perfect keynote from scratch, and I would not try to convince that person otherwise.
Code review never made it to slides
Every other artifact a team produces went through this same shift years ago. Configuration became files instead of a GUI you clicked through. Infrastructure became a file instead of a console you remembered how to use. The one artifact that never made the jump was the deck, because a deck felt like a design object first and a document second, and design objects get exported to a binary and handed around. That is also exactly why nobody could review a deck properly: you can attach a .pptx to a pull request, but nobody can see what changed between revision four and revision five, so nobody actually reviews it. A three-line change to the pricing slide and a full rewrite of the deck look identical in a file listing.
Why the export matters as much as the input
A text format that only a developer can use is not presentation as code, it is just a developer tool with slides attached. The other half of the idea is that the deck still has to leave the terminal. .slaide renders to a web deck and a PDF, and it exports to a real .pptx: actual text boxes, actual shapes, editable in PowerPoint by someone who has never heard of Slaide and never will. Import runs the other way too, so an existing deck can enter the text world instead of staying locked in a binary one. The point was never to make everyone write YAML. It was to make the file honest enough that a diff means something, a git blame means something, and a model can write the next revision without guessing.
That is the whole idea behind Slaide: treat a presentation the way you would treat any other artifact worth reviewing. Plain text in, a deck that renders correctly out, and a format an agent can actually get right on the first pass. Read the language reference if you want the whole grammar, or the agent skill page for how the self-check loop is wired up.