It always starts with: Hey… we need to produce a presentation for .... Thirty minutes before the ... starts 😂
What happens next is a mix of chaos driven development and creative writing under fire: you open PowerPoint, paste the same slide layout you’ve used for three years, copy numbers out of Jira or Grafana or whatever other data source by hand, and wonder why the heck it looks like crap. In the usual cycle those decks are THE MOST HATED part of the job, and unless you’re deeply committed to brand communications you treat them as a necessary evil…
To break that hostage cycle: why not open Copilot Chat, paste a prompt, wait ninety seconds and get a finished deck out of the other end?
Why HTML and not Markdown
The standard Reveal.js setup keeps content in a Markdown file and config in a separate HTML file. Two files to maintain, a build step to run, and agents tend to hallucinate the bridge between them.
One self-contained HTML file avoids all of that. open slides/index.html and the browser renders it, no server, no build. Git diffs it like any other text file. And an agent reading it has the structure and the content in the same context window instead of holding two files in its head at once.
PowerPoint is out for the obvious reason. It’s binary, the agent can’t read it.
How the template is built
The template is a Reveal.js presentation with a custom dark design system: design tokens in CSS custom properties, no hardcoded colours. Every visual component (stat tiles, tables, timelines, progress bars, Mermaid diagrams, Excalidraw embeds) lives in its own labelled CSS block that an agent can find without guessing.
The HTML structure uses <!-- COMPONENT: NAME --> markers throughout:
<!-- COMPONENT: STAT-GRID (4-col) -->
<div class="stat-grid four">
<div class="stat-card">
<div class="big-num green">99.8%</div>
<div class="big-label">uptime last 90 days</div>
</div>
...
</div>
<!-- END COMPONENT: STAT-GRID (4-col) -->
Nobody is meant to read those. They’re a machine-readable table of contents, and the prompt uses exactly the same names (Stat tiles → numbers, KPIs), so the agent can find the right component, copy it, and fill in real data instead of inventing structure.
The prompt embedded as the last slide
So where does the prompt live? Last slide of the deck:
<!-- SLIDE: GENERATE THIS DECK WITH COPILOT -->
<section>
<h2>Generate a deck like this with Copilot</h2>
<div class="prompt-block">
# Analyze this repository and generate a presentation.
# Do NOT invent data - read the codebase, docs, and git history.
Task:
1. Read README.md, architecture docs, and `git log --oneline -30`
2. Identify: purpose, capabilities, status, KPIs, contacts
3. Map content to components:
Flow steps → how-it-works sequences
Stat tiles → numbers, metrics, KPIs
Timeline → roadmap, sprint status
Tables → comparisons, risk registers
Alert boxes → blockers, highlights
4. Generate slides/index.html - replace ALL placeholder content
5. Keep to 8–12 slides. One message per slide. No filler.
Template: https://github.com/your-org/slides-template
</div>
</section>
That placement is the part that makes the whole thing work. When Copilot opens the file it’s about to edit, the instructions for editing it are already in the same buffer. Nobody has to remember to point it at a README first, and there’s no second file to drift out of sync with the first.
The multi-root workspace trick
Open your target repo and the template repo side by side as a VS Code multi-root workspace. Copilot then has both at once: the codebase it’s generating slides about, and the template it’s generating from.
File → Add Folder to Workspace → [select your project]
That’s what makes the “read the codebase, don’t invent data” line mean anything. Without the project in context Copilot just guesses, and it guesses confidently, which is worse. With the repo sitting there it reads git log, the README and the architecture docs and puts real numbers on the slides.
What the agent produces
The prompt maps content types onto components explicitly. That mapping is the part that’s easy to leave out, and leaving it out is why “generate a presentation” prompts come back with generic garbage.
Instead of “make me slides about this project”, the prompt says where things go: stat tiles get the numbers and KPIs, the timeline gets roadmap or migration phases, tables get comparisons and decision matrices, alert boxes get whatever is currently blocked.
Copilot finds each component by its HTML marker, copies the structure, and substitutes real data from the codebase. What comes out looks like the template instead of looking like whatever the model thinks slides should look like.
What still goes wrong: it over-fills. Ask for 8-12 slides and you get 12 where 8 would have been better, every single time, and I haven’t found a prompt line that fixes it. I just delete four slides at the end.
One thing I’d add: run the humanizer skill over the text afterwards. It cuts the ai’isms that anyone working with these models daily spots instantly and genuinely hates. Tune it with samples of your own writing and the deck starts sounding like you rather than like a model.
The numbers
A ten-slide deck out of a real codebase takes 90 to 120 seconds on Opus 4.7. There’s no build step, you open the HTML file in a browser, and there’s one file to maintain with the whole design system inside it. Nothing in it is project-specific either: the prompt reads git log and the README rather than any per-project config, so it works against whatever repo you point it at.
The template ships with 15+ components as working examples: stat grids, tables, progress bars, horizontal bar charts, tier bars, timelines, icon tiles, Mermaid diagrams (git graph, flowchart, sequence, ER, Gantt, pie), Excalidraw/draw.io SVG embeds, Excalifont “back of the envelope” style of writing / styling, code blocks, pull quotes, speaker notes, and incremental reveal fragments.
If you need more advanced charting, pull in a JS charting library from a CDN and tell Copilot how to use it. It’s all one file, so there’s nowhere for any of it to get lost.
The pattern, generalised
The slide template is one instance of something broader: put the agent’s instructions inside the artifact the agent is going to edit. No separate system prompt, no README, no wiki page somebody has to remember to link.
I think the same trick works for PR description templates, runbook stubs, ADR files, sprint review docs, because instructions in a separate file only help if the agent goes and reads that file. But I’ve only actually tried it on slides, so treat the rest as a guess I’d quite like somebody else to test for me.