Skip to content

Instantly share code, notes, and snippets.

@davo
Forked from mattdesl/spline-gradient.js
Created June 9, 2020 20:18
Show Gist options
  • Save davo/ba7061b58d8df615287f64b3ae786066 to your computer and use it in GitHub Desktop.
Save davo/ba7061b58d8df615287f64b3ae786066 to your computer and use it in GitHub Desktop.
global.THREE = require("three");
const canvasSketch = require('canvas-sketch');
const Random = require('canvas-sketch-util/random');
const gradientHeight = 512;
const settings = {
dimensions: [ 2048, gradientHeight * 2 ]
};
const sketch = (props) => {
return ({ context, width, height }) => {
context.fillStyle = 'white';
context.fillRect(0, 0, width, height);
// your stepped color data, to be filled in
const colorsAsHexList = [ /* '#ff0000' */ ];
const colorsAsLabList = [ /* [ 100, 0, 0 ] */ ];
const grd = context.createLinearGradient(0, 0, width, 0);
colorsAsHexList.forEach((hex, i, list) => {
const t = i / (list.length - 1);
grd.addColorStop(t, hex);
});
context.fillStyle = grd;
context.fillRect(0, 0, width, gradientHeight);
img = context.createImageData(width, gradientHeight);
// draw curve
const labPositions = colorsAsLabList.map(lab => {
return new THREE.Vector3().fromArray(lab);
});
const curve = new THREE.CatmullRomCurve3(labPositions);
curve.curveType = 'catmullrom';
// can play with tension to make sharper or softer gradients
curve.tension = 0.5;
// uncomment to make a seamless gradient that wraps around
// curve.closed = true;
const samples = getCurveDivisions(curve, img.width, false)
.map(p => p.toArray())
for (let y = 0; y < img.height; y++) {
for (let x = 0; x < img.width; x++) {
const i = x + y * img.width;
let Lab = labJitter(samples[x], 0.5);
// lab2rgb not implemented here
const [ R, G, B ] = YourColorConverter.lab2rgb(Lab);
img.data[i * 4 + 0] = R;
img.data[i * 4 + 1] = G;
img.data[i * 4 + 2] = B;
img.data[i * 4 + 3] = 255;
}
}
context.putImageData(img, 0, gradientHeight);
};
// Entirely optional, but as we are doing this per-pixel we may as well
// add subtle noise to reduce banding.
function labJitter (lab, s = 1) {
// fudged jittering in L*a*b* space
const lw = 100 / 200;
const K = 2.624;
const [ x, y, z ] = Random.insideSphere(Random.gaussian(0, s * K))
const [ L, a, b ] = lab;
return [ L + x * lw, a + y, b + z ];
}
function getCurveDivisions (curve, n, spaced = false) {
const points = [];
for (let i = 0; i < n; i++) {
const t = curve.closed ? (i / n) : (i / (n - 1));
let p = spaced ? curve.getPointAt(t) : curve.getPoint(t);
points.push(p);
}
return points;
}
};
canvasSketch(sketch, settings);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment