Metadata-Version: 2.4
Name: decktalk
Version: 0.6.0
Summary: Every picture lands on its word: DeckTalk turns a markdown script, HTML slides and your voice into one narrated mp4.
Keywords: presentation,narration,elevenlabs,video,slides,text-to-speech,markdown,video-generation,explainer-video,lesson,screencast,word-timestamps,playwright,ffmpeg,tutorial,narrated-video
Author: Jacob Beaudin
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
License-File: THIRD_PARTY_NOTICES.md
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Education
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Typing :: Typed
Classifier: Topic :: Education
Classifier: Topic :: Multimedia :: Graphics :: Presentation
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
Requires-Dist: blake3>=1.0
Requires-Dist: filelock>=3.20.1
Requires-Dist: playwright>=1.63.0,<2
Requires-Dist: pydantic>=2.11
Requires-Dist: rich>=13
Requires-Dist: tomlkit>=0.13
Requires-Dist: typer>=0.26
Requires-Python: >=3.12
Project-URL: Homepage, https://decktalk.ai
Project-URL: Repository, https://github.com/jacobcbeaudin/decktalk
Project-URL: Documentation, https://docs.decktalk.ai
Project-URL: Issues, https://github.com/jacobcbeaudin/decktalk/issues
Project-URL: Changelog, https://github.com/jacobcbeaudin/decktalk/blob/main/CHANGELOG.md
Description-Content-Type: text/markdown

# DeckTalk

**Every picture lands on its word, and you edit the video like a doc.**

DeckTalk turns a Markdown script and plain HTML slides into one narrated mp4, voiced by ElevenLabs in a stock voice or a clone of your own. It is for people who make technical tutorials, product demos and lessons, and for the coding agents that help them.

[![PyPI version](https://img.shields.io/pypi/v/decktalk?style=flat-square&label=pypi&labelColor=0a0a0a&color=f2b441)](https://pypi.org/project/decktalk/)
[![Python versions](https://img.shields.io/pypi/pyversions/decktalk?style=flat-square&label=python&labelColor=0a0a0a&color=f2b441)](https://pypi.org/project/decktalk/)
[![CI on main](https://img.shields.io/github/actions/workflow/status/jacobcbeaudin/decktalk/ci.yml?branch=main&style=flat-square&label=ci&labelColor=0a0a0a)](https://github.com/jacobcbeaudin/decktalk/actions/workflows/ci.yml?query=branch%3Amain)
[![License Apache-2.0](https://img.shields.io/pypi/l/decktalk?style=flat-square&label=license&labelColor=0a0a0a&color=f2b441)](https://github.com/jacobcbeaudin/decktalk/blob/main/LICENSE)

<!-- x-release-please-start-version -->

[![A moment from the film Follows. A built film plays an invoice app, and its Share button lights the instant the word "Share" is said, while the waveform below marks each spoken word as it lands.](https://raw.githubusercontent.com/jacobcbeaudin/decktalk/v0.6.0/assets/follows.gif)](https://decktalk.ai/films/follows)

<!-- x-release-please-end -->

DeckTalk built the film [Follows](https://decktalk.ai/films/follows) from text files: two voices in conversation, a demo that clicks on the word it hears, and a rebuild that voices only the one word that changed. Watch it with the sound on, then build your own below.

## Make your first video

<!-- x-release-please-start-version -->

```console
uv tool install decktalk==0.6.0
decktalk init my-lesson && cd my-lesson
decktalk build --no-spend
```

The first line pins 0.6.0, the release this page describes.

The same block runs on Windows in PowerShell 7 or cmd, and `pipx install decktalk==0.6.0` works in place of uv.

On Linux and macOS without uv, `curl -LsSf https://decktalk.ai/install.sh | DECKTALK_VERSION=0.6.0 sh` puts uv on the machine first, and uv brings its own Python. [Read the script](https://github.com/jacobcbeaudin/decktalk/blob/main/install.sh) before you run it.

<!-- x-release-please-end -->

`decktalk init` writes a starter of three sections that already builds. The build with `--no-spend` needs no account and spends nothing. It makes the whole film, captions and chapters included, with a click on every word where the voice would be, so the cues, the cuts and the pacing all run as they will when voiced. It prints this line, and one `TAKE_MISSING` per turn that has no voiced take yet, which in the starter is one per section, with the command that buys it.

<!-- sample: build-built-line, decktalk build --no-spend, on a fresh decktalk init my-lesson, the Built line -->
```text
       Built build/final/my-lesson.mp4, $0.00, 3 findings
```

The first build downloads Chromium and ffmpeg, one time per machine: about 347 MB on macOS on Apple silicon, and roughly 445 MB on Linux x86-64 and 495 MB on Windows. It prints a line as each download starts, a line now and then as it arrives, and a line as it ends. Each part of Chromium states its size on its first progress line. In CI or from an agent, run `decktalk install` first, or pass `--events` to read each `tool.fetch` line, so a command timeout never cuts the first build off mid-download. On Linux, run `decktalk install` first in any case, because it adds the system libraries Chromium needs. Recording steps each section one frame at a time, split into chunks that record several at once, so a longer film takes longer to record. [What is measured](#what-is-measured) has the times.

To hear your own voice, copy `.env.example` to `.env`, fill in your ElevenLabs API key, set `[voices.narrator] id` in `decktalk.toml` to your voice id, and run `decktalk build --spend --max-cost 1`. `decktalk check` prices the narration before anything is bought, and `decktalk storyboard` puts every slide at every cue on one page for a look first. The [quickstart](https://docs.decktalk.ai/quickstart) walks each step with its output.

## A short tour

### The four files in a project

`script.md` holds what the voice says, `decktalk.toml` ties each section to a page, to a clip of your own or to a program that draws it, `cues.json` names the spoken phrase each moment on the page waits for, and a page in `deck/` holds the slides as plain HTML. [Your first deck](https://docs.decktalk.ai/guides/first-deck#how-one-section-ties-four-files-together) has the table of all four.

One cue id ties them together. In the starter, the slide `1.1` declares a moment called `title`, and `cues.json` says that moment waits for the words "This is DeckTalk".

```html
<template data-slide="1.1" data-preview-seconds="10" data-describe="the opening title and the count of files">
  <div class="title" data-in="title" data-describe="the title, This is DeckTalk">This is DeckTalk</div>
</template>
```

```json
{ "id": "1.1:title", "phrase": "This is DeckTalk" }
```

`data-describe` names the picture for the transcript. No attribute on the page says when a cue fires. [Your first deck](https://docs.decktalk.ai/guides/first-deck) writes one section across all four files, and [the page contract](https://docs.decktalk.ai/concepts/page-contract) lists every attribute.

### What a section can be

- A page of slides, where every reveal lands on its word: [Your first deck](https://docs.decktalk.ai/guides/first-deck).
- A conversation between voices, each turn its own take: [Write a dialogue](https://docs.decktalk.ai/guides/dialogue).
- Something that moves between two words, or a picture a program draws: [Things that move](https://docs.decktalk.ai/guides/motion).
- A video of your own, playing with its own sound: [Play a clip](https://docs.decktalk.ai/guides/clip-section).
- Any frame shape, wide, square or vertical: [Design a slide](https://docs.decktalk.ai/guides/design-a-slide).

`decktalk init my-interview --example interview` writes a finished dialogue between two voices, and `--example motion` a deck that moves. [Examples](https://docs.decktalk.ai/examples) lists every project `init` writes.

### Using DeckTalk with an agent

The command line is the instruction set, settings and page attributes are what it changes, and the agent is the implementer.

`decktalk init` writes an `AGENTS.md` and six skills into the project. The skills live in `.agents/skills/`, which Codex, Cursor, Gemini CLI and most other agents read, and `.claude/skills` links to that folder for Claude Code. [Install the skills](https://docs.decktalk.ai/agents/install) lists every agent and the folders it reads.

Open your agent in the project and paste this.

```text
Read AGENTS.md, then make a three-section lesson on binary search.
Rehearse with decktalk build --no-spend, show me the storyboard,
and ask me before any run that spends money.
```

The agent reads `decktalk --help` for the commands, `decktalk schema build` for one command's flags and result, and `decktalk config explain KEY` for one setting. Every command prints one JSON object under `--json`, and `--events` streams progress as JSON lines. Exit 0 means nothing was found at or above the `--fail-on` threshold, 1 a finding at it, 2 a refused command line, 3 that DeckTalk could not run, and 130 that it was interrupted. The [reference card](https://docs.decktalk.ai/reference/card) puts the whole contract on one page.

Without a terminal, a build with something to buy refuses unless `--spend` or `--no-spend` is passed, so an agent left alone cannot buy speech by accident. A build whose takes are all on disk buys nothing and needs neither flag nor key. This is the whole answer from `decktalk --json build` in the starter with a voice named, which exits 2.

<!-- sample: build-json-no-terminal, decktalk --json build, on a fresh decktalk init my-lesson with [voices.narrator] id set and no API key, which exits 2 -->
```json
{
  "schema": 1,
  "ok": false,
  "findings": [],
  "error": {
    "code": "APPROVAL",
    "message": "This run costs $0.15 for 476 characters at $0.30 per 1,000 characters. No terminal is here to approve it.",
    "hint": "Run decktalk build --spend to approve that cost, or decktalk build --no-spend to play a placeholder wherever a take is missing and silence where a sound is unbought.",
    "location": null,
    "docs": "https://docs.decktalk.ai/reference/errors/APPROVAL"
  }
}
```

### Drive it from Python

The command line is the first client of a library. `decktalk.open` returns a `Project` with a method for each of the six stages and for `build`, `check`, `status`, `words`, `storyboard`, `clip` and `serve`. Each method returns the same object its command prints, and nothing in the library prints.

```python
import decktalk

project = decktalk.open("my-lesson")
project.events.subscribe(lambda event: print(event.event, event.run))

result = project.build()
print(result.ok, result.film)
for finding in result.findings:
    print(finding.code.name, finding.message, finding.location.where)
```

A call that buys takes `spend=True` and `max_cost`. The library refuses before the first paid request when the most the run can cost is above the cap. Without `spend=True` a call plays every take on disk and buys nothing, so it reads no key. A free provider such as `dtsp` still makes each missing take once a voice is named. [The Python API](https://docs.decktalk.ai/reference/python-api) documents every call.

### What a build writes

A build writes everything under `build/`, and `decktalk status` reads it back. The film lands in `build/final/` with what goes with it.

```text
my-lesson.mp4              the film
my-lesson.srt              captions, as SubRip
my-lesson.vtt              captions, as WebVTT
my-lesson.chapters.txt     one chapter per section
my-lesson-transcript.html  a transcript page
my-lesson-poster.png       a poster frame
my-lesson.words.json       every word the film says, on the film's clock
my-lesson-captioned.mp4    the film with its captions drawn in, when [output] captioned asks
placements.json            where every section sits in the film
```

The voiced takes are kept in `takes/`, named by their digest, which is the folder to commit. Every run's events are kept under `build/events/`. [Build artifacts](https://docs.decktalk.ai/reference/artifacts) lists every path.

## How it is built

DeckTalk is a pipeline of six stages: `narrate`, `cue`, `record`, `score`, `assemble` and `verify`. Each stage is one command and one package, and reads only what the stages before it wrote. `decktalk build` runs them in order, or any span of them.

- **The words.** The voice returns a start and an end for every word, and every other time in the film is derived from those. A cue in `cues.json` names a spoken phrase rather than a second, so a rewritten sentence moves every picture after it with no timeline to edit.
- **A content-addressed build over takes.** A take is named by a digest of its text, its voice, its model and its settings. A recording, a section video and a frozen frame are each kept under a digest of everything they read. Edit one sentence and only its turn is voiced again and its section recorded again, so a fix costs a few cents of speech and not the whole film.
- **Recording.** Headless Chromium records each page section against its word times, several sections at once, and ffmpeg cuts one mp4 with captions and chapters beside it.
- **Verify.** `decktalk verify` decodes the finished film and measures it: every section opens on a real picture, no cut lands on a word, a section marked seamless opens on the picture the one before it ended on, and every reveal changes the picture within a set limit of its word.
- **One contract.** The command line is the first client of a Python library, every command prints one JSON object under `--json`, and a test enforces the import graph from the vocabulary layer up to the command line.

[ARCHITECTURE.md](https://github.com/jacobcbeaudin/decktalk/blob/main/ARCHITECTURE.md) explains each decision.

<!-- x-release-please-start-version -->

![The edit cycle. One sentence changes in script.md, and only its section is voiced and recorded again, while every other section comes back from the cache.](https://raw.githubusercontent.com/jacobcbeaudin/decktalk/v0.6.0/docs/images/edit-cycle-light.svg)

<!-- x-release-please-end -->

## What is measured

<!-- measured: generated by scripts/build_measured.py -->
- **Landing.** Every reveal of the starter landed within 49 ms of its word, against a limit of 80 ms plus half a frame, with a median of 25 ms over 36 reveals in 3 builds.
- **Builds.** A cold build of its 50.4 second film took 7.5 s, the same build with nothing changed 0.56 s, and the build after one changed word 4.3 s, recording 1 of 3 sections again.
- **Coverage.** The suites reach 98.3 percent of the package's statements.

Measured on macOS 26.6.2 arm64 (Apple M5 Pro) with DeckTalk 0.6.0rc1 and placeholder takes. [Every number and how it was measured](https://docs.decktalk.ai/reference/measured).
<!-- end measured -->

## Requirements and costs

- **Software.** The one-line installer runs on Linux and macOS and brings its own Python. On Windows, install with uv or pipx, which needs Python 3.12 or later. The first build downloads Chromium and ffmpeg, and `decktalk install` fetches them up front for a Docker layer, a CI cache or an offline machine. On Linux, `decktalk install` is also the one command that installs Chromium's system libraries.
- **Accounts.** A build that does not spend needs no account. A build voiced by ElevenLabs needs an ElevenLabs API key and a voice id, and DeckTalk never prints the key. The local `dtsp` voice needs a voice id and a server on this machine, and no key.
- **Cost.** Only a voiced build spends money, at your own ElevenLabs rate per character. A turn whose text and voice have not changed is not voiced again.

[Requirements and costs](https://docs.decktalk.ai/requirements) lists every download and every command that costs money.

## Learn more

The docs are at [docs.decktalk.ai](https://docs.decktalk.ai), and agents can read them whole at [llms.txt](https://docs.decktalk.ai/llms.txt).

- [How it works](https://docs.decktalk.ai/concepts/how-it-works) walks the six stages and why they run in that order.
- [Cues](https://docs.decktalk.ai/concepts/cues) explains how a phrase becomes a second.
- [Sound](https://docs.decktalk.ai/concepts/sound) adds music, an ambience bed and effects on a cue.
- [The CLI reference](https://docs.decktalk.ai/reference/cli) lists every command and flag.
- [Configuration](https://docs.decktalk.ai/reference/configuration) lists every setting with its range and default.
- [Verify](https://docs.decktalk.ai/reference/verify) defines every measurement the finished film is judged by.
- [The FAQ](https://docs.decktalk.ai/help/faq#how-is-this-different-from-the-other-tools) compares DeckTalk with Remotion, Manim, Descript and Synthesia.
- [ARCHITECTURE.md](https://github.com/jacobcbeaudin/decktalk/blob/main/ARCHITECTURE.md) explains how the code is built.

## Status and support

DeckTalk is alpha, a minor release can still break things, and one person maintains it. CI runs every check on Linux. The browser, media, end-to-end, platform and wheel checks run on macOS and Windows too. Every release is published from CI by trusted publishing, and every file on PyPI carries a provenance attestation.

- Report bugs and ask questions in [Issues](https://github.com/jacobcbeaudin/decktalk/issues).
- Report a vulnerability privately, as [SECURITY.md](https://github.com/jacobcbeaudin/decktalk/blob/main/SECURITY.md) explains.
- Read what changed in the [changelog](https://github.com/jacobcbeaudin/decktalk/blob/main/CHANGELOG.md).
- Work on DeckTalk itself by starting with [CONTRIBUTING.md](https://github.com/jacobcbeaudin/decktalk/blob/main/CONTRIBUTING.md).

DeckTalk is licensed under Apache-2.0 and made by [Jacob Beaudin](https://github.com/jacobcbeaudin).
