██████████████████████████████████████████████████████████
█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█
█▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓█
█▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓█
█▓░ ░▓█
█▓░ ╭╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╮ ░▓█
█▓░ ┊ ### ┊ ░▓█
█▓░ ┊ ####### ### ###### ### ######## ######## ┊ ░▓█
█▓░ ┊ ### ### ### ### ┊ ░▓█
█▓░ ┊ ####### ### ### ## ### ####### ### ┊ ░▓█
█▓░ ┊ ## ### ### ## ### ### ### ┊ ░▓█
█▓░ ┊ ## ### ###### ####### ####### ### ┊ ░▓█
█▓░ ┊ ========================================== ┊ ░▓█
█▓░ ┊ __ ┊ ░▓█
█▓░ ┊ _______ ___________ _/ /_____ _____ ┊ ░▓█
█▓░ ┊ / ___/ / / / ___/ __ `/ __/ __ \/ ___/ ┊ ░▓█
█▓░ ┊ / /__/ /_/ / / / /_/ / /_/ /_/ / / ┊ ░▓█
█▓░ ┊ \___/\__,_/_/ \__,_/\__/\____/_/ ┊ ░▓█
█▓░ ╰╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╯ ░▓█
█▓░ ░▓█
█▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓█
█▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓█
█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█
██████████████████████████████████████████████████████████
A two-part toolkit for building and exploring a clean, well-organized FIGlet font collection:
- Curator (CLI) — import
.flf/.tlf/.flc, de-duplicate, organize into a repository, with optional output-based duplicate detection - Browser (Textual TUI) — preview
.flf/.tlffonts live, filter, and save previews; supports fonts packaged inside ZIP archives
Built with Rich / Textual. Rendering uses system
figlet(and optionallytoiletfor.tlf).
Curator — figlet_font_curator.py
- Imports
.flf,.tlf, and.flcfiles from--ininto--out - Content-based de-duplication using fast
xxhash - Optional output-based de-duplication (
--compare-output): hashes the rendered FIGlet output for a fixed sample string to detect duplicates that produce identical text output - Versioned name collisions:
name.ext→name_v02.ext,name_v03.ext, … - Optional recursive scan and structure preservation (
--maintain-structurewith--outsub+-r) - Rich progress bars and pretty console logs
- JSONL audit log saved to
--out
Browser — figlet_font_browser.py
- Recursively scans a font dir for
.flfand.tlf - ZIP support: transparently previews
.flf/.tlffound inside.zipfiles (cached extraction) - Live preview of your text (adjustable width)
- Optional FIGlet charmap (
.flc) via--flc(passed tofigletwith-C) - Optional
--use-toiletfor.tlfrendering - Filter/search list; save current or all previews
- Robust output normalization: CP437/Latin-1 fallbacks, ANSI repair, backspace overstrike handling
- Python 3.9+ (tested up to 3.13)
figletin yourPATH- Optionally
toilet(only if you plan to render.tlfwith--use-toilet)
# in your virtualenv
pip install rich textual xxhashScript: figlet_font_curator.py
Imports .flf, .tlf, and .flc from --in to --out with de-duplication and optional organization.
Duplicates are detected either by raw file content (fast, default), or by rendered output when --compare-output is set.
python figlet_font_curator.py \
--in /path/to/in_fonts \
--out /path/to/out_fonts \
[-r|--recursive] \
[--outsub source_name] \
[--maintain-structure] \
[--compare-output]--in, -i <dir>Input directory containing.flf/.tlf/.flc--out, -o <dir>Output directory (the master repo)-r, --recursiveRecurse into--insubdirectories--outsub <name>Place this run’s copies under--out/<name>/(still de-dups against all of--out)--maintain-structureEffective only with--outsuband--recursive; preserves the input’s subdirectory layout under--out/<outsub>/--compare-outputCompare fonts by the FIGlet-rendered output for a fixed sample string ("FIGLET FONT CURATOR") instead of raw file content (Requiresfigletto be installed.)
-
Default (content-based): A fast
xxhashdigest of the file bytes is used. If a match is found anywhere under--out(scanned recursively), the file is skipped. -
--compare-output: The Curator runsfigletwith-d <font_dir> -f <font_name>using a fixed sample string, and hashes the resulting text. Files that produce identical output are treated as duplicates even if their bytes differ.- This is useful to collapse near-identical
.flffiles that render the same. - Important: Output comparison applies to
.flffonts only. Non-FIGlet files like.tlfor.flccan’t be rendered byfiglet; those will be skipped (logged asERROR_FINGERPRINT) when--compare-outputis enabled. If your set includes.tlf/.flc, prefer the default content-based mode.
- This is useful to collapse near-identical
If a filename collision occurs (same name, different content/output), Curator writes the next available versioned name in the destination folder:
font.flf → font_v02.flf → font_v03.flf → ...
-
A JSONL audit log is written to:
--out/figlet_import_YYYYMMDD_HHMMSS.log.jsonlEach event includes timestamps, inputs, destination, fingerprint method, and action (
COPY,COPY_RENAMED,SKIP_DUPLICATE, errors, etc.). -
Console progress and summaries use Rich.
# Simple flat import (content-based de-dup)
python figlet_font_curator.py --in ./fonts_in --out ./fonts_repo
# Recursive import grouped under 'dump_2025_10_03' and preserve input tree
python figlet_font_curator.py --in ./dump --out ./repo -r --outsub dump_2025_10_03 --maintain-structure
# Output-based duplicate detection (FIGlet-rendered equivalence), .flf-only
python figlet_font_curator.py --in ./flf_only --out ./repo --compare-outputNotes & caveats
- If
--outis nested inside--inand you pass-r, Curator automatically excludes the--outsubtree to avoid re-ingesting its own output. --compare-outputuses a fixed sample string ("FIGLET FONT CURATOR"). To change the sample text, editDEFAULT_COMPARE_TEXTin the script.
Script: figlet_font_browser.py
A terminal UI for browsing and previewing FIGlet fonts. It recursively scans a font directory for .flf and .tlf files, including those inside ZIP archives, renders a live preview of your text, and (optionally) applies a FIGlet charmap (.flc) via --flc. You can filter, page through results, and save outputs.
python figlet_font_browser.py \
--font-dir ~/figlet-fonts \
--text "Hello World" \
[--width 80] \
[--flc /path/to/latin1.flc] \
[--out-dir ./out] \
[--out-prefix run_] \
[--use-toilet]-
Recursively scans
--font-dirfor:.flf(FIGlet fonts).tlf(TOIlet fonts)- Inside ZIPs:
.flf/.tlffiles are extracted to a temp cache and previewed seamlessly
-
--flc: pass a FIGlet charmap via-C(FIGlet-only; ignored fortoilet) -
Live preview with adjustable width (
w) -
Quick filter/search of font list (
/) -
Save the current preview (
s) or all filtered previews (a) -
Output normalization:
- Fixes ANSI sequences that get split by FIGlet’s wrapping
- Applies backspace overstrikes (for classic shading/bold tricks)
- Decodes with UTF-8, CP437, and Latin-1 fallbacks to preserve block characters
--font-dir <dir>: Base directory to scan recursively (default:~/figlet-fonts)--text <string>(required): The text to render--width <cols>: Render width (default: TTY width or80)--flc <path>: Path to a.flccharmap (FIGlet-only;toiletdoesn’t support-C)--out-dir <dir>: Where to save previews (s/aactions)--out-prefix <str>: Filename prefix when saving--use-toilet: Usetoiletto render.tlf(if installed)
/— focus filter inputw— change width (type a number, press Enter)j/kor ↓ / ↑ — move selections— save current preview to--out-dir/<prefix>N.asca— save all filtered previews (with headers) to--out-dirr— rescan fontsq— quit
# Browse a collection (recursively)
python figlet_font_browser.py --font-dir ~/figlet-fonts --text JSON
# Apply a specific charmap (FIGlet-only)
python figlet_font_browser.py --font-dir ~/figlet-fonts --text "Café déjà vu" \
--flc ~/figlet-fonts/charmaps/latin1.flc
# Prefer 'toilet' for .tlf fonts
python figlet_font_browser.py --font-dir ~/figlet-fonts --text "HELLO" --use-toilet
# Save previews as you browse
python figlet_font_browser.py --font-dir ~/figlet-fonts --text "Hello" \
--out-dir ./out --out-prefix run_-
Curate Use the Curator to gather fonts into a de-duplicated repo at
--out, optionally grouping each run with--outsuband mirroring structure with--maintain-structure. -
Browse Point the Browser at your curated repo (or any folder/ZIP collection), try
.flccharmaps, and export previews to share or compare.
Curator
- “It’s ingesting its own output” → If
--outis under--inand you used-r, the Curator excludes--outautomatically. - “Why are
.tlf/.flcskipped in--compare-outputmode?” → Output-comparison renders withfigletand is intended for.flf; non-FIGlet files can’t be rendered there and are skipped (with error logs). Use the default content-based mode for mixed sets.
Browser
- Charmap not applied →
--flconly applies to.flf(FIGlet);toiletdoes not support-C. - Garbled blocks/ANSI noise → The app repairs split ANSI, handles backspace overstrikes, and tries CP437/Latin-1 if UTF-8 fails. If a specific font still looks off, try a different width.
.
├─ figlet_font_curator.py # CLI import/dedupe (content or output-based)
├─ figlet_font_browser.py # Textual TUI w/ ZIP support
├─ README.md
└─ requirements.txt # rich, textual, xxhash
-
Code style: Python with 2-space indents (project preference).
-
Keep CLI (Curator) and TUI (Browser) concerns decoupled.
-
PRs welcome for:
- Making the Curator’s sample text configurable at runtime
- Optional watch mode for Curator (e.g.,
watchfiles) - Fuzzy/regex filter in the Browser
- Export presets, batch selection, or side-by-side comparisons in the Browser
MIT.