Skip to content

Instantly share code, notes, and snippets.

@mattdesl
Created January 2, 2024 17:11
Show Gist options
  • Save mattdesl/5d8549e614872ded7a03f5623021a0b0 to your computer and use it in GitHub Desktop.
Save mattdesl/5d8549e614872ded7a03f5623021a0b0 to your computer and use it in GitHub Desktop.
MIT license, messy genuary2024 code... "no palettes"
import canvasSketch from "canvas-sketch";
import { degToRad, linspace, radToDeg } from "canvas-sketch-util/math";
import { Lch, contrastRatio } from "../util/color";
import polyBool from "poly-bool";
import * as random from "canvas-sketch-util/random";
import { angleLerp } from "../util/angle";
export const settings = {
suffix: random.getSeed(),
animate: true,
fps: 2,
playbackRate: "throttle",
dimensions: [2048, 2048],
};
const background = "#e9e3d5";
export const sketch = () => {
let { points, altColor } = generate();
function generate() {
let attempts = 0;
const maxAttempts = 10000;
const targetMinRatio = 1.25;
const targetMaxRatio = 4;
let points,
altColor,
minRatio = 0,
maxRatio = 0;
do {
// const off = Math.SQRT1_2 / 4 / 2;
// const uvs = [
// [0.5 - off, 0.5 - off],
// [0.5 + off, 0.5 + off],
// ]
const off = random.gaussian(0, 0.05);
const [ox, oy] = random.onCircle(0.1);
const uvs = [
[0.5 - ox, 0.5 - oy],
[0.5 + ox, 0.5 + oy],
];
points = uvs.map((position) => {
const chroma = random.range(0, 40);
const light = random.range(0, 100);
const lch = [light, chroma, random.range(0, 360)];
return {
position,
lch,
color: Lch(...lch),
};
});
const [lchA, lchB] = points.map((c) => c.lch);
const l = (lchA[0] + lchB[0]) / 2;
const c = (lchA[1] + lchB[1]) / 2;
const h = radToDeg(angleLerp(degToRad(lchA[2]), degToRad(lchB[2]), 0.5));
altColor = Lch(l, c, h);
const [colorA, colorB] = points.map((c) => c.color);
const r0 = contrastRatio(colorA, colorB);
const r1 = contrastRatio(colorA, altColor);
const r2 = contrastRatio(colorB, altColor);
const r3 = contrastRatio(colorA, background);
const r4 = contrastRatio(colorB, background);
minRatio = Math.min(r0, r1, r2, r3, r4);
maxRatio = Math.max(r0, r1, r2, r3, r4);
} while (
attempts++ < maxAttempts &&
(maxRatio > targetMaxRatio || minRatio < targetMinRatio)
);
return { points, altColor };
}
return ({ context, width, height }) => {
context.fillStyle = background;
context.fillRect(0, 0, width, height);
const { points, altColor } = generate();
const dim = Math.min(width, height);
const radius = dim * 0.25;
const polygons = points.map(({ position, color }, i) => {
const [u, v] = position;
const x = u * width;
const y = v * height;
const startAngle =
random.gaussian(0, Math.PI * 0.5) * 0 +
(i / points.length) * Math.PI * 0.5;
const steps = 4;
return {
color,
path: linspace(steps).map((t) => {
const angle = t * Math.PI * 2 + startAngle;
return [x + Math.cos(angle) * radius, y + Math.sin(angle) * radius];
}),
};
});
const result = polyBool(polygons[0].path, polygons[1].path, "and");
const shapes = [...polygons, { path: result[0], color: altColor }];
shapes.forEach((shape) => {
context.beginPath();
shape.path.forEach((p) => context.lineTo(...p));
context.closePath();
context.fillStyle = shape.color;
context.fill();
});
};
};
export default function generate(opts = {}) {
return canvasSketch(sketch, {
...settings,
...opts,
});
}
if (typeof window["canvas-sketch-cli"] !== "undefined") {
generate();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment