# Slides docs

> Install @texuli/slides and @texuli/deck, parse a deck, present it, print it. In development.

Language: en
Canonical: https://texuli.com/guides/solutions/slides/
Markdown: https://texuli.com/guides/solutions/slides.md (this page). Every texuli.com page has a Markdown twin at its URL plus `.md` (the home page is https://texuli.com/index.md), and any page URL answers `Accept: text/markdown` with its twin instead of HTML.
Last Updated: 2026-11-13

---

Guides

Install @texuli/slides and @texuli/deck, parse a deck, present it, print it. In development.

[Back to overview](https://texuli.com/solutions/slides/)

## What Slides is

Slides is a complete present-a-deck system: `@texuli/deck` holds the framework-free model v2, JSON and Markdown codecs, navigation engine and templates; `@texuli/slides` is the Svelte 5 stage on top of it (layouts, presenter, print and PPTX). Both packages are published as `0.18.0` and are **in development** (pre-1.0). Pin the exact version or use `^0.17.0`.

The live demo on this site is on the Slides landing, `/solutions/slides/`. The technical docs you are reading live at `/guides/solutions/slides/`.

## What you get

- A validated deck as data (`formatVersion: 2`), not HTML.
- JSON or Markdown in, the same model out.
- A stage that scales a fixed canvas, follows `#/<slide>/<step>`, and takes keyboard and touch.
- 21 layouts, 13 background presets with a 4.5:1 text scrim, fragments, presenter view, print-to-PDF and local PPTX.

There is no hosted editor and no deck storage. The host app keeps the data.

## Install

Svelte 5 (`^5.57.2`) is a peer of `@texuli/slides`. `@texuli/deck` has no runtime or peer dependencies.

```
npm install @texuli/slides @texuli/deck svelte
```

Import the stylesheet once:

```
import '@texuli/slides/styles.css';
```

## A JSON deck on the stage

`DeckStage` validates before it paints and shows diagnostics instead of a broken slide. The default trust tier is `untrusted`.

```
<script lang="ts">
  import '@texuli/slides/styles.css';
  import { DeckStage } from '@texuli/slides/stage';

  const deck = {
    formatVersion: 2,
    meta: { title: 'Quarterly update', locale: 'en' },
    style: { theme: 'ocean', transition: 'slide' },
    slides: [
      {
        id: 'opening',
        layout: 'title-hero',
        props: { title: 'Quarterly update', subtitle: 'Fictional numbers for Northwind' },
      },
    ],
  };
</script>

<DeckStage {deck} />
```

## Parse first

`parseDeck` never throws. It reports every issue at once, each with a code, a JSON path and a fix.

```
import { parseDeck } from '@texuli/deck/model';
import { formatDiagnostic } from '@texuli/deck/schema';

const result = parseDeck({
  formatVersion: 2,
  meta: { title: 'Quarterly review', locale: 'en' },
  slides: [{ id: 'opening', layout: 'title-hero', props: { title: 'Quarterly review' } }],
});

if (result.ok) {
  console.log(result.deck.slides.length);
} else {
  for (const issue of result.issues) console.log(formatDiagnostic(issue));
}
```

## Model v2

The canonical document is data: `formatVersion`, `meta`, `style`, optional `navigation` and `outline`, and `slides`. Everything in `@texuli/deck/model` is a pure function. Untrusted input goes through `loadUntrustedDeck`, which bounds bytes, depth and nodes, migrates earlier shapes, then validates.

```
import { loadUntrustedDeck, migrateDeck, parseDeck } from '@texuli/deck/model';
```

A slide names a `layout` and `props` for that layout, or `blocks` on the `free` layout. Fragments and steps live on the model; the stage only paints them.

## Markdown dialect

`parseDeckMarkdown` from `@texuli/deck/markdown` reads the same model. `---` separates slides. `Note:` starts speaker notes. Pass `validateDeckBlock` from the stage so block bodies use the stage's checks. Raw HTML, iframes, `class`, `style` and event handlers are refused. The dialect is inspired by reveal.js Markdown and is not compatible with it.

```
<script lang="ts">
  import { parseDeckMarkdown } from '@texuli/deck/markdown';
  import { DeckStage, validateDeckBlock } from '@texuli/slides/stage';

  const result = parseDeckMarkdown(source, { validateBlock: validateDeckBlock });
</script>
```

## Engine

`createDeckController` in `@texuli/deck/engine` is the framework-free runtime: navigation, hash routes, the controls registry, canvas fit, auto-slide and the presenter protocol. It does not touch `window` or `document`.

```
import { createDeckController } from '@texuli/deck/engine';

const controller = createDeckController(deck);
controller.next();
controller.goTo('closing');
controller.getState();
```

## Stage

`DeckStage` from `@texuli/slides/stage` is the Svelte 5 presenter. Import `@texuli/slides/styles.css` once. Hosts that bring every renderer use `DeckStageCore` from `@texuli/slides/stage-core` so the build emits none of the default chunks.

The canvas is 1280 × 720 for 16:9 (also 4:3, 9:16 and 1:1) and scales into the host. Hash routes are `#/<slide>/<step>`. Only one stage on a page owns the hash.

## Layouts

Twenty-one layouts ship in `@texuli/slides/layouts`: title hero, section divider, splits, cards, media, quote, code, big stat, table, process, timeline, team, closing call to action, chart, and free blocks. Backgrounds are 13 presets, hex, gradients, image or video, with a scrim that keeps slide text at 4.5:1.

Any slide-renderable catalog component can sit on a slide, loaded lazily, at the host's trust tier (`@texuli/slides/components`).

## Print and PPTX

`@texuli/slides/export` prints one page per visible slide (the browser saves PDF) and writes a local, deterministic PPTX: text and tables as editable PowerPoint, images and charts as pictures the host supplies, plus a report of what it leaves out. There is no server-side PDF renderer.

## Keyboard and input

Keys, a click on the slide, touch swipes and the toolbar run the same engine actions. Vertical stacks walk steps, then the stack, then the next slide. The overview is a thumbnail grid by keyboard or pointer. Focus after a keyboard move waits for the incoming slide.

## Motion and contrast

Transitions (`none`, `fade`, `fade-up`, `slide`, `zoom`, `morph`) cut or fade under `prefers-reduced-motion`. Background scrims keep text at least 4.5:1. Stage styles include reduced-motion and forced-colors rules.

The keyboard map, reflow at 320px and screen-reader notes live with the package stage docs and the recorded slides accessibility transcripts.

## Status

Slides is **in development**. `@texuli/slides` and `@texuli/deck` are on npm as `0.18.0`. Under 0.x a new minor may break. Native rendering is planned, not built.

## Not built

- A presenter screen on another device
- A server-side PDF or image renderer
- Deck video export
- Inline `$…$` math inside text blocks
- A hosted editor or deck storage (the host keeps the data)

Model v1 decks still parse; `migrateDeck` and the stage migrate them. `@texuli/slides@0.3.0` is the previous stage. The upgrade path is in the package migration guide.

## Untrusted decks

A deck from an agent, a paste or a share link is untrusted data. Use `loadUntrustedDeck` from `@texuli/deck/model` before any deep work. `DeckStage` validates at the `untrusted` tier by default, so an agent-written deck is safe to pass as data. There is no HTML sink: the stage paints the model.

## Markdown and JSON

Agents can emit JSON (`formatVersion: 2`) or the closed Markdown dialect. `parseDeck` and `parseDeckMarkdown` return diagnostics instead of throwing. Hostile HTML in Markdown is refused.

The catalog can describe slide-renderable components; the stage loads only those renderers. Do not invent APIs or a hosted generation service. The live generation page on this site is a recorded replay, not a deployed agent.
