Summary
After a full tekton-dag demo regen on current docgen (Manim-only, local timestamps, scene-spec → compile → TTS → timestamps → Manim → compose), composed videos match audio length but on-screen content often has little relation to what is being spoken.
This is not primarily A/V stream drift (ffprobe durations are close). It is semantic / beat sync failure: visuals race through a generic diagram, latch to the wrong spoken words, then freeze while narration continues on other topics.
Observed in consumer (tekton-dag docs/demos)
Segment 01 (StackDAGScene):
- Narration talks about four pipelines, Flask orchestrator, optional CRD path, etc.
- Scene boxes include labels like
Demo-fe, Originator, Forwarder, Terminal that never appear in the regenerated narration.
- Compiled code waits with
wait_until_word(timing_words, 146) before revealing Originator, but word index 146 in timing.json is the token "operator" (~64s) — unrelated.
- Other boxes fade in via cascading
timed_play with no wait_until_word, so large chunks of the visual story finish in the first tens of seconds.
Segment 03 (HeaderPropagationScene):
- Loads
timing_words but mostly uses unpaced timed_play(FadeIn(...)) cascades, then relies on the audio-length tail / compose freeze for the remaining narration.
Validate can still report PASS for av_drift / timing_sync because the muxed video is padded to the mp3 duration even when the visual story is already over.
Root causes (suspected)
-
scene-spec-generate does not enforce narration-anchored labels
System prompt says to mirror narration beats, but the model freely invents diagram vocabulary (roles, app names) that are not spoken. There is no hard gate that every label must match a token/phrase in the segment narration (or a declared synonym list).
-
sync_row_labels_to_whisper_words(..., overwrite=True) fills bad matches
When a label is absent from timing.json words, matching appears to attach to a wrong nearby/fuzzy token (or a leftover LLM wait_word), baking incorrect indices into compiled scenes.py.
-
Compile path allows unpaced reveals
Boxes without a resolved wait_word still emit timed_play(FadeIn) immediately after the previous animation. That produces a short slideshow + long frozen hold, which feels “completely out of sync” even when total duration matches TTS.
-
Regen order amplifies the bug
Typical consumer flow regenerated scene specs before fresh TTS/timing.json (or compiled against sparse timing), then rendered Manim after local timestamps. Tooling should either require timing first, or treat missing timing as a hard failure for paced scenes instead of silent unpaced fallback.
Expected behavior
- Every paced box label should be a spoken anchor from that segment’s narration (or an explicit alias map).
wait_word indices must refer to the first occurrence of that anchor in timing.json words; unmatched labels must fail generate/compile (or force a redesign), not silently bind to unrelated tokens.
- Default compile behavior should not cascade unpaced
timed_play for story beats when timing exists; prefer wait-until-word (or wait-until-segment) for each reveal.
generate-all / docs should recommend: narration → TTS → timestamps → then scene-spec-generate/compile → Manim → compose (or auto-rerun compile after timestamps).
Proposed work
Environment
- docgen: current main (incl. local timestamps engine, image elements,
docgen.project hint merge)
- Consumer:
jmjava/tekton-dag docs/demos full regen (19 Manim segments)
- Timestamps engine used:
local (default)
Related
Consumer impact: tekton-dag demo recordings after Jul 2026 full regen are not shippable for content sync until this is addressed (or scenes are hand-constrained via much stricter hints + forced retime).
Summary
After a full tekton-dag demo regen on current docgen (Manim-only, local timestamps, scene-spec → compile → TTS → timestamps → Manim → compose), composed videos match audio length but on-screen content often has little relation to what is being spoken.
This is not primarily A/V stream drift (ffprobe durations are close). It is semantic / beat sync failure: visuals race through a generic diagram, latch to the wrong spoken words, then freeze while narration continues on other topics.
Observed in consumer (tekton-dag
docs/demos)Segment 01 (
StackDAGScene):Demo-fe,Originator,Forwarder,Terminalthat never appear in the regenerated narration.wait_until_word(timing_words, 146)before revealingOriginator, but word index 146 intiming.jsonis the token "operator" (~64s) — unrelated.timed_playwith nowait_until_word, so large chunks of the visual story finish in the first tens of seconds.Segment 03 (
HeaderPropagationScene):timing_wordsbut mostly uses unpacedtimed_play(FadeIn(...))cascades, then relies on the audio-length tail / compose freeze for the remaining narration.Validate can still report PASS for
av_drift/timing_syncbecause the muxed video is padded to the mp3 duration even when the visual story is already over.Root causes (suspected)
scene-spec-generatedoes not enforce narration-anchored labelsSystem prompt says to mirror narration beats, but the model freely invents diagram vocabulary (roles, app names) that are not spoken. There is no hard gate that every
labelmust match a token/phrase in the segment narration (or a declared synonym list).sync_row_labels_to_whisper_words(..., overwrite=True)fills bad matchesWhen a label is absent from
timing.jsonwords, matching appears to attach to a wrong nearby/fuzzy token (or a leftover LLMwait_word), baking incorrect indices into compiledscenes.py.Compile path allows unpaced reveals
Boxes without a resolved
wait_wordstill emittimed_play(FadeIn)immediately after the previous animation. That produces a short slideshow + long frozen hold, which feels “completely out of sync” even when total duration matches TTS.Regen order amplifies the bug
Typical consumer flow regenerated scene specs before fresh TTS/
timing.json(or compiled against sparse timing), then rendered Manim after local timestamps. Tooling should either require timing first, or treat missing timing as a hard failure for paced scenes instead of silent unpaced fallback.Expected behavior
wait_wordindices must refer to the first occurrence of that anchor intiming.jsonwords; unmatched labels must fail generate/compile (or force a redesign), not silently bind to unrelated tokens.timed_playfor story beats when timing exists; prefer wait-until-word (or wait-until-segment) for each reveal.generate-all/ docs should recommend: narration → TTS → timestamps → then scene-spec-generate/compile → Manim → compose (or auto-rerun compile after timestamps).Proposed work
scene-spec-generate/scene_spec.validate/sync_row_labels_to_whisper_words: reject or warn loudly when labels do not match narration tokens.pace: noneopt-out).scene-compile --retimethat only rewriteswait_until_wordindices from currenttiming.jsonwithout calling OpenAI.Environment
docgen.projecthint merge)jmjava/tekton-dagdocs/demosfull regen (19 Manim segments)local(default)Related
Consumer impact: tekton-dag demo recordings after Jul 2026 full regen are not shippable for content sync until this is addressed (or scenes are hand-constrained via much stricter hints + forced retime).