ASCII Render
Render an image or a video as live ASCII characters, sampled through a canvas and painted into a single pre element.
Installation
npx smoothui-cli add ascii-renderFeatures
- Works with both
imageandvideosources through the same luminance pipeline - The frame is sampled into an offscreen canvas exactly
columnswide, so the cost scales with the character grid, not the source resolution - Each frame is assembled as one string and written to a single
<pre>— never one DOM node per character color="source"keeps the glyphs but tints them with the frame usingbackground-clip: textand the sampled canvas, so colour costs no extra DOM- Custom
charsetramps ordered dense to sparse, plusinvertto flip the mapping fpsthrottles video sampling, and anIntersectionObserverstops the loop and pauses the video when the component scrolls out of viewpausedfreezes the current frame without tearing down the renderer- Graceful degradation: a tainted canvas, a decode error or a blocked autoplay leaves the original media visible
Usage notes
- The source must allow cross-origin reads. The media element requests it with
crossOrigin="anonymous"; if the canvas ends up tainted thegetImageDatacall throws and the component falls back to showing the media directly. columnsis clamped to8–240. Rows are derived from the source aspect ratio and a0.5character aspect correction, so glyph cells stay roughly square.- Videos are rendered
muted,loopandplaysInlineso browsers allow autoplay.fpsis clamped to1–60.
<AsciiRender
alt="Product demo loop"
color="mono"
columns={100}
fps={24}
source={{ src: "/media/demo.mp4", type: "video" }}
/>Accessibility
ARIA Attributes
| Attribute | Element | Purpose |
|---|---|---|
aria-hidden="true" | <pre> | Stops screen readers from reading thousands of punctuation glyphs |
aria-hidden="true" | <video> / <img> | Marks the sampled media as decorative — it only exists as a pixel source and as the visual fallback |
alt="" | Source <img> | Explicitly decorative, since the real description lives in the text alternative |
class="sr-only" | Text alternative | Exposes alt as the accessible description of the rendered result |
Screen Reader
- The ASCII output is
aria-hiddenandselect-none. Without this, a screen reader would announce every glyph in the grid — thousands of meaningless characters per frame. - The
altyou pass is rendered into a visually hidden<span>, so assistive technology gets exactly one clear description of what the render depicts. - The pause control in the example is a real
<button>with a text label, reachable by keyboard and operable with Enter and Space. - Nothing in the component uses a positive
tabIndex, and the decorative layers are not focusable.
Reduced Motion
This component respects the prefers-reduced-motion media query via useReducedMotion from Motion. When reduced motion is preferred, video sources are never played and no requestAnimationFrame loop is started — a single frame is sampled and left on screen. The same one-shot path is used for image sources, for paused, and whenever the component is scrolled out of the viewport.
Props
Created by
Powered by
© 2026 SmoothUI. Built by Eduardo Calvo.