Skip to content

Real graphics in a text terminal

A shaded teapot, drawn in terminal cells

A spinning, z-buffered, diffuse-shaded Utah teapot in a gyroscope, a full-cell red border, and a bouncing fisheye magnifier lens - all composited into a live terminal via 24-bit ANSI half-blocks. No game engine, no GPU: the 3-D maths, rasteriser, z-buffer, shading and palette quantiser are hand-written pure C#.

pure C# 24-bit ANSI truecolor mode-13h VGA software rasteriser + z-buffer
kullos@terminal: ~/gfx/teapot
A spinning shaded Utah teapot with a gyroscope, framed by a red border, with a bouncing fisheye magnifier lens sweeping across it, rendered as terminal half-block graphics.
kullos@terminal:~/gfx$ dotnet run --project KullOsRunner -- --teapot
Teapot + gyroscope

A surface-of-revolution teapot (swept spout and handle) rasterised at 3x supersampling with a real z-buffer and flat diffuse shading, box-downsampled to 320x200 and quantised to the VGA palette. Three coloured torus rings spin around it.

Red border frame

A full-cell red frame wraps the canvas every frame - explicit proof the terminal is a composited drawing surface, not a scrolling text stream.

Fisheye magnifier

A bouncing lens resamples the live canvas with a barrel warp, magnifying whatever is under it - the cells are readable and distortable pixel data, not a fixed TTY feed.

What you are looking at

This is KullOsRunner's --teapot composite from OnlyCSharp/1.1 - the exact program that runs in real Windows and Linux terminals. The 3-D maths, rasteriser, z-buffer, shading, palette quantiser, gyroscope, red border and fisheye lens are all hand-written pure C#, drawn into the emulated VGA mode-13h framebuffer at 0xA0000, read back through the VGA DAC, and painted to the terminal.

Each character cell renders the Unicode upper-half-block glyph (U+2580): the cell's foreground colour is the top pixel and its background colour is the bottom pixel, so one monospace cell shows two stacked pixels. Colours are set with 24-bit ANSI SGR escapes - ESC[38;2;r;g;bm for foreground and ESC[48;2;r;g;bm for background. In any truecolor terminal that is a real RGB pixel canvas. It is the well-known truecolor half-block trick used by tools like chafa and timg; the renderer here is our own.

The half-block, in one cell

# emit one two-pixel cell: top = (tr,tg,tb), bottom = (br,bg,bb)
ESC[38;2;tr;tg;tb;48;2;br;bg;bbm▀

The demo above is a 640x400 GIF of 64 frames - one full body revolution - captured headlessly: the same renderer writes a picture when its output is piped instead of sent to a TTY. It is encoded with the repo's own Gif89a encoder.