diff --git a/scripts/watch.mjs b/scripts/watch.mjs index d043d90..6ff9290 100644 --- a/scripts/watch.mjs +++ b/scripts/watch.mjs @@ -48,8 +48,10 @@ export const sampleTimes = (from, duration, frames) => export const frameName = (index, at) => `${String(index).padStart(2, '0')}-t${at.toFixed(1)}s.jpg`; +/** Columns from the frame count, so a 4-frame sheet is 2x2 instead of 3x2 with two black cells + * that read like failed frames. */ export function tileGrid(count) { - const columns = Math.min(3, Math.max(1, count)); + const columns = Math.min(3, Math.max(1, Math.ceil(Math.sqrt(count)))); return { columns, rows: Math.ceil(count / columns) }; } diff --git a/tests/watch.spec.mjs b/tests/watch.spec.mjs index 47a0a4f..990b9a5 100644 --- a/tests/watch.spec.mjs +++ b/tests/watch.spec.mjs @@ -28,9 +28,12 @@ test('sampleTimes centres one frame in each cell and spans the segment', () => { assert.ok(sampleTimes(10, 90, 12).every(at => at > 10 && at < 100)); }); -test('tileGrid never leaves an empty trailing cell row', () => { +test('tileGrid keeps at most one blank cell, so a blank reads as padding not a lost frame', () => { assert.deepEqual(tileGrid(1), { columns: 1, rows: 1 }); + assert.deepEqual(tileGrid(2), { columns: 2, rows: 1 }); + assert.deepEqual(tileGrid(4), { columns: 2, rows: 2 }); assert.deepEqual(tileGrid(5), { columns: 3, rows: 2 }); + assert.deepEqual(tileGrid(6), { columns: 3, rows: 2 }); assert.deepEqual(tileGrid(12), { columns: 3, rows: 4 }); });