Skip to content
mopi1402Public

About

Turn terminal output into a self-contained SVG: real ANSI colours, exact monospace alignment, and not one byte of embedded font.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

@tayomi/term2svg

Terminal output in, self-contained SVG out. Real ANSI colour, exact monospace alignment, and not one byte of embedded font.

Terminal attributes rendered by term2svg: bold, dim, italic, underline and reverse, 256-colour and true-colour text, accents, CJK and emoji

my-program | npx @tayomi/term2svg --font ./fonts/jetbrains-mono > output.svg
npx @tayomi/term2svg --font ./fonts/jetbrains-mono --theme one-light input.ansi out.svg
import { term2svg } from "@tayomi/term2svg";
const { svg } = await term2svg(ansi, { font: "./fonts/jetbrains-mono", theme: "one-dark" });

Why not one of the others

GitHub renders no ANSI, so colour plus guaranteed alignment means an image. The tools that exist take one of two bad trades: they embed the whole font as base64, at ~366 KB per image, or they name a font family and hope the reader has it, which is why a box-drawing frame comes apart on somebody else's machine.

term2svg vectorises only the glyphs the input actually uses, declares each one once in <defs>, and places it with <use x y>. Colour is carried by the enclosing group, so one drawing serves every tint. A banner comes out at 8 KB, identical on every machine.

Options

--font <spec> required. A .ttf/.otf/.woff file, a directory, or a URL cached in ~/.cache/term2svg
--theme <name> one-dark (default) or one-light
--background <hex> the paper colour, otherwise the theme's
--quiet no statistics on stderr
TERM2SVG_FONT the default for --font

Input comes from stdin or from a file named first, - meaning stdin when you also want to name an output file. The API takes the same options, plus loadFont() for many renders.

What it draws

Colour all 256 ANSI slots and 24-bit, foreground and background
Attributes bold, dim, italic, underline, reverse
Emoji real colour emoji, kept to their columns, drawn by the reader's own system
Wide characters CJK and emoji measured as 2 columns, so frames close
Control characters tab, carriage return and backspace, through a real cursor

Whatever a terminal would show, this shows: the graphic state outlives the line, \r and \b go back and overwrite, and a non-SGR escape is swallowed rather than printed. Cursor addressing is the deliberate limit, since obeying it means holding a screen buffer.

The font is yours

term2svg ships no font and --font has no default: you choose the typeface and you answer for its licence. A file gives that one face, so bold and italic come out as the roman; a directory gives four, read off each font's OS/2 tables and never off its filename.

Point it at one file, or at a directory holding one family: a system font directory holds many unrelated families, and pairing one family's roman with another's bold would pass without a word.

Working on it

pnpm verify   # lint, typecheck, suite
pnpm demo     # renders samples/attributes.ansi into out/, both themes

TypeScript throughout, with types shipped. Every module answers for itself: foo.ts is tested by foo.test.ts beside it, the CLI suite under tests/ drives the built binary, and the suite builds its own fonts rather than depending on the machine or the network.

Licence

MIT. No font ships here: the typeface is supplied at run time by whoever runs the tool, and the terms of the SVG it produces are that font's terms, not this project's.

About

Turn terminal output into a self-contained SVG: real ANSI colours, exact monospace alignment, and not one byte of embedded font.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages