JSFiddle - React, Tailwind, and code Playground

by Yaroslav Samardak

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>

JavaScript

const { 
	indexBy, prop, is, ifElse,
	always, __, pipe, flatten,
	append, clamp,
} = R

const NORMALIZE_ZERO_TO_ONE = 			1
const NORMALIZE_MINUS_ONE_TO_ONE = 	2
const NORMALIZE_MINUS_ONE_TO_ZERO =	3

function mapSpan(value, fromA, fromB, toA, toB) {
	return (value - fromA) * (toB - toA) / (fromB - fromA) + toA
}

class Point {
	constructor(x, y) {
		this.x = x
		this.y = y
	}

	relative(bBoxName) {
		return prop(bBoxName, indexedBoxes).map(this)
	}
}

class BoundingBox {
	constructor(
		name,
		left, top, right, bottom,
		normalization
	) {
		this.name = name
		this.left = left
		this.top = top
		this.right = right
		this.bottom = bottom

		switch (normalization) {
			case NORMALIZE_MINUS_ONE_TO_ONE:
				this.min = -1
				this.max = 1
				break
			case NORMALIZE_MINUS_ONE_TO_ZERO:
				this.min = -1
				this.max = 0
				break
			default:
				this.min = 0
				this.max = 1
				break
		}
	}

	mapX(x) {
		return mapSpan(x, this.left, this.right, this.min, this.max)
	}

	mapY(y) {
		return mapSpan(y, this.top, this.bottom, this.min, this.max)
	}
	
	map(point) {
		return new Point(this.mapX(point.x), this.mapY(point.y))
	}
}

class Glow extends Point {
	constructor(x, y) {
		super(x, y)
		this.r = 0
		this.g = 0
		this.b = 0
	}

	rgb(r, g, b) {
		this.r = r
		this.g = g
		this.b = b
	}

	hsv(h, s = 1, v = 1) {
		let r, g, b, i, f, p, q, t
		h = h % 360

		// Achromatic (grey)
		if (s === 0) return this.rgbh(v, v, v, height)

		h /= 60 // sector 0 to 5
		i = ~~(h)
		f = h - i // factorial part of h
		p = v * (1 - s)
		q = v * (1 - s * f)
		t = v * (1 - s * (1 - f))

		switch (i) {
			case 0:
				r = v;
				g = t;
				b = p;
				break
			case 1:
				r = q;
				g = v;
				b = p;
				break
			case 2:
				r = p;
				g = v;
				b = t;
				break
			case 3:
				r = p;
				g = q;
				b = v;
				break
			case 4:
				r = t;
				g = p;
				b = v;
				break
			default:
				r = v;
				g = p;
				b = q
		}

		return this.rgb(r, g, b)
	}
	
	color() {
		return {
			r: Math.round(this.r...