·project

ascii-art

Multi-layer ASCII art generator with dithering, edge detection, and compositing — browser-native.

Problem

ASCII art generators tend to be one-shot: throw an image in, get a single grayscale render out. There's no way to layer effects (dithering vs. edge detection vs. luminance ramp) or to compose pieces.

Solution

A browser-based ASCII compositor where each effect is a layer with its own palette, threshold, and blend mode. Stack edge-detected outlines over a dithered fill the same way you'd stack channels in a paint program.

How

  • Stack: TypeScript on the client, no backend.
  • Algorithms: Floyd-Steinberg dithering, Sobel edge detection, configurable luminance ramps.

The render pipeline runs in two parts. A global adjust pass greyscales the source and applies tone work — blur, high-pass, unsharp mask, levels, gamma, tone curve, posterize — exactly once. Then every layer runs the same four-step loop over that adjusted image: downsample to a character grid, score each cell's intensity, dither the result, and map intensity to a glyph by ink density. Finished layers are stacked with per-layer blend modes and opacity.

ascii-art rendering pipeline — a source image is greyscaled and tone-adjusted once, then each layer downsamples it to a character grid, scores per-cell intensity, applies Floyd–Steinberg dithering, and maps intensity to a glyph by ink density before the layers are composited with blend modes and opacity

The key trick is the character lookup table: the ramp isn't ordered by hand but by each glyph's measured coverage in the chosen font, so intensity maps to the visually correct character. Dithering then diffuses each cell's quantization error into its neighbours, recovering tone the coarse grid would otherwise lose.

Results

Live at ascii-art-sable.vercel.app.

Lessons

A "layer" mental model carries over surprisingly well from raster graphics to fixed-width text — the compositing math is the same.