Learning how to render 3D with letters and glyphs.

The tower of loops by andreasgysin is my favorite ASCII render. The characters somehow clearly and beautifully express the depth and rotation of the tower. These renders are done (as far as I'm aware) with this Javascript ASCII tool.

To make ASCII in webGL: First, you render your complete scene but in black and white (or in color if you are up for the challenge).

Then in a post-processing step, you take that white and black result and match it to an ASCII character. So, light/white pixels map to really dense characters like "@", and darker\black pixels might map to a less dense character like the dot. "."

Getting started


Single color ASCII

In this demo by Marco instead of changing the color of the ASCII, this site (mostly) lets the white space around the character give the impression of light/dark. Some characters like "w" cover more space than the "/", resulting in a darker/lighter impression.

Marco mentioned he creates the glyphs directly in the shader for this demo for fun's sake, like characters were designed in the Commodore64. However, the more performant and standard approach is to pre-create (with a canvas2D for example) a glyph texture used to sample the glyphs from.

Like a font spite sheet, but the texture should be evenly spaced and, for easy math in the shader, ordered from lighter to denser glyphs.


Multi-color ASCII

Once you have your texture ready, you need to sample it based on the lightness of the current cell. To get the cell lightness, you either need to render at a low resolution or lower the resolution in the shader like so:

vec2 grid =  vec2(uResolution / 10.);
vec2 gridUV = floor(uv * grid)/grid;
float dist =step( distance( gridUV * aspect, uMouse * aspect), 0.1);
vec4 renderColor = texture2D(uTex, gridUV);

This site by 0+X as the shade gets darker, so does the color. You can see it more if you focus on dark to black transition. And there's even some blue light added to the result.

The mouse has some mouse trains like Nathan made in this article but rendered in ASCII.

0X by 0X

Site-wide ASCII

Once you have your pixelated render, you need to sample the correct glyph based on the lightness of the cell, in this case I have 8 glyphs in my texture one next to the other. So depending on the red channel of the render, I'll jump to the next one:

float glyphCount = 8.;
vec2 fAsciiGrid = fract(uv * grid);
fAsciiGrid.x /= glyphCount;
vec2 jump = vec2(floor(renderColor.r * glyphCount) / glyphCount, 0.) ;
vec4 character = texture2D(uASCII, fAsciiGrid + jump );
vec4 result = character;

This site by STUDIO FREIGHT is the perfect example of a striking yet subtle ASCII effect. They've even made a great ASCII tool in React (which is also on the site) where you can lower the resolution and the glyphs real time.

Dragonfly by studio Freight

Fluid Ascii art

I wanted to show Aino's agency website as an amazing combination of two WebGL effects, the ASCII rendering and a fluid dynamic. However, there is no WebGL on this website. This ASCII is pure HTML updated in every frame.

This approach can be used in other parts of the site where the canvas wouldn't work because of layering. Plus, you don't need to sync the canvas to the scroll.

Aino by Aino

My Favorite Dev website

James's portfolio/blog is beautiful, and loads instantly, and James even wrote an article on the step-by-step process of making a similar ASCII scene.

Jame Warner's portfolio by himself

Further reading / Inspiration