Work

tirimba: explainer videos where the wrong number cannot appear

A Manim and local text-to-speech pipeline that builds finance explainer videos. One module owns every value on screen and asserts it before anything renders.

Status
in use
Stack
Python, Manim, Kokoro TTS, ffprobe, ffmpeg
Essay
Make the wrong number impossible, not unlikely

The problem

A graduate finance course needed short explainer videos: put-call parity, portfolio payoffs, the kind of thing an animated diagram teaches better than a paragraph. Producing them by hand is slow. Producing them with a machine introduces a new failure: a confident wrong number in a caption.

The constraint

A viewer will believe a number on screen. Review does not scale, and a reviewer who has watched the same 2:43 video nine times stops seeing it. The defense had to be structural.

What I built

A pipeline that renders Manim scenes with narration from a local text-to-speech model, synchronized captions included. One command builds the whole thing.

The design rule is that the scene file contains no numeric literal that can appear on screen. A single values.py module computes every displayed value from the inputs, asserts the expected results at import time, and formats the display strings. Change the call premium from 1.00 to 1.10 and the build fails on import, before either the audio or the video renders. That was tested by breaking it on purpose, as an acceptance criterion, not assumed.

The same move for time. Animation durations are not typed. Each narration segment is synthesized, measured with ffprobe, and written to a timings file; every beat in the scene lasts exactly its measured narration. Audio and animation cannot drift because there is no second clock. The build fails if total runtime falls outside the brief’s window.

And for words. The narration is locked in one file that is never edited by hand. If a line synthesizes badly, the build stops and says so. If runtime is wrong, the speaking rate changes, not the script. The thing a reviewer approved is the thing that ships.

What it cost or taught

The principle held in a place the brief did not name: axis tick labels. The first draft had x_range=[0, 40, 10] in the scene, which is a number on screen. Moving axis geometry into the values module as multiples of the strike meant a later request to tighten the range was a one-constant change with the tick labels following. The full argument is in Make the wrong number impossible, not unlikely.