Last updated: 4th October, 2021 | by Morgan


Ascii3D is a text-based 3D rendering library for JavaScript and TypeScript. It is open source on GitHub.


Water Shader


Install via npm: npm install ascii3d

Render Buffers

A render buffer contains the result of draw calls. They have a width, height, and an array of character-codes, RGBA, and depth values. A render buffer is created like so:

import { RenderBuffer } from "ascii3d";

const width = 30, height = 30;
const renderBuffer = new RenderBuffer(width, height);

Vertex Arrays

A vertex array contains arbitrary numeric data about vertices. They normally contain spacial data (X, Y, Z), color (R, G, B, A), UV, and/or character codes.

const vertexArray = [ // X Y R G B CharCode [-.5, -.5, 1.0, 1.0, 0.0, "#".charCodeAt(0)], [-.5, 0.5, 0.0, 1.0, 1.0, "#".charCodeAt(0)], [0.5, 0.5, 1.0, 0.0, 1.0, "#".charCodeAt(0)], [0.5, -.5, 1.0, 1.0, 0.0, "#".charCodeAt(0)] ];

A lot of 3D models are stored as vertex buffers and index buffers. You can convert them into a vertex array using the createVertexArray() function. For example:

import { createVertexArray } from "./ascii-3d.js"; const vertexBuffer = [ 1, 2, 3 ]; const vertexSize = 1; const indexBuffer = [ 1, 2, 3 ]; const vertexArray = createVertexArray(vertexBuffer, vertexSize, indexBuffer);

Vertex Shaders and Fragment Shaders

A vertex shader accepts a vertex as an input and outputs a clipspace-position and a fragment. The clipspace-position is 4-component vector. The fragment is an array of arbitrary numeric values describing the pixel at the vertex. It is interpolated for every pixel and sent to the fragment shader.

function vertexShader([x, y, r, g, b, charCode]) { return { position: [x, y, 0, 1], fragment: [r, g, b, 1, charCode] } }

A fragment shader accepts a fragment as an input (provided by the vertex shader), and outputs its color and character code.

function fragmentShader(fragment) { // output directly. ([r, g, b, a, charCode]) return fragment; }

Draw Calls

To make a draw call, use the renderBuffer.drawTriangles() method. If depth-testing is enabled, pixels with a greater depth will not be drawn over.

const doDepthTesting = true;
renderBuffer.drawTriangles(vertices, vertexShader, fragmentShader, doDepthTesting);

Rendering to a 2D canvas

One way to display a render buffer is through an HTML canvas element.

renderBuffer.renderToCanvas( ctx, // CanvasRenderingContext2D letterSpacing, // letter spacing 0, 0 // optional: start position (from bottom left) );


Special thanks to:


Licensed under MIT.

All files can be used for commercial or non-commercial purposes. Do not resell. Attribution is appreciated but not due.