Full-size Twindragon curve (900×700)

by Maccimo

HTML

<!DOCTYPE html>
<html>
    <head>
        <title>Full-size Twindragon Curve (900&times;700)</title>
    </head>
    <body onload="launchDragons();">
        <h1>Full-size Twindragon Curve</h1>
        <p>Here you can find a result of the <a href="https://codegolf.stackexchange.com/a/176846">tiny DOS demo</a> reverse engineering. This is full-size (900&times;700) version.</p>
        <p>Write-up can be found here: <a href="https://habr.com/ru/articles/881264/">https://habr.com/ru/articles/881264/</a><br /> Only in Russian language so far.</p>
        <br />
        <canvas id="screen" width="900" height="700" alt="Here be dragons!" title="Hic sunt dracones!">
        </canvas>
    </body>
</html>

CSS

body {
    background-color: white;
}

h1 {
    font-family: sans-serif;
}

canvas#screen { 
    background-color: black;
}

JavaScript

const COLORS = [
    "#000000",
    "#000080",
    "#008000",
    "#008080",
    "#800000",
    "#800080",
    "#808000",
    "#c0c0c0",
    "#808080",
    "#0000ff",
    "#00ff00",
    "#00ffff",
    "#ff0000",
    "#ff00ff",
    "#ffff00",
    "#ffffff"
];

const SCREEN_WIDTH = 900;
const SCREEN_HEIGHT = 700;
const HORIZONTAL_OFFSET = 200;
const VERTICAL_OFFSET = 350;

const DRAW_AXIS = true;
const AXIS_COLOR = "#00ff00";

const BATCH_SIZE = 2557;

const DELAY = 1;

function TwinDragon(
    context,
    screenWidth, 
    screenHeight,
    horizontalOffset,
    verticalOffset,
    showAxis,
    axisColor,
    batchSize
) {
    this.context = context;
    this.screenWidth = screenWidth;
    this.screenHeight = screenHeight;
    this.horizontalOffset = horizontalOffset;
    this.verticalOffset = verticalOffset;
    this.showAxis = showAxis;
    this.axisColor = axisColor;
    this.batchSize = batchSize;

    this.X = 255;
    this.Y = 0;

    this.step = function() {
        let flag = (Math.random() < 0.5);

        if (flag) {
            this.Y = 256 + ((this.Y  - this.X - 1) >> 1);
        } else {
            this.Y = ((this.Y - this.X) >> 1);
        }

        this.X = this.Y + this.X;

        this.putPixel(this.X, this.Y, this.randomColor());

    }

    this.putPixel = function(x, y, colorIndex) {
        context.fillStyle = COLORS[colorIndex & 0xF];
        context.fillRect(x, y, 1, 1);
    }

    this.randomColor = function() {
        return Math.trunc(Math.random() * 15);
    }

    this.drawFrame = function() {
        for (var i = 0; i < this.batchSize; i++) {
            this.step();
        }
        this.drawAxis();
    }

    this.drawAxis = function() {
        if (this.showAxis) {
            context.lineWidth = 1;
            context.strokeStyle = this.axisColor;
            context.moveTo(-this.horizontalOffset, 0);
            context.lineTo(this.screenWidth - this.horizontalOffset, 0);
            context.moveTo(0, -this.verticalOffset);
...