"""µFrame Big Text Fonts — multi-line ASCII art letter definitions. Each font is a dict mapping characters to a list of strings (one per line). All characters in a font have the same height. """ from __future__ import annotations # --------------------------------------------------------------------------- # Block font — solid █ with box-drawing. Height: 6 lines. # --------------------------------------------------------------------------- _BLOCK: dict[str, list[str]] = { "A": [" █████╗ ", "██╔══██╗", "███████║", "██╔══██║", "██║ ██║", "╚═╝ ╚═╝"], "B": ["██████╗ ", "██╔══██╗", "██████╔╝", "██╔══██╗", "██████╔╝", "╚═════╝ "], "C": [" ██████╗", "██╔════╝", "██║ ", "██║ ", "╚██████╗", " ╚═════╝"], "D": ["██████╗ ", "██╔══██╗", "██║ ██║", "██║ ██║", "██████╔╝", "╚═════╝ "], "E": ["███████╗", "██╔════╝", "█████╗ ", "██╔══╝ ", "███████╗", "╚══════╝"], "F": ["███████╗", "██╔════╝", "█████╗ ", "██╔══╝ ", "██║ ", "╚═╝ "], "G": [" ██████╗ ", "██╔════╝ ", "██║ ███╗", "██║ ██║", "╚██████╔╝", " ╚═════╝ "], "H": ["██╗ ██╗", "██║ ██║", "███████║", "██╔══██║", "██║ ██║", "╚═╝ ╚═╝"], "I": ["██╗", "██║", "██║", "██║", "██║", "╚═╝"], "J": [" ██╗", " ██║", " ██║", "██ ██║", "╚█████╔╝", " ╚════╝ "], "K": ["██╗ ██╗", "██║ ██╔╝", "█████╔╝ ", "██╔═██╗ ", "██║ ██╗", "╚═╝ ╚═╝"], "L": ["██╗ ", "██║ ", "██║ ", "██║ ", "███████╗", "╚══════╝"], "M": ["███╗ ███╗", "████╗ ████║", "██╔████╔██║", "██║╚██╔╝██║", "██║ ╚═╝ ██║", "╚═╝ ╚═╝"], "N": ["███╗ ██╗", "████╗ ██║", "██╔██╗ ██║", "██║╚██╗██║", "██║ ╚████║", "╚═╝ ╚═══╝"], "O": [" ██████╗ ", "██╔═══██╗", "██║ ██║", "██║ ██║", "╚██████╔╝", " ╚═════╝ "], "P": ["██████╗ ", "██╔══██╗", "██████╔╝", "██╔═══╝ ", "██║ ", "╚═╝ "], "Q": [" ██████╗ ", "██╔═══██╗", "██║ ██║", "██║▄▄ ██║", "╚██████╔╝", " ╚══▀▀═╝ "], "R": ["██████╗ ", "██╔══██╗", "██████╔╝", "██╔══██╗", "██║ ██║", "╚═╝ ╚═╝"], "S": ["███████╗", "██╔════╝", "███████╗", "╚════██║", "███████║", "╚══════╝"], "T": ["████████╗", "╚══██╔══╝", " ██║ ", " ██║ ", " ██║ ", " ╚═╝ "], "U": ["██╗ ██╗", "██║ ██║", "██║ ██║", "██║ ██║", "╚██████╔╝", " ╚═════╝ "], "V": ["██╗ ██╗", "██║ ██║", "██║ ██║", "╚██╗ ██╔╝", " ╚████╔╝ ", " ╚═══╝ "], "W": ["██╗ ██╗", "██║ ██║", "██║ █╗ ██║", "██║███╗██║", "╚███╔███╔╝", " ╚══╝╚══╝ "], "X": ["██╗ ██╗", "╚██╗██╔╝", " ╚███╔╝ ", " ██╔██╗ ", "██╔╝ ██╗", "╚═╝ ╚═╝"], "Y": ["██╗ ██╗", "╚██╗ ██╔╝", " ╚████╔╝ ", " ╚██╔╝ ", " ██║ ", " ╚═╝ "], "Z": ["███████╗", "╚══███╔╝", " ███╔╝ ", " ███╔╝ ", "███████╗", "╚══════╝"], "0": [" ██████╗ ", "██╔═══██╗", "██║ ██║", "██║ ██║", "╚██████╔╝", " ╚═════╝ "], "1": [" ██╗", "███║", "╚██║", " ██║", " ██║", " ╚═╝"], "2": ["██████╗ ", "╚════██╗", " █████╔╝", "██╔═══╝ ", "███████╗", "╚══════╝"], "3": ["██████╗ ", "╚════██╗", " █████╔╝", " ╚═══██╗", "██████╔╝", "╚═════╝ "], "4": ["██╗ ██╗", "██║ ██║", "███████║", "╚════██║", " ██║", " ╚═╝"], "5": ["███████╗", "██╔════╝", "███████╗", "╚════██║", "███████║", "╚══════╝"], "6": [" ██████╗", "██╔════╝", "██████╗ ", "██╔══██╗", "╚█████╔╝", " ╚════╝ "], "7": ["███████╗", "╚════██║", " ██╔╝", " ██╔╝ ", " ██║ ", " ╚═╝ "], "8": [" █████╗ ", "██╔══██╗", "╚█████╔╝", "██╔══██╗", "╚█████╔╝", " ╚════╝ "], "9": [" █████╗ ", "██╔══██╗", "╚██████║", " ╚═══██║", " █████╔╝", " ╚════╝ "], "-": [" ", " ", "██████╗ ", "╚═════╝ ", " ", " "], " ": [" ", " ", " ", " ", " ", " "], ".": [" ", " ", " ", " ", "██╗", "╚═╝"], "!": ["██╗", "██║", "██║", "╚═╝", "██╗", "╚═╝"], } # --------------------------------------------------------------------------- # Thin font — light single-stroke. Height: 3 lines. # --------------------------------------------------------------------------- _THIN: dict[str, list[str]] = { "A": ["┌─┐", "├─┤", "┘ └"], "B": ["┬─┐", "├─┤", "┴─┘"], "C": ["┌─ ", "│ ", "└─ "], "D": ["┬─┐", "│ │", "┴─┘"], "E": ["┬──", "├─ ", "┴──"], "F": ["┬──", "├─ ", "┘ "], "G": ["┌─ ", "│ ┐", "└─┘"], "H": ["┐ ┌", "├─┤", "┘ └"], "I": ["┬", "│", "┴"], "J": [" ┬", " │", "└─┘"], "K": ["┐ ┌", "├┬┘", "┘└ "], "L": ["│ ", "│ ", "└──"], "M": ["┌┬┐", "│││", "┘ └"], "N": ["┌┐ ", "│└┐", "┘ └"], "O": ["┌─┐", "│ │", "└─┘"], "P": ["┌─┐", "├─┘", "┘ "], "Q": ["┌─┐", "│ │", "└─┤"], "R": ["┌─┐", "├─┤", "┘ └"], "S": ["┌─ ", "└─┐", " ─┘"], "T": ["┬─┬", " │ ", " ┴ "], "U": ["┐ ┌", "│ │", "└─┘"], "V": ["┐ ┌", "│ │", "└┬┘"], "W": ["┐ ┌", "│││", "└┴┘"], "X": ["╲ ╱", " ╳ ", "╱ ╲"], "Y": ["┐ ┌", "└┬┘", " ┴ "], "Z": ["──┐", " ╱ ", "└──"], "0": ["┌─┐", "│ │", "└─┘"], "1": [" ┐", " │", " ┴"], "2": ["─┐", "┌┘", "└─"], "3": ["─┐", " ┤", "─┘"], "4": ["┐ ┐", "└─┤", " ┘"], "5": ["┌─", "└┐", "─┘"], "6": ["┌─", "├┐", "└┘"], "7": ["──┐", " │", " ┘"], "8": ["┌┐", "├┤", "└┘"], "9": ["┌┐", "└┤", "─┘"], "-": [" ", "── ", " "], " ": [" ", " ", " "], ".": [" ", " ", "·"], "!": ["│", " ", "·"], } # --------------------------------------------------------------------------- # Pixel font — retro bitmap. Height: 3 lines. # --------------------------------------------------------------------------- _PIXEL: dict[str, list[str]] = { "A": ["▀▀▀▄", "█▀▀█", "▀ ▀"], "B": ["▀▀▀▄", "█▀▀▄", "▀▀▀ "], "C": ["▄▀▀▀", "█ ", "▀▀▀ "], "D": ["▀▀▀▄", "█ █", "▀▀▀ "], "E": ["▀▀▀ ", "█▀ ", "▀▀▀ "], "F": ["▀▀▀ ", "█▀ ", "▀ "], "G": ["▄▀▀ ", "█ ▀█", "▀▀▀ "], "H": ["▀ ▀ ", "█▀▀█", "▀ ▀"], "I": ["▀", "█", "▀"], "J": [" ▀ ", " █ ", "▀▀ "], "K": ["▀ ▄ ", "█▀▄ ", "▀ ▀"], "L": ["▀ ", "█ ", "▀▀▀ "], "M": ["▀▄▄▀", "█▀▀█", "▀ ▀"], "N": ["▀▄ ▀", "█ ▀█", "▀ ▀"], "O": ["▄▀▀▄", "█ █", "▀▀▀ "], "P": ["▀▀▀▄", "█▀▀ ", "▀ "], "Q": ["▄▀▀▄", "█ █", "▀▀▀▄"], "R": ["▀▀▀▄", "█▀▀▄", "▀ ▀"], "S": ["▄▀▀ ", "▀▀▀▄", " ▀▀ "], "T": ["▀▀▀▀", " █ ", " ▀ "], "U": ["▀ ▀", "█ █", "▀▀▀ "], "V": ["▀ ▀", "█ █", " ▀▀ "], "W": ["▀ ▀", "█▄▄█", "▀▀▀▀"], "X": ["▀ ▀", " ▀▀ ", "▀ ▀"], "Y": ["▀ ▀", " ▀▀ ", " ▀ "], "Z": ["▀▀▀▀", " ▄▀ ", "▀▀▀▀"], "0": ["▄▀▀▄", "█ █", "▀▀▀ "], "1": [" ▄", " █", " ▀"], "2": ["▀▀▄", " ▄▀", "▀▀▀"], "3": ["▀▀▄", " ▀▄", "▀▀ "], "4": ["▀ ▀", "▀▀█", " ▀"], "5": ["▀▀▀", "▀▀▄", "▀▀ "], "6": ["▄▀▀", "█▀▄", "▀▀ "], "7": ["▀▀▀", " █", " ▀"], "8": ["▄▀▄", "█▀█", "▀▀ "], "9": ["▄▀▄", "▀▀█", "▀▀ "], "-": [" ", " ▀▀ ", " "], " ": [" ", " ", " "], ".": [" ", " ", "▄"], "!": ["█", " ", "▄"], } # --------------------------------------------------------------------------- # Font registry # --------------------------------------------------------------------------- FONTS: dict[str, dict[str, list[str]]] = { "block": _BLOCK, "thin": _THIN, "pixel": _PIXEL, } FONT_HEIGHTS: dict[str, int] = { "block": 6, "thin": 3, "pixel": 3, } def render_big_text(text: str, font_name: str = "block", kerning: int = 1) -> list[str]: """Render text as multi-line ASCII art using the specified font. Args: text: the string to render (uppercase recommended for block/pixel) font_name: "block", "thin", or "pixel" kerning: space between characters (0=tight, 1=normal, 2=wide) Returns: List of strings, one per line of the rendered text. """ font = FONTS.get(font_name, _BLOCK) height = FONT_HEIGHTS.get(font_name, 6) text_upper = text.upper() # Build each line by concatenating character columns lines: list[str] = ["" for _ in range(height)] spacer = " " * kerning for i, ch in enumerate(text_upper): glyph = font.get(ch, font.get("?", [" " * 3] * height)) for row in range(height): if row < len(glyph): lines[row] += glyph[row] else: lines[row] += " " * (len(glyph[0]) if glyph else 3) if i < len(text_upper) - 1: lines[row] += spacer return lines def get_text_width(text: str, font_name: str = "block", kerning: int = 1) -> int: """Calculate the rendered width of big text without rendering it.""" font = FONTS.get(font_name, _BLOCK) text_upper = text.upper() width = 0 for i, ch in enumerate(text_upper): glyph = font.get(ch, font.get("?", [" " * 3])) width += len(glyph[0]) if glyph else 3 if i < len(text_upper) - 1: width += kerning return width