workerScript = {
const blob = new Blob([`
// Just a dumb fade + hue shift effect, to demonstrate processing this in a worker
// Using a Uint16Array to reduce rounding errors (shown as colors that never fade out)
let fadeArr = new Uint16Array(0);
onmessage = event => {
// rgba has been transferred
const {data: {rgba}} = event;
// dynamically adjust fadeArr to webcam dimensions
if (fadeArr.length !== rgba.length) {
// Initiate fadeArr with first frame
fadeArr = Uint16Array.from(rgba);
// we start with white to also ensure that opacity is 100%
fadeArr.fill(0xFFFF);
}
// update fade (which is not transferred back)
for(let i = 0; i < rgba.length;) {
// Trick to convert 8-bit value to 16-bit square value.
// value between 1-256, so in range notation: [0x01,0x100]
let r = (rgba[i] + 1);
// convert to fit precisely in 16 bits:
// [0x01 * 0x01, 0x100 * 0x100] = [0x1, 0x1000]
// [0x1, 0x1000] - 1 = [0x00, 0xFFFF]
r = r*r - 1;
// Take a slow average of the frame
const shift = 6;
let fade = fadeArr[i];
fade = (fade << shift) - fade; // faster than multiplication
fadeArr[i++] = (fade + r) >>> shift;
// repeat for green and blue channels
let g = (rgba[i] + 1);
g = g*g - 1;
fade = fadeArr[i];
fade = (fade << shift) - fade; // faster than multiplication
fadeArr[i++] = (fade + g) >>> shift;
let b = (rgba[i] + 1);
b = b*b - 1;
fade = fadeArr[i];
fade = (fade << shift) - fade; // faster than multiplication
fadeArr[i++] = (fade + b) >>> shift;
i++; // skip opacity, which is 100% anyway
}
for(let i = 0; i < rgba.length;) {
let r = fadeArr[i];
let g = fadeArr[i+1];
let b = fadeArr[i+2];
// Hue-shift, then reverse the whole squaring thing from before
rgba[i++] = Math.sqrt((g+b+2)>>>1) & 0xFF;
rgba[i++] = Math.sqrt((r+b+2)>>>1) & 0xFF;
rgba[i++] = Math.sqrt((g+r+2)>>>1) & 0xFF;
i++; // skipping opacity again
}
// Transfer the rgba array back, avoiding another allocation
postMessage({rgba}, [rgba.buffer]);
};
`], {type: "text/javascript"});
const script = URL.createObjectURL(blob);
invalidation.then(() => URL.revokeObjectURL(script));
return script;
}