# 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][kitty]. ![The word "home04" in heavy sans-serif letters, colored with a diagonal rainbow](docs/banner.png) It does the same job as [figurine][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 ```console $ 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][oklab] 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: ```nix { 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 ```console $ 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][zig-font] reads the font files; - [zig-font-config][zig-font-config] finds fonts the way fontconfig does; - [zig-font-shaper][zig-font-shaper] shapes the text; - [zig-font-renderer][zig-font-renderer] draws the glyphs onto a [z2d][z2d] surface; - [z2dimg][z2dimg] encodes the PNG. ## Where this lives ```console git clone https://git.jcollie.dev/jeff/zigurine.git ``` The repository is mirrored on Tangled at . ## Issues and pull requests Please report issues and send pull requests on the Tangled mirror, . See [CONTRIBUTING.md](CONTRIBUTING.md) for how the project is put together. ## License MIT. The project follows the [REUSE](https://reuse.software/) specification, and `reuse lint` passes. ## References cited - Goyal, Kovid. "Terminal Graphics Protocol." kitty documentation. - Moy, Edward, Stephen Gildea, and Thomas Dickey. "XTerm Control Sequences." - Ottosson, Björn. "A Perceptual Color Space for Image Processing." December 23, 2020. - Atkins Jr., Tab, Chris Lilley, and Lea Verou, eds. "CSS Color Module Level 4." W3C, 2026. - Shirvani, Arsham. *figurine*. Version 2.1.1. Go, 2026. [kitty]: https://sw.kovidgoyal.net/kitty/graphics-protocol/ [figurine]: https://github.com/arsham/figurine [oklab]: https://bottosson.github.io/posts/oklab/ [zig-font]: https://git.jcollie.dev/jeff/zig-font [zig-font-config]: https://git.jcollie.dev/jeff/zig-font-config [zig-font-shaper]: https://git.jcollie.dev/jeff/zig-font-shaper [zig-font-renderer]: https://git.jcollie.dev/jeff/zig-font-renderer [z2d]: https://github.com/vancluever/z2d [z2dimg]: https://git.jcollie.dev/jeff/z2dimg