Move flow-fields code here

This commit is contained in:
Greg Shuflin 2023-10-23 02:16:06 -07:00
parent df621db3a2
commit ef2f98ce53
5 changed files with 141 additions and 0 deletions

View File

@ -11,3 +11,18 @@ Or build with:
```
$ pnpm run build
```
# Individual Projects
## Flow Fields
Inspired by https://youtu.be/M_SUcX66SDA Low Byte Productions Flow Fields video
Uses code from:
* https://github.com/francisrstokes/vec-la-fp/tree/master
* https://github.com/francisrstokes/microcan
## Konva-ball
Experimenting with konva library

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flow Fields</title>
<script type="module" src="index.js"></script>
</head>
<body>
<canvas id="main"></canvas>
</body>
</html>

104
src/flow-fields/index.js Normal file
View File

@ -0,0 +1,104 @@
// Inspired by https://youtu.be/M_SUcX66SDA Low Byte Productions Flow Fields video
import { vScale, vAdd, vAngle } from "./util.js";
//const vAngle = (a) => [Math.cos(a), Math.sin(a)];
const canvas = document.getElementById("main");
const ctx = canvas.getContext("2d");
const width = 800;
const height = 800;
// A 10x10 grid, transformed onto the canvas
const n = 25;
const fieldSize = width/n;
canvas.setAttribute("width", width);
canvas.setAttribute("height", height);
const fill = (ctx, r = 0, g = 0, b = 0, a = 255) => {
ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${a})`;
}
const stroke = (ctx, r = 0, g = 0, b = 0, a = 255) => {
ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${a})`;
};
const line = (ctx, v, v2) => {
ctx.beginPath();
ctx.moveTo(...v);
ctx.lineTo(...v2);
ctx.stroke();
ctx.closePath();
}
const ellipse = (ctx, v, rx, ry = rx, oa = 0, sa = 0, ea = Math.PI * 2) => {
ctx.beginPath();
ctx.ellipse(...v, rx, ry, oa, sa, ea, false);
ctx.stroke();
ctx.fill();
ctx.closePath();
}
const background = (ctx, r = 0, g = 0, b = 0, a = 255) => {
fill(ctx, r, g, b, a);
ctx.fillRect(0, 0, width, height);
}
fill(ctx, 0,0,0,0);
stroke(ctx, 255,255,255,1);
background(ctx, 0, 0, 255, width, height);
const vRandom = () => vAngle(Math.random() * Math.PI * 2);
/*
for (let y = 0; y < n; y++) {
for (let x = 0; x < n; x++) {
const sv = vAdd([fieldSize/2, fieldSize/2], vScale(fieldSize, [x, y]));
ellipse(ctx, sv, fieldSize/2);
}
}
*/
let prevTimestamp;
const draw = (timestamp) => {
if (prevTimestamp === undefined) {
prevTimestamp = timestamp;
}
const elapsed = timestamp - prevTimestamp;
if (elapsed > 500) {
prevTimestamp = timestamp;
const field = Array.from({length: n}, () => Array.from({length: n}, () => {
return vRandom();
}));
fill(ctx, 0,0,0,0);
stroke(ctx, 255,255,255,1);
background(ctx, 0, 0, 255, width, height);
field.forEach((row, y) => row.forEach((fv, x) => {
const sv = vAdd([fieldSize/2, fieldSize/2], vScale(fieldSize, [x, y]));
const upper = vAdd(sv, vScale(fieldSize/2, fv));
const lower = vAdd(sv, vScale(-fieldSize/2, fv));
line(ctx, upper, lower);
fill(ctx, 255,255,255,1);
ellipse(ctx, upper, 2);
}));
}
window.requestAnimationFrame(draw);
};
draw();

8
src/flow-fields/util.js Normal file
View File

@ -0,0 +1,8 @@
const vScale = (scale, vec) => vec.map(n => n * scale);
const vAdd = (v0, v1) => [v0[0] + v1[0], v0[1] + v1[1]];
const vAngle = (a) => [Math.cos(a), Math.sin(a)];
export { vAdd, vScale, vAngle };

View File

@ -8,6 +8,7 @@
<h1>Spazer</h1>
<ul>
<li> <a href="./konva-ball/index.html">Konva-ball</a>
<li> <a href="./flow-fields/index.html">Flow-fields</a>
</ul>
</body>
</html>