Created
September 17, 2019 14:18
-
-
Save mattdesl/eefda925e5388cb2d77dcaf59ba2f675 to your computer and use it in GitHub Desktop.
random grid connections / Licensed under Polyform Non Commercial 1.0.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// License: Polyform Non Commercial 1.0.0 | |
// https://polyformproject.org/licenses/noncommercial/1.0.0/ | |
const canvasSketch = require('canvas-sketch'); | |
const Random = require('canvas-sketch-util/random'); | |
const Color = require('canvas-sketch-util/color'); | |
const { linspace, lerp } = require('canvas-sketch-util/math'); | |
const risoColors = require('riso-colors').map(h => h.hex).filter(c => { | |
const hex = Color.parse(c).hex.toLowerCase(); | |
return hex !== '#000000' && hex !== '#ffffff' | |
}); | |
const paperColors = require('paper-colors').map(h => h.hex); | |
const settings = { | |
dimensions: [ 2048, 2048 ], | |
}; | |
const sketch = ({ width, height, data }) => { | |
const { | |
seed = Random.getRandomSeed() | |
} = data; | |
const random = Random.createRandom(seed); | |
const { | |
background = 'tomato', | |
foreground = 'black', | |
thickness = 0.035, | |
// border = false, | |
border = Random.boolean(), | |
// thickness = random.range(0.025, 0.05), | |
margin = 0.1 | |
} = data; | |
const lines = []; | |
const dim = Math.min(width, height); | |
const clipMargin = dim * 0.0; | |
const marginPx = dim * margin; | |
const repeats = Random.rangeFloor(1, 4); | |
for (let i = 0; i < repeats; i++) { | |
let grid = []; | |
const gridSize = random.rangeFloor(2, 4); | |
for (let y = 0; y < gridSize; y++) { | |
for (let x = 0; x < gridSize; x++) { | |
const u = x / (gridSize - 1); | |
const v = y / (gridSize - 1); | |
const px = lerp(marginPx, width - marginPx, u); | |
const py = lerp(marginPx, height - marginPx, v); | |
grid.push([ px, py ]); | |
} | |
} | |
while (grid.length > 2) { | |
const count = Random.range(2, 4); | |
const points = random.shuffle(grid).slice(0, count); | |
grid = grid.filter(p => !points.includes(p)); | |
lines.push(points); | |
} | |
} | |
return ({ context }) => { | |
context.clearRect(0, 0, width, height); | |
context.fillStyle = background; | |
context.fillRect(clipMargin, clipMargin, width - clipMargin * 2, height - clipMargin * 2); | |
context.strokeStyle = foreground; | |
context.lineJoin = 'round'; | |
context.lineCap = 'round'; | |
context.lineWidth = dim * thickness; | |
if (border) { | |
context.strokeRect(marginPx, marginPx, width - marginPx * 2, height - marginPx * 2); | |
} | |
lines.forEach(line => { | |
context.beginPath(); | |
line.forEach(([ x, y ]) => context.lineTo(x, y)); | |
context.stroke(); | |
}); | |
}; | |
}; | |
function repeater (sketch, settings = {}) { | |
const gridSize = settings.gridSize || 4; | |
const dimensions = settings.dimensions || [ 2048, 2048 ]; | |
let margin = 0; | |
if ('marginNormalized' in settings) { | |
margin = settings.marginNormalized * Math.min(dimensions[0], dimensions[1]); | |
} else if ('margin' in settings) { | |
margin = settings.margin; | |
} | |
const background = settings.background; | |
const marginStroke = settings.marginStroke; | |
settings = { ...settings, dimensions }; | |
delete settings.margin; | |
delete settings.marginStroke; | |
delete settings.marginNormalized; | |
delete settings.gridSize; | |
delete settings.background; | |
canvasSketch(async ({ context, width, height }) => { | |
const sketches = []; | |
const cw = dimensions[0] / gridSize; | |
const ch = dimensions[1] / gridSize; | |
for (let y = 0; y < gridSize; y++) { | |
for (let x = 0; x < gridSize; x++) { | |
sketches.push({ | |
sketch, | |
x, | |
y, | |
size: [ cw, ch ], | |
position: [ x * cw, y * ch ] | |
}); | |
} | |
} | |
context.clearRect(0, 0, width, height); | |
if (background) { | |
context.fillStyle = background; | |
context.fillRect(0, 0, width, height); | |
} | |
// const hsl = Color.parse(background).hsl; | |
const mode = 'riso'; | |
await sketches.reduce(async (promise, data, i) => { | |
await promise; | |
// const base = Random.pick(paperColors); | |
const base = Random.pick(risoColors); | |
const baseSat = 50 + Random.gaussian(0, 5); | |
const baseLight = 50 + Random.gaussian(0, 10); | |
let hsl = mode === 'riso' | |
? Color.parse(base).hsl | |
: [ Random.range(0, 360), baseSat + Random.gaussian(0, 5), baseLight + Random.gaussian(0, 5) ]; | |
const [ h, s, l ] = hsl; | |
const foreground = Color.parse({ | |
hsl | |
}).hex; | |
const colorStep = 1 / sketches.length; | |
// const hue = h + colorStep * i * 360 + 45; | |
const colorOffsetAmount = 45; | |
const colorOffsets = new Array(360 / colorOffsetAmount).fill(0).map((_, i) => colorOffsetAmount * i); | |
const offset = Random.pick(colorOffsets); | |
const sketchBackground = mode === 'riso' | |
? Random.pick(risoColors.filter(c => c !== base)) | |
: Color.parse({ | |
hsl: [ h + offset + Random.gaussian(0, 20), s + Random.gaussian(0, 5), l + Random.gaussian(0, 5) ] | |
// hsl: [ h + 90, s, l ] | |
// hsl: [ h + 180 + lerp(0, 360, colorStep * i), 50, 50 ] | |
// hsl: [ h, lerp(25, 75, colorStep * i), 50 ] | |
}).hex; | |
const manager = await canvasSketch(data.sketch, { | |
data: { | |
...data, | |
...settings.data, | |
background: sketchBackground, | |
foreground | |
}, | |
parent: false, | |
dimensions: [ cw, ch ] | |
}); | |
draw(context, width, height, manager, data); | |
manager.unload(); | |
}, Promise.resolve()); | |
if (background && marginStroke) { | |
context.strokeStyle = background; | |
const borderThickness = margin; | |
for (let y = 0; y <= gridSize; y++) { | |
const v = y / gridSize; | |
context.beginPath(); | |
context.moveTo(0, v * height); | |
context.lineTo(width, v * height); | |
const borderScale = y === 0 || y === gridSize ? 2 : 1; | |
context.lineWidth = borderThickness * borderScale; | |
context.stroke(); | |
} | |
for (let x = 0; x <= gridSize; x++) { | |
const u = x / gridSize; | |
context.beginPath(); | |
context.moveTo(u * width, 0); | |
context.lineTo(u * width, height); | |
const borderScale = x === 0 || x === gridSize ? 2 : 1; | |
context.lineWidth = borderThickness * borderScale; | |
context.stroke(); | |
} | |
} | |
}, settings); | |
function draw (context, width, height, manager, data) { | |
const curMargin = marginStroke ? 0 : margin; | |
context.drawImage( | |
manager.props.canvas, | |
data.position[0] + curMargin, | |
data.position[1] + curMargin, | |
data.size[0] - curMargin * 2, | |
data.size[1] - curMargin * 2 | |
); | |
} | |
} | |
repeater(sketch, { | |
gridSize: Random.rangeFloor(2, 4), | |
background: 'white', | |
marginNormalized: 0.0, | |
marginStroke: false, | |
dimensions: [ 2048, 2048 ], | |
data: { | |
margin: Random.range(0.1, 0.3) | |
} | |
}); | |
function getColors () { | |
const background = Color.parse({ | |
hsl: [ Random.range(0, 360), 50, 50 ] | |
}).hex; | |
const [ h, s, l ] = Color.parse(background).hsl; | |
const foreground = Color.parse({ | |
hsl: [ h + 360 / 2, s, l ] | |
}).hex; | |
return { background, foreground }; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment