> ## Documentation Index
> Fetch the complete documentation index at: https://docs.decktalk.app/llms.txt
> Use this file to discover all available pages before exploring further.

# The page contract

> How a DeckTalk page talks to the recorder, with the play modes, the t0=signal handshake, cue ownership, stage design at 1920 by 1080, and the reveal effects.

A DeckTalk page is an HTML file that the recorder can drive from the narration. The
contract consists of a few URL parameters, one Promise, and one global.
`decktalk-runtime.js` implements it, and [a page can implement it by hand](/guides/page-by-hand).
Slides are plain HTML that you style yourself, and the runtime adds no styling beyond
the stage. [The runtime reference](/reference/runtime) lists every parameter, field, and
attribute with its default. This page explains how the pieces fit.

## Modes

A page plays in one of four modes, and `window.__decktalk.mode` says which.

| Mode       | Opened as               | What happens                                                                                                                                                                                                          |
| ---------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `index`    | no query                | A list of every scene and step with play and freeze links.                                                                                                                                                            |
| `autoplay` | `?scene=N`              | The steps mount in order, each holding for `hold` seconds divided by `speed`. Reveals fire at `data-at`, and a step's `cues` object fires handler cues at those seconds after the mount. This is the browser preview. |
| `cues`     | `?scene=N&beats=id@s,…` | The resolved cues drive the page. Each step mounts at its earliest cue, the first cued step at t=0, and the last cued step holds until the recorder stops. A step with no cue never shows. This is the recording.     |
| `frozen`   | `?step=ID`              | One step with every reveal in its end state and its handler cues fired. `decktalk shots` uses it.                                                                                                                     |

In `cues` mode an element whose `data-cue` is in the list stays hidden until that cue
fires. Every other reveal fires `data-at` seconds after the mount, which covers an element
with `data-at` alone and an element whose cue is not in the list. When a cue fires, the
matching `data-cue` elements reveal first, then the step's `on[id]` handler runs, then
every `DeckTalk.on(id, fn)` handler.

## The handshake

The recorder opens the page as `file:///…/deck/index.html?scene=N&beats=…&t0=signal`
plus any `params` from the section. `t0=signal` tells the page not to start its clock at
load. The recorder then waits for `load`, for `document.fonts.ready`, for
`window.__sceneReady` when the page has one, for the settle time, and for a minimum lead
after the recorder was created. Then it calls `DeckTalk.startClock()`, and every cue is
scheduled from that instant. Without `t0=signal`, the page starts its clock at `load` plus
the `t0` seconds given, which is what a browser preview does.

After the recording, the recorder reads `window.__decktalk.warnings` and logs every
string, and the `check` stage adds a `KATEX?` verdict when one of them says that KaTeX
never loaded. [How it works](/concepts/how-it-works#why-the-cuts-are-exact) explains the
magenta cover that makes the first clean frame narration t=0.

<Warning>A page written by hand must start its clock only when `DeckTalk.startClock()`
is called. A page that starts at load fires every cue early by the settle time and the
recorder's lead, and every reveal in the video lands before its word.</Warning>

## Cue ownership

A cue belongs to exactly one step, and the step mounts at the earliest of its cues. The
runtime resolves the owner in this order.

1. The step with the same id as the cue.
2. The step whose `cues` list or object names the cue.
3. The step whose id is the longest prefix of the cue id. The cue `4.2b1` belongs to step `4.2`, and `9a` belongs to `9`.

A cue that no step owns is pushed onto `window.__decktalk.warnings` as an unknown cue id,
unless a `DeckTalk.on` handler is registered for it. When no listed cue has an owner,
nothing mounts and the page warns about that too. The scaffold names every cue in its
step's `cues` object, which also gives the browser preview its autoplay timing.

## Designing the stage

The stage is 1920 by 1080 CSS pixels and scales to fit the window, so every size in the
page is a pixel size at that frame. These are the sizes the scaffold uses, and they read
well on a laptop screen and a phone alike.

| Element                    | Size                                                                                                                     |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Safe margin                | 96 px from every edge, and 160 px for titles. The scaffold pads slides by 100 px top and bottom and 160 px at the sides. |
| Body text                  | 40 px or larger.                                                                                                         |
| Captions and eyebrows      | 28 px to 30 px, in the muted color.                                                                                      |
| Headlines                  | 88 px to 120 px. The scaffold's hero is 96 px.                                                                           |
| Labels and column headings | 56 px.                                                                                                                   |

One idea per slide. A slide that reveals more than three or four elements reads as an
animation, and a step with one headline and one supporting line is easier to cue than a
dense one. Steps are cheap, so split a busy slide into two.

## Reveal effects

The `data-fx` attribute picks the animation an element plays when it reveals. Each one
suits a kind of element, and each one has a case it makes worse.

| Effect           | For                                                                                                              | Against                                                                                   |
| ---------------- | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `rise` (default) | Lines of text, labels, and cards. It moves up 14 px as it fades in, which reads as a new line arriving.          | Code, tables, and anything aligned to a grid, where the motion looks like a layout shift. |
| `fade`           | Code lines, chat bubbles, images, and anything that must not move.                                               | A single small element on a large slide, where a fade alone can be missed.                |
| `draw`           | An SVG path with `pathLength="1"`. The stroke draws itself over `data-dur`.                                      | Anything that is not a stroke. A filled shape does not draw.                              |
| `drop`           | A tile or a stamp that should land. It falls 24 px over half a second.                                           | Body text, where the fall is too heavy.                                                   |
| `pop`            | The answer, the number, the one thing the section builds to. It overshoots to 112% and settles over 0.9 seconds. | More than one element per slide. Two pops compete.                                        |
| `dim`            | An element that should recede when a cue fires. It starts visible and fades to 16%.                              | An element that has not been on screen long enough to be noticed.                         |
| `none`           | An element that should appear on the frame of its cue with no animation, such as a cursor or a highlight.        | Text, where a hard cut looks like a glitch.                                               |

A scene may also set `camera: "push"`, a slow push from 100% to 103% over the scene.
Use it on at most one scene, usually the open, because a push under every scene reads as
the whole video breathing. The `verify` stage's control span accounts for the push, so it
does not disturb the cue checks.

## Build artifacts a page or a script may read

The page receives its cues as `?beats=` from `build/audio/beats.json`, and a script of
your own may read `build/audio/timeline.json` for every word with its absolute time.
[Build artifacts](/reference/artifacts) has every shape.
