Glyph Video
no source

Glyph Video — render an MP4 as a monospace glyph field

Canvas 2D · full colour · nothing leaves this machine

Drop an MP4 anywhere on this page, or pick one below. Every frame is downsampled to the character grid, quantised onto a glyph ramp, and painted in the frame's own colours.

0:00 / 0:00 grid —
120 cols
2.00
0
1.00
1.25
Glyph set
Colour

Sources

Three ways in

A local file is the simple case: it is read with URL.createObjectURL and decoded in place. A direct video link works too, as long as the server sends an Access-Control-Allow-Origin header — without one the browser will play the video but refuse to let the canvas read it back.

A YouTube or TikTok link is the case that cannot work in a page. The player is a cross-origin iframe, and the media URL behind it is signed and CORS-locked, so there are no pixels to read. Capture a tab goes around the problem from the other side: share the tab that is playing the clip and the frames arrive as an ordinary MediaStream, which the same renderer treats like any other source. Running the page from serve.command adds the second route — a small local helper fetches the link with yt-dlp and serves the file from this origin, so pasting a link works directly.

What the dials do

Resolution is the whole picture

The video is never drawn to the screen. Each frame is scaled down to exactly one pixel per character cell, that pixel's luminance is corrected and quantised onto the glyph ramp, and the row is printed as text. Raising the resolution adds columns, which shrinks the type to match — the grid always fills the same frame.

Colour comes from the frame itself. The glyph layer is drawn white into an offscreen canvas and the downsampled frame is composited through it, so every cell keeps its own colour at full opacity — the character carries the brightness, the fill carries the hue. Saturation pivots around each cell's luminance, so pushing it never changes which glyph gets picked.

ControlRangeEffect
Resolution24 – 320 colsColumns across the frame. Rows follow from the video's aspect ratio and the cell aspect. High values are detailed but soft; low values are legible as type.
Cell aspect1.0 – 2.8How tall a character cell counts as, relative to its width. Around 2.0 keeps a monospace grid looking square; lower stretches the image vertically.
Brightness−0.6 – +0.6Added to every channel before quantising, so it lifts the colour and the glyph density together. Push it up to pull detail out of dark footage.
Contrast0.4 – 2.8Scales every channel around mid grey. High contrast makes the ramp snap between empty and solid.
Saturation0 – 2.5Pushes each cell's colour away from its own grey. Zero renders in luminance only; above one puts the colour back that averaging a cell down to one pixel takes out.
Glyph set5 setsRamp is the classic ten-step; Fine is a 70-step ramp for detail; Blocks and Bars use Unicode shading; Binary is ones and zeros.
Colour3 modesFull colour masks the frame's own colour through the glyphs at full opacity. Ink and Accent fall back to a single theme colour graded by ramp opacity.