# Sandbox

> What a MakoDeck deck can and can't do in the browser, and the practical alternative for each thing it can't.

Every deck runs in a sandboxed frame on a separate site, with no network beyond its own files. It can load its own files (and the site's libraries and fonts), run scripts — inline ones, `eval` and WebAssembly included — and nothing from anywhere else. Viewers, the presenter window, the audience window, thumbnails and the PDF each run their own copy.

## Works

| Feature | Notes |
|---|---|
| Scripts, styles, images, fonts, media, `fetch` | From the deck's own files, by relative path. |
| `data:` and `blob:` images, `blob:` media | Also `data:` fonts: the site moves them into files, with a `font_externalized` warning; bundle the font as a file instead. |
| Canvas, SVG, WebGL, WebAssembly | See https://makodeck.com/ai/interactive.md for WebGL in thumbnails. |
| Web Workers | Only from a `blob:` URL, and still flagged at upload; prefer `requestAnimationFrame` chunks. |
| `<iframe srcdoc="…">` | Up to 4 levels deep; each is a document with the same rules. |
| `localStorage`, `sessionStorage` | In memory only: emptied every time the deck loads. |
| `BroadcastChannel` | Within the one page only. |
| Links to other sites (`https:`, `http:`, `mailto:`, `tel:`) | Open in a new tab once the person confirms ("Open a link from this presentation?"; for `mailto:`, "Write an email from this presentation?"; for `tel:`, "Call this number from this presentation?"). A `tel:` link must be a plain number — digits, an optional leading `+`, and `-`, `.`, `(`, `)` or spaces between them (`tel:+1 (936) 330-6597`), 3 to 15 digits — and is called as its digits alone; letters, `*`, `#`, `;ext=` or anything else, and the link does nothing. |
| Keys and clicks | All but a plain `f`/`F` outside form fields, which the site keeps for fullscreen. |

## Doesn't work — do this instead

| Blocked | Instead |
|---|---|
| Anything from another site: CDN scripts and `import`s, stylesheets, images, fonts, API calls, analytics | Download it into the deck folder and use a relative path (check the licence). Chart.js, D3, Tailwind and others are supplied at `_mako/lib/`, and a classic `<script>` asking jsDelivr or unpkg for D3, Chart.js, roughjs or Tailwind at the site's major version (cdnjs too for D3 and Chart.js), or Tailwind 3's Play CDN, gets the site's copy by itself (https://makodeck.com/ai/interactive.md); Google Fonts families by name (https://makodeck.com/ai/brand-and-design.md). |
| Live data | Freeze a snapshot in `data/*.json` or `data/*.csv`, and put its date in `dataAsOf` (https://makodeck.com/ai/format.md). |
| Embedding a web page, video site or map (`<iframe src>`, `<object>`, `<embed>`) | Put the content on the slide: a screenshot, a bundled video, an SVG map, a chart — with a plain link to the original. |
| Links to another HTML file of the deck | Keep every slide in `index.html`. The site stops a deck that navigates its frame ("This presentation tried to leave its frame"). |
| `location.hash = …` or `href="#…"` to move between slides | Leave moving to MakoDeck; code that must move a slide (an agenda button) marks it `is-active` (https://makodeck.com/ai/format.md). |
| Submitting forms | Use inputs and buttons marked `data-interactive` with script, and `Mako.share` to mirror them to the audience (https://makodeck.com/ai/interactive.md). |
| Pop-ups (`window.open` returns `null`), `alert`, `confirm`, `prompt`, `print()` | Show messages on the slide. The site has its own print (the PDF download). |
| `<a download>` and saving files | `Mako.requestDownload` for files the author attached (https://makodeck.com/ai/interactive.md). |
| Fullscreen, clipboard | The site has fullscreen (`f`). Show text on the slide to copy. |
| Cookies, IndexedDB, Cache API (they throw), lasting storage | Keep state in memory, or in the in-memory `localStorage`. |
| Service workers, workers from a file URL | Workers from `blob:` URLs, or plain `requestAnimationFrame` chunks. |
| Camera, microphone, location, USB, payments | Not available to decks. |

## Timing

The site gives a deck about 3 seconds after it loads to start. Don't block the main thread at load, don't throw before the slides exist, and don't wait on anything to show the first slide — or the viewer shows "This presentation didn’t start."
