dssl / scripts /lib /pixels.mjs
EHS-Studio's picture
Claude Sonnet 5.5
v0.9.0: texture (30 presets), aura glow and particles, range sliders, lint, CSS import
39309b1
Raw History Blame Contribute Delete
1.19 kB
/* pixels.mjs: look at what a browser actually drew.
* const img = decodePng(await page.screenshot({ clip }))
* px(img, 10, 20) -> [r, g, b, a]
* stats(img, x, y, w, h) -> { mean:[r,g,b], variance, lit, n } (lit = pixels brighter than the floor)
*/
import { PNG } from 'pngjs';
export const decodePng = (buf) => PNG.sync.read(buf);
export const px = (img, x, y) => {
const i = (Math.round(y) * img.width + Math.round(x)) * 4;
return [img.data[i], img.data[i + 1], img.data[i + 2], img.data[i + 3]];
};
/** colour distance (0..441) */
export const dist = (a, b) => Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);
export function stats(img, x0, y0, w, h, floor = 40) {
let n = 0, lit = 0, sr = 0, sg = 0, sb = 0, ssq = 0;
for (let y = y0; y < y0 + h && y < img.height; y++) for (let x = x0; x < x0 + w && x < img.width; x++) {
const [r, g, b] = px(img, x, y);
n++; sr += r; sg += g; sb += b;
const l = (r + g + b) / 3;
ssq += l * l;
if (l > floor) lit++;
}
const mr = sr / n, mg = sg / n, mb = sb / n, ml = (mr + mg + mb) / 3;
return { mean: [mr, mg, mb].map((v) => Math.round(v)), variance: ssq / n - ml * ml, lit, n };
}