function proxy(draw, duration, options = {}) {
const {fps = 30, factor = 2, gamma = 2, caRange = .5} = options;
const preview = draw(0),
imageData = getImageData(preview),
data = imageData.data,
ctx = preview.cloneNode().getContext('2d'),
frames = Array.from({length: factor}, () => new Uint16Array(data.length));
const sum = new Uint32Array(data.length),
len = Math.ceil(duration / 1000 * fps * factor),
gammaInv = 1 / gamma,
s = 1 / factor;
return t => {
const i1 = Math.floor(t * len),
i0 = i1 - factor;
for(let i = i0; i < i1; i++) {
const d = getImageData(draw(i / len)).data;
const f = frames[i-i0];
for(let j = 0; j < d.length; j += 4) {
f[j ] = d[j ] ** gamma;
f[j+1] = d[j+1] ** gamma;
f[j+2] = d[j+2] ** gamma;
}
}
sum.fill(0);
for(let n = 0; n < frames.length; n++) {
const t = n / frames.length * (1 - caRange);
const nr = Math.floor(factor * (t + caRange * 1));
const ng = Math.floor(factor * (t + caRange * .5));
const nb = Math.floor(factor * (t + caRange * 0));
for(let i = 0; i < sum.length; i += 4) {
sum[i ] += frames[nr][i ];
sum[i+1] += frames[ng][i+1];
sum[i+2] += frames[nb][i+2];
}
}
for(let i = 0; i < data.length; i += 4) {
data[i ] = (sum[i ] * s) ** gammaInv;
data[i+1] = (sum[i+1] * s) ** gammaInv;
data[i+2] = (sum[i+2] * s) ** gammaInv;
}
ctx.putImageData(imageData, 0, 0);
return ctx.canvas;
};
}