`kind` on `create_presentation` chooses the runtime. It is not inferred from the HTML.

Content runs in a sandboxed iframe: no `localStorage`, no cookies, no top-level navigation.

## Slides (`kind=presentation`)

Each slide is an element with class `slide`. Exactly one also has class `active`. Hide the rest with CSS:

```css
.slide { display: none; }
.slide.active { display: block; }
```

Design each slide to fill a 16:9 frame (rendered at 1280×720 and scaled). Keep content inside that frame so it stays centered.

```html
<section class="slide active" data-notes="Opening remarks.">
  <h1>Hello</h1>
</section>
<section class="slide" data-notes="Main point.">
  <h2>Topic</h2>
</section>
```

Prezzly injects the runtime when it serves the deck. You do not need your own JavaScript for arrow keys. The runtime toggles `active` (keyboard, presenter view, `?slide=N`, thumbnails).

A deck may move `active` with its own ArrowLeft / ArrowRight handler; that is respected.

Optional and harmless:

```html
<script src="https://api.prezzly.ai/runtime/v1/prezzly-present.js"></script>
```

Do not require `prezzly.io` as the runtime host.

## Dashboards (`kind=dashboard`)

Build one vertically scrollable layout, not slides. Mark major sections with `id` or `data-prezzly-section` (fallback: `h1`–`h3`) so section navigation and scroll sync work.

Internal links, buttons, and modals are fine. The same sandbox rules apply.

## Speaker notes

Put notes in `data-notes` on each `.slide`, or set them later with `get_notes` / `set_note` / `set_notes`. UI notes override code notes in presenter view.

## Templates

`list_templates` and `get_template` return your style packs, including `SKILL.md` and a download URL. Build against that skill, then upload with `create_presentation`. Do not list templates as a prerequisite for a first upload unless the user asked for a style.

## Externally built decks

Reveal.js, hand-written HTML, and other 16:9 decks work as-is if one slide element carries `active` and CSS hides the rest. Guest upload from the Prezzly app accepts the same `index.html` or ZIP.

## What the sandbox blocks

Do not rely on `localStorage`, cookies, or navigating the top window. Use in-memory state. Load fonts and images from the deck files or `https` URLs.

If slides do not change, check that exactly one element has both `slide` and `active`. If a dashboard has no section nav, add `id` or `data-prezzly-section` on the major blocks. See [Troubleshooting](/docs/troubleshooting/).