Created
May 22, 2024 08:24
-
-
Save mattdesl/d8b1f5fa26d3410218f0f38077add2ed to your computer and use it in GitHub Desktop.
quickly create a linear gradient in software in JS
This file contains 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
const worker = new Worker(new URL("./gradient.js", import.meta.url), { | |
type: "module", | |
}); | |
worker.postMessage({ | |
// image options | |
width: 128, | |
height: 256, | |
channels: 4, | |
depth: 8 | |
}); | |
worker.addEventListener("message", (ev) => { | |
// Get the typed array view of the resulting pixels | |
const pixels = ev.data; | |
console.log(pixels); | |
}); |
This file contains 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
/** | |
This is a WebWorker that quickly generates a 2D linear gradient image from a set of input params. | |
It is useful for testing, and for creating high bit-depth linear gradients. | |
This uses copyWithin() to expand the gradient across the entire array. | |
*/ | |
self.onmessage = async (msg) => { | |
const { width = 256, height = 256, depth = 8, channels = 4 } = msg.data; | |
const ArrType = depth === 16 ? Uint16Array : Uint8ClampedArray; | |
const maxValue = depth === 16 ? 0xffff : 0xff; | |
let data = new ArrType(width * height * channels).fill(maxValue); | |
const A = [1, 0, 0]; | |
const B = [0, 0, 1]; | |
for (let x = 0; x < width; x++) { | |
const u = width <= 1 ? 1 : x / (width - 1); | |
const [r, g, b] = lerpArray(A, B, u).map((n) => toByte(n)); | |
data[x * channels + 0] = r; | |
data[x * channels + 1] = g; | |
data[x * channels + 2] = b; | |
} | |
// quickly generate an image of expected size | |
for (let y = 1; y < height; y++) { | |
const x = 0; | |
const idx = x + y * width; | |
data.copyWithin(idx * channels, 0, width * channels); | |
} | |
self.postMessage(data); | |
function lerp(min, max, t) { | |
return min * (1 - t) + max * t; | |
} | |
function lerpArray(min, max, t, out = []) { | |
for (var i = 0; i < min.length; i++) { | |
out[i] = lerp(min[i], max[i], t); | |
} | |
return out; | |
} | |
function toByte(v) { | |
return Math.max(0, Math.min(maxValue, Math.round(v * maxValue))); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment