Skip to main content
A cue names a spoken phrase and never a second. cues.json says which phrase a moment lands on, the cue stage turns that phrase into a second on its own section’s clock, and the recorder plays the page to those seconds. Read this page when you choose a phrase, or when a cue and its page disagree. Writing for the ear is the guide for writing phrases.

The cue id

A cue id is the slide id, a colon, and then the cue name the page writes. So data-in="expand" inside <template data-slide="4.1"> is the cue id 4.1:expand, and 4.1:expand is what cues.json carries. The author writes a short cue name that means something inside its own slide, and the runtime qualifies it with the slide it was written in, so two slides may each have a moment called expand and no cue is ever ambiguous. Every other page names this rule and links here. The slide id, not the section number, is the first half. A section can play a scene whose slides are numbered differently, and the cue id follows the slide. Section 1 of the starter plays scene 1, whose two slides are 1.1 and 1.2, which is why its rows begin with both. Each of the four moments an element declares is a cue id of its own: data-in when it arrives, data-back when it steps back, data-front when it comes forward, and data-out when it leaves. A handler registered with DeckTalk.on takes the cue id too, because it may be registered anywhere in the deck, while a slide’s own on map takes the bare cue name, because the slide is already known. That split is the whole design. cues.json owns the seconds and the page owns the moments. No page attribute says when a cue fires, and no row of cues.json says what a reveal looks like. Each file can be edited without reading the other, and a rename in one is a finding against the other rather than a silent miss. The starter’s section 1 shows one cue, 1.2:script, in all three files.
The page writes data-in="script" inside the slide 1.2, so the cue id is 1.2:script. cues.json gives that cue id the phrase what you will say, and its second is the start of the word “what”.

What decktalk cue does

decktalk cue is the second stage. It reads the take index build/narrate/takes.json to find which take each section plays, reads that take’s words file for the section’s words and their times, resolves every row of cues.json against them, and writes build/cue-times.json. Every code it raises begins with CUE.
A run aimed at some sections leaves every other section’s rows in build/cue-times.json as they were, so a cue run for one section never drops the cues of the rest. Which findings fail a run holds for cue as for every command. The same arithmetic runs inside decktalk check, against the words a voiced run would leave rather than the words it already left, so a phrase that will not match is met before anything is bought.

Matching rules

The stage matches a cue phrase against the section’s spoken words with these rules.
  1. It splits the phrase and the spoken words on whitespace.
  2. Each token keeps its letters and digits, in any script, and its apostrophes, with a curly apostrophe read as the straight one. So café, naïve and η are tokens as written.
  3. Matching ignores case unless the cue sets case_sensitive to true.
  4. A token with no letter or digit left is ignored, so the phrase learning rate - matches as learning rate. A letter is never ignored, so the phrase learning rate η needs a spoken η.
  5. A word that punctuation divides, such as state-of-the-art or R&D, matches whole and by its parts. The phrases state of the art and state-of-the-art both match a spoken state-of-the-art, and zig-zag matches a spoken zig zag. A phrase that starts inside such a word lands on that word’s start. A word with no letter or digit in it, such as an & or a / spoken as a word of its own, is skipped on both sides, so R & D and tools / fast resolve.
  6. The stage looks through the spoken words in order for a run that matches the phrase token for token. occurrence picks which match, counting from 1, and the default is the first.
  7. The second is the start of that run’s first word, plus the cue’s offset_seconds, rounded to a millisecond and never earlier than the section’s own start.
  8. $start is the section’s own start, which is 0 seconds on its clock.
  9. $end is the end of the section’s last spoken word.
A phrase that occurs more than once on a cue that names no occurrence still resolves, on the first match. The stage says so as a warning that names every match with its time, because the cue did resolve and the choice was made for you. Write a cue phrase the way the voice says it, because the spoken words come from the voice. The starter’s script says “decktalk dot AI” and its end card shows decktalk.ai, so the cue 3.1:make matches on “Make your own” and never on the text of the card. A number written in digits comes back in whatever form the voice chose, so write numbers as words in the script and show digits on the slide. Directions are not spoken words. A plain direction such as [beat] becomes a dash the voice reads as a short pause, and a [pause N] becomes a pause of N seconds. Neither is a word, so a phrase that spans one still matches. script.md has the rules for directions.

Which sections have cues

Every section key in cues.json must name a [[section]] in decktalk.toml, and a key that names no section fails the load with an error naming the section. A section may have no cues at all. A clip section is never read by the voice, so its rows resolve to nothing and the stage passes over them rather than judging them. min_seconds on a section says how long that section’s visuals need. A section whose speech ends sooner is reported as a sentence rather than as a finding, because nothing is wrong with the film yet.

Cue mismatches

Nine codes name a cue that does not agree with something. Five of them are read from the two files before a picture exists, three are measured from a frozen frame or from the finished film, and one compares the cue times on disk with the cue file they were placed from. Every one carries the sentence below, its severity, the object it judged and the fix when there is one. What each one means for the film, and what clears it:
  • CUE_UNLISTED is a moment on the page that nothing in cues.json gives a second to. Add the row, or take the moment off the page. Its fix adds the row for you, which the next section describes.
  • CUE_UNKNOWN is a row whose cue id no slide of the section’s scene declares. The row is named and never deleted. When exactly one stale row sits beside exactly one moment nothing lists in the same section, the two are read as a rename and an unsafe fix changes the id alone, keeping the phrase you already wrote. The phrase is what survives a rename, so the row that carries it is the row for that moment. --allow CUE_UNKNOWN carries on past it, for a deck that builds ids at run time.
  • CUE_UNRESOLVED is a phrase the section does not speak. Fix the phrase, or fix the script. A section with no take at all resolves nothing, and the message says which of the two it is.
  • CUE_STALE is a cue file edited after the film was built. verify measures the film on disk, and that film was cut to the cue times of the last build, so a row whose phrase or offset changed since, a row added since and a row removed since are all measured against moments nobody asks for now. Nothing is wrong with the phrase. Run decktalk build, which places the cues again and records only the sections they moved.
  • CUE_NO_ONSET is a cue whose second is 0, which is where the section starts rather than where a word does, or a cue in the finished film that changed the picture with no frame rising by verify.onset_rise_points. Nothing measures its landing against a word, so the offset check cannot run for it. What a cue at 0 reveals arrives as a cut on the section’s first frame.
  • CUE_OVERLAP is two cues closer together than the first one’s own motion lasts. The second moment starts while the first is still playing, so a viewer cannot tell them apart and neither can the measurement.
  • CUE_NO_CHANGE is a cue where less of the picture changed than verify.changed_share_min_percent, or whose margin over its control was under verify.margin_min_points. The reveal is too small or too pale to see, or it never played.
  • CUE_THIN_CHANGE is a cue that passed with less than verify.thin_change_factor times that floor. It is a second opinion rather than a failure, and setting the factor to 1 turns it off.
  • CUE_OFF is a reveal whose measured onset sits further from its word than verify.cue_offset_max_ms, or a word whose click sounds further from the second it was promised than verify.av_offset_max_ms. The sound has the wider limit, because an mp3 frame smears a transient and the encode adds its own.
Configuration gives every one of those keys with its range and its unit, and decktalk config explain verify.cue_offset_max_ms prints the layers of any one of them.

The fix that writes cues.json

CUE_UNLISTED carries a safe EditFix that adds the row, so a deck can be written first and its seconds named afterwards.
--fix lives on check and on build, which are the two commands that apply a fix to a project’s files, and doctor --fix applies the fixes a machine offers. cue reports the same codes and applies nothing. Both comparisons read the moments off the catalog the page itself published rather than off a scan of its markup, because data-spotlight, data-class and data-owns all declare moments no text scan can see. check reads a catalog live. cue reads the one the last recording kept while that recording still stands, and opens the page and reads it as it is now once anything the recording was made from has changed, so a cue renamed in the page and in cues.json together is judged by its new name before record has run. The two reach the same judgements. A section whose page has never been opened is left unjudged rather than guessed at, so check --no-pages reaches neither CUE_UNLISTED nor CUE_UNKNOWN and names both as judgements it could not make. The fix writes {"id": "<cue id>", "phrase": ""} and leaves phrase empty, because the phrase is your line and not DeckTalk’s. A project with no cues.json at all gets one whole file with a row for every moment the deck declares. A project that has one gets the rows added to the section block they belong to, or a new block for a section the file holds none for. A fix only ever adds, so it is idempotent. The second run finds the rows it wrote already declared and already listed, so no moment of the section is missing any more and it writes nothing. A hand-written cues.json that the fix cannot place a row in is given the rows to paste instead, as a fix that is printed and never applied. The rename fix is the one fix here that is unsafe, because it rewrites an id you typed from a pairing that is a reading rather than a fact. --fix prints it and does not apply it.

Phrase choice

These guidelines help a moment land on the word you meant. Writing for the ear explains each one.
  • Start the phrase with the word that names the thing that happens, because the second is the start of the phrase’s first word. A noun such as box of dials works, and so does a verb with its object, such as steps downhill. A connective such as “and then” does not.
  • If a word repeats in the section, use two or three words, or set occurrence. Setting occurrence to 1 keeps the first match and silences the warning.
  • Set a small positive offset_seconds, 0.1 to 0.2 seconds, so the viewer hears the word begin before the picture moves.
  • Use a negative offset_seconds only when the audience has to read along, and remember that a cue can never resolve before its own section starts.
  • Put a [beat] or a [pause N] before a moment that should feel like an event.
  • Land a summary on $end, so it arrives as the voice stops.
  • Set verify to false on a row whose change is too small or too slow for a frame difference to see, which leaves that cue out of the measurement rather than out of the film.

Sound on a cue

A [[mix.effect]] table names a section and a cue, and assemble places that sound at the second the cue resolved to plus the effect’s own offset_seconds. A music marker matches a spoken phrase by these same rules, through its own on, occurrence, case_sensitive and offset keys, and raises or mutes the music there. Sound explains both.

Terms

Glossary holds the vocabulary of the whole tool.

Next