Skip to main content
Write a script; your voice reads it with a time for every word; slides reveal on the words in Chromium; ffmpeg cuts one mp4.Write a script; your voice reads it with a time for every word; slides reveal on the words in Chromium; ffmpeg cuts one mp4.
decktalk build runs seven stages in order. Each stage is a function that takes the project, writes a typed artifact under build/, and can be run on its own by the command of the same name. A clip section skips record and measure. Its own audio replaces the narration for its span. Build artifacts gives the shape of every file.

Why the cuts are exact

A strip of recorded frames opens magenta while the page is covered. The first clean frame is narration t=0, and the frames in which the curve draws and the number appears line up with the words curve and number.A strip of recorded frames opens magenta while the page is covered. The first clean frame is narration t=0, and the frames in which the curve draws and the number appears line up with the words curve and number.
A browser does not start recording at a known instant, and Chromium on Windows starts later than Chromium on Linux. A timer therefore cannot say where the narration begins inside a recording. DeckTalk does not use one. The recorder covers the page in magenta from its first paint. It waits for the page’s load event, for window.__sceneReady, for the settle time, and for a minimum lead after the recorder was created. Then it removes the cover and starts the page’s clock in the same tick. The measure stage scans the recording for the magenta run and takes the first clean frame after it as t=0. That frame is t=0 by construction, whenever the capture began. Every cue is a spoken word with a timestamp from the same origin, so the page fires the reveal at the right second, and the assembler cuts the recording at the frame that matches the narration. Nothing in the chain depends on wall-clock time. The verify stage closes the loop on the finished mp4. For a cue it compares a frame just before the cue with frames shortly after it, counts the share of pixels that changed by more than a threshold, and compares that share with the same measure over a quiet span just before the cue. The control catches motion that is always there, such as a slow camera push, so only the reveal itself counts.

Caching and cost

The narrate stage keys each section by a hash of its text and its voice settings. A build after an edit re-synthesizes only the sections whose words changed, and re-records only those sections. Everything else comes from build/. The --force flag ignores the cache, and --only N limits a build to the sections named. The --silent flag replaces the voice with silence and estimates word times from the word count. Every other stage runs as usual, so a silent build proves the cues, the pages, the recording, and the assembly without an API key.

Concurrency and safety

Stages run one after another and never in parallel with themselves. Every JSON artifact is written to a temporary file and renamed into place, so a reader never sees a half-written file. The final mp4 is published the same way, and a timestamped copy sits beside it. Errors raise a DeckTalkError subclass with the file or field named, and the command line turns that into exit code 1 with the message on stderr.