Asciify is a small library for converting images, videos, and 3D renders into rasterized ASCII art.
The API is documented inline — every export carries TSDoc, so your editor is the reference.
Asciify rasterizes directly to a canvas, so it’s much faster than other libraries that use the DOM to render text nodes. This comes at the cost of an actual textual representation, but if you’re looking for a fast way to convert 3D animations to ASCII art, Asciify is a perfect fit.
By default it rasterizes the whole frame in a single WebGL draw call — around 0.3ms for a 4K output, with no per-character work on the CPU at all. Where WebGL2 isn’t available it falls back to a Canvas2D rasterizer automatically, so you always get a picture.
Weighing in at less than 7kb when minified and gzipped, Asciify is small enough to be added to your project without worrying about bloat. And Asciify has zero dependencies, so it’s easy to integrate with your existing codebase.
Asciify can rasterize images, videos, and 3D scenes. Anything that can be rendered to a canvas can be converted to ASCII art. Asciify also supports custom fonts and character sets, so you can use it to create text art for any purpose!
Asciify is also written in TypeScript and includes type definitions with full documentation.
yarn add @sister.software/asciify
# or
npm install --save @sister.software/asciify
import { createAsciify } from "https://deno.land/x/asciify/index.ts"
import { createAsciify } from "@sister.software/asciify"
// Create an Asciify renderer and attach it to a canvas. This picks WebGL where it can,
// and falls back to Canvas2D where it can't.
const canvas = document.createElement("canvas")
const asciify = createAsciify(canvas)
const renderer = new THREE.WebGLRenderer({
powerPreference: "high-performance",
precision: "lowp",
})
asciify.setSize(window.innerWidth, window.innerHeight)
// Size the 3D renderer so that each pixel of the scene becomes one ASCII character...
renderer.setSize(asciify.columnCount, asciify.rowCount)
// Render a 3D scene...
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
renderer.render(scene, camera)
// Rasterize the scene into ASCII art!
asciify.rasterizeWebGLRenderer(renderer)
Images work the same way:
const asciify = createAsciify(canvas)
asciify.setSize(640, 480)
await asciify.rasterizeImage(myImageElement)
createAsciify handles this for you, but the pieces are exported if you want them directly.
| renderer | when |
|---|---|
AsciifyWebGL |
The default. One draw call per frame; cost is independent of how many characters you’re drawing. |
Asciify2D |
Automatic fallback when WebGL2 is missing. Also the one to pick if you need a 2D context on the output canvas yourself — a WebGL context claims the canvas exclusively. |
AsciifyPass |
You already have a WebGL2 context and want asciify to render inside it, sampling a texture you already hold. Skips a per-frame upload; roughly 2× the WebGL renderer at 1080p. |
Pass a preference if you need to force one:
createAsciify(canvas, { renderer: "2d" }) // "auto" (default) | "webgl" | "2d"
If you’re already running an EffectComposer, asciify can be the last pass in the chain:
import { AsciifyComposerPass } from "@sister.software/asciify"
const composer = new EffectComposer(renderer)
composer.addPass(new RenderPass(scene, camera))
const asciiPass = new AsciifyComposerPass(renderer, { fontSize: 12 })
asciiPass.renderToScreen = true
composer.addPass(asciiPass)
// Asciify wants one source pixel per character, so the composer's buffers
// are sized to the character grid rather than to the canvas.
asciiPass.syncComposerSize(composer)
Check out our examples for more info on how Asciify can be used!
Asciify is licensed under the MIT License. If you use Asciify in your project, let us know at @SisterSoftware! We would love to see what you’re working on.