Video Lab · post-to-video (script, voice, lip-synced hosts, Remotion edit, QA, YouTube package)

From post to YouTube: how every Video Lab article becomes a hosted, narrated video

Rated G

One post folder in, a handful of commands, and out come a short film, an instructional hosted by AI hosts, a narration, an interactive player and a folder built to YouTube's upload specs. What each stage costs on one DGX Spark, and what we still decide by hand.

Listen

Narrated by Theo Lindqvist (AI voice, ElevenLabs)

Transcript

Approximate read-along: sentence timing is estimated from the audio length.

Hi, I'm Theo Lindqvist, an AI voice on the LEJ Video Lab. This one is about the machine that turns every post on this page into a video. Picture it like this: a post folder goes in at one end, and a captioned, hosted video comes out the other, ready for YouTube. This post is the first one to go through the last stage too, the YouTube folder. Here's how it works, one stage at a time. Stage one is the script. An agent reads the post and writes five files: the narration you're hearing now, the lines the on-camera hosts say, the edit for the instructional video, the shot list for the short film, and the data for the interactive player. This is the stage with judgment in it, so we don't pretend it's automated. One rule shapes everything after it. On-camera speech is the expensive part, so every host line stays under twenty seconds, and each video gets at most a minute on camera. This post has fifty-five seconds on camera, in four lines, and about two minutes of voice-over. Stage two is the voices. Each line goes to ElevenLabs through an endpoint that returns timestamps, so every word comes back with a start time and an end time. Those timings are the backbone of everything: the captions you see, the lip-sync checks, and the caption file for YouTube. For this post, eleven lines came back in roughly three to five seconds each. That's about a quarter of a second of waiting for every second of speech. Stage three is the AI hosts, and here's the trick. A script called host-segments takes each line, refuses anything over twenty seconds, and puts one job on the GPU queue. The queue runs one heavy job at a time. That job gives each host's studio portrait and the line's audio to LTX two point five, which turns them into a talking clip. In our smoke test, that cost fifteen to sixteen seconds of GPU for every second of speech, and for this post's four lines it was sixteen to eighteen. This is the only stage that uses the GPU at all. Stage four is the edit. The instructional is one JSON file: a list of blocks, like a title card, a host clip, an explainer panel, another host clip, each with a length. The host blocks get their length from the audio. The voice-over panels carry their audio and their word timings, so the captions line up on their own. Stage five is the render. A script called post-to-video checks every file before it starts, waits until the machine has enough free memory, and hands the edit to Remotion, which renders it on the CPU. A thirty-four second test video rendered in about thirty-four seconds. So, real time. The same tool also makes the short film and this narration, and it never overwrites an earlier version. Stage six is quality control. A QA script checks the codec, the size, that the file starts playing fast, that the audio is really there, and that no placeholder text or private path slipped through. It checked a thirty-six second video in three and a half seconds, and it draws a contact sheet of every video. Does that make sense? Good, because here's the twist. Our explainer panels are dark on purpose, so the black-frame check flags them every time. That's why it only warns, and why the last gate is still a person looking at the frames: faces, hands, mouths, text, and whether the hosts are labeled as AI. Stage seven is the YouTube folder. A script called youtube-package takes the finished video and builds everything YouTube wants. It re-encodes the video to YouTube's recommended settings when it needs to, fixes the color range, and brings the loudness up to where YouTube plays things back. It writes captions from the same word timings, chapters from the panel titles, a thumbnail from a frame of the host with the title next to it, and a title, description and tags, with a plain note that the hosts are AI. For half a minute of video, that took about eight seconds. It doesn't upload anything, and it doesn't need any keys. So what's still done by hand? Writing the scripts. Picking the better host take. Choosing the thumbnail frame, because the automatic one caught our host mid-blink the very first time. Looking at every frame sheet. And the upload itself, which is still a person in YouTube Studio. Making this post also shook out three bugs. Re-rendering the video re-rendered the hosts on the GPU too, the renderer didn't keep a copy of the edit it rendered, and the colors came out in the wrong range for YouTube. All three got fixed the same night. One thing we didn't fix: the hosts' lip-sync is loose at pauses. Their mouths closed at only six of twenty-one pauses. The next host lines get a voice model that holds longer pauses, but we haven't shown yet that it fixes the mouths. That's the machine. One post in, a video folder out. The full write-up, with every number and where it came from, is on the page.

The short film: the making of this post as a fast montage of its own files and renders, in pipeline order: the review, the host lines, the word timings, the GPU queue, the AI host clips, the edit, the render log, the finished instructional, QA and the YouTube folder. 53 s, 16:9. Music: a bed synthesized with ffmpeg (sine tones and a pulse); no music model.
Prompt and settings

Settings: Remotion ShortFilm, 1920x1080, 30 fps, 12-frame cross-fades. File cards rendered from the real files with tools/capture.py; host clips from LTX 2.5 ia2v at 1280x704.

The instructional: AI hosts Daisy Lane and Ama Boateng (AI voices, ElevenLabs) walk through six steps (script, voices, hosts, edit and render, QA, YouTube folder), with the measured time of most on screen. 55 s on camera in four segments, the rest voice-over panels. Sync is loose at pauses: the hosts' mouths closed at only 6 of 21 pauses; on speech the mouth moves in most frames. 191 s. Poster: the YouTube thumbnail this pipeline made.
Prompt and settings

Settings: Four on-camera segments by LTX 2.5 22B distilled image+audio-to-video at 1280x704, seed 42, from each host's on-set still; voices eleven_v4 at the cast settings; Remotion Instructional, 1920x1080, 30 fps, captions from the word timings.

The first host take of the night straight off the GPU queue: AI host Daisy Lane, 5.68 s of speech, 93.2 s of LTX wall time (16.4 s per second). Raw clip, before any edit.
Prompt and settings

Prompt: Okay, let's play. This is the first real host take of the night, straight off the queue.

Settings: bin/host-segments smoke test: LTX 2.5 22B distilled ia2v, 1280x704, 24 fps, seed 42, image strength 1.0, Daisy Lane on-set still, eleven_v4 voice at the cast settings, clean mp3 muxed back over the clip.

The pipeline, stage by stageClick a stage to see what goes in, what comes out, and the time we measured for it on one DGX Spark.

Verdict

The pipeline works end to end on one DGX Spark: a post folder goes in, post-to-video renders the short film, a hosted instructional and the narration (it can build the player too; for this post we built it with build-player), and youtube-package builds a folder to YouTube's published upload settings (not uploaded yet, so not tested against YouTube Studio). The only GPU stage is the AI hosts, at 16 to 18 s of compute per second of on-camera speech for this post (16 minutes for 55 s), and their lip-sync is loose at pauses; voices, rendering, QA and packaging run at about real time or faster. Still a judgment call, not a script: the scripts, the host takes, the thumbnail frame, the final look at every frame sheet, and the upload.

Credits and settings

WorkflowLEJ post-to-YouTube pipeline
MakerLEJ Video Lab (house pipeline)
VersionNov 2 2026 build: bin/post-to-video, host-segments, qa-post, youtube-package; Remotion 4.0.539; ElevenLabs eleven_v4; LTX 2.5 22B distilled (int8) image+audio-to-video
What it doespost-to-video (script, voice, lip-synced hosts, Remotion edit, QA, YouTube package)
LicenseHouse scripts, no license. Parts: LTX-2.x Community License (LTX 2.5), Remotion License (free for individuals and companies with up to 3 employees), ElevenLabs API (paid plan terms)
HardwareDGX Spark: NVIDIA GB10, ARM (aarch64), 128 GB unified memory (121.7 GiB visible to Linux), 20 CPU cores. LTX 2.5 in ComfyUI 0.43.0 on the GPU; Remotion renders on the CPU in headless Chrome; ffmpeg 8.1.
Speed6.3 s of compute per second of video. 6.3 = 963.9 s of LTX for the four host clips plus 241.9 s to render, per 191.2 s of instructional. Per stage on one DGX Spark: voices about 0.25 s per second of speech; AI hosts 16.3 to 18.4 s of GPU per second of on-camera speech (this post, tests/HOSTS.tsv); Remotion render about 1x real time on the CPU; QA 3.5 s and YouTube packaging 7 to 9 s for a half-minute video.
Peak memoryFree memory (MemAvailable) dipped to 9 GiB during the smoke-test host job and 13 GiB during this post's host job (logs/gpu-queue.log, whole GiB rounded down); post-to-video waits for 20 GiB free before any CPU render.
Tested onNov 2, 2026
AI hosts

Daisy Lane (AI host; AI voice)

Ama Boateng (AI host; AI voice)

Narration
Theo Lindqvist (AI voice, ElevenLabs)
Music source
Not supplied

What it does well

  • One tool for the renders: post-to-video writes the film, instructional and narration as new versioned files and never overwrites one
  • Captions, lip-sync checks and the YouTube .srt all come from the same ElevenLabs word timings
  • GPU cost is confined to on-camera host lines (55 s for this post); everything else renders on the CPU at about real time
  • QA fails a post on the wrong codec, size or aspect, missing faststart or audio, placeholders and private paths before anything is uploaded
  • youtube-package builds captions, chapters, thumbnail, title, description and tags in 7 to 9 s per half minute of video, with no keys and no upload

Where it breaks

  • Three pipeline bugs surfaced while making this post (hosts re-rendered with every edit render, no copy of the rendered edit, full-range colour); all three were fixed the same night
  • The automatic thumbnail frame landed mid-blink on the first real host clip
  • The mix lands near -17 LUFS (this post's instructional -17.0, the first test fixture -17.4), quieter than YouTube plays back; youtube-package normalizes it to -14 LUFS
  • The black-frame check flags our dark explainer panels every time, so it can only warn
  • Lip-sync is loose at pauses: across this post's four host takes the mouth closed at 6 of 21 pauses, under our 4-of-6 gate (eleven_v4 pauses are only 0.36 to 0.60 s)
  • Scripts, take selection and the upload are still manual

The goal is simple to say: every post on this page should also exist as a video we can put on YouTube. Not someday, not as a weekend editing project per post. A post folder goes in, and a finished, captioned, hosted video comes out.

So tonight we built that machine, and this post is the first to go through the last stage too, the YouTube folder. The short film above is the making-of: this post's own files and renders as they came out, in pipeline order. The instructional is the pipeline explaining itself, hosted by two of our AI hosts, Daisy Lane and Ama Boateng (AI characters with AI voices). The narration is Theo Lindqvist, also an AI voice.

Here's what's automated, what each stage costs on one DGX Spark, and what we still decide by hand.

How we tested

Everything ran on one DGX Spark on Nov 2, 2026, during a long overnight run of Video Lab tests. Two kinds of runs feed the numbers below:

  • This post itself. Its four on-camera host lines, seven voice-over lines, edit, film, narration and player went through the real tools. The TTS numbers come from the JSON line bin/tts.py prints for every call (saved in media/tts-hosts.jsonl and media/vo/tts-vo.jsonl). The host render numbers come from tests/HOSTS.tsv, which bin/host-segments appends one row to per finished clip.
  • Test fixtures. Before trusting the tools with a real post, we ran them on two small fixtures: a 30 s instructional built from a two-host smoke test (Daisy and Rafael, one line each, rendered on the GPU queue), and a 34-36 s instructional that used an older lip-sync clip as a stand-in host. Render, QA and packaging times come from those runs' logs.

Nothing here was uploaded to YouTube. The pipeline stops at a folder that's ready to upload.

The pipeline, stage by stage

#StageToolWho does itMeasuredSource
1Scripts from the postan agent sessionan agent (not a script)not measured
2Voices with word timingsbin/tts.py (ElevenLabs, eleven_v4)automated3.36 to 5.10 s per call for 11.8 to 20.9 s lines (11 calls)media/tts-hosts.jsonl, media/vo/tts-vo.jsonl
3AI host clipsbin/host-segments -> GPU queue -> LTX 2.5 image+audio-to-videoautomated, queuedthis post's four takes 16.3 to 18.4 s of GPU per second of speech (smoke test 15.1 and 16.4)tests/HOSTS.tsv
4The editinstructional.edit.json (+ host-segments --fill-edit)lengths automated, content writtennot measured
5Renderbin/post-to-video -> bin/render-remotion (Remotion 4.0.539)automated34.2 s instructional in 33.7 s (30.4 rendered frames per wall second)fixture media/renders.log
6Narrationbin/post-to-video --narration (tts.py in chunks)automated288.0 s of narration in 74.8 s (67.6 s of it TTS latency, 2 chunks)media/tts-narration.jsonl
7Playerremotion/bin/build-player.mjsautomatedabout 0.2 s to bundle a demo playertests/post-to-video/report.md
8QAbin/qa-postautomated checks + a human look36.2 s video checked in 3.5 sfixture run
9YouTube folderbin/youtube-packageautomated7.2 to 8.6 s for a 30 to 36 s videofixture youtube/*/metadata.json
10Publish heresite.sh --file, then --publisha person runs itnot measured
11Upload to YouTubeYouTube Studioa personnot done yet

The instructional and the narration group these into six or seven steps (script, voices, hosts, edit and render, QA, YouTube folder); the table splits render, narration and player out.

1. Scripts

An agent reads the post and writes five files: narration.md (the article rewritten for the ear, with a front-matter line naming the voice), hosts.json (the on-camera lines), instructional.edit.json (the blocks of the instructional), film.props.json (the short film's shot list) and player.props.json. This is the stage with judgment in it, so it's the one we don't pretend is automated.

The rule that shapes everything downstream: on-camera speech is the expensive part, so each host line stays under 20 s and each instructional gets at most 60 s on camera. Everything else is the host's voice running under Remotion panels, which costs no GPU. This post has 55.12 s on camera in four lines (11.84, 15.20, 14.88 and 13.20 s) and 124 s of voice-over.

2. Voices

bin/tts.py calls ElevenLabs' with-timestamps endpoint, so every line comes back as an mp3 plus a words.json with a start and end time for every word. Voice and settings come from the cast registry, so Daisy always sounds like Daisy. The word timings are the backbone of the whole thing: they drive the burned-in captions, the lip-sync scoring, and the YouTube caption file.

For this post: 11 calls on eleven_v4, latency 3.36 to 5.10 s each, for lines of 11.8 to 20.9 s. That's roughly a quarter second of waiting per second of speech.

3. The AI hosts

bin/host-segments reads hosts.json, voices any line that isn't voiced yet, refuses any line over 20 s, and writes one GPU job into the queue. The queue runs one heavy job at a time under one lock. The job feeds each host's studio still plus the line's audio to LTX 2.5 (22B distilled, image+audio-to-video) at 1280x704, then muxes the clean mp3 back over the clip so the last syllable can't get clipped.

The smoke test (two 5.6-5.7 s lines) cost 93.2 s and 84.3 s of LTX wall time: 16.4 and 15.1 s of GPU per second of speech. The whole queue job, including freeing the other server and the model load, took 182 s, and free memory dipped to 9 GiB during it (logs/gpu-queue.log, which rounds down to whole GiB). This post's own four lines cost 192.5, 273.8, 274.1 and 223.5 s of LTX wall time: 16.3, 18.0, 18.4 and 16.9 s per second of speech, 963.9 s (16.1 minutes) for 55.12 s on camera, or 17.5 s per second overall. The queue job took 969 s and free memory bottomed out at 13 GiB.

The honest part: lip-sync is loose at pauses. We score every take with a frame sheet: one frame in the middle of every pause between words, where the mouth should be closed, and one on every fourth word, where it should be moving. Across the four takes the mouth was closed at 6 of 21 pauses, well under our gate of 4 of 6 (sheets in qa/score/). On speech the mouth is open or moving in most sampled frames; a few land closed mid-word. One guess at the cause is the voice: eleven_v4 at our cast settings keeps pauses short (these 21 measure 0.36 to 0.60 s), which may be too short for the model to close the mouth and reopen it. The evidence so far doesn't back that guess: eleven_v3 holds much longer pauses, but the v3 host takes scored tonight on another post closed at only about 3 to 4 of 11. So the next host lines use eleven_v3 with "..." as cheap insurance, not as a known fix. We didn't re-render these.

4 and 5. The edit and the render

The instructional is one JSON file: a list of blocks (title card, host clip, explainer panel, host clip, ...) with a length in frames. Host block lengths come from the audio, using host-segments' own rule (audio length plus half a second). Voice-over panels carry their mp3 and its word timings as a caption overlay.

bin/post-to-video checks every path before it starts. It waits until the box has more than 20 GiB free, so a CPU render can't push a GPU job into swap. Then it renders through Remotion, keeps the file under the site's 40 MB cap, picks a poster frame that isn't black, and writes a new versioned file every time; it refuses to overwrite one. Remotion renders on the CPU in headless Chrome. On the 20-core GB10 the test renders ran at about real time:

RenderLengthWallRendered frames per wall second
Fixture instructional (title cards, one host clip, two panels)34.2 s33.7 s30.4
Same fixture, longer title card36.2 s30.8 s35.3
Same edit re-rendered by youtube-package --remaster36.2 s38.0 s28.6
Smoke fixture with both real host clips (concurrency 6)30.3 s32.7 s27.8
This post's instructional (13 blocks, four host clips)191.2 s241.9 s for the whole call (render, BT.709 encode, poster); the split wasn't savednot saved
This post's short film (14 shots, final take)53.2 s79.2 s, plus an 8.6 s BT.709 encode; 88.9 s for the whole call20.1
Demo short film9.0 s11.7 snot printed

The whole post-to-video --instructional call for the 34.2 s fixture took 34.1 s, render included.

6 and 7. Narration and player

post-to-video --narration strips the Markdown, turns tables into "see the table on the page", splits the text into chunks under 4,500 characters, voices them in order and joins them into one mp3 with its transcript. For this post: 4,809 characters became two chunks, 251.3 s and 36.7 s of audio, with 59.7 s and 7.9 s of TTS latency; the whole call took 74.8 s for 288.0 s of narration. The player is a single self-contained HTML file (React, the Remotion player and the composition, all inlined) that the page shows in a sandboxed frame. This post's player is the pipeline itself: click a stage to see what goes in, what comes out, and what it cost.

8. Quality gates

bin/qa-post fails a post for: a video that isn't H.264 with audio, a film or instructional that isn't 16:9 at 720p or 1080p, no faststart, a narration that doesn't decode to its stated length, a player that loads anything from outside its own file, and any leftover placeholder or private path in the review. It warns on long dark stretches and on videos over 20 MB, and it draws a timestamped contact sheet of every video. It checked the 36.2 s fixture in 3.5 s. On this post's player it also warned five times that a fetch() inside the bundled Remotion code can't be checked statically; every resource tag in the file is inline, but that check is literal, not a guarantee. (Faststart means the file's index sits at the front, so playback starts before the download finishes.)

The warnings matter as much as the failures. Our explainer panels are near-black by design, so the black-frame check flags them every time. That's why it's a warning, and why the last gate is still a person looking at the frame sheets: faces, hands, mouths, text, and whether the AI host is labeled as AI.

9. The YouTube folder

bin/youtube-package is the last piece, and it doesn't upload anything or need any keys. From a post that has a rendered instructional, it writes youtube/<version>/:

  • video.mp4: copied if it already meets YouTube's recommended upload settings, otherwise re-encoded to H.264 High, 4:2:0, closed GOP of half the frame rate, two B-frames, capped at YouTube's recommended 8 Mbps for 1080p at 24-30 fps, AAC at 48 kHz, moov atom first (YouTube's upload encoding settings).
  • captions.en.srt: from the same ElevenLabs word timings, each host line and voice-over block shifted by where its block starts in the edit, grouped into the same short lines the burned-in captions show.
  • chapters.txt: from the panel titles, with YouTube's chapter rules applied: first one at 0:00, at least three, each at least 10 s (YouTube's chapter rules). Short blocks fold into the chapter before them.
  • thumbnail.jpg: 1280x720, a frame from the first host clip with the title drawn next to it and an "AI host" badge, plus a contact sheet of six candidate frames (YouTube's thumbnail guidance).
  • title, description, tags, metadata.json: the title cut to 100 characters at a clause break, a description with the dek, the chapters, a plain AI disclosure naming the hosts, and a link back to the post here.

On the fixtures the whole package took 7.2 to 8.6 s for 30 to 36 s of video, most of it the encode (4.8 to 5.7 s).

The YouTube package for this post

This post went through the last stage too. bin/youtube-package --remaster re-rendered the instructional from the copy of the edit post-to-video saved, normalized the mix to -14.00 LUFS (true peak -1.80 dBTP), and wrote 89 caption cues from 477 timed words. It took 229 s, 208 s of it the re-render. Its thumbnail is the poster on the instructional above; the frame is one we picked from the six-frame sheet, 1.78 s into Daisy's opening line. The chapters it wrote:

0:00 Intro
0:31 1. The script
0:50 2. Voices with word timings
1:07 3. The AI hosts
1:28 4. The edit and the render
1:47 5. Quality gates
2:18 6. The YouTube folder
2:36 Still not automatic
2:53 Wrap-up

The captions file, chapters, thumbnail, title, description, tags and metadata are in the download link at the bottom of this page. The YouTube video itself (43.3 MB) isn't on this page: it's the same edit as the instructional above, so we keep it with the post's source files until the upload.

Setup and gotchas

  • Remotion wrote full-range color (fixed during the run). Its H.264 came out as yuvj420p (full range, BT.601 matrix). We measured two fixes on the same frame: converting only the range came out 1.1 to 2.3 levels (mean, per channel) from the source; also converting the matrix to BT.709 came out 2.8 to 4.0 levels off. By the time this post rendered, bin/render-remotion encoded BT.709 limited range itself (8.6 s for this post's 53 s film, media/render-film-v2.log), and youtube-package still converts any full-range file it's handed.
  • The mix is quieter than YouTube plays. Our voices are loudness-normalized at -16 LUFS in a single pass, which measured -17.5 LUFS in the TTS tests, the rendered fixture measured -17.4 LUFS, and this post's instructional -17.0. (LUFS is average loudness; closer to zero is louder.) YouTube publishes no loudness target, but playback has been measured at -14 LUFS, and quieter uploads aren't turned up (Production Advice). So youtube-package does a two-pass normalization to -14 LUFS and -1 dBTP when the mix is under -15.5. The fixture came out at -14.01 LUFS, true peak -1.43 dBTP.
  • The automatic thumbnail frame can land mid-blink. It did on the very first real host clip. That's why the package includes a six-frame candidate sheet, and picking the frame is still a person's call (--thumb-at).
  • Re-rendering the instructional used to re-render the hosts (fixed during the run). post-to-video --instructional always calls host-segments, which didn't skip clips that already existed, so every re-render of the edit queued every host line on the GPU again and replaced the take you picked. host-segments now skips any line that already has its clip and its seg.json, unless you pass --force.
  • The renderer kept no copy of the edit it rendered (fixed during the run). If the edit file changed after a render, the captions and chapters would be computed against the wrong timeline. post-to-video now saves instructional-<version>.edit.json next to each render, youtube-package reads that copy, and it still refuses an edit whose length doesn't match the MP4 within half a second.
  • The site's 40 MB cap is not YouTube's. post-to-video squeezes long renders under 40 MB for this page. youtube-package --remaster re-renders the same edit at full quality for YouTube, which took 38.0 s for the 36.2 s fixture.
  • CPU renders wait for memory. post-to-video won't start a render below 20 GiB free. During a host job on the GPU, free memory went as low as 9 GiB, so renders queue up behind GPU work on their own.
  • eleven_v4 doesn't hold long pauses. At our cast settings neither "..." nor a break tag gets a pause past about 0.55 s (from our TTS tests; word timings come in 40 ms steps, so one pause here measures 0.60 s). Fine for voice-over. eleven_v3 holds longer pauses, but it hasn't yet been shown to fix the mouths (see section 3).

Settings

  • Voices: ElevenLabs eleven_v4, cast settings from the registry (Daisy: stability 0.45, similarity 0.75, style 0.3; Ama: the same; Theo: stability 0.55, style 0.15), with-timestamps endpoint, mp3 44.1 kHz 128 kbps, loudness-normalized at -16 LUFS.
  • Hosts: LTX 2.5 22B distilled image+audio-to-video, 1280x704, seed 42, image strength 1.0, each host's on-set studio still, one queue job per post.
  • Edit and render: Remotion 4.0.539, 1920x1080, 30 fps, H.264 with faststart, concurrency 6 (the render-remotion default since a 03:48 memory fix; the first fixture renders, before that change, used 10).
  • YouTube re-encode: libx264 High, CRF 18 capped at 8 Mbps (1080p, 24-30 fps), GOP 15 at 30 fps, 2 B-frames, closed GOP, limited range, AAC 384 kbps stereo at 48 kHz, two-pass loudnorm to -14 LUFS / -1 dBTP when needed.
  • Thumbnail: 1280x720 JPEG under 2 MB, frame from the first host clip, DejaVu Sans Bold, drawn with Pillow.

Speed and memory

The only GPU stage is the hosts. Everything else runs on the CPU:

  • Voices: about 0.25 s of waiting per second of speech for short lines, 0.24 s for the 4-minute narration chunk.
  • Hosts: 16.3 to 18.4 s of GPU per second of on-camera speech. With 55.12 s on camera, this post's instructional cost 963.9 s (16.1 minutes) of LTX wall time (tests/HOSTS.tsv).
  • Render: about 1x real time on the test renders; this post's 191.2 s instructional took 241.9 s for the whole call, about 1.3x.
  • QA: a few seconds. YouTube folder: under 10 s for half a minute of video.

Memory: free memory dipped to 9 GiB during the smoke-test host job and to 13 GiB during this post's (logs/gpu-queue.log); the render step waits for 20 GiB free before it starts.

What we still do by hand

  • Writing the scripts. An agent writes them from the post, and the measured numbers in them get checked against the files.
  • Picking host takes. One seed per line by default; when a take is off, we render another seed and pick from the contact sheets.
  • Choosing the thumbnail frame from the candidate sheet.
  • Watching the frame sheets before anything ships: faces, hands, mouths, text.
  • Publishing here and uploading to YouTube. The folder is ready; the upload is a person in YouTube Studio for now, including answering YES to the altered or synthetic content question, because the hosts are realistic AI people.

What's next

Run every published Video Lab post through youtube-package, move host lines to eleven_v3 with real pauses and see whether lip-sync improves at the stops (so far it hasn't been shown to), and then decide on the upload itself: by hand from the folder, or through the YouTube API with a review step in front of it.

YouTube package for this post (zip): captions .srt, chapters, thumbnail, title, description, tags, metadata ↗