For the complete documentation index, see llms.txt. Markdown variants are available by appending .md to any URL or sending an Accept: text/markdown header. The asciicn agent skill, for building any ASCII effect on the engine, is at /.well-known/agent-skills/asciicn/SKILL.md.

ASCII image

Any photo redrawn in live glyphs, with every charset and colour mode, auto levels and a pointer spotlight.

Controls
Photo
Charset
Colour
Cell9px
Pointer
Auto levels

Installation

pnpm dlx shadcn@latest add https://asciicn.dev/r/ascii-image.json

Usage

import { AsciiImage } from "@/components/asciicn/ascii-image";
 
export function Cover() {
  return (
    <AsciiImage
      src="/photos/launch.jpg"
      alt="The launch pad at dawn"
      charset="dense"
      reveal="spotlight"
      className="aspect-video w-full"
    />
  );
}

The image is sampled on the CPU. Each glyph takes the area average of the pixels under its cell, so fine detail averages out instead of flickering into noise. Braille samples 2×4 dots per cell and quadrants 2×2, which gives those charsets four to eight times the detail of a ramp at the same cell size.

Switching charset or colorMode redraws from the samples already taken. Resizing, a new fit or a new src samples the image again, once.

On a dark page, bright pixels draw dense glyphs. On a light page it flips, so dark pixels draw dense glyphs and the photo still reads the right way round. Set invert to pick one yourself. Phosphor and duotone looks bring their own dark glass and never flip.

autoLevels stretches the image so its darkest and brightest 1% of pixels reach the ends of the ramp. Flat, foggy photos gain the most. Turn it off to keep a photo's own exposure, then use grade to adjust it.

Examples

Amber phosphor in Braille

Two by four dots per cell in one ink, with the P3 amber glass behind it.

See the photo under the pointer

reveal="photo" opens a soft window onto the original file around the pointer.

Edges and blocks

charset="edge" draws strong contours as - / | \ strokes across the gradient and fills the rest from a ramp. Next to it, ANSI blocks through the sodium ramp.

Props

PropTypeDefault
src

Image URL. Files on another origin need CORS headers, or the canvas can't read their pixels.

Type: stringDefault –
alt

What the image shows. Read out by screen readers. Pass "" for a decorative image.

Type: stringDefault –
charset

Which glyphs draw the tones.

Type: "standard" | "dense" | "blocks" | "quadrants" | "braille" | "cp437" | "petscii" | "katakana" | "dots" | "edge"Default "standard"
chars

A custom ramp from empty to dense, such as " .oO@". Wins over charset.

Type: stringDefault –
colorMode

truecolor takes each cell's own colour. ansi16 snaps it to 16 terminal colours. mono draws in one ink. duotone and palette colour glyphs by tone.

Type: "mono" | "truecolor" | "ansi16" | "duotone" | "palette"Default "truecolor"
phosphor

With mono: a CRT ink and its dark glass.

Type: "p1" | "p3" | "ibm" | "blueprint"Default –
ramp

With duotone: a named ramp or your own stops, dark to light.

Type: RampName | string[]Default "mainframe"
ansi

With ansi16: which 16-colour table.

Type: "vga" | "xterm"Default "vga"
grade

Tone and colour grading before glyphs are chosen.

Type: { brightness?, contrast?, gamma?, saturation? }Default –
invert

true: dark pixels draw dense glyphs. false: bright pixels do. Unset, it follows the page.

Type: booleanDefault follows the theme
threshold

Braille and quadrants: the tone that lights a dot.

Type: numberDefault 0.5
edgeThreshold

Edge charset: how strong a contour must be to draw a stroke.

Type: numberDefault 0.22
dither

Ordered dithering between glyph levels, which smooths gradients in short ramps.

Type: "none" | "bayer2" | "bayer4" | "bayer8" | "blue-noise"Default "none"
background

transparent draws glyphs only, over whatever is behind.

Type: "paper" | "transparent"Default "paper"
fit

How the image fills its box, as in object-fit.

Type: "cover" | "contain" | "fill"Default "cover"
focus

Where the image sits when it overflows or underfills, 0 to 1 per axis.

Type: [x, y]Default [0.5, 0.5]
autoLevels

Stretch the image's tones to use the whole ramp.

Type: booleanDefault true
reveal

spotlight thins glyphs away from the pointer. photo shows the original file around it.

Type: "none" | "spotlight" | "photo"Default "none"
revealRadius

Radius of the reveal in CSS pixels.

Type: numberDefault 120
intro

Glyphs resolve in from noise once the image has loaded.

Type: booleanDefault true
cell

Glyph cell height in CSS pixels.

Type: numberDefault 10
animate

false skips the intro and the loading sweep.

Type: booleanDefault true
crossOrigin

Passed to the image request.

Type: "anonymous" | "use-credentials"Default "anonymous"
handle

Filled with a handle for export: the current frame as text, ANSI, SVG or PNG.

Type: RefObject<AsciiHandle | null>Default –

Notes

  • The wrapper is announced as an image labelled with alt. The canvas inside is hidden from assistive technology. With alt="" the whole thing is decorative.
  • While the file loads, a faint sweep of glyphs and a spinner hold its place. If it fails to load, the box says so in glyphs.
  • With reduced motion, the image appears without the intro. The spotlight still follows the pointer.
  • A still image draws once and then stops. Only the intro, the loading sweep and reveal="spotlight" keep a frame loop running, and that loop pauses offscreen and in hidden tabs.
  • Give the box a size, such as aspect-video w-full. The image fills it and never sets its own height.