Slide HTML Authoring
Rules and conventions for writing slides as self-contained HTML.
Each slide in an AuraDeck deck is a self-contained HTML document rendered in an iframe. There is no shared JS runtime between slides, no template engine, no Markdown layer — just HTML, CSS, and JavaScript.
Requirements
A valid slide must:
- Be a complete HTML document with
<!DOCTYPE html>,<html>,<head>, and<body>. - Inline all CSS in
<style>tags inside<head>— no external stylesheets. - Inline all JavaScript in
<script>tags — no external scripts. - Reference images using the
./images/filename.extconvention so AuraDeck can inline them at present time.
That is the entire spec. Everything else is convention.
Conventions
These are not enforced by AuraDeck but make slides behave consistently:
Reset and box model
Start every slide with a tight reset:
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; }
overflow: hidden matters — without it, slides that overflow the viewport will scroll, which looks broken in a presentation.
Use viewport units
Sizing in vw, vh, vmin, and vmax lets slides scale naturally to any display:
h1 { font-size: 8vmin; }
.padding { padding: 4vw 6vw; }
Avoid pixel values for typography and layout — they will look tiny on a 4K projector and oversized on a 1024×768 conference-room display.
Pick a font you can rely on
The system stack works on every platform without bundling:
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
If you want a custom font, embed it as a base64 @font-face declaration in the same <style> block. Network @font-face works in the editor and viewer but does not survive PDF/PPTX export because html2canvas runs before async font loads complete.
Minimal slide
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My Slide</title>
<style>
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; }
.slide {
width: 100vw; height: 100vh; overflow: hidden;
font-family: system-ui, sans-serif;
display: flex; align-items: center; justify-content: center;
background: #0a1628; color: #fff;
}
h1 { font-size: 8vmin; }
</style>
</head>
<body>
<div class="slide">
<h1>Hello World</h1>
</div>
</body>
</html>
Animations
CSS animations and JavaScript run when the slide is displayed — use this for entrance effects:
<style>
@keyframes fadein { from { opacity: 0; transform: translateY(2vh); } to { opacity: 1; } }
.slide h1 { animation: fadein 0.6s ease-out 0.1s both; }
</style>
Each slide has its own DOM, so animations re-run every time you navigate to that slide — there is no need to reset state manually.
Interactive content
The full power of HTML/CSS/JS is available: Canvas, SVG, WebGL, embedded videos, chart libraries, anything. A few patterns work especially well:
- Live-coded examples — embed CodeMirror or a
<textarea>and a result<iframe>to demo something interactively. - Animated diagrams — drive an SVG with a JavaScript
requestAnimationFrameloop. - Self-running demos — start a
setIntervalon slide load to advance through scripted states.
JS errors are silent in the viewer
A slide that throws a JavaScript error during load will simply render whatever it managed to render before the error. Test in tauri dev (right-click → Inspect) to see the actual stack trace.
What does not work
- Cross-slide state — every slide is a fresh iframe; you cannot share variables across slides.
- Top-level navigation —
window.locationchanges inside a slide are blocked. - Persistent storage —
localStoragewrites inside a slide are scoped to that iframe and reset on reload.
If you need any of these, do it from the AuraDeck app shell, not from inside slide HTML.