/** * Minimal 8x8 bitmap font for baking captions onto screenshot composites. * * Glyphs are the public-domain `font8x8_basic` set (Daniel Hepper's font8x8, * https://github.com/dhepper/font8x8 — public domain / "do whatever you want"), * printable ASCII 0x20–0x7E, plus a custom middle-dot (·, 0xB7) used as the label * separator. Public domain, so fine to embed under our GPLv3. * * Each glyph is 8 row-bytes (top→bottom). Within a row byte, bit `c` (LSB = 0) is * column `c`, left→right: pixel (c,row) is set iff `(byte >> c) & 1`. */ // prettier-ignore const GLYPHS: Record = { ' ': [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], '!': [0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00], '"': [0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], '#': [0x36, 0x36, 0x7f, 0x36, 0x7f, 0x36, 0x36, 0x00], '$': [0x0c, 0x3e, 0x03, 0x1e, 0x30, 0x1f, 0x0c, 0x00], '%': [0x00, 0x63, 0x33, 0x18, 0x0c, 0x66, 0x63, 0x00], '&': [0x1c, 0x36, 0x1c, 0x6e, 0x3b, 0x33, 0x6e, 0x00], "'": [0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00], '(': [0x18, 0x0c, 0x06, 0x06, 0x06, 0x0c, 0x18, 0x00], ')': [0x06, 0x0c, 0x18, 0x18, 0x18, 0x0c, 0x06, 0x00], '*': [0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00], '+': [0x00, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x00, 0x00], ',': [0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x06], '-': [0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00], '.': [0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00], '/': [0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x01, 0x00], '0': [0x3e, 0x63, 0x73, 0x7b, 0x6f, 0x67, 0x3e, 0x00], '1': [0x0c, 0x0e, 0x0c, 0x0c, 0x0c, 0x0c, 0x3f, 0x00], '2': [0x1e, 0x33, 0x30, 0x1c, 0x06, 0x33, 0x3f, 0x00], '3': [0x1e, 0x33, 0x30, 0x1c, 0x30, 0x33, 0x1e, 0x00], '4': [0x38, 0x3c, 0x36, 0x33, 0x7f, 0x30, 0x78, 0x00], '5': [0x3f, 0x03, 0x1f, 0x30, 0x30, 0x33, 0x1e, 0x00], '6': [0x1c, 0x06, 0x03, 0x1f, 0x33, 0x33, 0x1e, 0x00], '7': [0x3f, 0x33, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x00], '8': [0x1e, 0x33, 0x33, 0x1e, 0x33, 0x33, 0x1e, 0x00], '9': [0x1e, 0x33, 0x33, 0x3e, 0x30, 0x18, 0x0e, 0x00], ':': [0x00, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x0c, 0x00], ';': [0x00, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x0c, 0x06], '<': [0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x00], '=': [0x00, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x00], '>': [0x06, 0x0c, 0x18, 0x30, 0x18, 0x0c, 0x06, 0x00], '?': [0x1e, 0x33, 0x30, 0x18, 0x0c, 0x00, 0x0c, 0x00], '@': [0x3e, 0x63, 0x7b, 0x7b, 0x7b, 0x03, 0x1e, 0x00], 'A': [0x0c, 0x1e, 0x33, 0x33, 0x3f, 0x33, 0x33, 0x00], 'B': [0x3f, 0x66, 0x66, 0x3e, 0x66, 0x66, 0x3f, 0x00], 'C': [0x3c, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3c, 0x00], 'D': [0x1f, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1f, 0x00], 'E': [0x7f, 0x46, 0x16, 0x1e, 0x16, 0x46, 0x7f, 0x00], 'F': [0x7f, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x0f, 0x00], 'G': [0x3c, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7c, 0x00], 'H': [0x33, 0x33, 0x33, 0x3f, 0x33, 0x33, 0x33, 0x00], 'I': [0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x00], 'J': [0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1e, 0x00], 'K': [0x67, 0x66, 0x36, 0x1e, 0x36, 0x66, 0x67, 0x00], 'L': [0x0f, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7f, 0x00], 'M': [0x63, 0x77, 0x7f, 0x7f, 0x6b, 0x63, 0x63, 0x00], 'N': [0x63, 0x67, 0x6f, 0x7b, 0x73, 0x63, 0x63, 0x00], 'O': [0x1c, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1c, 0x00], 'P': [0x3f, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x0f, 0x00], 'Q': [0x1e, 0x33, 0x33, 0x33, 0x3b, 0x1e, 0x38, 0x00], 'R': [0x3f, 0x66, 0x66, 0x3e, 0x36, 0x66, 0x67, 0x00], 'S': [0x1e, 0x33, 0x07, 0x0e, 0x38, 0x33, 0x1e, 0x00], 'T': [0x3f, 0x2d, 0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x00], 'U': [0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3f, 0x00], 'V': [0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x0c, 0x00], 'W': [0x63, 0x63, 0x63, 0x6b, 0x7f, 0x77, 0x63, 0x00], 'X': [0x63, 0x63, 0x36, 0x1c, 0x1c, 0x36, 0x63, 0x00], 'Y': [0x33, 0x33, 0x33, 0x1e, 0x0c, 0x0c, 0x1e, 0x00], 'Z': [0x7f, 0x63, 0x31, 0x18, 0x4c, 0x66, 0x7f, 0x00], '[': [0x1e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1e, 0x00], '\\': [0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x40, 0x00], ']': [0x1e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1e, 0x00], '^': [0x08, 0x1c, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00], '_': [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff], '`': [0x0c, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00], 'a': [0x00, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x6e, 0x00], 'b': [0x07, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x3b, 0x00], 'c': [0x00, 0x00, 0x1e, 0x33, 0x03, 0x33, 0x1e, 0x00], 'd': [0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6e, 0x00], 'e': [0x00, 0x00, 0x1e, 0x33, 0x3f, 0x03, 0x1e, 0x00], 'f': [0x1c, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0f, 0x00], 'g': [0x00, 0x00, 0x6e, 0x33, 0x33, 0x3e, 0x30, 0x1f], 'h': [0x07, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x67, 0x00], 'i': [0x0c, 0x00, 0x0e, 0x0c, 0x0c, 0x0c, 0x1e, 0x00], 'j': [0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1e], 'k': [0x07, 0x06, 0x66, 0x36, 0x1e, 0x36, 0x67, 0x00], 'l': [0x0e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x00], 'm': [0x00, 0x00, 0x33, 0x7f, 0x7f, 0x6b, 0x63, 0x00], 'n': [0x00, 0x00, 0x1f, 0x33, 0x33, 0x33, 0x33, 0x00], 'o': [0x00, 0x00, 0x1e, 0x33, 0x33, 0x33, 0x1e, 0x00], 'p': [0x00, 0x00, 0x3b, 0x66, 0x66, 0x3e, 0x06, 0x0f], 'q': [0x00, 0x00, 0x6e, 0x33, 0x33, 0x3e, 0x30, 0x78], 'r': [0x00, 0x00, 0x3b, 0x6e, 0x66, 0x06, 0x0f, 0x00], 's': [0x00, 0x00, 0x3e, 0x03, 0x1e, 0x30, 0x1f, 0x00], 't': [0x08, 0x0c, 0x3e, 0x0c, 0x0c, 0x2c, 0x18, 0x00], 'u': [0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00], 'v': [0x00, 0x00, 0x33, 0x33, 0x33, 0x1e, 0x0c, 0x00], 'w': [0x00, 0x00, 0x63, 0x6b, 0x7f, 0x7f, 0x36, 0x00], 'x': [0x00, 0x00, 0x63, 0x36, 0x1c, 0x36, 0x63, 0x00], 'y': [0x00, 0x00, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x1f], 'z': [0x00, 0x00, 0x3f, 0x19, 0x0c, 0x26, 0x3f, 0x00], '{': [0x38, 0x0c, 0x0c, 0x07, 0x0c, 0x0c, 0x38, 0x00], '|': [0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00], '}': [0x07, 0x0c, 0x0c, 0x38, 0x0c, 0x0c, 0x07, 0x00], '~': [0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], '·': [0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00], // custom middle-dot separator }; const BLANK = GLYPHS[' ']; /** 8 row-bytes for a character; falls back to a blank cell for anything unmapped. */ export function glyphFor(ch: string): number[] { return GLYPHS[ch] ?? BLANK; } /** Whether a character has a real glyph (used for width estimation / fitting). */ export function hasGlyph(ch: string): boolean { return ch in GLYPHS; }