summaryrefslogtreecommitdiff
path: root/random-attractors
diff options
context:
space:
mode:
Diffstat (limited to 'random-attractors')
-rw-r--r--random-attractors/index.html21
-rw-r--r--random-attractors/js/main.js96
2 files changed, 117 insertions, 0 deletions
diff --git a/random-attractors/index.html b/random-attractors/index.html
new file mode 100644
index 0000000..a9834a7
--- /dev/null
+++ b/random-attractors/index.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <title>s1nical - Random Attractors</title>
+ <script src="/random-attractors/js/main.js"></script>
+ <style>
+ html, body {
+ margin: 0;
+ height: 100vh;
+ overflow: hidden;
+ }
+ canvas {
+ background: #000;
+ }
+
+ </style>
+ </head>
+ <body>
+ <canvas id="canvas"></canvas>
+ </body>
+</html> \ No newline at end of file
diff --git a/random-attractors/js/main.js b/random-attractors/js/main.js
new file mode 100644
index 0000000..5355c6e
--- /dev/null
+++ b/random-attractors/js/main.js
@@ -0,0 +1,96 @@
+NUM_ATTRACTORS = 10;
+const canvas = document.getElementById("canvas");
+const ctx = canvas.getContext("2d");
+const { innerWidth, innerHeight } = window;
+const { random, floor, cos, sin } = Math;
+canvas.width = innerWidth;
+canvas.height = innerHeight;
+const w = innerWidth / 2;
+const h = innerHeight / 2;
+
+ctx.translate(w, h);
+ctx.globalCompositeOperation = "lighter";
+const range = n =>
+ Array(n)
+ .fill(0)
+ .map((_, i) => i);
+const randomInt = (s, e) => s + floor((e - s) * random());
+const drawParticle = ({ x, y, c }) => {
+ ctx.beginPath();
+ ctx.fillStyle = c;
+ ctx.fillRect(x, y, 0.5, 0.5);
+ ctx.closePath();
+};
+
+const attractors = range(NUM_ATTRACTORS).map(() => ({
+ x: randomInt(-w, w),
+ y: randomInt(-h, h),
+ g: randomInt(0, 30),
+ c: `rgba(${randomInt(0, 255)}, ${randomInt(0, 255)}, ${randomInt(
+ 0,
+ 255
+ )}, ${random()})`
+}));
+
+// https://codepen.io/ge1doot/pen/ooNvgx
+class Particle {
+ constructor() {
+ this.damp = 0.00006;
+ this.accel = 3200;
+ this.x = randomInt(-w, w);
+ this.y = randomInt(-h, h);
+ this.vx = this.accel * random();
+ this.vy = this.accel * random();
+ this.currentColor = "#fff";
+ }
+ draw() {
+ const { x, y, currentColor } = this;
+ drawParticle({ x, y, c: currentColor });
+ }
+ step() {
+ const { x, y } = this;
+
+ let color = 0;
+ let largestVal = 0;
+
+ attractors.map(a => {
+ const dx = a.x - x;
+ const dy = a.y - y;
+ const d2 = (dx * dx + dy * dy) / a.g;
+ if (d2 > 0.1) {
+ this.vx += this.accel * (dx / d2);
+ this.vy += this.accel * (dy / d2);
+ }
+ if (d2 > largestVal) {
+ largestVal = d2;
+ color = a.c;
+ }
+ });
+ this.x += this.vx;
+ this.y += this.vy;
+
+ this.vx *= this.damp;
+ this.vy *= this.damp;
+
+ this.currentColor = color;
+ this.draw();
+ }
+}
+
+const particles = range(8000).map(() => new Particle());
+const animate = () => {
+ particles.map(particle => {
+ particle.step();
+ });
+};
+
+let iter = 0;
+
+const update = () => {
+ animate();
+ iter += 1;
+ if (iter < 1500) {
+ requestAnimationFrame(update);
+ }
+};
+update();