SYSTEM: ONLINE
THREAT FEED: LIVE
LAST SCAN: August 14, 2026
247plan_net

How to Make ASCII Art That Doesn't Look Bad

Quick answer: ASCII art is a luminance-mapping problem. Order characters by how much ink they put on screen, sample your image, and swap each pixel for the character whose weight matches its brightness. Two steps decide whether it works. First, squash the image vertically by about half, because a terminal cell is roughly twice as tall as it is wide. Second, get the ramp pointing the right way: on a dark terminal, dense characters read as bright, which is the reverse of every ramp published for black ink on white paper.


    ███████     ████████      ███████     ████████
   ███   ████  ████  █████  ████  ████   ████  ████
  ████   ████  ████         ████  █████  ████  ████
        ████   █████████    ████  █████  ████  ████
       ████    ████  █████  ████  █████  ████  ████
     █████     ████  █████  ████  █████  ████  ████
    █████      ████  █████  ████  █████  ████  ████
   █████       ████  ████   ████  ████   ████  ████
  ██████████    ████████      ███████     ████████

That banner was not drawn by hand. It was rendered from a bitmap by the method described below, and by the end of this you will be able to reproduce it.

An amber CRT monitor displaying dense blocky character art with visible scanlines

The ramp is the whole idea

Every character puts a different amount of ink on screen. A period covers almost nothing. A hash covers a lot. Order characters by coverage and you have a ramp: a lookup table from brightness to glyph.

The canonical one comes from Paul Bourke, who published it in February 1997. It has seventy characters, and he prints it black to white:

$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,"^`'. 

He also gives a shorter one, which he says is "more convincing" for ten levels of grey:

 .:-=+*#%@

Look carefully, because these two run in opposite directions. The seventy-character ramp starts at `$` for black. The ten-character ramp starts with a space and ends at `@` for black. Bourke labels the direction on only one of them. Copy either into code without checking and your image comes out as a photographic negative, which is the single most common first-attempt failure.

The part nobody tells you: the ramp flips on a dark terminal

Bourke's ramps assume black ink on white paper. More ink means darker.

A terminal inverts that. Light characters sit on a dark background, so more ink means brighter. Every ramp published for print has to be reversed before you use it on a black screen.

This was understood in the 90s and written down properly. The alt.ascii-art FAQ carried Jorn Barger's light-value scale, and it is not a one-dimensional list at all. It is a table with two labelled ends: one ordering for letters on a dark background, the reverse ordering for letters on a bright background.

Every example in this article is rendered for a dark terminal, because that is what you are reading it on. So a sphere lit from the upper left shows its bright side in dense characters:

SHORT RAMP, dark-terminal order                LONG RAMP, same order
                       *                                              J
             #%%%%%%%#####****++=-                          bo****oahkdpwZ0LJXuj1
          %%%%%%%%%%%%%#####***+++==-                    M&888&&WWM#oahbdqmOQCYcnj\{
       %%@@@@@@@%%%%%%%#####****+++==--:              M8%BBBB%%8&WM#*ohkdpwZ0LJXcnj\1?i
     %@@@@@@@@@@@%%%%%%#####****+++==--::.          W%B@@@@@BB%8&WM#*ohkdpwZ0LJXcnrt(}->"
   %%@@@@@@@@@@@%%%%%%%#####***++++==---:.        *&%B@@@@@BB%88&WM*oakbpqmOQCUXcnj/({?~l'
  %%@@@@@@@@@@%%%%%%%%#####****+++===--::..      *&%BB@@@BB%%8&WM#*oakbdqmZ0LJYzuxf/(}?~l"
 %%%@@@@@@@@%%%%%%%%######****++++===--::..     oM&8%%B%%%88&WWM#*ohkbpqmZ0LJYzvnjt|1[-<I^
#%%%%%%%%%%%%%%%%%%#####*****++++===--:::.     b*MW&88888&&WMM#*oakbdpwmOQLJYzvnrt\)}?~i:'
#%%%%%%%%%%%%%%%#######*****+++====---::..     ko#MMWWWWMM##*oahkbdpqmZ0QCUXzvxjt\)}?+>I"
##%%%%%%%%%%%########*****++++====--:::..      dhao******ooahhkbdpwmZ0QCJYzcuxf/|1}?+>I"
##################******++++====---:::..       qdkhhhhhhhkkbddpqwZO0QCJYXcuxjt\({[-~iI"
*##############*******++++====----::...        OwqpdddddppqqwmZO0QLCUYzcuxrf/|1}]_<!;^
*****####**********+++++====----:::..          JQOZmmmmmmZZO0QQLJUYXcvnxjt/|)}]-~iI,'
++*************++++++=====----:::..            nYJCLQQQQQLLCJUYXzcvuxrft\(1}]-~>l:`
 =++++++++++++++++=====----::::..               rvzXYYYYYXXzzcvunxjft\(){[?_~il:^
  ===+++++++========-----:::...                  |frnnuunnnxrrjft\|(1{[?_~>!I,`
   --==========------::::....                     ?)|\/////\\|()1{[]-_~>!I:^
     ::---------::::::...                           ~?][}}}[[]?-_+~>il;,`
       ..::::::......                                 ,li>>>ii!lI;,"`

The short ramp reads as a sphere. The long one reads as static.

At this size each of the seventy characters is doing too little work to be told apart from its neighbours, and the eye cannot recover a shape from that many near-identical textures. The smaller the output, the shorter the ramp. Under about 60 columns, ten levels is plenty. Photographs at 150 columns and up are where a long ramp starts earning its keep.

There is a second problem with long ramps. They are ordered by ink coverage in one specific typeface. Change the font and the order is wrong. Bourke says so himself: "An obvious problem is the variation in apparent density between some typefaces." A `#` and a `%` swap places between fonts more often than you would expect, and a ramp tuned elsewhere produces visible banding.

The aspect-ratio trap

This is the one that ruins most output, and it is invisible until you see the comparison.

Terminal cells are not square. Classic VGA text mode is 80 by 25 characters of 8 by 16 pixels, which is 720 by 400 pixels shown on a 4:3 display. A character cell is about twice as tall as it is wide. Sample an image on a square grid, print it as characters, and every row gets stretched to double height.

Same sphere, same ramp. The only difference is whether the vertical squash was applied:

CORRECTED (squashed ~2:1)                      NOT CORRECTED
                       *                          #%%%%%%%%%%%%%%%##########*******++++===-
             #%%%%%%%#####****++=-             %%%%%%%%%%%%%%%%%%%%%%##########*******+++++==
          %%%%%%%%%%%%%#####***+++==-          @@@@@@@@@%%%%%%%%%%%%%%##########*******++++++
       %%@@@@@@@%%%%%%%#####****+++==--:       @@@@@@@@@@%%%%%%%%%%%%%##########*******++++++
     %@@@@@@@@@@@%%%%%%#####****+++==--::.     @@@@@@@@%%%%%%%%%%%%%%##########*******+++++++
   %%@@@@@@@@@@@%%%%%%%#####***++++==---:.     @@@@@%%%%%%%%%%%%%%%##########********+++++++=
  %%@@@@@@@@@@%%%%%%%%#####****+++===--::..    @%%%%%%%%%%%%%%%%###########*********+++++++==
 %%%@@@@@@@@%%%%%%%%######****++++===--::..    %%%%%%%%%%%%%%###########*********++++++++====
#%%%%%%%%%%%%%%%%%%#####*****++++===--:::.     %%%%%%%%%#############**********+++++++=======
#%%%%%%%%%%%%%%%#######*****+++====---::..     %%%###############**********+++++++++=======--
##%%%%%%%%%%%########*****++++====--:::..      #############***********+++++++++========-----
##################******++++====---:::..       ######**************+++++++++========-------::
*##############*******++++====----::...        **************+++++++++++========-------::::::
*****####**********+++++====----:::..          ******+++++++++++++==========-------::::::....
++*************++++++=====----:::..            ++++++++++++===========--------:::::::.....
 =++++++++++++++++=====----::::..              ================----------:::::::......
  ===+++++++========-----:::...                ======-------------::::::::.......
   --==========------::::....                  --------::::::::::::.......
     ::---------::::::...                      :::::::...........
       ..::::::......

The left one is a ball. The right one is a lens. Same code, same ramp, same source. One multiplication.

Bourke's own instruction is to "sample half as often in the vertical direction," which is the crude version. The precise version is to know your font's cell ratio and use it. Modern tools expose this directly: chafa has a `--font-ratio` flag that exists purely for this.

The BBS scene took it seriously enough to record it in the file. The SAUCE metadata record, which we will come back to, has two bits reserved for aspect ratio: whether a piece was drawn for legacy elongated pixels and should be stretched, or for square pixels and should not. Render a 1995 piece with the wrong geometry and the file itself was trying to warn you.

Block characters change the game

Code page 437, which shipped in the IBM PC's ROM in 1981, includes four shading blocks: `░` light, `▒` medium, `▓` dark, `█` full. Those four plus a space give five levels where every level is a solid area fill rather than a glyph with a shape of its own.

             ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒░
          ███████████▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒░
       ██████████████▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒░░░
     ████████████████▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒░░░
   ▓████████████████▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒░░░░
  █████████████████▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒░░░░░
 ▓████████████████▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒░░░░░
▓▓██████████████▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░
▓▓███████████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒░░░░░░
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒░░░░░░░
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒░░░░░░
▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒░░░░░░░
▒▒▒▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░
 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░
  ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░
   ░░▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░
     ░░░░░░░░░░░░░░░░░░
        ░░░░░░░░░░

Five levels, and it reads more cleanly than seventy levels of punctuation did. Glyph shape is noise when you are trying to represent tone. The blocks have no shape to distract from their weight.

That is also the key to how ANSI art actually achieved colour depth. Those three shade characters blend foreground and background at roughly 25, 50 and 75 percent. Chain them with a full block and you get a five-step gradient between any two of the sixteen colours. The palette was never sixteen colours; it was sixteen colours times a hardware dither, and that is why good ANSI work looks painted rather than blocky.

For higher resolution, subdivide the cell. Half blocks like `▀` give you two independently coloured halves. Braille characters, `⠀` through `⣿`, pack a two-by-four dot matrix into one cell for eight toggleable subpixels. Unicode added proper octants in 2024 that do the same eight subpixels as solid rectangles rather than round dots. Braille has been in Unicode since 1999 and renders nearly everywhere; octants look better but font coverage is still thin. Pick reach or fidelity.

The five-step pipeline

  1. Load and desaturate. Colour is a separate problem. Fix luminance first.
  2. Squash vertically by the cell ratio, roughly 2:1.
  3. Resize to your target column count. Lanczos beats nearest-neighbour badly.
  4. Map brightness through your ramp, in the direction your background demands.
  5. Trim trailing whitespace. It is invisible and it doubles your file size.

Two things not in that list. Stretch the contrast first: most photographs live in the middle of the range and never touch pure black or white, so a straight mapping wastes both ends of the ramp. And choose the source deliberately. The alt.ascii-art FAQ has been telling people the same thing since the 90s: use a wide, even tonal distribution, keep it simple, crop tightly, avoid busy backgrounds. Its most honest line is about expectations: "Be prepared to quickly run through a series of conversions, you will probably not like 9 to 11 out of 12."

Touch-up afterward is assumed, not optional.

Banners from text

The banner at the top was made by rendering "2600" into a bitmap with a heavy font and running it through the same pipeline with a two-level ramp of space and full block.

The dedicated tool is FIGlet, written in the spring of 1991 by Glenn Chappell, inspired by a friend's email signature. The name stands for "Frank, Ian and Glen's letters." It stores hand-designed letterforms in `.flf` font files rather than converting a bitmap, so its output is sharper than any conversion, and there are hundreds of fonts. toilet is a later reimplementation with colour and Unicode output, named as a joke: "The Other Implementation's letters."

Rendering a real typeface to a bitmap wins when you need a specific face or a logo FIGlet has no font for. FIGlet wins on everything else, and it wins on speed.

The scene that took this seriously

Character art on computers is older than the personal computer. Radio teletype operators were sending text images as early as the 1920s, and a contest circuit produced hundreds of works. When those files migrated onto bulletin boards decades later they arrived, as the archivists put it, "often with the credits stripped."

Remember that detail, because it explains everything the scene later built.

The PC era organised fast. Aces of ANSI Art formed in 1989, the first group assembled specifically to make and distribute this work. A schism produced ACiD Productions in September 1990, and iCE followed in January 1991, releasing its first monthly artpack in August 1992. The two were rivals for a decade, each shipping monthly packs of art, group news and membership lists, hand-carried between boards worldwide by couriers.

The output was not small. Across the archive, ACiD released 152 packs between 1990 and 2013, iCE released 330 between 1992 and 2004, and the modern group Blocktronics has released 43 since 2008 containing more total lines than either. The full archive at 16colo.rs holds roughly 5,500 packs spanning 37 years. The shape of that timeline tells its own story: about 843 packs in 1996 at the peak, down to three in 2012, and back to a steady twenty to thirty a year now.

Two pieces of engineering from that era still matter.

The ninth column. In VGA's 9-pixel-wide text modes the ninth column is normally blank spacing, except for characters 0xC0 through 0xDF, where the eighth column is repeated into the ninth so that box-drawing lines join seamlessly. It is why period ANSI looks continuous on real hardware and subtly broken in an emulator set to 8-pixel cells.

SAUCE, the Standard Architecture for Universal Comment Extensions, created in 1994 by ACiD's Olivier Reubens. It appends a 128-byte record after the end-of-file marker carrying title, author handle, group, date, dimensions, and flags for iCE colours, letter spacing and aspect ratio. It is a metadata standard whose entire purpose was to make credit survive the file being separated from its pack. A scene that had watched a half-century of anonymous teletype art arrive with the signatures cut off solved the problem in the file format.

Tools worth using in 2026

Status here is from the repositories, not the project websites, several of which are badly out of date.

ToolForStatus
chafaImages to textThe strongest in the category. Braille, sextants, half-blocks, plus real pixels via sixel and kitty. Released April 2026
FIGlet / toiletText bannersFrozen but stable, packaged everywhere. The format has not needed to change
jp2aJPEG/PNG to ASCIIActively maintained, released December 2025. `--chars` takes your own ramp
ascii-image-converterImages, braille outputWorks, but no release since November 2022. Treat as stale
libcaca / img2txtImages, colour, ditheringAlive despite appearances: the site advertises 2014, the repo shipped in 2021 and commits this month
ansiloveRender `.ans` to PNGActively maintained, June 2026. Reads SAUCE, honours iCE colours, handles DOS aspect ratio. The reference renderer
Moebius BeyondDrawing ANSI, half-block brushThe live desktop line, July 2026. Plain "Moebius" has not shipped since 2021
text0wnzDrawing ANSI in a browserActive, November 2025. Offline-capable, optional collaborative editing
DurdrawDrawing in the terminalActive. Modeled on TheDraw and ACiDDraw, does frame animation, exports mIRC colour
PabloDrawDrawing, collaborativeMaintained slowly. Also handles RIPscrip vector art
REXPaintDrawing, game mockupsFree but not open source, Windows only. Aimed at roguelike developers

One naming trap worth knowing before you go reading. In this scene, "RIP" means RIPscrip, a vector graphics format for bulletin boards. It has nothing to do with ripping or theft. It is a first-class file type in the archives alongside `.ans`.

A note on conversion versus drawing. Everything above the table is about conversion, which is signal processing. Hand-drawn ANSI is a different discipline, closer to pixel art, where an artist places each character deliberately and uses the box-drawing and half-block glyphs as shapes rather than as tones. Conversion gets you a recognisable image in a second. Drawing gets you something worth signing, and the scene's own tutorials, dozens of which survive in the packs, are almost all about letterforms.

Getting it to survive contact with the internet

The credit rules, which are older than you think

The scene's etiquette is unusually explicit, and it exists because of that half-century of teletype art arriving unsigned.

The agreed rules are simple: if a piece carries initials, leave them on. If it does not, say that you did not draw it. If you have the original with the signature intact, repost that version.

The FAQ puts it more memorably than any modern licence does: "If the picture contains a few letters in one corner which don't seem to be part of the picture, they're the artist's initials. DO NOT remove these initials. Would you cut away the part of a Van Gogh painting containing his name?"

There is also a politeness scale, attributed to a poster called Krogg, that has aged perfectly:

1.) Ultra polite:...ya make yer own ascii and use it.
2.)  Very polite:...Ya contact the author and ask if ya can use it...
3.)       polite:...Ya use it but you keep the Credits in there like they should be.
4.)         rude:...Ya use it and strip credits.
5.)    Very rude:...Ya use it and claim that it Is _Your_ very own creation...

The default is three. Anything below it, the scene noticed.

Where this still lives

Command-line tools still print banners. `/etc/motd` still greets you on a fresh server. `fortune | cowsay` is still the canonical joke. If you want system-info art, use fastfetch; neofetch was archived read-only in 2024 and recommending it dates you instantly.

It also still gets pasted into chat. IRC is very much alive in 2026, and a channel topic or a bot greeting is one of the last places where a small piece of character art is not just tolerated but expected. The constraint that shaped the form, a fixed grid and no images, is native there.

The scene itself is working, not preserved. The archive's forum currently carries paid commission requests for BBS menus and logos, alongside new tool releases.

Here is the thing worth ending on. For terminals that support sixel or the kitty graphics protocol, chafa can emit actual pixels. The technical reason for character art is gone. People keep making it anyway, which means that after sixty years it finally became what it always looked like: a deliberate aesthetic rather than a limitation.

If this is your corner of computing, pulling data out of the radio spectrum is the same exercise in a different medium, and our security audiobook shortlist covers a fair bit of the culture both grew out of.

Frequently Asked Questions

What is the best character ramp for ASCII art?

For output under about 60 columns, a short ramp of roughly ten characters such as ` .:-=+*#%@` beats a long one. For solid shapes and logos, the CP437 block set ` ░▒▓█` is better still, because those glyphs have no shape of their own to distract from their weight. Long seventy-character ramps only earn their keep on large photographic output, and they are tuned to one specific font.

Why does my ASCII art look stretched?

You skipped aspect correction. A terminal character cell is about twice as tall as it is wide, so an image sampled on a square grid comes out doubled in height. Squash the source vertically by roughly half before converting, or set your tool's font-ratio option.

Why does my converted image look like a negative?

Your ramp is pointing the wrong way for your background. Ramps published for print assume black ink on white paper, so dense characters mean dark. On a terminal, light text on a dark background means dense characters read as bright, and the ramp must be reversed. Bourke's own two published ramps famously run in opposite directions, which catches almost everyone once.

What is the difference between ASCII art and ANSI art?

ASCII art uses only printable ASCII and no colour, so it displays anywhere. ANSI art adds the CP437 extended set, including the shading and box-drawing glyphs, plus escape codes for sixteen foreground colours and eight background colours, or sixteen backgrounds if the piece uses iCE colours. ANSI is the BBS-era form, saved as `.ans`, and needs a renderer such as ansilove to display on the modern web.