@ginden/blinkstick-v2
Version:
Improved Blickstick API for Node.js
86 lines • 3.14 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.wave = wave;
const complex_frame_1 = require("../frame/complex-frame");
const tsafe_1 = require("tsafe");
/**
* @summary Build wave effect
*
* @remarks Build wave effect by time-line stitching – this guarantees the overall
* duration is exactly:
* animationDuration + lagMs × (ledCount - 1)
* and avoids the subtle frame-cutting rules of
* `convertSimpleFramesToComplexFrame`.
* @experimental
* @category Animation
*/
function wave(animation, { fillWith = [0, 0, 0], ledCount, lagMs }) {
(0, tsafe_1.assert)(ledCount > 0, 'ledCount must be greater than 0');
(0, tsafe_1.assert)(lagMs >= 0, 'lagMs must be greater than or equal to 0');
const srcFrames = Array.isArray(animation)
? animation.slice()
: Array.from(animation);
if (srcFrames.length === 0) {
return [];
}
// Pre-compute cumulative end-times of the source animation (relative to its
// own start, i.e. LED-0).
const cumulativeEnds = [0];
for (const f of srcFrames)
cumulativeEnds.push(cumulativeEnds.at(-1) + f.duration);
// Collect every timestamp at which *any* LED may change colour.
const changeTs = [];
for (let led = 0; led < ledCount; led += 1) {
const offset = led * lagMs;
for (const t of cumulativeEnds)
changeTs.push(offset + t);
}
changeTs.sort((a, b) => a - b);
// de-dupe
const uniq = [];
for (const t of changeTs)
if (uniq[uniq.length - 1] !== t)
uniq.push(t);
// Helper: colour of given LED at (inclusive) time `t`.
function colourAt(led, t) {
const start = led * lagMs;
if (t < start)
return [...fillWith];
let rel = t - start;
for (const f of srcFrames) {
if (rel < f.duration)
return f.rgb;
rel -= f.duration;
}
return srcFrames[srcFrames.length - 1].rgb;
}
return {
*[Symbol.iterator]() {
const MIN_MS = 10; // do not emit frames shorter than this
let prev = null;
for (let i = 0; i < uniq.length - 1; i += 1) {
const start = uniq[i];
const end = uniq[i + 1];
const duration = end - start;
const colours = Array.from({ length: ledCount }, (_, led) => colourAt(led, start));
const frame = new complex_frame_1.ComplexFrame(colours, duration);
if (!prev) {
prev = frame;
continue;
}
if (frame.duration < MIN_MS) {
// Merge very short slice into previous frame to avoid excessive FPS.
prev.duration += frame.duration;
continue;
}
// Emit previous frame now that we know the current one is long enough.
yield prev;
prev = frame;
}
if (prev) {
yield prev;
}
},
};
}
//# sourceMappingURL=wave.js.map