Skip to content

Instantly share code, notes, and snippets.

@Shadowking1235
Created April 30, 2019 10:13
Show Gist options
  • Save Shadowking1235/5f0f86c8b60be68e50c480432aa34feb to your computer and use it in GitHub Desktop.
Save Shadowking1235/5f0f86c8b60be68e50c480432aa34feb to your computer and use it in GitHub Desktop.
Pipes
const Random = { shuffle, pick, rangeFloor };
const EPSILON = Number.EPSILON;
const settings = {
animate: true,
duration: 6,
// dimensions: [800, 600],
scaleToView: true,
};
const PALETTE = Random.shuffle([
'#fff',
'#fff791',
'#9aeeeb',
'#1a5ece',
'#6ee99d',
'#000',
'#faf8f4',
]);
const GRID_SIZE = 16;
const sketch = async app => {
const { canvas } = app;
// Take a background color
const background = PALETTE.shift();
const pipes = linspace(24 + 6).map(() => ({
pts: pipeOfLength(12), // [[1, 1], [3, 1], [3, 4], [6, 4], [6, 6], [8, 6], [10, 6], [10, 12]]
color: Random.pick(PALETTE),
}));
// Return the renderer object
return {
// The draw function
render({ deltaTime, context, width, height, time, playhead }) {
// Draw background
context.fillStyle = background;
context.lineCap = 'round';
context.lineJoin = 'round';
context.fillRect(0, 0, width, height);
// Draw pipes
const drawPipe = drawPipeToScale(context, [width, height]);
pipes.forEach(({ color, pts }) => {
drawPipe(pts, color, background, playhead);
});
// drawGrid(context, width, height);
},
};
};
canvasSketch(sketch, settings);
function drawPipeToScale(context, [width, height]) {
return (_pts, color, bg, playhead) => {
const t = Math.sin(playhead * Math.PI);
const pts = _pts.map(uvToXy([width, height]));
let l = 0;
for (let i = 1; i < pts.length; i++) {
const a = pts[i];
const b = pts[i - 1];
l = l + Math.hypot(a[0] - b[0], a[1] - b[1]);
}
context.setLineDash([l * 0.5, l]);
context.lineDashOffset = mapRange(t, 0, 1, 0, -l * 0.5);
// bg
context.strokeStyle = bg;
context.lineWidth = 24;
drawShape(context, pts, false);
context.stroke();
// outer
context.strokeStyle = color;
context.lineWidth = 18;
drawShape(context, pts, false);
context.stroke();
// middle
context.setLineDash([l * 0.4, l]);
context.lineDashOffset = mapRange(t, 0, 1, 0, -l * 0.6);
context.strokeStyle = bg;
context.lineWidth = 12;
drawShape(context, pts, false);
context.stroke();
// inner
context.setLineDash([l * 0.3, l]);
context.lineDashOffset = mapRange(t, 0, 1, 0, -l * 0.7);
context.strokeStyle = color;
context.lineWidth = 6;
drawShape(context, pts, false);
context.stroke();
};
}
function uvToXy([width, height]) {
return ([x, y]) => [
mapRange(x, 0, GRID_SIZE, 0, width),
mapRange(y, 0, GRID_SIZE, 0, height),
];
}
function pipeOfLength(length = 6) {
let prevDir = [0, 0];
const start = [
Random.rangeFloor(1, GRID_SIZE - 1),
Random.rangeFloor(1, GRID_SIZE - 1),
];
return linspace(length).reduce(
polyline => {
const dir = randomDir(prevDir);
const a = polyline[polyline.length - 1];
const b = dir.map(v => v * Random.rangeFloor(1, 3));
prevDir = dir;
return polyline.concat([
[clampToGrid(b[0] + a[0]), clampToGrid(b[1] + a[1])],
]);
},
[start],
);
}
function randomDir(prevDir) {
const prev = prevDir.map(v => v * -1);
return Random.pick(
[[1, 0], [0, 1], [-1, 0], [0, -1]].filter(
dir => !(prev && dir[0] === prev[0] && dir[1] === prev[1]),
),
);
}
function clampToGrid(v) {
return clamp(v, 1, GRID_SIZE - 1);
}
function drawGrid(context, width, height) {
const s = 2;
for (let x = 1; x < GRID_SIZE; x++) {
for (let y = 1; y < GRID_SIZE; y++) {
// get a 0..1 UV coordinate
const u = GRID_SIZE <= 1 ? 0.5 : x / (GRID_SIZE - 1);
const v = GRID_SIZE <= 1 ? 0.5 : y / (GRID_SIZE - 1);
// scale to dimensions
const [ptx, pty] = uvToXy([width, height])([x, y]);
context.fillStyle = '#000';
context.fillRect(ptx - s / 2, pty - s / 2, s, s);
}
}
}
function drawShape(context, [start, ...pts], closed = true) {
context.beginPath();
context.moveTo(...start);
pts.forEach(pt => {
context.lineTo(...pt);
});
if (closed) {
context.closePath();
}
}
/**
* From Canvas Sketch Util
*/
function mapRange (value, inputMin, inputMax, outputMin, outputMax, clamp) {
// Reference:
// https://openframeworks.cc/documentation/math/ofMath/
if (Math.abs(inputMin - inputMax) < EPSILON) {
return outputMin;
} else {
var outVal = ((value - inputMin) / (inputMax - inputMin) * (outputMax - outputMin) + outputMin);
if (clamp) {
if (outputMax < outputMin) {
if (outVal < outputMax) outVal = outputMax;
else if (outVal > outputMin) outVal = outputMin;
} else {
if (outVal > outputMax) outVal = outputMax;
else if (outVal < outputMin) outVal = outputMin;
}
}
return outVal;
}
}
function linspace (n, opts) {
n = defined(n, 0);
if (typeof n !== 'number') throw new TypeError('Expected n argument to be a number');
opts = opts || {};
if (typeof opts === 'boolean') {
opts = { endpoint: true };
}
var offset = defined(opts.offset, 0);
if (opts.endpoint) {
return newArray(n).map(function (_, i) {
return n <= 1 ? 0 : ((i + offset) / (n - 1));
});
} else {
return newArray(n).map(function (_, i) {
return (i + offset) / n;
});
}
}
function clamp (value, min, max) {
return min < max
? (value < min ? min : value > max ? max : value)
: (value < max ? max : value > min ? min : value);
}
function defined () {
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] !== undefined) return arguments[i];
}
}
function shuffle (arr) {
if (!Array.isArray(arr)) {
throw new TypeError('Expected Array, got ' + typeof arr);
}
var rand;
var tmp;
var len = arr.length;
var ret = arr.slice();
while (len) {
rand = Math.floor(value() * len--);
tmp = ret[len];
ret[len] = ret[rand];
ret[rand] = tmp;
}
return ret;
}
function rangeFloor (min, max) {
if (max === undefined) {
max = min;
min = 0;
}
if (typeof min !== 'number' || typeof max !== 'number') {
throw new TypeError('Expected all arguments to be numbers');
}
return Math.floor(range(min, max));
}
function pick (array) {
if (array.length === 0) return undefined;
return array[rangeFloor(0, array.length)];
}
function range (min, max) {
if (max === undefined) {
max = min;
min = 0;
}
if (typeof min !== 'number' || typeof max !== 'number') {
throw new TypeError('Expected all arguments to be numbers');
}
return value() * (max - min) + min;
}
function value() {
return Math.random();
}
function newArray (n, initialValue) {
n = defined(n, 0);
if (typeof n !== 'number') throw new TypeError('Expected n argument to be a number');
var out = [];
for (var i = 0; i < n; i++) out.push(initialValue);
return out;
}
<script src="https://unpkg.com/canvas-sketch@0.3.0/dist/canvas-sketch.umd.js"></script>
body {
margin: 0;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment