Making art in the terminal window
Mona Lisa in the Console
© Lead Image © Gennadiy Poznyakov, 123RF.com
You can create living, breathing art using nothing but C++ code, 16.7 million colors, and the Linux console.
This article invites readers into the world of generative art – but not the kind rendered by GPUs or displayed through glassy GUI frameworks. In this case, the canvas is the Linux terminal, and the brush is pure C++ code. You'll learn how to breathe life into grids of characters, how patterns emerge from logic, and how randomness itself can become rhythm. I don't have the space to print all the code used for this article, but you'll find it all at my GitHub site [1].
Using a text terminal, and a deep respect for the expressive power of simplicity, I'll construct living systems made entirely of text and shades of color. By the end, your terminal will have transcended its humble role as a command prompt, becoming a living canvas of color, movement, and form. From oscillating plasma to self-replicating cellular automata, you'll watch as computation turns into motion, emotion, and art.
The Canvas
Before you can draw, you must understand the medium. The Linux terminal, often dismissed as a relic of textual computing, is actually a grid-based display system, capable of far more nuance than it first appears. At its heart, every terminal window is a matrix of character cells, each with a foreground and background color.
The contents of each cell is rendered by your terminal emulator, which translates ANSI escape codes (short textual commands) into color, brightness, and character output. Modern terminal emulators, descendants of the green-on-black glass plates of the past, have undergone a remarkable transformation from mundane monochrome. Where once you had a proud but limited 16-green palette, you can now find the opulence of 256-color modes and even 24-bit True Color when correctly picking your terminal emulator. That's right – a staggering 16.7 million shades of vibrant decadence.
ASCII art emerged in the 1960s and 70s on teletype machines and early terminals, where engineers and bored scientists used letters, numbers, and punctuation marks to draw faces, logos, and scenes. As technology advanced, so did the art form – ANSI art arrived in the 1980s alongside colorful bulletin board systems (BBS). Using ANSI escape codes, artists could finally add 16 colors and cursor positioning to their creations, giving rise to dazzling, animated text compositions that defined the underground digital aesthetic of that era.
But those days are gone, and gone, too, are the restrictions that existed when the terminal was shackled to the spartan 80x25 grid. Modern emulators like Terminator, Alacritty, and kitty allow you to stretch out and breathe. Your "canvas" is now limited mainly by your screen resolution and how far you dare to zoom out before the text turns into microscopic ants.
In short, the modern terminal has evolved from a mere command-line type-enter-repeat sequence into a full-fledged digital atelier – capable not only of executing commands but of painting with them.
Every time you run the following command:
printf "\033[38;2;255;0;0m\033[48;2;0;0;255m\u2588\033[0m\n"
you are not merely printing a character; you are painting a pixel – the Unicode glyph 2588 acts as a full-height block, or, artistically viewed: a pixel.
Gentle Introduction to ANSI Sequences
Before you panic at the sight of that wild-looking printf incantation and flee for your life, take a moment to read this short introduction to ANSI escape sequences – because that's all that mysterious black colorful magic really is.
The ANSI escape sequences are those curious little runes that make your terminal abundant with color, move the cursor about, and occasionally reduce you to tears when you forget to reset them properly.
An ANSI escape sequence starts, fittingly, with an escape character – \033 (or \x1B in hex, also known as ESC). The escape character is followed by a left square bracket [ and then a series of parameters and commands.
For example:
\033[31m
means "switch the text color to red".
At the end of the day, it's just printed text – the terminal interprets these sequences and changes its behavior accordingly.
The original ANSI color palette offered eight base colors (Table 1), each with a bright variant – making a total of 16.
Table 1
Original ANSI Color Palette
| Code | Color | Bright |
|---|---|---|
| 30-37 |
Foreground (Black to White) |
90-97 |
| 40-47 |
Background (Black to White) |
100-107 |
In the following example:
std::cout << "\033[31mRed text\033[0m" << std::endl;
the 31 sets the foreground to red. The \033[0m at the end resets all attributes (like all well-behaving ANSI sequences do after they have finished painting the world).
Backgrounds are similar:
std::cout << "\033[42mGreen background\033[0m" << std::endl;
And if you want both (because who doesn't?):
std::cout << "\033[93;44mBright yellow on blue\033[0m" << std::endl;
The 256-Color Mode
Eventually, someone decided 16 colors weren't enough to express the full emotional range of a C++ developer, so terminals introduced the 256-color mode. To use it:
\033[38;5;<n>m<C> : Foreground color :\033[48;5;<n>m<C> : Background color
Where <n> is between 0 and 255, and m is just the character "m." The 256 colors are distributed as follows:
- 0-15: the original 16 ANSI colors
- 16-231: a 6x6x6 RGB cube (216 colors)
- 232-255: 24 shades of grayscale (from dark to light)
The C++ program in Listing 1 exemplifies this colorful palette and showcases the result in Figure 1.
Listing 1
The Colorful Palette
#include <iostream>
#include <iomanip>
int main() {
std::cout << "\033[0m"; // Reset colors
for (int row = 0; row < 16; ++row) {
for (int col = 0; col < 16; ++col) {
int color = row * 16 + col;
std::cout << "\033[48;5;" << color << "m" // Set background color
<< std::setw(4) << color // Print color index
<< "\033[0m "; // Reset after each
}
std::cout << "\n";
}
std::cout << "\033[0m"; // Final reset
return 0;
}
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
New Linux Flaw Lets Attackers Escape VMs
A 16-year-old vulnerability allows an attacker to escape a virtual machine, gain access to the host, and execute malicious code.
-
Hannah Montana Linux Is Back!
Developer Noah Cagle decided the world needed the once obscure but beloved Linux distribution and gave it a decidedly pink refresh.
-
System76 Refreshes the Lemur Laptop
If you're looking for a laptop with tons of power and battery, look no further than the latest iteration of the System76 Lemur Pro.
-
More than 43 Million Lines of Code in Linux Kernel 7.2
Using the cloc utility, Michael Larabel of Phoronix discovered that Linux kernel 7.2 has over 43 million lines of code.
-
Kubuntu Focus Goes Ultra
The Kubuntu Focus team has upped the performance ante of its M2 and Zr laptops with the latest, greatest CPUs from Intel.
-
Linux Gamers May Soon See Less Mouse Lag in KDE Plasma
Gamers using KDE’s Plasma desktop have been suffering from a slight input delay in mouse movement that could lead to getting fragged.
-
Three Lines of Code Improve Linux Storage Performance
A developer changed three lines of code, giving Linux storage performance a 5% bump.
-
AUR Hit Again with Malicious Packages
Once again the Arch User Repository is plagued by a high volume of malicious packages.
-
Alpine Linux 3.24 Features Fresh Desktops and a Newer Kernel
If you're a fan of Alpine Linux, it's time to upgrade because the latest version has been released with KDE Plasma 6.6, Gnome 50, and Linux kernel 6.18 LTS.
-
EU Open Source Strategy Plays Key Role in Tech Sovereignty Package
Comprehensive measures adopted by the European Commission aim to reduce dependency on non-EU countries.
