JSFiddle - React, Tailwind, and code Playground

by mvasilkov

HTML

<canvas></canvas>

CSS

body {
    background: #fbfbfb;
    margin: 0;
    overflow: hidden;
}
canvas {
    background: #000;
    display: block;
    left: 50%;
    margin: -250px 0 0 -250px;
    position: absolute;
    top: 50%;
}

JavaScript

/* https://github.com/mvasilkov/new-year-fir-tree */

if (typeof requestAnimationFrame != 'function') {
    ['moz', 'webkit', 'ms'].some(function (p) {
        var f = this[p + 'RequestAnimationFrame']
        return typeof f == 'function'? (requestAnimationFrame = f): false
    }) || (requestAnimationFrame = function (f) {
        return setTimeout(f, 0)
    })
}

(function (canvas) {
    /* Settings */
    var thetaEnd = 6 * Math.PI,
        lineSpacing = 1 / 30,
        lineLength = 0.5 * lineSpacing,
        rate = 1 / (2 * Math.PI),
        factor = rate / 3,
        cycle = 200,
        opacityMin = 0.69,
        opacityDif = 48,
        scene = [],
        /* Rendering */
        offsetX = 250,
        offsetY = 310,
        scaleX = 400,
        scaleY = 400,
        camX = 0,
        camY = 2,
        camZ = -3,
        cSize = 500,
        c = canvas.getContext('2d')

    canvas.width = canvas.height = cSize
    c.lineWidth = 1.44

    scene.push(new Coil({ color: '255,0,0', theta0: Math.PI }))
    scene.push(new Coil({ color: '100,200,255' }))

    requestAnimationFrame(paint)

    function paint() {
        var offset = 1 - Date.now() / cycle % 1, i = 0
        requestAnimationFrame(paint)
        c.clearRect(0, 0, cSize, cSize)
        for (; i < scene.length; ++i)
            scene[i].paint(offset)
    }

    function project(point) {
        return [offsetX + scaleX * (point[0] - camX) / -(point[2] + camZ),
                offsetY + scaleY * (point[1] - camY) / -(point[2] + camZ)]
    }

    function clamp(val, a, b) {
        return (val < a)? a: (val > b)? b: val
    }

    function Coil(options) {
        this.color       = options.color       || '255,255,255'
        this.theta0      = options.theta0      || 0
        this.lineSpacing = options.lineSpacing || lineSpacing
        this.lineLength  = options.lineLength  || lineLength
        this.rate        = options.rate        || rate
        this.factor      = options.factor      || factor
   ...