Skip to content
← All posts
8 min read

TTFX rewrote 37 Python terminal effects in Rust. The benchmark is the easy part.

The repo shows 37 effects ported in hours, byte-level parity, and a benchmark that has already moved past the viral post.

The 9.6x claim is already stale. The repo tells a better story about agent-built software.

TerminalTextEffects, or TTE, is a Python library that animates text piped through a terminal. ChrisBuilds wrote it. It is MIT-licensed, and its pyproject.toml declares no runtime packages of its own. Using it still means installing a Python package and paying for an interpreter start every time a shell prompt wants an animation.

That stopped being the only option on 9 August 2026. David Heinemeier Hansson and Omacom published TTFX, a Rust port of TTE v0.15.0 built for the Omarchy Linux setup and since tested on macOS. It ships as one compiled binary with no interpreter to provision.

The post that carried TTFX around opened with "The SaaS monopoly ends this year." TTE is not SaaS and was never a monopoly, so we read the Git history, the plan file, and the checked-in benchmarks to see which parts of the story the repository supports and which parts have quietly moved since launch.

git clone https://github.com/omacom-io/ttfx.git
cd ttfx
cargo build --release
git log --oneline -10 | ./target/release/ttfx matrix

What the Git history supports

The timeline holds. The first commit is stamped 12:50 PDT on 9 August 2026. All 37 effects passing the parity suite landed at 14:23, ninety-three minutes later, with 354 parity cases behind them. The v0.1 tag followed at 16:01. That is one afternoon, and every commit in it is public.

A compatibility job, not a translation

The most useful file in the repository is plan.md, all 473 lines of it. It pins the source to TTE v0.15.0 at commit 7a91dd9, sets byte-identical frames as the goal, lists the deliberate differences, and maps the Python object graph into Rust before a single effect module goes to an agent.

Python lets characters, scenes, paths, events, and callbacks hold references to each other freely. The Rust port replaces that graph with arenas and small IDs. Engine methods fetch state again after synchronous event dispatch, which preserves Python's callback order without holding conflicting Rust borrows. Python closures become enum variants with owned payloads.

The port also reproduces behavior a normal rewrite would call a bug and fix: banker's rounding, integer floor division inside gradients, a Bezier length approximation that drops its final segment, and looping scenes that report completion on every tick. Those quirks are in the contract because any one of them can change a frame.

The repository checks more than rendering:

CheckRepository claimWhat it covers
Effect parity354 casesEvery effect across inputs, configurations, and two fixed seeds
Terminal stream41 casesCursor moves, canvas setup, output bytes, and teardown
CLI corpus19 casesExit codes and stdout/stderr routing
PTY and Rust testsBehavior tests plus goldensResizing, signals, geometry, easing, gradients, and engine state
Verification described in the TTFX README

The parity harness injects the same test PRNG into both programs so it can compare frames byte for byte. Outside that harness the two diverge on purpose: TTFX runs xoshiro256++ and Python runs Mersenne Twister, so the same `--seed` does not produce matching random choices across them. Python plugin effects are unsupported. The current README limits byte-exact parity to Linux and glibc, because macOS math can differ in the last bit.

The benchmark moved after launch

The circulated post says startup fell from 87 ms to 2 ms and rendering became 9.6x faster. The 9.6x figure is in the repository. That exact startup pair is not, in any commit we inspected.

Circulated claimWhat the repository recordsHow to read it
87 ms to 2 ms startupThe v0.1 README said 107 ms to 1.2 ms. The current README says 64 ms to 0.5 ms.The circulated pair is not the checked-in benchmark. All three tell the same broad startup story on different runs.
9.6x renderingThe v0.1 README reported a 9.6x median across all 37 effects. The current README reports 27.5x across 35 effects after more optimization.9.6x was an early repository number. It is now stale.
3 MB executableThe build instructions say about 3.3 MB for the x86_64 Linux musl target.Fair shorthand for one target, not a universal binary size.
Zero dependenciesThe static binary has no runtime dependencies. Cargo.toml declares clap, clap_complete, and terminal_size, and Cargo.lock resolves 28 third-party packages plus ttfx.No runtime setup is not the same claim as no software dependencies.
11M tokens, one-shotNo token ledger or original prompt is checked in. v0.1 took 67 commits and includes eight named worktree-agent batch merges.The repository proves heavy agent use and a short wall-clock build, not the token total or a literal single shot.
The viral wording compared with the checked-in record
There is one reproducibility wrinkle. The README says both commands were measured best of five, while tools/tests/bench_full.py defaults to three repeats. Pass 5 explicitly if you want to match the stated method.

What the benchmark measures

The benchmark harness runs the real `ttfx` and `python -m terminaltexteffects` commands, sends their output to the null device, and keeps the fastest wall-clock result. For the main throughput test it disables frame pacing. At 200 by 50 cells, the current README reports slide at 76 ms against 2,203 ms, beams at 181 ms against 5,564 ms, rings at 521 ms against 10,439 ms, and waves at 374 ms against 8,745 ms.

That is engine throughput, and it is real. It is not the same thing as every animation feeling 27.5 times faster. A normally paced effect sleeps between frames on purpose, and matrix and thunderstorm contain fixed wall-clock phases. TTFX can draw more frames inside a three-second phase. It cannot make the phase shorter than three seconds without changing the effect.

The repository publishes the harness, which is better evidence than a number on its own. It does not record the benchmark machine in the README, and these are maintainer results rather than an independent run. Treat the ratios as reproducible claims to test on your own target, not as hardware-neutral constants.

Why the agents moved this fast

The first commit did not turn 37 agents loose on 37 files. It landed a 473-line plan, a pinned Python tree, the Rust engine scaffold, an ANSI input parser, Python-semantics helpers, a renderer, and 112 first-frame parity checks. Before any effect was written, the project had a narrow contract and an oracle that could reject a wrong answer without a human reading it.

Once the engine held, the effects became good parallel work. Each one lived in its own module, used the same engine, and had parity cases waiting to fail it. The Git history then shows worktree-agent batches landing separate groups of effects. Claude Fable 5 appears as co-author throughout the initial run, with David Heinemeier Hansson as the commit author.

What one-shot hides

It was still iterative software work. There were 67 commits before v0.1, multiple worktree merges, benchmark corrections, another performance pass, macOS support, terminal resize handling, and signal cleanup. The current history has contributions from four people. A repository can be created in an afternoon and still need maintenance the next morning.

Our read

Our read, and this is the studio's opinion rather than anything the repository states: the transferable part is not Rust, and it is not the agent count. It is that "port this library" was rewritten as "match this pinned program byte for byte under these inputs, keep these four known exceptions, and do not merge until this suite passes." That sentence is a build system. Agents go fast when the task splits cleanly and wrong answers fail loudly, and TTFX bought both before it wrote a single effect. What TTFX does not tell us is what happens when the acceptance test is a customer's changing behavior, a regulator's judgment, a production incident, or five years of compatibility promises. Those do not compile.

Run the proof, not the slogan

Clone both pinned trees, build the release binary, and run the repository's own test entry point. On Linux that covers the Rust tests, the CLI corpus, PTY behavior, and the byte-level parity suites.

./bin/test
TTFX_BENCH_COLS=200 TTFX_BENCH_LINES=50 TTFX_BENCH_FILL=1 \
  python3 tools/tests/bench_full.py 5

Then inspect one failed or slow effect before you change anything architectural.

Sources: TTFX at commit 6e24dac, its v0.1.0 README, and TerminalTextEffects at commit 7a91dd9. Every number above is read from those trees, not from the posts about them.
EngineeringRustAI agentsOpen sourceDev toolsTTFXTerminalTextEffectsRustLangAIAgentsOpenSourceDeveloperToolsSoftwareEngineeringCLIBuildInPublicGattyWorks

Ready to know?

Send what you want checked or built. Fixed scope, price, and date in writing inside 24 hours, or the website or audit fee on your first project is refunded in full.

24 clock hours. Weekends included.