← All effects

ASCII Renderer

BackgroundVanilla JS · zero dependenciesno pixels are read · one value per character
-- fps
prefers-reduced-motion detected — one still frame, no animation

X-ray · layers

the moving brightness the characters are read from
brightness picks the character — off and every cell uses one
your word raised out of the field
hue shifts with brightness — off and it is one ink

Parameters

Your word
Cell size14 px
Speed1.00
Contrast1.30
Hue265
your version · updates as you tinker

How this effect works

Almost every ASCII renderer on the web works the same way: draw a picture, read the canvas back pixel by pixel, average each block of pixels, then print a character. This one never reads a pixel of the moving image, because there is no moving image to read. The brightness of a character is calculated directly, once, for that character. The stage is divided into cells the size of one letter — the cell size slider is literally that grid — and for each cell we evaluate a small sum of sine waves at its centre. Four sines: two running across the grid at different rates, one along the diagonal, and one rippling outward from the middle. Their average is a number between 0 and 1, and that number is the whole picture.

Turning that number into a letter is the ramp: a string of characters ordered from thin to dense,  .:-=+*#%@. Brightness 0 lands on a space, brightness 1 lands on @, and everything else falls where it falls. Switch the Ramp layer off and every lit cell is drawn with the same character — the shape stays, the shading dies, which is a fast way to see that in ASCII art the shading is the alphabet. The contrast slider pushes the numbers away from the middle before they hit the ramp, so the picture goes from a soft grey mush to hard black and white.

Your word is the one place a pixel really is read, and only once. The word is painted on an off-screen canvas with fillText, and for every cell we check whether the centre of that cell landed on ink. That produces a small true/false grid which is stored and reused, and it is recomputed only when the word, the cell size or the stage size changes — never per frame. Cells that landed on the word get their brightness lifted near the top of the ramp, so the word rises out of the field as denser characters instead of being written over it.

Production notes: respects prefers-reduced-motion (one static frame, no loop) · no getImageData in the animation loop — the only read is the word stencil, on change only · the word is drawn with fillText and never inserted as HTML · cells that resolve to a space are skipped instead of drawn · the copied snippet is self-contained HTML + JS.