Custom Code Experiment •
Chromatophores 2
Source Code View HTML / CSS / JavaScript
<!DOCTYPE html>
<html>
<head>
<style>
html, body {
overflow: hidden;
background: #000;
padding: 0px;
margin: 0px;
width: 100%;
height: 100%;
}
canvas {
display: block;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var w = canvas.width = window.innerWidth;
var h = canvas.height = window.innerHeight;
window.onresize = function() {
w = canvas.width = window.innerWidth;
h = canvas.height = window.innerHeight;
};
var pixels = [];
var emitterCount = 4;
var maxPixels = 130;
var pixelSize = 18;
var gap = 6;
var lineWidth = 2;
var maxLifetime = 4500;
var minLifetime = 2000;
var spawnRate = 400;
var opacity = 0.22;
var hue = 0;
var hueRange = 60;
var fadeAlpha = 0.018;
var shapes = ["rect", "arc", "triangle", "diamond", "cross", "star"];
function drawShape(shape, x, y, size, pulse) {
var s = size * pulse;
ctx.beginPath();
switch(shape) {
case "rect":
ctx.rect(x - s/2, y - s/2, s, s);
break;
case "arc":
ctx.arc(x, y, s / 2, 0, 2 * Math.PI);
break;
case "triangle":
ctx.moveTo(x, y - s / 2);
ctx.lineTo(x + s / 2, y + s / 2);
ctx.lineTo(x - s / 2, y + s / 2);
ctx.closePath();
break;
case "diamond":
ctx.moveTo(x, y - s / 2);
ctx.lineTo(x + s / 2, y);
ctx.lineTo(x, y + s / 2);
ctx.lineTo(x - s / 2, y);
ctx.closePath();
break;
case "cross":
var t = s / 4;
ctx.rect(x - t/2, y - s/2, t, s);
ctx.rect(x - s/2, y - t/2, s, t);
break;
case "star":
var spikes = 5;
var outerR = s / 2;
var innerR = s / 4.5;
var rot = (Math.PI / 2) * 3;
var step = Math.PI / spikes;
ctx.moveTo(x, y - outerR);
for (var k = 0; k < spikes; k++) {
ctx.lineTo(
x + Math.cos(rot) * outerR,
y + Math.sin(rot) * outerR
);
rot += step;
ctx.lineTo(
x + Math.cos(rot) * innerR,
y + Math.sin(rot) * innerR
);
rot += step;
}
ctx.lineTo(x, y - outerR);
ctx.closePath();
break;
}
}
function emit() {
for (var i = 0; i < emitterCount; i++) {
if (pixels.length >= maxPixels) {
pixels.splice(0, 1);
}
var step = pixelSize + gap;
pixels.push({
x: Math.ceil((Math.random() * w) / step) * step,
y: Math.ceil((Math.random() * h) / step) * step,
t: Math.random() * (maxLifetime - minLifetime) + minLifetime,
s: Date.now(),
h: Math.random() * ((hue + hueRange) - (hue - hueRange)) + (hue - hueRange),
shape: shapes[Math.floor(Math.random() * shapes.length)],
pulseOffset: Math.random() * Math.PI * 2,
pulseSpeed: 2 + Math.random() * 3
});
}
}
function draw() {
var now = Date.now();
for (var i = 0; i < pixels.length; i++) {
var p = pixels[i];
var diff = (now - p.s) / p.t;
var perc = Math.round(diff * 100);
var pulse = 1 + 0.4 * Math.sin(p.pulseOffset + (now / 1000) * p.pulseSpeed);
ctx.save();
ctx.beginPath();
ctx.globalAlpha = opacity;
ctx.lineWidth = lineWidth;
ctx.strokeStyle = "hsl(" + p.h + "," + perc + "%,55%)";
ctx.fillStyle = "hsl(" + p.h + "," + perc + "%,55%)";
drawShape(p.shape, p.x + pixelSize/2, p.y + pixelSize/2, pixelSize, pulse);
ctx.stroke();
ctx.restore();
}
}
function animate() {
var step = pixelSize + gap;
for (var i = 0; i < pixels.length; i++) {
if (pixels[i].s + pixels[i].t < Date.now()) {
pixels.splice(i, 1);
i--;
} else {
var dir = Math.round(Math.random() * 8) % 8;
switch(dir) {
case 0: pixels[i].y -= step; break;
case 1: pixels[i].x += step; pixels[i].y -= step; break;
case 2: pixels[i].x += step; break;
case 3: pixels[i].x += step; pixels[i].y += step; break;
case 4: pixels[i].y += step; break;
case 5: pixels[i].x -= step; pixels[i].y += step; break;
case 6: pixels[i].x -= step; break;
case 7: pixels[i].x -= step; pixels[i].y -= step; break;
}
}
}
}
function render() {
ctx.globalAlpha = fadeAlpha;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, w, h);
ctx.globalAlpha = 1;
draw();
animate();
requestAnimationFrame(render);
}
emit();
setInterval(emit, spawnRate);
requestAnimationFrame(render);
</script>
</body>
</html>