From 6924ec1e60407dceb1382c5af049ef1635660885 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 28 Sep 2026 10:25:45 +0200 Subject: [PATCH] Add a font with the branch drawing symbols for the demo recordings The terminal that vhs records is xterm.js running in a browser, and the xterm.js that ttyd bundles doesn't draw the branch drawing symbols itself. So they have to come from a font, and SauceCodePro NF doesn't have them, nor does any font that macOS comes with. The detailed commit graph shows up as garbage. Newer versions of xterm.js do draw the symbols, but only in the WebGL renderer. vhs forces the canvas renderer, and xterm.js has removed that since, so moving to a newer xterm.js would mean patching both ttyd and vhs. The Flog Symbols font has the symbols, but it draws its lines for a smaller cell than the one xterm.js uses at our font settings. As a fallback font, it leaves a gap at the edges of every cell, and each line of the graph comes out dashed. Add a copy of the font that fits the cells of the recordings. xterm.js clips each character to its row, so the vertical strokes reach well past the top and bottom of the cell and end exactly at the row's edges. It doesn't clip a character to its cell horizontally, so the horizontal strokes reach only a little way into the neighbouring cells. Any further, and they would show past the start of a bend in the next cell. Give the font a bold face with the same outlines. lazygit draws the lines of the selected commit in bold, and without a bold face the browser makes the symbols bold itself by thickening them. That leaves gaps where they meet. Add the script that made the font, and list the font after SauceCodePro NF in demo/settings.tape so that the browser takes the symbols from it. Co-Authored-By: Claude Opus 5.5 (1M context) --- demo/fonts/FlogSymbolsDemo-Bold.ttf | Bin 0 -> 9716 bytes demo/fonts/FlogSymbolsDemo-Regular.ttf | Bin 0 -> 9668 bytes demo/fonts/LICENSE-FlogSymbols | 21 +++++ demo/fonts/fit_flog_symbols.py | 116 +++++++++++++++++++++++++ demo/settings.tape | 6 +- docs-master/dev/Demo_Recordings.md | 3 + 6 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 demo/fonts/FlogSymbolsDemo-Bold.ttf create mode 100644 demo/fonts/FlogSymbolsDemo-Regular.ttf create mode 100644 demo/fonts/LICENSE-FlogSymbols create mode 100644 demo/fonts/fit_flog_symbols.py diff --git a/demo/fonts/FlogSymbolsDemo-Bold.ttf b/demo/fonts/FlogSymbolsDemo-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..864b6449599ec703f441671a2e1232d362c0606f GIT binary patch literal 9716 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 r_t$UjA+q{Eq{~= RIGHT - EDGE_TOLERANCE: + x = CELL_WIDTH + HORIZONTAL_OVERLAP + else: + x += dx + if y <= BOTTOM + EDGE_TOLERANCE: + y -= VERTICAL_REACH + elif y >= TOP - EDGE_TOLERANCE: + y += VERTICAL_REACH + coordinates[i] = (x, y) + glyph.recalcBounds(glyf) + font["hmtx"][name] = (CELL_WIDTH, glyph.xMin) + + +def set_style(font, family, style): + bold = style == "Bold" + postscript_name = f"{family.replace(' ', '')}-{style}" + full_name = family if not bold else f"{family} {style}" + for record in font["name"].names: + if record.nameID == 1: + record.string = family + elif record.nameID == 2: + record.string = style + elif record.nameID == 4: + record.string = full_name + elif record.nameID in (3, 6): + record.string = postscript_name + + os2 = font["OS/2"] + os2.usWeightClass = 700 if bold else 400 + fs_bold, fs_regular = 1 << 5, 1 << 6 + os2.fsSelection &= ~(fs_bold | fs_regular) + os2.fsSelection |= fs_bold if bold else fs_regular + font["head"].macStyle = 1 if bold else 0 + + +if __name__ == "__main__": + main() diff --git a/demo/settings.tape b/demo/settings.tape index 3c98a213b..96e81c55d 100644 --- a/demo/settings.tape +++ b/demo/settings.tape @@ -2,8 +2,10 @@ # demo/record_demo.sh generates for a demo sources this file. # Use the non-Mono Nerd Font variant; the Mono variant renders the icons too -# small. -Set FontFamily "SauceCodePro NF" +# small. The terminal that vhs records doesn't draw the branch drawing symbols +# of the commit graph itself, so they come from the second font, which is in +# demo/fonts. +Set FontFamily "SauceCodePro NF,Flog Symbols Demo" Set FontSize 24 Set LineHeight 1.0 Set Padding 20 diff --git a/docs-master/dev/Demo_Recordings.md b/docs-master/dev/Demo_Recordings.md index 29b835f32..207500711 100644 --- a/docs-master/dev/Demo_Recordings.md +++ b/docs-master/dev/Demo_Recordings.md @@ -20,6 +20,9 @@ go install github.com/charmbracelet/vhs@v0.11.0 wget https://github.com/ryanoasis/nerd-fonts/releases/download/v3.0.2/SourceCodePro.tar.xz && \ tar -xf SourceCodePro.tar.xz -C ~/Library/Fonts && \ rm SourceCodePro.tar.xz + +# font with the branch drawing symbols of the commit graph +cp demo/fonts/FlogSymbolsDemo-*.ttf ~/Library/Fonts ``` ## Creating a demo