JSFiddle - React, Tailwind, and code Playground

by jcubed111

HTML

<script src="https://kit.fontawesome.com/9c26a6d367.js"></script>
<canvas id="lineArea" width=600 height=600></canvas>
<div id="iconArea"></div>

CSS

body{
    background: #111;
    color: #fff;
}

#iconArea{
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    
    margin-left: 50%;
    margin-top: 50%;
}

.powerIcon{
    position: absolute;
    line-height: 1;
    --fa-primary-opacity: 1;
    --fa-secondary-opacity: 1;
    width: 65px;
    height: 65px;
    text-align: center;
    font-size: 40px;
    box-sizing: border-box;
    padding-top: 13px;
    border: 2px solid #666;
    border-radius: 50%;
    background: #111;
}

#lineArea{
    position: absolute;
    top: 0;
    left: 0;
}

JavaScript

const levelWidth = 100;
const ICON_RADIUS = 65;

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

let itemPropList = [
    ['main', [], 'user', '#242', '#7D5B33'],
        ['strike', ['main'], 'sword', '#833', '#999'],
        ['shoot', ['main'], 'bow-arrow', '#999', '#742'],
        ['magic missile', ['main'], 'wand', '#e72', '#f5f'],
            ['staff', ['magic missile'], 'staff', '#742', '#bbf'],
            ['fortify', ['strike', 'magic missile'], 'fist-raised', '#646', '#757'],
            ['savage strike', ['strike'], 'mace', '#999', '#833'],
            ['stab', ['strike', 'shoot'], 'dagger fa-rotate-180', '#242', '#999'],
];


function angleMean(angles) {
	if(angles.length == 1) return angles[0];
	let points = angles.map(a => [Math.cos(a), Math.sin(a)]);
    let sumPoint = points.reduce(([a,b], [c,d]) => [a+c, b+d], [0, 0]);
    if(sumPoint[0]**2 + sumPoint[1]**2 < 0.0001) {
    	// we're probably averaging things evenly spaced on the circle
        return ((angles[0] + angles[angles.length-1]) / 2) % (Math.PI * 2);
    }
    return normalizeAngle(Math.atan2(sumPoint[1], sumPoint[0]));
}
function normalizeAngle(a) {
	// returns a value between 0 and 2*Math.PI
	while(a < 0) a += Math.PI * 2;
    while(a >= Math.PI*2) a -= Math.PI*2;
    return a;
}
function angleLerp(a, b, factor) {
	a = normalizeAngle(a);
    b = normalizeAngle(b);
	if(b < a) b += Math.PI*2;
    if(Math.abs(b - a) > Math.PI) {
    	a += Math.PI*2;
    }
	return normalizeAngle(a * (1 - factor) + b * factor);
}
function angleDist(a, b) {
	let d = normalizeAngle(a - b);
    if(d > Math.PI) d = 2*Math.PI - d;
    return d;
}

class Item{
	constructor(name, index, icon, color0, color1) {
    	this.name = name;
        this.index = index;
        this.parents = [];
        this.children = [];
        this.icon = icon;
        this.colors = [color0, color1];
        this.level = 0;
        
        this.theta = 0;
    }
    
    setLevel(i) {
    	this.level =...