v0.10.0¶
Release Date: 2026-10-25
Adds native HTML slide decks alongside Marp: write narration into the deck, and vac generates the transcript and video config, serves the deck, and records it — each slide timed to its own narration. Decks can be divided into lessons, each recorded as its own video for a course platform, and voiceover audio is cached per clip so only edited narration is sent to TTS again.
Highlights¶
vac html video: serve an HTML deck on a loopback port and record it with TTS voiceover in one command — no separate web server or build stepvac html init: generate a transcript and avac browser videoconfig from a deck, keeping translations and pronunciations across re-runs- Per-slide timing: browser segments whose transcript has one segment per step now time each step to its own narration instead of an equal share of the total
- Course lessons:
vac html video --lessons allrecords one video per lesson with alessons.jsonmanifest;--lessons changedre-records only lessons whose slides, narration, voice, or pronunciations changed - Clip cache: each voiceover's audio is named by a hash of its text and voice, so unchanged narration is never synthesized twice and edited narration never plays stale audio
Added¶
pkg/htmldeck— parses HTML decks (elements with aslideclass) and reads each slide's narration from adata-voattribute or a child<aside class="notes">(reveal.js speaker notes), with[PAUSE:ms]directives as in Marp voiceover commentshtmldeck.Deck.Transcript— the deck's narration as a videoascode transcript, split into sentences, keeping other languages from an existing transcripthtmldeck.Deck.VideoConfig— a validated browser video config with one step per slide and narration for every language that covers all slidesvac html init— writesvoiceover/transcript.jsonanddeck.video.jsonnext to the deck; flags for title, voice, narration language, pronunciations file, URL query, next key, initial wait, slide class, and narration attributevac html video— serves the deck directory and records it; accepts allvac browser videorecording, TTS, and subtitle flags, and reads translations from the transcriptexamples/html-deck/— a four-slide deck in two lessons showingdata-vo, speaker notes, a pause, a pronunciation file, and opening at a slide from the URL fragment- Lessons: a slide with a
data-lessonattribute (or the class given by--lesson-class) starts a lesson, titled by the attribute's value; slides before the first lesson start join the first lesson.htmldeck.Deck.Lessons,Deck.Lesson(by ID or number), andLesson.Name(such as02-designing-endpoints) htmldeck.Deck.LessonVideoConfig— a config recording one lesson, opening the deck at its first slide with a URL fragment:#{id}by default, or--start-fragmentwith{id},{n}, or{i}(for example#/{i}for reveal.js)htmldeck.Manifestandhtmldeck.LessonFingerprint—lessons.jsonlists each lesson's slides, videos per language, duration, and a fingerprint of its slide HTML and config (narration in every language, voice, pronunciations, timing)vac html video --lessons— record lessons by ID or number,all, orchanged, into--output-dir(defaultlessons/next to the deck), updating the manifest after eachvac html lessons— list lessons with their slides, estimated length, and status (not recorded,changed, orrecordedwith the video's length)tts.ClipKey— the content hash that names a voiceover clip
Fixed¶
- Browser segments with segment-level transcripts gave every step an equal share of the total narration time, so slides drifted out of sync with the voiceover. When every language's transcript has one segment per step, each step now lasts its own segment's duration plus its pause (the longest across languages), matching how the audio track is assembled. Transcripts that don't line up with the steps keep the proportional distribution.
- Browser video reused cached audio by segment name and voiceover position, and the default cache lives in the system temp directory across runs, so edited narration, a new pronunciation, or a different voice could play the old audio. Clips are now keyed by their spoken text, language, and voice settings, and a segment's assembled audio is rebuilt whenever one of its clips or pauses changes.
Changed¶
vac browser video's flags and recording pipeline are shared withvac html video; the run summary's first line now readsInput:instead ofConfig:- Browser video TTS audio is stored as clips in
{audio-dir}/{language}/clips/and assembled per segment. Audio cached by earlier versions is not reused; it is generated once more in the new layout. vac html videoreads pronunciations fromdeck.video.jsonnext to the deck when--pronunciationsis not given, asvac html initdoes
Usage¶
# Record an HTML deck directly
vac html video --input deck/index.html --output deck.mp4 --provider deepgram
# Generate a transcript and reusable config
vac html init --input deck/index.html --provider deepgram --voice aura-asteria-en
# Record a translation added to voiceover/transcript.json
vac html video --input deck/index.html --output deck.mp4 --lang en-US,fr-FR
# List lessons and record one video per lesson
vac html lessons --input deck/index.html
vac html video --input deck/index.html --lessons all
# After editing, re-record only the lessons that changed
vac html video --input deck/index.html --lessons changed
A slide:
<section class="slide" data-id="intro" data-title="Introduction"
data-vo="Welcome. This deck explains the protocol in five minutes. [PAUSE:500]">
<h1>Introduction</h1>
</section>
A slide that starts a lesson:
<section class="slide" data-id="sec-design" data-lesson="Designing Endpoints"
data-vo="Good endpoints are named for the resources they serve.">
Documentation¶
- New guide: HTML Slide Decks
- New example page: HTML Deck
- New guide: Lessons and Courses, including course terminology — course, section, lesson, deck, slide, clip, line, and chapter
- Audio caching docs in the CLI reference, browser video guide, and multi-language guide updated for clips
- CLI reference, browser video guide, architecture, README, and home page updated for HTML decks and per-slide timing
Dependencies¶
golang.org/x/netis now a direct dependency (HTML parsing)- Upgraded
mogoto v0.75.0 - Upgraded
omnivoice-coreto v0.16.1 - Upgraded
golang.org/x/netto v0.61.0 and updated indirect dependencies