JSFiddle - React, Tailwind, and code Playground
by jcubed111
HTML
<canvas id="view"></canvas>
<div id="bottomBar">
<div>
Dispersion:
<input id="dispersion" type="range" min=0 max=1 step=0.01 value=0.5 />
</div>
<div>
Velocity:
<input id="velocity" type="range" min=0.5 max=3 step=0.01 value=1.5 />
</div>
<div>
Spawn Rate:
<input id="spawnRate" type="range" min=1 max=10 step=1 value=5 />
</div>
<div>
View Angle:
<label>Top <input type="radio" name="viewAngle" value="0" checked=true></label>
<label>Side <input type="radio" name="viewAngle" value="1"></label>
</div>
<div>Particle Count: <span id="particleCount"></span></div>
</div>
CSS
canvas{
position: absolute;
background: #fff; /*#110022;/**/
top: 0;
left: 0;
right: 0;
bottom: 0;
}
#bottomBar{
position: absolute;
bottom: 0;
left: 0;
right: 0;
display: flex;
background: rgba(17, 0, 34, 0.5);
color: #fa8;
font-family: sans-serif;
padding: 5px;
}
#bottomBar *{
vertical-align: middle;
}
#bottomBar>div{
padding-right: 30px;
}
label{
padding-left: 5px;
}
JavaScript
var scale = 100;
var sideView = false;
function clampInt(min, max, n) {
return ~~Math.max(min, Math.min(max, n));
}
function dispFun(n) {
return Math.pow(n, 5)*0.8 + n*0.2;
}
function velMul(xF, zF) {
return (1/Math.pow(Math.abs(xF)+1, 2) + 0.75) * (1/Math.pow(Math.abs(zF)+1, 2) + 0.75);
}
class Particle{
constructor() {
this.x = Math.random() * 0.05;
this.y = Math.random() * 0.05;
this.z = 0;
const xF = dispFun(Math.random());
const xAngle = xF * Math.PI*0.5 * document.getElementById("dispersion").value;
const zF = Math.random()*2;
const zAngle = zF * Math.PI*0.5;
let vel = Math.random() + 1;
vel *= (2-xF);
const speedFactor = document.getElementById("velocity").value;
this.vx = speedFactor * vel * -Math.cos(xAngle);
this.vy = speedFactor * vel * Math.sin(xAngle) * Math.cos(zAngle);
this.vz = speedFactor * vel * Math.sin(xAngle) * Math.sin(zAngle) + 0.2;
this.heat = 1 + Math.random()*0.25 + vel*0.1;
}
step(t=1/60) {
this.x += this.vx * t;
this.y += this.vy * t;
this.z += this.vz * t;
this.vz -= 20 * t * t;
this.heat -= 0.004 * 60 * t;
if(this.vz < 0 && this.z <= 0) this.vz *= -1;
}
transform([x, y, z]) {
if(sideView) {
return [x, z, y];
}else{
return [x, y, z];
}
}
transformed() {
return this.transform([this.x, this.y, this.z]);
}
transformedVel() {
return this.transform([this.vx, this.vy, this.vz]);
}
render(ctx, t=1/60) {
const [x, y, z] = this.transformed();
const [vx, vy, vz] = this.transformedVel();
let radius = Math.max(1, Math.sqrt(Math.abs(z)) * 10 - 3);
let colorFactor = 1.5 / (radius*radius);
colorFactor = 0.5 + 0.5*colorFactor;
colorFactor *= this.heat;
let r = clampInt(0, 255, 255 * colorFactor);
let g = clampInt(0, 255, 180 * colorFactor);
let b = clampInt(0, 255, 128 * colorFactor);
ctx.beginPath();
if(-this.vx * t > 6/scale) {
t*=2;
// draw as line
ctx.moveTo(x*scale, y*scale);
ctx.lineTo((x +...