Nº09 · Personal tool · Oct 2026个人工具 · 2026 年 10 月Script-to-video pipeline · local speech synthesis · Playwright · ffmpeg脚本生成视频 · 本地语音合成 · Playwright · ffmpeg

Narrated Study Videos

I write a system-design walkthrough as one sentence per line, and one command turns it into a narrated mock interview: two voices, Chinese and English subtitles, guess-then-reveal quizzes, motion on whatever changed, and code traces taken from actually running the code. Five episodes so far, each one improving the engine.我把系统设计讲解写成一行一句的脚本,一条命令就生成一场模拟面试视频:两个声音、中英字幕、先猜再揭晓的小测、变化的地方会动,代码执行画面来自真跑代码。目前做了五集,每一集都让引擎更好一点。

A video frame: token-bucket Python code with one line marked red in a spot-the-bug question, English and Chinese subtitles below

01Problem问题

Explaining a design out loud is the part of an interview you can't practise by reading. Screen-recording myself is slow to redo, one typo means a full retake, and hand-drawn code traces are easy to get subtly wrong.把设计讲出来,是面试里光靠读资料练不到的部分。自己录屏改一次就得重来,一个口误就要整段重录;手画的代码执行过程也很容易出细微错误。

02How it works原理

  • The script is the source of truth: each line is one spoken sentence, who says it, its Chinese subtitle and the scene shown while it plays. Fix one line and only that line is re-voiced.脚本是唯一来源:每行是一句话、谁说、中文字幕,以及这句话播放时的画面。改一行,只重新配这一行。
  • Scenes are data, not drawings. A line names a layout (table, bullets, flow, code trace, array, linked list, tree, split) and its content; the engine renders it as HTML and screenshots it at 1920 × 1080.画面是数据,不是画出来的。每行指定一种版式(表格、要点、流程、代码执行、数组、链表、树、左右分栏)和内容;引擎把它渲染成 HTML,再按 1920 × 1080 截图。
  • Code traces are generated by running the algorithm: the build script executes the code, records each step (line, variables, verdict) and asserts the expected result, so the picture cannot drift from what the code does.代码执行画面由真跑算法生成:构建脚本执行代码,记下每一步(行号、变量、结果),并断言预期输出,画面不可能和代码实际行为不一致。
  • Each sentence becomes its own clip, sized to its audio plus a pause (0.9 s on a scene change, 0.6 s on a speaker change, 0.35 s otherwise); clips are concatenated and normalised to -16 LUFS, a common loudness target for online video.每句话单独成段,时长 = 音频 + 停顿(换画面 0.9 秒、换人 0.6 秒、其他 0.35 秒);拼接后响度统一到 -16 LUFS,这是在线视频常用的响度标准。

03What I built我做了什么

  • One engine, six commands: check (missing audio or subtitles), tts (resumable), preview (one frame per distinct scene), render (one chapter or the whole video), install, plus a translation to-do list.一个引擎、六条命令:check(查缺音频或字幕)、tts(可续跑)、preview(每种画面出一帧)、render(单章或全片)、install,以及待翻译清单。
  • Two voices on a local Kokoro server behind an OpenAI-compatible speech API: one for the candidate, one for the interviewer; interviewer subtitles sit on a different colour band.两个声音,跑在本地 Kokoro 服务上(兼容 OpenAI 语音接口):候选人一个、面试官一个;面试官的字幕底条换颜色。
  • Eleven built-in layouts; a topic can add its own scenes in a small Python hook without touching the engine.内置 11 种版式;专题可以在一个小的 Python 钩子里加自己的画面,不用改引擎。
  • Preview before render: every distinct scene is screenshotted first and checked for clipped or off-stage text; a rubric then scores the script (quizzes, think pauses, code written before it runs, one bug hunt, no still over 15 s) before anything is rendered.先预览再渲染:每种画面先截图,并自动检查文字是否被截断或超出画面;再用评分表给脚本打分(小测、思考停顿、代码先写后跑、一个找 bug 环节、静止画面不超过 15 秒),通过了才渲染。
  • Interview structure for system design: prompt, clarifying questions with what each answer locks in, functional and non-functional requirements, an estimate, the algorithm trade-off, the design, a deep dive with interviewer follow-ups, then a recap.系统设计按面试结构走:出题 → 澄清(每个答案锁定什么)→ 功能和非功能需求 → 估算 → 算法取舍 → 架构 → 深挖(面试官追问)→ 总结。
  • Free and local: no paid API, no upload; the encoder comes from a pip package, so nothing is installed system-wide.免费、本地:不调付费 API、不上传;编码器来自 pip 包,不往系统里装东西。

04The series系列

Five classic interview questions, each a mock interview with an interviewer and a candidate voice. Every concept follows the same order: feel the problem, see a picture or an everyday analogy, then the mechanism, then guess before the answer. Chapter buttons jump straight to a section.五道经典面试题,每道都是一场模拟面试,有面试官和候选人两个声音。每个概念都按同一个顺序讲:先感到问题,再看一张图或一个生活类比,然后讲机制,最后先猜再揭晓。点章节按钮可直接跳到那一段。

EP 01 · 6:30

Design a Rate Limiter

Token bucket, because bursts are allowed; one Lua script so twenty gateways share an atomic count; fail open when Redis is down.选令牌桶,因为允许突发;一个 Lua 脚本让 20 台网关共享原子计数;Redis 挂了就 fail open。

EP 02 · 6:36

Design a URL Shortener

A counter plus base62 instead of a truncated hash, which by the birthday paradox collides within the first half hour; 302 to keep click data.用发号器 + base62,而不是截断哈希:按生日悖论,后者开张半小时左右就会撞车;用 302 保留点击数据。

EP 03 · 6:05

Design a News Feed

Push for regular users, pull for celebrities, merged at read time; feeds store post IDs only, 800 GB instead of 1 PB.普通人推、明星拉,读时合并;推送只存帖子 ID:800 GB,而不是 1 PB。

EP 04 · 7:10

Design a Notification System

Accept fast, deliver later: an express lane so login codes never wait 83 minutes behind a promo, and an idempotency key born with the message so a retry after a lost response never sends the text twice.先收下、之后送:验证码走快车道,不会排在促销后面等 83 分钟;幂等键跟着消息诞生,响应丢失后的重试不会把短信发两次。

EP 05 · 8:04

Design a Distributed Job Scheduler

Workers claim rows with SKIP LOCKED under a lease, renew it with a heartbeat, and finish only if their token is still current, so a worker that comes back after its lease expired changes zero rows. In a simulation, polling without a lock ran 1,000 jobs 4,245 times with 32 workers.工作者用 SKIP LOCKED 加租约认领任务,用心跳续租,只有令牌还对得上才算完成,所以租约过期后才回来的工作者一行都改不了。在模拟里,不加锁轮询让 32 个工作者把 1,000 个任务跑了 4,245 次。

05What each episode taught the engine每一集让引擎学到什么

  • EP 01 Previewing every distinct scene before rendering caught three mistakes by eye: a double-escaped <, a code-trace frame one step behind its narration, and a diagram that put Redis on the request path.渲染前逐个预览每种画面,肉眼抓到三处错:一个被转义两次的 <、一帧代码执行比旁白慢一步、一张把 Redis 画在请求路径上的图。
  • EP 01 v2 A review rubric scored the first cut 2 of 8. The remake opens on an incident, adds three guess-then-reveal quizzes with think pauses, writes the code line by line before running it, adds a spot-the-bug moment, and keeps every still under 15 s. Now 8 of 8.评分表给第一版打了 2/8。重做后:开场是一个事故,加三道先猜再揭晓的题和思考停顿,代码先逐行写再运行,加一个找 bug 环节,每个静止画面不超过 15 秒。现在 8/8。
  • EP 02 Render now writes chapter timestamps (they drive the buttons above). Estimates are computed in code and spoken as words, since the speech model would read “2.2M” as “two point two M”. Preview flags clipped or off-stage text automatically.渲染时输出章节时间点(就是上面的按钮)。估算由代码计算,并转成读得出的说法,因为语音模型会把「2.2M」读成「two point two M」。预览自动标出被截断或超出画面的文字。
  • EP 02 Found and fixed a highlighter bug: any string literal showed up as &#x27;, because the comment rule matched the # inside the escaped quote.发现并修了一个代码高亮 bug:任何字符串字面量都显示成 &#x27;,因为注释规则匹配到了转义引号里的 #。
  • EP 03 Numbers argue for a design choice on screen: the memory estimate (1 PB of posts vs 800 GB of IDs) is what decides that feeds store IDs only.让数字在画面上为设计决定说话:内存估算(整条帖子 1 PB vs 只存 ID 800 GB)直接决定了推送只存 ID。
  • EP 04 First episode on the stricter 13-point rubric: it opens with recall questions from earlier episodes (one shared question bank across the system design and algorithm series), shows the naive design failing on a real chart, re-checks an invariant (“each text reaches the phone at most once”) on a simulated lost response, and ends with a mixed drill across all four episodes. It also added a check that warns when a quiz's side picture gives the answer away, after this episode's first draft did exactly that.第一集按更严格的 13 条评分表做:开场先回忆前几集(系统设计和算法两个系列共用一个题库),用真实曲线展示朴素设计失败,在模拟的「响应丢失」上逐步检查不变量(每条短信最多到手机一次),最后是覆盖四集的混合速答。还加了一个检查:小测旁边的图如果泄露答案就警告,因为这一集的初稿就犯了这个错。
  • Engine Upgrade after episode 4, aimed at the stated limits: motion (only what changed since the last sentence moves; new pictures build in, chart lines draw after their dots), a subtitle check for numbers and names (it raised 67 flags across eight episodes; fixing the parser left 3, all real), bundled open-source fonts so frames don't depend on macOS, and script marks for beats and emphasis in the voice.第 4 集之后针对已知局限的一次升级:动画(只动和上一句相比变化的部分;新画面逐个出现,曲线在点出现后自己画出来)、字幕数字与名称检查(8 集里报了 67 处,修好解析后剩 3 处,都是真问题)、自带开源字体让画面不依赖 macOS、配音的停顿和重音标记。
  • EP 05 First episode made on the upgraded engine. Its checks caught a real slip on the first run: an English line said “about two million” where the Chinese said 2.2 million. The naive-polling simulation was also fixed before any number reached the screen: an assertion failed because the first model let a single worker re-read its own job.第一集用升级后的引擎做。检查第一次跑就抓到一处真错:一句英文说「about two million」,中文却是 220 万。不加锁轮询的模拟也在数字上屏之前修好了:断言失败,因为第一版模型让单个工作者重读了自己的任务。

06Measured测量结果

5
mock-interview episodes so far: rate limiter, URL shortener, news feed, notification system, job scheduler (34 min in total)集模拟面试:限流器、短链接、新闻推送、通知系统、任务调度(共 34 分钟)
src · render logs, 2026-10-16 (private)
14 / 14
on the current rubric for episodes 4 and 5; the first cut of episode 1 scored 2 / 8 on the original one第 4、5 集在现行评分表上的得分;第 1 集第一版在最初的评分表上是 2 / 8
src · review command output (private)
29
guess-then-reveal quizzes and 5 spot-the-bug moments across the series道先猜再揭晓的小测,外加 5 个找 bug 环节
src · scripts (private)
0
speech retries across 319 lines, and 0 paid API calls次配音重试(319 行),0 次付费 API 调用
src · speech logs, 2026-10-16 (private)
~9 MB
per 720p episode on this page; 1080p masters kept locally本页每集 720p 视频大小;1080p 原片留在本地
src · output files

07Limits, stated plainly局限,直说

  • Motion is generated, not hand-animated: parts build in, changed values flash and chart lines draw themselves, but there are no free camera moves or custom transitions.动画是生成的,不是手做的:元素逐个出现、变化的值闪一下、曲线自己画出来,但没有自由运镜或定制转场。
  • The voices are synthetic. Beats and emphasis can be marked in the script, but delivery is still flatter than a person's.声音是合成的。脚本里可以标停顿和重音,但语气仍然比真人平。
  • The subtitle check compares numbers and names between the English and the Chinese; it cannot judge whether a translation reads naturally.字幕检查比对中英文里的数字和名称,但判断不了译文读起来是否自然。
  • Speech runs on my home GPU server, so the pipeline is not yet a one-command install elsewhere (frames now render the same on any machine with the bundled fonts).配音跑在家用 GPU 服务器上,所以还不能在别的机器上一条命令装好(画面已经用自带字体,在任何机器上渲染都一样)。

08Next下一步

  • Next episode in the same format: typeahead search.按同一格式做下一集:搜索联想。
  • Remake episodes 1–3 on the upgraded engine (motion, current rubric), keeping only the better version.用升级后的引擎重做第 1–3 集(动画、现行评分表),只保留更好的版本。
  • Word-level subtitle timing from the speech model's timestamps.用语音模型给出的时间戳做逐词字幕。