JSFiddle - React, Tailwind, and code Playground

HTML

<a id="anchor" download="3dplot2.chr">3dplot2.chr</a><br>
<pre id="output"></pre>
<canvas id="canvas" width="256" height="240"></canvas>
<textarea id="textarea" cols="150" rows="35"></textarea>

CSS

canvas {
	width: 512px;
	image-rendering: pixelated;
}

JavaScript

"use strict";

let ctx;

onload = function() {
	draw();
	chrgen();
};

function draw() {
	ctx = canvas.getContext("2d");
	ctx.fillStyle = "#000000";
	ctx.fillRect(0, 0, canvas.width, canvas.height);

	let yt = new Array(256).fill(240);
	let yb = new Array(256).fill(-1);

	ctx.fillStyle = "#00c000";
	for (let y = -180; y <= 180; y += 4) {
		for (let x = -180; x <= 180; x += 4) {
			let rad = Math.sqrt(x ** 2 + y ** 2) * Math.PI / 180;
			let z = Math.cos(rad) * 100 - Math.cos(3 * rad) * 30;
			let sx = Math.round(128 + x / 2 - y / 4);
			let sy = Math.round(108 - (y / 4 + z / 2));
			if (sx < 0 || 256 <= sx) continue;
			let draw = false;
			if (yt[sx] > sy) {
				yt[sx] = sy;
				draw = true;
			}
			if (yb[sx] < sy) {
				yb[sx] = sy;
				draw = true;
			}
			if (draw) {
				ctx.fillRect(sx, sy, 1, 1);
			}
		}
	}
}

function chrgen() {
	const colors = ["#000080","#500000","#a00000"];
	const limit = 254;
	let count = 0;
	let chr = new Uint8Array(8192);
	let name_table = new Uint8Array(960);

	ctx.globalCompositeOperation = "lighter";

	for (let cy = 0; cy < 30; cy++) {
		for (let cx = 0; cx < 32; cx++) {
			let imgData = ctx.getImageData(cx * 8, cy * 8, 8, 8);
			let data = imgData.data;
			let flag = false;
			let a = [];
			let p = 1;	// G
			for (let y = 0; y < 8; y++) {
				let c = 0;
				for (let x = 0; x < 8; x++) {
					c = (c << 1) | (data[p] >= 0x80 ? 1 : 0);
					p += 4;
				}
				a[y] = c;
				if (c) flag = true;
			}

			let plane = 0;
			let idx = 0;
			if (flag) {
				count++;
				if (count <= limit) {
					plane = 1;
					idx = count;
				} else {
					plane = 2;
					idx = count - limit;
				}
				for (let i = 0; i < 8; i++) {
					chr[idx * 16 + (plane - 1) * 8 + i] = a[i];
				}
			}
			ctx.fillStyle = colors[plane];
			ctx.fillRect(cx * 8 + 1, cy * 8 + 1, 7, 7);
			name_table[cy * 32 + cx] = idx;
		}
	}

	ctx.fillStyle = "#400040";
	for (let i = 0; i < 256; i += 16) {
		ctx.fillRect(i, 0, 1, 256);
		ctx.fillRect(0, i, 256,...