Overzicht
ttfx is een command-line tool geschreven in Rust die diverse visuele teksteffecten toevoegt aan de terminal. Het project is een port van het Python-gebaseerde TerminalTextEffects (TTE), ontwikkeld door ChrisBuilds.
Waarom ttfx?
Het primaire doel van deze port is het elimineren van de overhead die gepaard gaat met een Python-interpreter. Hierdoor start ttfx in een halve milliseconde en biedt het een aanzienlijk hogere framerate bij zware animaties op volledig scherm vergeleken met het origineel.
Belangrijkste kenmerken
- Hoge Getrouwheid (Fidelity): De tool is zo ontwikkeld dat hij byte-identieke frames produceert ten opzichte van de Python-versie, wat mechanisch is geverifieerd in CI.
- Uitgebreide Effectenlijst: Bevat 37 verschillende effecten, variërend van het bekende
matrix-regeneffect tot complexere animaties zoals blackhole, beams en vhstape.
- Eenvoudig Gebruik: De tool werkt via pipes (
<producer> | ttfx <effect>), waardoor het naadloos in shell-pipelines past.
- Technische specificaties: Het is een statisch binair bestand zonder afhankelijkheden, ondersteund op Linux en macOS, en gelicenseerd onder MIT.
Installatie en Bouwen
Het project kan worden gebouwd met cargo build --release, waarbij ook de mogelijkheid bestaat om een volledig statisch binary voor Linux (musl) te genereren.
ttfx: Terminalteksteffecten als een enkel statisch binair bestand
ls -la | ttfx decrypt
cat banner.txt | ttfx beams
fortune | ttfx --random-effect
git log --oneline -10 | ttfx matrix
Erkenningen
Dit project is een port van TerminalTextEffects (TTE), ontwikkeld door ChrisBuilds. Elk effect, de animatie-engine en de command-line interface zijn hun ontwerp; dit project vertaalt dat werk naar Rust en voegt niets eigen toe aan de artistieke vormgeving. Als je het resultaat waardeert, wordt aangeraden om het origineel een ster te geven.
TTE is gelicenseerd onder MIT en deze port is dat ook; het oorspronkelijke copyright is behouden in de LICENSE en NOTICE bestanden. Ideeën voor nieuwe effecten dienen upstream te worden ingediend.
Waarom een port?
TTE is een Python-pakket. Dat is de juiste keuze voor een bibliotheek, maar voor een shell-tool die in je prompt-pipeline leeft, betekent dit dat er een interpreter nodig is, er een installatiestap aan voorafgaat en er ongeveer 65 ms importtijd verstrijkt voordat het eerste frame verschijnt. ttfx is één binair bestand zonder afhankelijkheden dat start in een halve milliseconde.
Dit verschil is de reden waarom dit project bestaat. Op een canvas op volledig scherm raken zwaardere effecten onder Python tekort aan rekenkracht. Hieronder volgt de tijd die nodig is om een volledige animatie te renderen (met pacing uitgeschakeld, zodat doorvoersnelheid wordt gemeten in plaats van sleep()):
Bij 200×50 cellen
| Effect | Frames | ttfx tijd | Python TTE tijd | ttfx fps |
| slide | 375 | 76 ms | 2.203 ms | 4.930 |
| beams | 732 | 181 ms | 5.564 ms | 4.050 |
| rings | 1.566 | 521 ms | 10.439 ms | 3.004 |
| waves | 633 | 374 ms | 8.745 ms | 1.693 |
| startup | — | 0,5 ms | 64 ms | — |
Over de 35 effecten die niet worden beperkt door de kloktijd (wall-clock time), is de mediane versnelling 27,5× (bereik 17,1×–47,4×). De twee effecten die dat wel zijn — matrix en thunderstorm — besteden het grootste deel van hun runtime aan een vaste animatieduur die door geen enkele implementatie kan worden verkort; deze scoren respectievelijk 1,9× en 1,3×. Wat ttfx hier biedt, is een veel hogere framerate binnen dat tijdsbestek, niet een kortere duur.
Dit kan worden gereproduceerd met python3 tools/tests/benchfull.py, of door TTFXBENCHCOLS, TTFXBENCHLINES en TTFXBENCH_FILL=1 in te stellen voor de bovengenoemde fullscreen-cijfers. Beide zijden voeren hun echte user-facing commando uit, beste van vijf.
De effecten
Er zijn 37 effecten, die elk het Omarchy-logo animeren. Elk frame uit de Rust-binary is byte-identiek aan wat het Python-origineel produceert met dezelfde input en seed.
- beams: Creëert stralen die over het canvas bewegen en de tekens erachter verlichten.
- binarypath: Binaire representaties van elk teken bewegen naar de home-coördinaat van het teken.
- blackhole: Tekens worden opgeslokt door een zwart gat en exploderen naar buiten.
- bouncyballs: Tekens zijn stuiterballen die van bovenaf op het canvas vallen.
- bubbles: Tekens vormen bellen die naar beneden zweven en knappen.
- burn: Brandt verticaal in het canvas.
- colorshift: Toont een gradiënt waarbij kleuren over de terminal verschuiven.
- crumble: Tekens verliezen kleur, verbrokkelen tot stof, worden opgezogen en opnieuw gevormd.
- decrypt: Toont een decryptie-effect in filmstijl.
- errorcorrect: Sommige tekens beginnen op de verkeerde positie en worden opeenvolgend gecorrigeerd.
- expand: Breidt de tekst uit vanuit één enkel punt.
- fireworks: Tekens lanceren en exploderen als vuurwerk voordat ze op hun plek vallen.
- highlight: Laat een speculaire highlight over de tekst lopen.
- laseretch: Een laser etst tekens op de terminal.
- matrix: Het digitale regen-effect uit The Matrix.
- middleout: Tekst breidt uit in één rij of kolom in het midden van het canvas en verspreidt zich daarna.
- orbittingvolley: Vier launchers cirkelen rond het canvas en vuren salvo's tekens naar binnen om de inputtekst vanuit het centrum op te bouwen.
- overflow: Inputtekst loopt over en scrolt door de terminal in een willekeurige volgorde totdat deze uiteindelijk geordend verschijnt.
- pour: Giet de tekens vanuit de opgegeven richting in positie.
- print: Regels worden één voor één geprint, volgend op een printhoud. De printhoud voert line feed en carriage return uit.
- rain: Laat tekens regenen vanaf de bovenkant van het canvas.
- randomsequence: Print de inputdata in een willekeurige volgorde.
- rings: Tekens worden verspreid en vormen draaiende ringen.
- scattered: Tekst is verspreid over het canvas en beweegt naar de juiste positie.
- slice: Snijdt de input doormidden en schuift deze vanuit tegenovergestelde richtingen op zijn plek.
- slide: Schuift tekens in beeld vanuit buiten de terminal.
- smoke: Rook vult het canvas en kleurt alle tekens die het kruist.
- spotlights: Spotlights doorzoeken het tekstgebied, verlichten tekens, komen samen in het centrum en breiden zich daarna uit.
- spray: Tekent de tekens die met variërende snelheden ontstaan vanuit één enkel punt.
- swarm: Tekens worden gegroepeerd in zwermen en bewegen over de terminal voordat ze op hun plek landen.
- sweep: Veegt over het canvas om ongekleurde tekst te onthullen; een omgekeerde veeg kleurt de tekst in.
- synthgrid: Creëert een raster dat wordt gevuld met tekens die oplossen in de uiteindelijke tekst.
- thunderstorm: Creëert een onweersbui in de terminal.
- unstable: Genereert tekens in een rommelige volgorde, laat ze exploderen naar de rand van het canvas en voegt ze daarna samen in de juiste lay-out.
- vhstape: Regels tekens glitchen naar links en rechts en verliezen detail, zoals bij een oude VHS-band.
- waves: Golven bewegen over de terminal en laten de tekens achter.
- wipe: Veegt de tekst over de terminal om tekens te onthullen.
Elk effect heeft zijn eigen opties; gebruik ttfx <effect> --help. Enkele van de voorbeelden maken gebruik van verkorte tijdsfasen om de loop observeerbaar te houden (matrix --rain-time 3, thunderstorm --storm-time 3, vhstape --total-glitch-time 250, spotlights --search-duration 80, errorcorrect --error-pairs 0.5); alle overige instellingen zijn standaard.
Getrouwheid (Fidelity)
Dit is een pariteitsport, geen "reimplementatie in geest". Bij dezelfde input, configuratie en willekeurige trekkingen produceert ttfx byte-identieke frames als het Python-origineel. Dit is mechanisch geverifieerd in CI tegen een vastgepinde upstream checkout (v0.15.0), niet op basis van visuele inspectie.
Testsuite
| Checks | Wat het bewijst |
tools/parity/run_suite.sh (354) | De framestroom van elk effect, byte voor byte, over configuraties en seeds. |
tools/parity/tty_compare.sh (41) | De volledige terminal byte-stream — canvasvoorbereiding, cursorbewegingen, teardown. |
tools/tests/cli_corpus.sh (19) | Exit-codes en stdout/stderr routing. |
cargo test | Goldens + traces: easing/geometry/gradient waarden en engine state machines. |
Om dit mogelijk te maken, zijn de eigenaardigheden van upstream bewust gereproduceerd in plaats van "gecorrigeerd": Python's banker's rounding, gradiënten gebouwd op basis van integer-vloerdeling in plaats van float-interpolatie, een bezier booglengte-benadering die het laatste segment weglaat, en loop-scènes die zichzelf bij elke tick als voltooid rapporteren. Deze zijn gecatalogiseerd in plan.md; de plaatsen waar Python's ongeordende iteratie moest worden vastgelegd staan in docs/ordering-inventory.md.
Er zijn twee bewuste verschillen:
- De generatie van willekeurige getallen is niet bit-compatibel met CPython — ttfx gebruikt xoshiro256++, dus
--seed is reproduceerbaar binnen ttfx, maar komt niet overeen met de Mersenne Twister van Python. (De pariteitsharness wisselt een gedeelde PRNG in beide zijden, wat framevergelijking mogelijk maakt).
- Python-plugin effecten worden niet ondersteund, aangezien er geen interpreter is om deze te laden.
Gebruik
Het basisgebruik volgt dit patroon: <producer> | ttfx [terminal opties] <effect> [effect opties]
ttfx --help : Toont alle 37 effecten en de terminal-opties.
ttfx <effect> --help : Toont de opties voor één specifiek effect.
ttfx --random-effect : Kiest een willekeurig effect (--include-effects / --exclude-effects om te filteren).
ttfx --print-completion bash|zsh : Genereert autocomplete-scripts.
Terminal-opties (canvasgrootte, anchoring, kleurafhandeling, framerate, tekstwrapping) komen vóór de effectnaam; effect-opties komen erna. De optienaam en standaardwaarden komen overeen met tte, zodat bestaande aanroepen werken door enkel de naam van het binary te vervangen.
Bouwen
cargo build --release
cargo build --release --target x86_64-unknown-linux-musl # statisch, ~3,3 MB
Voor het draaien van de pariteitssuites zijn python3 en een kopie van upstream nodig:
./tools/parity/fetch_reference.sh # Cloont TTE op de gepinde commit
./tools/parity/run_suite.sh
Upstream is hier niet als vendor opgenomen — de harness haalt het op, omdat het hun code is.
Scope en Compatibiliteit
Ondersteund op Linux en macOS. Oorspronkelijk gebouwd voor Omarchy; er is geen target voor een specifieke libc, en CI draait de tests en CLI corpus op beide platforms. De byte-exacte pariteitsuites blijven gepind aan Linux/glibc — Apple's libm rondt een paar transcendentale functies net anders af (last-ulp), wat in echte frames door kwantisering wordt verborgen, maar bij een bit-exacte vergelijking naar voren zou komen.
Licentie
MIT — zie het LICENSE bestand, dat zowel het copyright van dit project als het originele TerminalTextEffects copyright bevat, en het NOTICE bestand voor de volledige attributie.
ttfx: Terminalteksteffecten als een enkel statisch binair bestand
ls -la | ttfx decrypt
cat banner.txt | ttfx beams
fortune | ttfx --random-effect
git log --oneline -10 | ttfx matrix
Erkenningen
Dit project is een port van TerminalTextEffects (TTE), ontwikkeld door ChrisBuilds. Elk effect, de animatie-engine en de command-line interface zijn hun ontwerp; dit project vertaalt dat werk naar Rust en voegt niets eigen toe aan de artistieke vormgeving. Als je het resultaat waardeert, wordt aangeraden om het origineel een ster te geven.
TTE is gelicenseerd onder MIT en deze port is dat ook; het oorspronkelijke copyright is behouden in de LICENSE en NOTICE bestanden. Ideeën voor nieuwe effecten dienen upstream te worden ingediend.
Waarom een port?
TTE is een Python-pakket. Dat is de juiste keuze voor een bibliotheek, maar voor een shell-tool die in je prompt-pipeline leeft, betekent dit dat er een interpreter nodig is, er een installatiestap aan voorafgaat en er ongeveer 65 ms importtijd verstrijkt voordat het eerste frame verschijnt. ttfx is één binair bestand zonder afhankelijkheden dat start in een halve milliseconde.
Dit verschil is de reden waarom dit project bestaat. Op een canvas op volledig scherm raken zwaardere effecten onder Python tekort aan rekenkracht. Hieronder volgt de tijd die nodig is om een volledige animatie te renderen (met pacing uitgeschakeld, zodat doorvoersnelheid wordt gemeten in plaats van sleep()):
Bij 200×50 cellen
| Effect | Frames | ttfx tijd | Python TTE tijd | ttfx fps |
| slide | 375 | 76 ms | 2.203 ms | 4.930 |
| beams | 732 | 181 ms | 5.564 ms | 4.050 |
| rings | 1.566 | 521 ms | 10.439 ms | 3.004 |
| waves | 633 | 374 ms | 8.745 ms | 1.693 |
| startup | — | 0,5 ms | 64 ms | — |
Over de 35 effecten die niet worden beperkt door de kloktijd (wall-clock time), is de mediane versnelling 27,5× (bereik 17,1×–47,4×). De twee effecten die dat wel zijn — matrix en thunderstorm — besteden het grootste deel van hun runtime aan een vaste animatieduur die door geen enkele implementatie kan worden verkort; deze scoren respectievelijk 1,9× en 1,3×. Wat ttfx hier biedt, is een veel hogere framerate binnen dat tijdsbestek, niet een kortere duur.
Dit kan worden gereproduceerd met python3 tools/tests/benchfull.py, of door TTFXBENCHCOLS, TTFXBENCHLINES en TTFXBENCH_FILL=1 in te stellen voor de bovengenoemde fullscreen-cijfers. Beide zijden voeren hun echte user-facing commando uit, beste van vijf.
De effecten
Er zijn 37 effecten, die elk het Omarchy-logo animeren. Elk frame uit de Rust-binary is byte-identiek aan wat het Python-origineel produceert met dezelfde input en seed.
- beams: Creëert stralen die over het canvas bewegen en de tekens erachter verlichten.
- binarypath: Binaire representaties van elk teken bewegen naar de home-coördinaat van het teken.
- blackhole: Tekens worden opgeslokt door een zwart gat en exploderen naar buiten.
- bouncyballs: Tekens zijn stuiterballen die van bovenaf op het canvas vallen.
- bubbles: Tekens vormen bellen die naar beneden zweven en knappen.
- burn: Brandt verticaal in het canvas.
- colorshift: Toont een gradiënt waarbij kleuren over de terminal verschuiven.
- crumble: Tekens verliezen kleur, verbrokkelen tot stof, worden opgezogen en opnieuw gevormd.
- decrypt: Toont een decryptie-effect in filmstijl.
- errorcorrect: Sommige tekens beginnen op de verkeerde positie en worden opeenvolgend gecorrigeerd.
- expand: Breidt de tekst uit vanuit één enkel punt.
- fireworks: Tekens lanceren en exploderen als vuurwerk voordat ze op hun plek vallen.
- highlight: Laat een speculaire highlight over de tekst lopen.
- laseretch: Een laser etst tekens op de terminal.
- matrix: Het digitale regen-effect uit The Matrix.
- middleout: Tekst breidt uit in één rij of kolom in het midden van het canvas en verspreidt zich daarna.
- orbittingvolley: Vier launchers cirkelen rond het canvas en vuren salvo's tekens naar binnen om de inputtekst vanuit het centrum op te bouwen.
- overflow: Inputtekst loopt over en scrolt door de terminal in een willekeurige volgorde totdat deze uiteindelijk geordend verschijnt.
- pour: Giet de tekens vanuit de opgegeven richting in positie.
- print: Regels worden één voor één geprint, volgend op een printhoud. De printhoud voert line feed en carriage return uit.
- rain: Laat tekens regenen vanaf de bovenkant van het canvas.
- randomsequence: Print de inputdata in een willekeurige volgorde.
- rings: Tekens worden verspreid en vormen draaiende ringen.
- scattered: Tekst is verspreid over het canvas en beweegt naar de juiste positie.
- slice: Snijdt de input doormidden en schuift deze vanuit tegenovergestelde richtingen op zijn plek.
- slide: Schuift tekens in beeld vanuit buiten de terminal.
- smoke: Rook vult het canvas en kleurt alle tekens die het kruist.
- spotlights: Spotlights doorzoeken het tekstgebied, verlichten tekens, komen samen in het centrum en breiden zich daarna uit.
- spray: Tekent de tekens die met variërende snelheden ontstaan vanuit één enkel punt.
- swarm: Tekens worden gegroepeerd in zwermen en bewegen over de terminal voordat ze op hun plek landen.
- sweep: Veegt over het canvas om ongekleurde tekst te onthullen; een omgekeerde veeg kleurt de tekst in.
- synthgrid: Creëert een raster dat wordt gevuld met tekens die oplossen in de uiteindelijke tekst.
- thunderstorm: Creëert een onweersbui in de terminal.
- unstable: Genereert tekens in een rommelige volgorde, laat ze exploderen naar de rand van het canvas en voegt ze daarna samen in de juiste lay-out.
- vhstape: Regels tekens glitchen naar links en rechts en verliezen detail, zoals bij een oude VHS-band.
- waves: Golven bewegen over de terminal en laten de tekens achter.
- wipe: Veegt de tekst over de terminal om tekens te onthullen.
Elk effect heeft zijn eigen opties; gebruik ttfx <effect> --help. Enkele van de voorbeelden maken gebruik van verkorte tijdsfasen om de loop observeerbaar te houden (matrix --rain-time 3, thunderstorm --storm-time 3, vhstape --total-glitch-time 250, spotlights --search-duration 80, errorcorrect --error-pairs 0.5); alle overige instellingen zijn standaard.
Getrouwheid (Fidelity)
Dit is een pariteitsport, geen "reimplementatie in geest". Bij dezelfde input, configuratie en willekeurige trekkingen produceert ttfx byte-identieke frames als het Python-origineel. Dit is mechanisch geverifieerd in CI tegen een vastgepinde upstream checkout (v0.15.0), niet op basis van visuele inspectie.
Testsuite
| Checks | Wat het bewijst |
tools/parity/run_suite.sh (354) | De framestroom van elk effect, byte voor byte, over configuraties en seeds. |
tools/parity/tty_compare.sh (41) | De volledige terminal byte-stream — canvasvoorbereiding, cursorbewegingen, teardown. |
tools/tests/cli_corpus.sh (19) | Exit-codes en stdout/stderr routing. |
cargo test | Goldens + traces: easing/geometry/gradient waarden en engine state machines. |
Om dit mogelijk te maken, zijn de eigenaardigheden van upstream bewust gereproduceerd in plaats van "gecorrigeerd": Python's banker's rounding, gradiënten gebouwd op basis van integer-vloerdeling in plaats van float-interpolatie, een bezier booglengte-benadering die het laatste segment weglaat, en loop-scènes die zichzelf bij elke tick als voltooid rapporteren. Deze zijn gecatalogiseerd in plan.md; de plaatsen waar Python's ongeordende iteratie moest worden vastgelegd staan in docs/ordering-inventory.md.
Er zijn twee bewuste verschillen:
- De generatie van willekeurige getallen is niet bit-compatibel met CPython — ttfx gebruikt xoshiro256++, dus
--seed is reproduceerbaar binnen ttfx, maar komt niet overeen met de Mersenne Twister van Python. (De pariteitsharness wisselt een gedeelde PRNG in beide zijden, wat framevergelijking mogelijk maakt).
- Python-plugin effecten worden niet ondersteund, aangezien er geen interpreter is om deze te laden.
Gebruik
Het basisgebruik volgt dit patroon: <producer> | ttfx [terminal opties] <effect> [effect opties]
ttfx --help : Toont alle 37 effecten en de terminal-opties.
ttfx <effect> --help : Toont de opties voor één specifiek effect.
ttfx --random-effect : Kiest een willekeurig effect (--include-effects / --exclude-effects om te filteren).
ttfx --print-completion bash|zsh : Genereert autocomplete-scripts.
Terminal-opties (canvasgrootte, anchoring, kleurafhandeling, framerate, tekstwrapping) komen vóór de effectnaam; effect-opties komen erna. De optienaam en standaardwaarden komen overeen met tte, zodat bestaande aanroepen werken door enkel de naam van het binary te vervangen.
Bouwen
cargo build --release
cargo build --release --target x86_64-unknown-linux-musl # statisch, ~3,3 MB
Voor het draaien van de pariteitssuites zijn python3 en een kopie van upstream nodig:
./tools/parity/fetch_reference.sh # Cloont TTE op de gepinde commit
./tools/parity/run_suite.sh
Upstream is hier niet als vendor opgenomen — de harness haalt het op, omdat het hun code is.
Scope en Compatibiliteit
Ondersteund op Linux en macOS. Oorspronkelijk gebouwd voor Omarchy; er is geen target voor een specifieke libc, en CI draait de tests en CLI corpus op beide platforms. De byte-exacte pariteitsuites blijven gepind aan Linux/glibc — Apple's libm rondt een paar transcendentale functies net anders af (last-ulp), wat in echte frames door kwantisering wordt verborgen, maar bij een bit-exacte vergelijking naar voren zou komen.
Licentie
MIT — zie het LICENSE bestand, dat zowel het copyright van dit project als het originele TerminalTextEffects copyright bevat, en het NOTICE bestand voor de volledige attributie.