diff --git a/README.md b/README.md index 977a3aa..8768d92 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/src/flow-fields/index.html b/src/flow-fields/index.html new file mode 100644 index 0000000..0952e84 --- /dev/null +++ b/src/flow-fields/index.html @@ -0,0 +1,13 @@ + + + + + + Flow Fields + + + + + + + diff --git a/src/flow-fields/index.js b/src/flow-fields/index.js new file mode 100644 index 0000000..42469e4 --- /dev/null +++ b/src/flow-fields/index.js @@ -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(); diff --git a/src/flow-fields/util.js b/src/flow-fields/util.js new file mode 100644 index 0000000..c967bcd --- /dev/null +++ b/src/flow-fields/util.js @@ -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 }; diff --git a/src/index.html b/src/index.html index ecd2d7d..83d0abf 100644 --- a/src/index.html +++ b/src/index.html @@ -8,6 +8,7 @@

Spazer