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

# Slide recipes

> Copy six common slides into a project, each with its script lines, section table, cues, and scene.

This page has six slides that you can copy into a project. Use a recipe when you need a common
slide, such as a derivation or a code block.

* [Sync a subtitle to the voice](#sync-a-subtitle-to-the-voice)
* [Show a derivation line by line](#show-a-derivation-line-by-line)
* [Show a chat before and after](#show-a-chat-before-and-after)
* [Show code one line per phrase](#show-code-one-line-per-phrase)
* [Compare two columns](#compare-two-columns)
* [Wait for a screenshot to load](#wait-for-a-screenshot-to-load)

## Before you start

Each recipe is one section, shown as four files: `script.md`, `decktalk.toml`, `cues.json`, and
`deck/index.html`. The recipes use section numbers 7 to 12, which the starter does not use. Each
`<style>` block defines the classes that its recipe needs. The recipes also use the starter's
`.eyebrow` class and its color and font variables.

To add a recipe to a project, follow these steps:

1. Paste the `script.md` lines after the last section of the script.
2. Paste the `[[section]]` table after the last `[[section]]` in `decktalk.toml`.
3. Paste the `cues.json` entry inside the `sections` object.
4. Paste the `<style>` block into the page's `<style>`, and the scene markup into `<body>`.
5. If the section number is already in use, change it in all four files.

## Sync a subtitle to the voice

An element with `data-text="spoken"` shows its words one at a time, as the voice says them.

<CodeGroup>
  ```md script.md theme={null}
  ## 7. The idea

  Write the script. [beat] Build the video. [beat] Every picture waits for its word.
  ```

  ```toml decktalk.toml theme={null}
  [[section]]
  number = 7
  page = "deck/index.html"
  scene = 7
  ```

  ```json cues.json theme={null}
  "7": { "cues": [
    { "cue": "7.1a", "on": "Write the script" },
    { "cue": "7.1b", "on": "Build the video" },
    { "cue": "7.1c", "on": "Every picture" }
  ] }
  ```

  ```html deck/index.html theme={null}
  <style>
    .stack { position: absolute; left: 120px; top: 360px; display: flex; flex-direction: column; gap: 32px; }
    .stack > * { margin: 0; }
    .line { font: 450 48px/1.4 var(--sans); color: var(--ink); }
  </style>
  <script>
  DeckTalk.scene(7, { name: "The idea", slides: [
    { id: "7.1", hold: 10, preview: { "7.1a": 1, "7.1b": 3.5, "7.1c": 6 }, render: () => `
      <div>
        <p class="eyebrow">The idea</p>
        <div class="stack">
          <p class="line" data-cue="7.1a" data-text="spoken">Write the script.</p>
          <p class="line" data-cue="7.1b" data-text="spoken">Build the video.</p>
          <p class="line" data-cue="7.1c" data-text="spoken">Every picture waits for its word.</p>
        </div>
      </div>` },
  ]});
  </script>
  ```
</CodeGroup>

The cue makes each line appear, and its words appear one at a time from there. The text must match
the script word for word. If a line differs by one word, it appears whole, and the page warns
`data-text="spoken" text not found in the spoken words`. To check the slide at one cue, open
`?slide=7.1&after=7.1b`, which hides the line for `7.1c`.

## Show a derivation line by line

Each line of the derivation is its own element with its own cue. `data-tex-display` typesets it as
display math, and the answer uses `pop` so it stands out. The starter's `deck/index.html` loads
KaTeX from the copy `decktalk init` put beside it.

<Warning>Inside the backticks of a `render` function, write every backslash twice, because a single
backslash breaks the TeX or blanks the page. In markup a backslash is written once, which is the
reason this recipe is a `<template data-slide>` ([`data-tex`](/reference/runtime#data-tex)).</Warning>

<CodeGroup>
  ```md script.md theme={null}
  ## 8. The derivative of x squared

  Start with the definition of the derivative, the limit of a difference quotient. [beat]
  Expand the square, and the x squared terms cancel. [beat] Only two x is left.
  ```

  ```toml decktalk.toml theme={null}
  [[section]]
  number = 8
  page = "deck/index.html"
  scene = 8
  ```

  ```json cues.json theme={null}
  "8": { "cues": [
    { "cue": "8.1a", "on": "definition" },
    { "cue": "8.1b", "on": "Expand" },
    { "cue": "8.1c", "on": "Only two x", "offset": 0.2 }
  ] }
  ```

  ```html deck/index.html theme={null}
  <style>
    .derivation { position: absolute; left: 120px; top: 300px; display: flex; flex-direction: column; gap: 56px; }
    .math { margin: 0; font-size: 58px; color: var(--ink); }
    .math .katex-display { margin: 0; }
    .math .katex-display > .katex { text-align: left; }
    .answer { color: var(--accent); }
  </style>
  <div data-scene="8" data-name="The derivative of x squared">
    <template data-slide="8.1" data-hold="14" data-preview="8.1a@1 8.1b@5 8.1c@9">
      <div class="derivation">
        <p class="math" data-cue="8.1a" data-tex-display
           data-tex="\frac{d}{dx}\,x^2 = \lim_{h \to 0} \frac{(x+h)^2 - x^2}{h}">(d/dx) of x^2 = the limit as h goes to 0 of ((x+h)^2 - x^2) / h</p>
        <p class="math" data-cue="8.1b" data-tex-display
           data-tex="= \lim_{h \to 0} \frac{2xh + h^2}{h} = \lim_{h \to 0} (2x + h)">= the limit of (2xh + h^2) / h = the limit of (2x + h)</p>
        <p class="math answer" data-cue="8.1c" data-reveal="pop" data-tex-display
           data-tex="\frac{d}{dx}\,x^2 = 2x">(d/dx) of x^2 = 2x</p>
      </div>
    </template>
  </div>
  ```
</CodeGroup>

The plain text inside each element shows when KaTeX is absent, so write it as a readable fallback.
In markup a backslash is written once. A slide built by a `render` function is a JavaScript string,
where every backslash has to be written twice, which is the reason to prefer a `<template>`.

## Show a chat before and after

The question types in with `data-text="type"`, and the reply fades in one line at a time. The bubble and
its first line share a cue, so the bubble's background appears when its text starts. The second
slide is the "after", and its cue `9.2` mounts it.

<CodeGroup>
  ```md script.md theme={null}
  ## 9. Before and after

  Watch a vague prompt first. [beat] Write about photosynthesis. [beat] The reply is true,
  and it is flat. [beat] One line says what it is. [beat] Another line says where it happens.

  [Slide 9.2.]

  Now ask for what you actually want. [beat] Explain it to a ninth grader, in three
  sentences. [beat] Same model, better prompt.
  ```

  ```toml decktalk.toml theme={null}
  [[section]]
  number = 9
  page = "deck/index.html"
  scene = 9
  ```

  ```json cues.json theme={null}
  "9": { "cues": [
    { "cue": "9.1ask", "on": "Write about" },
    { "cue": "9.1r1", "on": "One line" },
    { "cue": "9.1r2", "on": "another line" },
    { "cue": "9.2", "on": "Now ask" },
    { "cue": "9.2ask", "on": "Explain it" },
    { "cue": "9.2reply", "on": "Same model" }
  ] }
  ```

  ```html deck/index.html theme={null}
  <style>
    .chat { position: absolute; left: 120px; top: 300px; width: 1680px; display: flex; flex-direction: column; gap: 32px; }
    .bubble { max-width: 1100px; padding: 28px 40px; border-radius: 24px; font: 450 36px/1.4 var(--sans); }
    .bubble p { margin: 0 0 12px; }
    .ask { align-self: flex-end; background: var(--accent); color: var(--ground); }
    .reply { align-self: flex-start; background: #f4f4f5; color: var(--ink); }
  </style>
  <script>
  DeckTalk.scene(9, { name: "Before and after", slides: [
    { id: "9.1", hold: 12, preview: { "9.1ask": 1, "9.1r1": 5, "9.1r2": 7 }, render: () => `
      <div>
        <p class="eyebrow">Before</p>
        <div class="chat">
          <div class="bubble ask" data-cue="9.1ask" data-text="type 40ms" data-reveal="fade">Write about photosynthesis.</div>
          <div class="bubble reply" data-cue="9.1r1" data-reveal="fade">
            <p data-cue="9.1r1" data-reveal="fade">Photosynthesis is the process by which plants convert light into energy.</p>
            <p data-cue="9.1r2" data-reveal="fade">It takes place in the chloroplasts.</p>
          </div>
        </div>
      </div>` },
    { id: "9.2", hold: 12, preview: { "9.2ask": 1, "9.2reply": 6 }, render: () => `
      <div>
        <p class="eyebrow">After</p>
        <div class="chat">
          <div class="bubble ask" data-cue="9.2ask" data-text="type 30ms" data-reveal="fade">Explain photosynthesis to a ninth grader in three sentences.</div>
          <div class="bubble reply" data-cue="9.2reply" data-reveal="pop">
            <p>Plants catch sunlight and use it to turn water and air into sugar.</p>
          </div>
        </div>
      </div>` },
  ]});
  </script>
  ```
</CodeGroup>

## Show code one line per phrase

Each line of code is a block element with its own cue. The container keeps the indentation with
`white-space: pre` and a monospace font. The lines use `fade`, because the motion of `rise` looks
wrong on code.

<CodeGroup>
  ```md script.md theme={null}
  ## 10. Three commands

  Three commands run the whole thing. [beat] Initialize a project. [beat] Build it
  without voice, with no key. [beat] Then build it with your voice.
  ```

  ```toml decktalk.toml theme={null}
  [[section]]
  number = 10
  page = "deck/index.html"
  scene = 10
  ```

  ```json cues.json theme={null}
  "10": { "cues": [
    { "cue": "10.1a", "on": "Initialize" },
    { "cue": "10.1b", "on": "without voice" },
    { "cue": "10.1c", "on": "your voice" }
  ] }
  ```

  ```html deck/index.html theme={null}
  <style>
    .code { position: absolute; left: 120px; top: 360px; font: 500 40px/1.5 var(--mono); white-space: pre; color: var(--ink); background: #f4f4f5; border-radius: 24px; padding: 40px 56px; }
    .code .cmt { color: var(--mute); }
  </style>
  <script>
  DeckTalk.scene(10, { name: "Three commands", slides: [
    { id: "10.1", hold: 10, preview: { "10.1a": 1, "10.1b": 4, "10.1c": 7 }, render: () => `
      <div>
        <div class="code"><div data-cue="10.1a" data-reveal="fade">decktalk init my-lesson</div><div data-cue="10.1b" data-reveal="fade">decktalk build --no-voice   <span class="cmt"># no key</span></div><div data-cue="10.1c" data-reveal="fade">decktalk build</div></div>
      </div>` },
  ]});
  </script>
  ```
</CodeGroup>

Keep the lines on one physical line inside the `render` template. With `white-space: pre`, the
page would otherwise show the template's own indentation.

## Compare two columns

Two columns appear left and then right, and each column has one cue. The `<style>` block lays them
out with flex.

<CodeGroup>
  ```md script.md theme={null}
  ## 11. Two ways to time a reveal

  On the left, a timeline editor. Every reveal is a number of seconds, and every edit moves them
  by hand. [beat] On the right, the words. Every reveal is a phrase, and it moves with the
  sentence.
  ```

  ```toml decktalk.toml theme={null}
  [[section]]
  number = 11
  page = "deck/index.html"
  scene = 11
  ```

  ```json cues.json theme={null}
  "11": { "cues": [
    { "cue": "11.1left", "on": "timeline editor" },
    { "cue": "11.1right", "on": "the words" }
  ] }
  ```

  ```html deck/index.html theme={null}
  <style>
    .cols { position: absolute; left: 120px; right: 120px; top: 300px; display: flex; gap: 48px; }
    .pane { flex: 1; background: #f4f4f5; border-radius: 24px; padding: 48px; min-height: 520px; }
    .pane h2 { margin: 0 0 24px; font: 600 56px/1.1 var(--sans); letter-spacing: -.02em; color: var(--ink); }
    .pane .line { margin: 0 0 16px; font: 450 36px/1.4 var(--sans); color: var(--ink); }
    .pane .caption { margin: 0; font: 450 30px/1.4 var(--sans); color: var(--mute); }
    .pane .accent { color: var(--accent); }
  </style>
  <script>
  DeckTalk.scene(11, { name: "Two ways to time a reveal", slides: [
    { id: "11.1", hold: 12, preview: { "11.1left": 1, "11.1right": 6 }, render: () => `
      <div>
        <div class="cols">
          <div class="pane" data-cue="11.1left">
            <h2>A timeline editor</h2>
            <p class="line">Every reveal is a number of seconds.</p>
            <p class="caption">Every edit moves them by hand.</p>
          </div>
          <div class="pane" data-cue="11.1right">
            <h2 class="accent">The words</h2>
            <p class="line">Every reveal is a phrase.</p>
            <p class="caption">It moves with the sentence.</p>
          </div>
        </div>
      </div>` },
  ]});
  </script>
  ```
</CodeGroup>

## Wait for a screenshot to load

The recorder starts the clock only after `window.__decktalk.ready` resolves. This recipe hands the
decode of a large image to `DeckTalk.waitFor`, so the image is ready before narration t=0. `waitFor`
adds a condition to the runtime's own wait rather than replacing it, so the KaTeX wait still applies.

<CodeGroup>
  ```md script.md theme={null}
  ## 12. The status report

  Here is the status report after a build. [beat] Every section shows a recording and a
  cut, and the captions and chapters sit beside the video.
  ```

  ```toml decktalk.toml theme={null}
  [[section]]
  number = 12
  page = "deck/index.html"
  scene = 12
  ```

  ```json cues.json theme={null}
  "12": { "cues": [
    { "cue": "12.1screenshot", "on": "status report" },
    { "cue": "12.1note", "on": "captions" }
  ] }
  ```

  ```html deck/index.html theme={null}
  <style>
    .screenshot { position: absolute; left: 260px; top: 140px; width: 1400px; border-radius: 16px; box-shadow: 0 24px 80px rgba(0,0,0,.25); }
    .note { position: absolute; left: 260px; top: 960px; margin: 0; font: 450 30px/1.4 var(--sans); color: var(--mute); }
  </style>
  <script>
  DeckTalk.scene(12, { name: "The status report", slides: [
    { id: "12.1", hold: 10, preview: { "12.1screenshot": 0.5, "12.1note": 5 }, render: () => `
      <div>
        <img class="screenshot" src="../media/status.png" alt="" data-cue="12.1screenshot" data-reveal="fade">
        <p class="note" data-cue="12.1note">Captions and chapters sit beside the video.</p>
      </div>` },
  ]});

  // Narration t=0 also waits until the screenshot has decoded.
  const image = new Image();
  image.src = "../media/status.png";
  DeckTalk.waitFor(image.decode());
  </script>
  ```
</CodeGroup>

`DeckTalk.waitFor` takes a Promise and holds narration t=0 until it settles. A Promise that rejects,
or one that has not settled after five seconds, becomes a page warning and the recording goes ahead,
so a missing image never hangs a build. [`window.__decktalk.ready`](/reference/runtime#window-__decktalk-ready)
explains the default wait.

## Next

* **Size a slide and choose reveal effects:** [Design a slide](/guides/design-a-slide)
* **Look up every attribute:** [Runtime](/reference/runtime#data-attributes)
* **Write phrases that time well:** [Writing for the ear](/guides/writing-for-the-ear)
