zigurine #
A login banner: the machine's name, drawn in a real font and colored with a rainbow, shown as an image in a terminal that supports the kitty graphics protocol.

It does the same job as figurine, which prints the name in FIGlet characters colored with ANSI escape codes. zigurine draws the name instead: the text is shaped and rendered in an ordinary TrueType or OpenType font at the terminal's own pixel size, so the letters are as sharp as the screen can show them. Any terminal that cannot show images gets nothing at all, and the login goes on as usual.
It is written in Zig 0.17.
Using it #
$ zigurine # the short hostname
$ zigurine some other words # or any text, on one line
$ zigurine -o banner.png --height-px 200 hello
| Option | Default | |
|---|---|---|
-f, --font PATTERN |
Inter:black |
The font, as a fontconfig pattern. |
--font-file PATH |
Draw with the font in this file, without fontconfig. | |
--font-index N |
0 |
Which font of a collection (.ttc) --font-file names. |
--random |
Choose at random among the installed fonts the pattern matches, the way fc-list matches. A generic name such as sans-serif matches no font that way, so use a property: --random -f :weight=bold. |
|
--rows N |
4 |
How tall the banner is, in terminal rows. |
--angle DEGREES |
45 |
The direction the rainbow runs in, counterclockwise from left to right. |
--cycles N |
1 |
How many times the rainbow goes round the spectrum across the banner. |
--hue DEGREES |
random | The hue the rainbow starts at. |
-o, --output FILE |
Write the banner to a PNG file instead of the terminal. | |
--height-px N |
128 |
The banner's height in pixels when writing a file. |
How it decides what to draw #
Before drawing anything, zigurine asks the terminal four questions:
- whether it supports kitty graphics;
- how big a cell is in pixels;
- how big the window is, in pixels and in cells;
- its device attributes.
Every terminal answers the last one, so its answer means the others are all
in. If the terminal says it supports graphics, the banner is drawn exactly
--rows cells tall at the terminal's real pixel size, shrunk if needed to fit
the window's width, and sent as a PNG placed at the cursor.
zigurine prints nothing if any of these is true:
- standard input or output is not a terminal;
- the terminal does not support kitty graphics;
- nothing answers within 150 milliseconds.
A terminal that answers late may leave its replies in the shell's input.
The rainbow #
The colors sweep through hue in OKLCH at a fixed lightness and chroma, rather than through HSV. Brightness therefore stays even across the banner, without HSV's glaring yellow and cyan or its dim blue. A hue that sRGB cannot show at that chroma has its chroma reduced until it fits. Each run starts at a random hue, so the banner differs from one login to the next.
NixOS #
The flake provides a module that runs zigurine from login shells, fish and bash alike:
{
inputs.zigurine.url = "git+https://git.jcollie.dev/jeff/zigurine";
outputs = { nixpkgs, zigurine, ... }: {
nixosConfigurations.host = nixpkgs.lib.nixosSystem {
modules = [
zigurine.nixosModules.default
{ services.zigurine.enable = true; }
];
};
};
}
| Option | Default | |
|---|---|---|
services.zigurine.enable |
false |
Show the banner at login. |
services.zigurine.text |
networking.hostName |
The text shown. |
services.zigurine.font |
"Inter:black" |
The fontconfig pattern. |
services.zigurine.fontPackages |
[ pkgs.inter ] |
Fonts installed for it, since a server rarely has any. |
services.zigurine.random |
false |
Choose a font at random among the pattern's matches. |
services.zigurine.rows |
4 |
Height in rows. |
services.zigurine.angle |
45 |
The rainbow's direction. |
services.zigurine.cycles |
1 |
Turns of the spectrum across the banner. |
services.zigurine.package |
this flake's | The package used. |
Building #
$ nix develop
$ zig build # zig-out/bin/zigurine
$ zig build test
$ nix build # the package, ReleaseSafe
The font work is done by these libraries:
- zig-font reads the font files;
- zig-font-config finds fonts the way fontconfig does;
- zig-font-shaper shapes the text;
- zig-font-renderer draws the glyphs onto a z2d surface;
- z2dimg encodes the PNG.
Where this lives #
git clone https://git.jcollie.dev/jeff/zigurine.git
The repository is mirrored on Tangled at https://tangled.org/jcollie.dev/zigurine.
Issues and pull requests #
Please report issues and send pull requests on the Tangled mirror, https://tangled.org/jcollie.dev/zigurine. See CONTRIBUTING.md for how the project is put together.
License #
MIT. The project follows the REUSE specification,
and reuse lint passes.
References cited #
- Goyal, Kovid. "Terminal Graphics Protocol." kitty documentation. https://sw.kovidgoyal.net/kitty/graphics-protocol/
- Moy, Edward, Stephen Gildea, and Thomas Dickey. "XTerm Control Sequences." https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
- Ottosson, Björn. "A Perceptual Color Space for Image Processing." December 23, 2020. https://bottosson.github.io/posts/oklab/
- Atkins Jr., Tab, Chris Lilley, and Lea Verou, eds. "CSS Color Module Level 4." W3C, 2026. https://www.w3.org/TR/css-color-4/
- Shirvani, Arsham. figurine. Version 2.1.1. Go, 2026. https://github.com/arsham/figurine