Skip to main content
This card lists the whole DeckTalk contract on one page, and each group links to the page that explains it. Use it to look up one rule, option, or exit code, or give it to an agent that writes a project. Every doc page is also served as plain text at llms.txt. The whole site is one file at llms-full.txt.

Inputs

You write four files, in this order: script.md, decktalk.toml, cues.json, and the page. All of them live in the project directory. Your first deck writes each one.

script.md

  • ## N. Title starts section N.
  • ## N. Title — 0:40 to 1:10 adds a time budget.
  • ---, # Title, or ## Title with no number ends the section.
  • A page section needs a ## N. heading. A clip section does not.
  • [any text] and [beat] make a beat. The voice reads a dash there.
  • [pause N] sends <break time="Ns" />. No other direction sends a break tag.
  • A written <break time="1s" /> passes through as written.
  • [CAPS_1] is a placeholder. Its pattern is [A-Z][A-Z0-9_]*.
  • narrate refuses a placeholder without --allow-placeholders.
  • narrate removes Markdown formatting before it sends the text.
  • DeckTalk adds lead_break_seconds (0.7) of silence before the first spoken section.
  • DeckTalk pads each section to at least min_tail_seconds after its last word.
  • The default min_tail_seconds is 0.7. The scaffold sets 1.3.
  • The est column assumes 140 words per minute.
  • A silent build assumes 150 words per minute plus 0.7 s per beat.
Full rules: script.md.

decktalk.toml

  • [project] holds name and the optional script, cues, and build paths.
  • [voice] holds voice settings. The voice id and key live in .env.
  • Each [[section]] has a number and an optional title.
  • A page section adds page and an optional scene. scene defaults to number.
  • A clip section adds clip, and the optional slate_seconds, optional, and words.
  • words names a words file of the speech inside the clip, and the captions add it.
  • Consecutive sections with the same title share one chapter.
  • A clip section with optional = true plays its slate under --strict too.
  • A clip section can sit before, between, or after page sections.
  • A page section can set lead_seconds, tail_seconds, and hold_seconds to add silence. A hold pauses the narration.
  • [transition], [mix], [soundscape], and the tuning tables are optional.
  • An unknown top-level table fails the load.
  • DeckTalk warns about an unknown key inside a table, then ignores the key.
Full rules: decktalk.toml.

cues.json

This shape shows the file. It is not a sample.
  • Each section key is a section number as a string. It must exist in decktalk.toml.
  • step works as another name for cue.
  • $start is 0.0 s. $end is the end of the section’s last spoken word.
  • Matching splits the phrase and the spoken words on whitespace only.
  • A hyphenated word is one token.
  • Each token keeps only A to Z, a to z, 0 to 9, and the straight apostrophe.
  • Matching ignores case unless case_sensitive is true.
  • The cue time is the matched word’s start plus the offset key.
  • occurrence picks a later match. The default is the first.
  • A cue id must not contain a comma, because a comma breaks ?beats=. DeckTalk does not check this.
  • An @ inside an id still works. By convention, ids have no @.
  • beats ignores a top-level key other than sections, such as _comment.
Full rules: cues.json and Cues.

Pages

  • A page is any HTML file that a [[section]] names.
  • The scaffold has deck/index.html and deck/lesson.html.
  • Load decktalk-runtime.js before any DeckTalk.scene call.
  • DeckTalk.scene(N, {name, camera?, steps}) defines scene N.
  • Each step is {id, hold?, cues?, render, enter?, on?}.
  • enter, each on[id], and DeckTalk.on(id, fn) receive (slide, {id, at, frozen, step}).
  • An element appears on its cue with data-cue="id", or at a time with data-at="s".
  • data-sync, data-count, and data-type also need data-cue or data-at.
  • Inside render backticks, write every backslash twice.
  • The runtime creates the stage element #dt-stage at 1920 by 1080.
  • A step owns a cue with its own id, a cues entry, or the longest id prefix.
  • decktalk runtime copies the packaged runtime into a project.
Full rules: Runtime and Page contract.

.env

  • A voiced build needs ELEVENLABS_API_KEY and ELEVENLABS_VOICE_ID.
  • An exported variable wins over .env.
  • A value that starts with < counts as unset.
  • A silent build needs neither key.

One number for each section

  • The number N is the same in the script heading, [[section]], and the cues.json key.
  • A section can play a scene with another number. In the scaffold, section 8 plays scene 7.
  • beats exits 1 on a cue id that its page never quotes.
  • build stops on such an id unless you pass --allow-unknown.
Cue mismatches lists every page warning about cues.

A minimal page

This page is the smallest page that plays one scene. For KaTeX, copy the cached katex directory that decktalk doctor prints into deck/katex/, and keep the two KaTeX tags before the runtime.
deck/index.html
The runtime mounts each slide as a .dt-slide with position: absolute; inset: 0. Set your own background on html, body and #dt-stage.

Commands

  • A project command takes -p DIR. The default is DECKTALK_PROJECT, then the current directory.
  • -v and -q go before or after the command name.
  • -p goes before the command name, or after it on every command except init, setup, and doctor.
  • A repeatable option takes one value each time. Write --only 3 --only 6.
  • --strict on assemble and build fails on a missing recording or a missing clip.
  • A clip section with optional = true still plays its slate under --strict.
Five read-only commands share three options. Every option: CLI.

Gate a script on the video

  • build checks section starts, cuts, and cut continuity. It measures no cue.
  • build exits 0 on TRUNCATED, STALLED, and NO COVER.
  • To gate on the whole video, run decktalk build --silent && decktalk check && decktalk verify.
  • The offset column must be between -80 ms and +80 ms.
  • After a silent build, the a/v column must be between -120 ms and +120 ms.
  • OFF CUE prints no distance. Compare the columns with those limits.
  • A - in the a/v column means no click was found. The JSON reason is NO_CLICK, and it does not fail.
  • Every cut must be at most -40 dBFS in its last 0.15 s. Clip sections have no cut row.
  • A silent build skips the loudness pass.
A skipped row never fails. A named cue that is not in beats.json is UNRESOLVED, which fails. Measurement details: verify. To test a new project with no key, run these commands in order.
  1. For a project with no runtime copy, run decktalk runtime.
  2. Run decktalk build --silent.
  3. Run decktalk verify.
  4. Run decktalk shots.
To see the cue times before anything records, run decktalk narrate --silent and then decktalk beats.

Stages and artifacts

build runs narrate, beats, record, measure, check, assemble, and verify, in that order. After a clip between page sections, final-video times are later than narration times by the clip lengths before them. Time bases gives each clock. Build artifacts gives every field.

Settings

Settings come from five layers. Each layer overrides the layer before it.
  1. DeckTalk’s defaults.
  2. The per-machine file at DECKTALK_CONFIG. It can hold tuning tables only.
  3. Tables of the same name in decktalk.toml.
  4. DECKTALK_<TABLE>_<FIELD> environment variables.
  5. The options --preset, --crf, --settle, and --model.
The tuning tables are these seven.
  • [video]
  • [narration]
  • [record]
  • [align]
  • [audio]
  • [verify]
  • [elevenlabs]
DECKTALK_CACHE_DIR moves the KaTeX cache. DECKTALK_FFMPEG and DECKTALK_FFPROBE point at your own binaries. Set both. CLI gives the default paths, and Configuration lists every field.

Exit codes and errors

An error prints error: <message> on stderr and exits 1, even with --no-fail. Logs go to stderr through the decktalk logger. DeckTalk never prints a key.

Python

This example builds the scaffold silently and prints the final path.
Python API lists every public name.